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
43 return isActivityPubUrlValid(video.id) &&
44 isVideoNameValid(video.name) &&
45 isActivityPubVideoDurationValid(video.duration) &&
46 isUUIDValid(video.uuid) &&
47 (!video.category || isRemoteNumberIdentifierValid(video.category)) &&
48 (!video.licence || isRemoteNumberIdentifierValid(video.licence)) &&
49 (!video.language || isRemoteStringIdentifierValid(video.language)) &&
50 isVideoViewsValid(video.views) &&
51 isBooleanValid(video.sensitive) &&
52 isBooleanValid(video.commentsEnabled) &&
53 isDateValid(video.published) &&
54 isDateValid(video.updated) &&
55 (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) &&
56 isRemoteVideoIconValid(video.icon) &&
57 video.url.length !== 0 &&
58 video.attributedTo.length !== 0
61 function isRemoteVideoUrlValid (url: any) {
62 // FIXME: Old bug, we used the width to represent the resolution. Remove it in a few release (currently beta.11)
63 if (url.width && !url.height) url.height = url.width
65 return url.type === 'Link' &&
67 // TODO: remove mimeType (backward compatibility, introduced in v1.1.0)
68 ACTIVITY_PUB.URL_MIME_TYPES.VIDEO.indexOf(url.mediaType || url.mimeType) !== -1 &&
69 isActivityPubUrlValid(url.href) &&
70 validator.isInt(url.height + '', { min: 0 }) &&
71 validator.isInt(url.size + '', { min: 0 }) &&
72 (!url.fps || validator.isInt(url.fps + '', { min: -1 }))
75 ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.indexOf(url.mediaType || url.mimeType) !== -1 &&
76 isActivityPubUrlValid(url.href) &&
77 validator.isInt(url.height + '', { min: 0 })
80 ACTIVITY_PUB.URL_MIME_TYPES.MAGNET.indexOf(url.mediaType || url.mimeType) !== -1 &&
81 validator.isLength(url.href, { min: 5 }) &&
82 validator.isInt(url.height + '', { min: 0 })
85 (url.mediaType || url.mimeType) === 'application/x-mpegURL' &&
86 isActivityPubUrlValid(url.href) &&
91 // ---------------------------------------------------------------------------
94 sanitizeAndCheckVideoTorrentUpdateActivity,
95 isRemoteStringIdentifierValid,
96 sanitizeAndCheckVideoTorrentObject,
100 // ---------------------------------------------------------------------------
102 function setValidRemoteTags (video: any) {
103 if (Array.isArray(video.tag) === false) return false
105 video.tag = video.tag.filter(t => {
106 return t.type === 'Hashtag' &&
107 isVideoTagValid(t.name)
113 function setValidRemoteCaptions (video: any) {
114 if (!video.subtitleLanguage) video.subtitleLanguage = []
116 if (Array.isArray(video.subtitleLanguage) === false) return false
118 video.subtitleLanguage = video.subtitleLanguage.filter(caption => {
119 return isRemoteStringIdentifierValid(caption)
125 function isRemoteNumberIdentifierValid (data: any) {
126 return validator.isInt(data.identifier, { min: 0 })
129 function isRemoteStringIdentifierValid (data: any) {
130 return typeof data.identifier === 'string'
133 function isRemoteVideoContentValid (mediaType: string, content: string) {
134 return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content)
137 function isRemoteVideoIconValid (icon: any) {
138 return icon.type === 'Image' &&
139 isActivityPubUrlValid(icon.url) &&
140 icon.mediaType === 'image/jpeg' &&
141 validator.isInt(icon.width + '', { min: 0 }) &&
142 validator.isInt(icon.height + '', { min: 0 })
145 function setValidRemoteVideoUrls (video: any) {
146 if (Array.isArray(video.url) === false) return false
148 video.url = video.url.filter(u => isRemoteVideoUrlValid(u))
153 function setRemoteVideoTruncatedContent (video: any) {
155 video.content = peertubeTruncate(video.content, CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max)