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'
6 isVideoAbuseReasonValid,
11 isVideoTruncatedDescriptionValid,
14 import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc'
15 import { VideoState } from '../../../../shared/models/videos'
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.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 // ---------------------------------------------------------------------------
81 sanitizeAndCheckVideoTorrentCreateActivity,
82 sanitizeAndCheckVideoTorrentUpdateActivity,
83 isVideoTorrentDeleteActivityValid,
84 isRemoteStringIdentifierValid,
86 sanitizeAndCheckVideoTorrentObject
89 // ---------------------------------------------------------------------------
91 function setValidRemoteTags (video: any) {
92 if (Array.isArray(video.tag) === false) return false
94 video.tag = video.tag.filter(t => {
95 return t.type === 'Hashtag' &&
96 isVideoTagValid(t.name)
102 function setValidRemoteCaptions (video: any) {
103 if (!video.subtitleLanguage) video.subtitleLanguage = []
105 if (Array.isArray(video.subtitleLanguage) === false) return false
107 video.subtitleLanguage = video.subtitleLanguage.filter(caption => {
108 return isRemoteStringIdentifierValid(caption)
114 function isRemoteNumberIdentifierValid (data: any) {
115 return validator.isInt(data.identifier, { min: 0 })
118 function isRemoteStringIdentifierValid (data: any) {
119 return typeof data.identifier === 'string'
122 function isRemoteVideoContentValid (mediaType: string, content: string) {
123 return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content)
126 function isRemoteVideoIconValid (icon: any) {
127 return icon.type === 'Image' &&
128 isActivityPubUrlValid(icon.url) &&
129 icon.mediaType === 'image/jpeg' &&
130 validator.isInt(icon.width + '', { min: 0 }) &&
131 validator.isInt(icon.height + '', { min: 0 })
134 function setValidRemoteVideoUrls (video: any) {
135 if (Array.isArray(video.url) === false) return false
137 video.url = video.url.filter(u => isRemoteVideoUrlValid(u))
142 function setRemoteVideoTruncatedContent (video: any) {
144 video.content = peertubeTruncate(video.content, CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max)
150 function isRemoteVideoUrlValid (url: any) {
151 return url.type === 'Link' &&
153 ACTIVITY_PUB.URL_MIME_TYPES.VIDEO.indexOf(url.mimeType) !== -1 &&
154 isActivityPubUrlValid(url.href) &&
155 validator.isInt(url.width + '', { min: 0 }) &&
156 validator.isInt(url.size + '', { min: 0 })
159 ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.indexOf(url.mimeType) !== -1 &&
160 isActivityPubUrlValid(url.href) &&
161 validator.isInt(url.width + '', { min: 0 })
164 ACTIVITY_PUB.URL_MIME_TYPES.MAGNET.indexOf(url.mimeType) !== -1 &&
165 validator.isLength(url.href, { min: 5 }) &&
166 validator.isInt(url.width + '', { min: 0 })