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 // ---------------------------------------------------------------------------
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 // FIXME: Old bug, we used the width to represent the resolution. Remove it in a few realease (currently beta.11)
152 if (url.width && !url.height) url.height = url.width
154 return url.type === 'Link' &&
156 ACTIVITY_PUB.URL_MIME_TYPES.VIDEO.indexOf(url.mimeType) !== -1 &&
157 isActivityPubUrlValid(url.href) &&
158 validator.isInt(url.height + '', { min: 0 }) &&
159 validator.isInt(url.size + '', { min: 0 }) &&
160 (!url.fps || validator.isInt(url.fps + '', { min: 0 }))
163 ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.indexOf(url.mimeType) !== -1 &&
164 isActivityPubUrlValid(url.href) &&
165 validator.isInt(url.height + '', { min: 0 })
168 ACTIVITY_PUB.URL_MIME_TYPES.MAGNET.indexOf(url.mimeType) !== -1 &&
169 validator.isLength(url.href, { min: 5 }) &&
170 validator.isInt(url.height + '', { min: 0 })