1 import * as validator from 'validator'
2 import { ACTIVITY_PUB, CONSTRAINTS_FIELDS } from '../../../initializers'
3 import { peertubeTruncate } from '../../core-utils'
4 import { exists, isArray, isBooleanValid, isDateValid, isUUIDValid } from '../misc'
10 isVideoTruncatedDescriptionValid,
13 import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc'
14 import { VideoState } from '../../../../shared/models/videos'
16 function sanitizeAndCheckVideoTorrentUpdateActivity (activity: any) {
17 return isBaseActivityValid(activity, 'Update') &&
18 sanitizeAndCheckVideoTorrentObject(activity.object)
21 function isActivityPubVideoDurationValid (value: string) {
22 // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
23 return exists(value) &&
24 typeof value === 'string' &&
25 value.startsWith('PT') &&
26 value.endsWith('S') &&
27 isVideoDurationValid(value.replace(/[^0-9]+/g, ''))
30 function sanitizeAndCheckVideoTorrentObject (video: any) {
31 if (!video || video.type !== 'Video') return false
33 if (!setValidRemoteTags(video)) return false
34 if (!setValidRemoteVideoUrls(video)) return false
35 if (!setRemoteVideoTruncatedContent(video)) return false
36 if (!setValidAttributedTo(video)) return false
37 if (!setValidRemoteCaptions(video)) return false
40 if (!isVideoStateValid(video.state)) video.state = VideoState.PUBLISHED
41 if (!isBooleanValid(video.waitTranscoding)) video.waitTranscoding = false
42 if (!isBooleanValid(video.downloadEnabled)) video.downloadEnabled = true
44 return isActivityPubUrlValid(video.id) &&
45 isVideoNameValid(video.name) &&
46 isActivityPubVideoDurationValid(video.duration) &&
47 isUUIDValid(video.uuid) &&
48 (!video.category || isRemoteNumberIdentifierValid(video.category)) &&
49 (!video.licence || isRemoteNumberIdentifierValid(video.licence)) &&
50 (!video.language || isRemoteStringIdentifierValid(video.language)) &&
51 isVideoViewsValid(video.views) &&
52 isBooleanValid(video.sensitive) &&
53 isBooleanValid(video.commentsEnabled) &&
54 isBooleanValid(video.downloadEnabled) &&
55 isDateValid(video.published) &&
56 isDateValid(video.updated) &&
57 (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) &&
58 isRemoteVideoIconValid(video.icon) &&
59 video.url.length !== 0 &&
60 video.attributedTo.length !== 0
63 function isRemoteVideoUrlValid (url: any) {
64 // FIXME: Old bug, we used the width to represent the resolution. Remove it in a few release (currently beta.11)
65 if (url.width && !url.height) url.height = url.width
67 return url.type === 'Link' &&
69 // TODO: remove mimeType (backward compatibility, introduced in v1.1.0)
70 ACTIVITY_PUB.URL_MIME_TYPES.VIDEO.indexOf(url.mediaType || url.mimeType) !== -1 &&
71 isActivityPubUrlValid(url.href) &&
72 validator.isInt(url.height + '', { min: 0 }) &&
73 validator.isInt(url.size + '', { min: 0 }) &&
74 (!url.fps || validator.isInt(url.fps + '', { min: -1 }))
77 ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.indexOf(url.mediaType || url.mimeType) !== -1 &&
78 isActivityPubUrlValid(url.href) &&
79 validator.isInt(url.height + '', { min: 0 })
82 ACTIVITY_PUB.URL_MIME_TYPES.MAGNET.indexOf(url.mediaType || url.mimeType) !== -1 &&
83 validator.isLength(url.href, { min: 5 }) &&
84 validator.isInt(url.height + '', { min: 0 })
87 (url.mediaType || url.mimeType) === 'application/x-mpegURL' &&
88 isActivityPubUrlValid(url.href) &&
93 // ---------------------------------------------------------------------------
96 sanitizeAndCheckVideoTorrentUpdateActivity,
97 isRemoteStringIdentifierValid,
98 sanitizeAndCheckVideoTorrentObject,
102 // ---------------------------------------------------------------------------
104 function setValidRemoteTags (video: any) {
105 if (Array.isArray(video.tag) === false) return false
107 video.tag = video.tag.filter(t => {
108 return t.type === 'Hashtag' &&
109 isVideoTagValid(t.name)
115 function setValidRemoteCaptions (video: any) {
116 if (!video.subtitleLanguage) video.subtitleLanguage = []
118 if (Array.isArray(video.subtitleLanguage) === false) return false
120 video.subtitleLanguage = video.subtitleLanguage.filter(caption => {
121 return isRemoteStringIdentifierValid(caption)
127 function isRemoteNumberIdentifierValid (data: any) {
128 return validator.isInt(data.identifier, { min: 0 })
131 function isRemoteStringIdentifierValid (data: any) {
132 return typeof data.identifier === 'string'
135 function isRemoteVideoContentValid (mediaType: string, content: string) {
136 return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content)
139 function isRemoteVideoIconValid (icon: any) {
140 return icon.type === 'Image' &&
141 isActivityPubUrlValid(icon.url) &&
142 icon.mediaType === 'image/jpeg' &&
143 validator.isInt(icon.width + '', { min: 0 }) &&
144 validator.isInt(icon.height + '', { min: 0 })
147 function setValidRemoteVideoUrls (video: any) {
148 if (Array.isArray(video.url) === false) return false
150 video.url = video.url.filter(u => isRemoteVideoUrlValid(u))
155 function setRemoteVideoTruncatedContent (video: any) {
157 video.content = peertubeTruncate(video.content, CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max)