1 import * as validator from 'validator'
2 import { ACTIVITY_PUB, CONSTRAINTS_FIELDS } from '../../../initializers'
3 import { peertubeTruncate } from '../../core-utils'
4 import { exists, isBooleanValid, isDateValid, isUUIDValid } from '../misc'
10 isVideoTruncatedDescriptionValid,
13 import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc'
14 import { VideoState } from '../../../../shared/models/videos'
15 import { isVideoAbuseReasonValid } from '../video-abuses'
17 function sanitizeAndCheckVideoTorrentCreateActivity (activity: any) {
18 return isBaseActivityValid(activity, 'Create') &&
19 sanitizeAndCheckVideoTorrentObject(activity.object)
22 function sanitizeAndCheckVideoTorrentUpdateActivity (activity: any) {
23 return isBaseActivityValid(activity, 'Update') &&
24 sanitizeAndCheckVideoTorrentObject(activity.object)
27 function isVideoTorrentDeleteActivityValid (activity: any) {
28 return isBaseActivityValid(activity, 'Delete')
31 function isVideoFlagValid (activity: any) {
32 return isBaseActivityValid(activity, 'Create') &&
33 activity.object.type === 'Flag' &&
34 isVideoAbuseReasonValid(activity.object.content) &&
35 isActivityPubUrlValid(activity.object.object)
38 function isActivityPubVideoDurationValid (value: string) {
39 // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
40 return exists(value) &&
41 typeof value === 'string' &&
42 value.startsWith('PT') &&
43 value.endsWith('S') &&
44 isVideoDurationValid(value.replace(/[^0-9]+/g, ''))
47 function sanitizeAndCheckVideoTorrentObject (video: any) {
48 if (!video || video.type !== 'Video') return false
50 if (!setValidRemoteTags(video)) return false
51 if (!setValidRemoteVideoUrls(video)) return false
52 if (!setRemoteVideoTruncatedContent(video)) return false
53 if (!setValidAttributedTo(video)) return false
54 if (!setValidRemoteCaptions(video)) return false
57 if (!isVideoStateValid(video.state)) video.state = VideoState.PUBLISHED
58 if (!isBooleanValid(video.waitTranscoding)) video.waitTranscoding = false
60 return isActivityPubUrlValid(video.id) &&
61 isVideoNameValid(video.name) &&
62 isActivityPubVideoDurationValid(video.duration) &&
63 isUUIDValid(video.uuid) &&
64 (!video.category || isRemoteNumberIdentifierValid(video.category)) &&
65 (!video.licence || isRemoteNumberIdentifierValid(video.licence)) &&
66 (!video.language || isRemoteStringIdentifierValid(video.language)) &&
67 isVideoViewsValid(video.views) &&
68 isBooleanValid(video.sensitive) &&
69 isBooleanValid(video.commentsEnabled) &&
70 isDateValid(video.published) &&
71 isDateValid(video.updated) &&
72 (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) &&
73 isRemoteVideoIconValid(video.icon) &&
74 video.url.length !== 0 &&
75 video.attributedTo.length !== 0
78 function isRemoteVideoUrlValid (url: any) {
79 // FIXME: Old bug, we used the width to represent the resolution. Remove it in a few release (currently beta.11)
80 if (url.width && !url.height) url.height = url.width
82 return url.type === 'Link' &&
84 // TODO: remove mimeType (backward compatibility, introduced in v1.1.0)
85 ACTIVITY_PUB.URL_MIME_TYPES.VIDEO.indexOf(url.mediaType || url.mimeType) !== -1 &&
86 isActivityPubUrlValid(url.href) &&
87 validator.isInt(url.height + '', { min: 0 }) &&
88 validator.isInt(url.size + '', { min: 0 }) &&
89 (!url.fps || validator.isInt(url.fps + '', { min: -1 }))
92 ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.indexOf(url.mediaType || url.mimeType) !== -1 &&
93 isActivityPubUrlValid(url.href) &&
94 validator.isInt(url.height + '', { min: 0 })
97 ACTIVITY_PUB.URL_MIME_TYPES.MAGNET.indexOf(url.mediaType || url.mimeType) !== -1 &&
98 validator.isLength(url.href, { min: 5 }) &&
99 validator.isInt(url.height + '', { min: 0 })
103 // ---------------------------------------------------------------------------
106 sanitizeAndCheckVideoTorrentCreateActivity,
107 sanitizeAndCheckVideoTorrentUpdateActivity,
108 isVideoTorrentDeleteActivityValid,
109 isRemoteStringIdentifierValid,
111 sanitizeAndCheckVideoTorrentObject,
112 isRemoteVideoUrlValid
115 // ---------------------------------------------------------------------------
117 function setValidRemoteTags (video: any) {
118 if (Array.isArray(video.tag) === false) return false
120 video.tag = video.tag.filter(t => {
121 return t.type === 'Hashtag' &&
122 isVideoTagValid(t.name)
128 function setValidRemoteCaptions (video: any) {
129 if (!video.subtitleLanguage) video.subtitleLanguage = []
131 if (Array.isArray(video.subtitleLanguage) === false) return false
133 video.subtitleLanguage = video.subtitleLanguage.filter(caption => {
134 return isRemoteStringIdentifierValid(caption)
140 function isRemoteNumberIdentifierValid (data: any) {
141 return validator.isInt(data.identifier, { min: 0 })
144 function isRemoteStringIdentifierValid (data: any) {
145 return typeof data.identifier === 'string'
148 function isRemoteVideoContentValid (mediaType: string, content: string) {
149 return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content)
152 function isRemoteVideoIconValid (icon: any) {
153 return icon.type === 'Image' &&
154 isActivityPubUrlValid(icon.url) &&
155 icon.mediaType === 'image/jpeg' &&
156 validator.isInt(icon.width + '', { min: 0 }) &&
157 validator.isInt(icon.height + '', { min: 0 })
160 function setValidRemoteVideoUrls (video: any) {
161 if (Array.isArray(video.url) === false) return false
163 video.url = video.url.filter(u => isRemoteVideoUrlValid(u))
168 function setRemoteVideoTruncatedContent (video: any) {
170 video.content = peertubeTruncate(video.content, CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max)