1 import * as validator from 'validator'
2 import { ACTIVITY_PUB, CONSTRAINTS_FIELDS } from '../../../initializers/constants'
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.originallyPublishedAt || isDateValid(video.originallyPublishedAt)) &&
58 (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) &&
59 isRemoteVideoIconValid(video.icon) &&
60 video.url.length !== 0 &&
61 video.attributedTo.length !== 0
64 function isRemoteVideoUrlValid (url: any) {
65 // FIXME: Old bug, we used the width to represent the resolution. Remove it in a few release (currently beta.11)
66 if (url.width && !url.height) url.height = url.width
68 return url.type === 'Link' &&
70 // TODO: remove mimeType (backward compatibility, introduced in v1.1.0)
71 ACTIVITY_PUB.URL_MIME_TYPES.VIDEO.indexOf(url.mediaType || url.mimeType) !== -1 &&
72 isActivityPubUrlValid(url.href) &&
73 validator.isInt(url.height + '', { min: 0 }) &&
74 validator.isInt(url.size + '', { min: 0 }) &&
75 (!url.fps || validator.isInt(url.fps + '', { min: -1 }))
78 ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.indexOf(url.mediaType || url.mimeType) !== -1 &&
79 isActivityPubUrlValid(url.href) &&
80 validator.isInt(url.height + '', { min: 0 })
83 ACTIVITY_PUB.URL_MIME_TYPES.MAGNET.indexOf(url.mediaType || url.mimeType) !== -1 &&
84 validator.isLength(url.href, { min: 5 }) &&
85 validator.isInt(url.height + '', { min: 0 })
88 (url.mediaType || url.mimeType) === 'application/x-mpegURL' &&
89 isActivityPubUrlValid(url.href) &&
94 // ---------------------------------------------------------------------------
97 sanitizeAndCheckVideoTorrentUpdateActivity,
98 isRemoteStringIdentifierValid,
99 sanitizeAndCheckVideoTorrentObject,
100 isRemoteVideoUrlValid
103 // ---------------------------------------------------------------------------
105 function setValidRemoteTags (video: any) {
106 if (Array.isArray(video.tag) === false) return false
108 video.tag = video.tag.filter(t => {
109 return t.type === 'Hashtag' &&
110 isVideoTagValid(t.name)
116 function setValidRemoteCaptions (video: any) {
117 if (!video.subtitleLanguage) video.subtitleLanguage = []
119 if (Array.isArray(video.subtitleLanguage) === false) return false
121 video.subtitleLanguage = video.subtitleLanguage.filter(caption => {
122 return isRemoteStringIdentifierValid(caption)
128 function isRemoteNumberIdentifierValid (data: any) {
129 return validator.isInt(data.identifier, { min: 0 })
132 function isRemoteStringIdentifierValid (data: any) {
133 return typeof data.identifier === 'string'
136 function isRemoteVideoContentValid (mediaType: string, content: string) {
137 return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content)
140 function isRemoteVideoIconValid (icon: any) {
141 return icon.type === 'Image' &&
142 isActivityPubUrlValid(icon.url) &&
143 icon.mediaType === 'image/jpeg' &&
144 validator.isInt(icon.width + '', { min: 0 }) &&
145 validator.isInt(icon.height + '', { min: 0 })
148 function setValidRemoteVideoUrls (video: any) {
149 if (Array.isArray(video.url) === false) return false
151 video.url = video.url.filter(u => isRemoteVideoUrlValid(u))
156 function setRemoteVideoTruncatedContent (video: any) {
158 video.content = peertubeTruncate(video.content, CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max)