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
59 if (!isBooleanValid(video.downloadingEnabled)) video.downloadingEnabled = true
61 return isActivityPubUrlValid(video.id) &&
62 isVideoNameValid(video.name) &&
63 isActivityPubVideoDurationValid(video.duration) &&
64 isUUIDValid(video.uuid) &&
65 (!video.category || isRemoteNumberIdentifierValid(video.category)) &&
66 (!video.licence || isRemoteNumberIdentifierValid(video.licence)) &&
67 (!video.language || isRemoteStringIdentifierValid(video.language)) &&
68 isVideoViewsValid(video.views) &&
69 isBooleanValid(video.sensitive) &&
70 isBooleanValid(video.commentsEnabled) &&
71 isBooleanValid(video.downloadingEnabled) &&
72 isDateValid(video.published) &&
73 isDateValid(video.updated) &&
74 (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) &&
75 isRemoteVideoIconValid(video.icon) &&
76 video.url.length !== 0 &&
77 video.attributedTo.length !== 0
80 function isRemoteVideoUrlValid (url: any) {
81 // FIXME: Old bug, we used the width to represent the resolution. Remove it in a few release (currently beta.11)
82 if (url.width && !url.height) url.height = url.width
84 return url.type === 'Link' &&
86 ACTIVITY_PUB.URL_MIME_TYPES.VIDEO.indexOf(url.mimeType) !== -1 &&
87 isActivityPubUrlValid(url.href) &&
88 validator.isInt(url.height + '', { min: 0 }) &&
89 validator.isInt(url.size + '', { min: 0 }) &&
90 (!url.fps || validator.isInt(url.fps + '', { min: -1 }))
93 ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.indexOf(url.mimeType) !== -1 &&
94 isActivityPubUrlValid(url.href) &&
95 validator.isInt(url.height + '', { min: 0 })
98 ACTIVITY_PUB.URL_MIME_TYPES.MAGNET.indexOf(url.mimeType) !== -1 &&
99 validator.isLength(url.href, { min: 5 }) &&
100 validator.isInt(url.height + '', { min: 0 })
104 // ---------------------------------------------------------------------------
107 sanitizeAndCheckVideoTorrentCreateActivity,
108 sanitizeAndCheckVideoTorrentUpdateActivity,
109 isVideoTorrentDeleteActivityValid,
110 isRemoteStringIdentifierValid,
112 sanitizeAndCheckVideoTorrentObject,
113 isRemoteVideoUrlValid
116 // ---------------------------------------------------------------------------
118 function setValidRemoteTags (video: any) {
119 if (Array.isArray(video.tag) === false) return false
121 video.tag = video.tag.filter(t => {
122 return t.type === 'Hashtag' &&
123 isVideoTagValid(t.name)
129 function setValidRemoteCaptions (video: any) {
130 if (!video.subtitleLanguage) video.subtitleLanguage = []
132 if (Array.isArray(video.subtitleLanguage) === false) return false
134 video.subtitleLanguage = video.subtitleLanguage.filter(caption => {
135 return isRemoteStringIdentifierValid(caption)
141 function isRemoteNumberIdentifierValid (data: any) {
142 return validator.isInt(data.identifier, { min: 0 })
145 function isRemoteStringIdentifierValid (data: any) {
146 return typeof data.identifier === 'string'
149 function isRemoteVideoContentValid (mediaType: string, content: string) {
150 return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content)
153 function isRemoteVideoIconValid (icon: any) {
154 return icon.type === 'Image' &&
155 isActivityPubUrlValid(icon.url) &&
156 icon.mediaType === 'image/jpeg' &&
157 validator.isInt(icon.width + '', { min: 0 }) &&
158 validator.isInt(icon.height + '', { min: 0 })
161 function setValidRemoteVideoUrls (video: any) {
162 if (Array.isArray(video.url) === false) return false
164 video.url = video.url.filter(u => isRemoteVideoUrlValid(u))
169 function setRemoteVideoTruncatedContent (video: any) {
171 video.content = peertubeTruncate(video.content, CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max)