]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/helpers/custom-validators/activitypub/videos.ts
Fix dev instance following test instances
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / activitypub / videos.ts
CommitLineData
7cde3b9c 1import validator from 'validator'
d9a2a031
C
2import { logger } from '@server/helpers/logger'
3import { ActivityTrackerUrlObject, ActivityVideoFileMetadataUrlObject } from '@shared/models'
f443a746 4import { LiveVideoLatencyMode, VideoState } from '../../../../shared/models/videos'
74dc3bca 5import { ACTIVITY_PUB, CONSTRAINTS_FIELDS } from '../../../initializers/constants'
c73e83da 6import { peertubeTruncate } from '../../core-utils'
b2111066 7import { isArray, isBooleanValid, isDateValid, isUUIDValid } from '../misc'
f443a746 8import { isLiveLatencyModeValid } from '../video-lives'
65fcc311 9import {
f713f36b 10 isVideoDescriptionValid,
65fcc311 11 isVideoDurationValid,
65fcc311 12 isVideoNameValid,
2186386c 13 isVideoStateValid,
e34c85e5 14 isVideoTagValid,
8e10cf1a 15 isVideoViewsValid
65fcc311 16} from '../videos'
b2111066 17import { isActivityPubUrlValid, isActivityPubVideoDurationValid, isBaseActivityValid, setValidAttributedTo } from './misc'
0d0e8dd0 18
1d6e5dfc 19function sanitizeAndCheckVideoTorrentUpdateActivity (activity: any) {
0d0e8dd0 20 return isBaseActivityValid(activity, 'Update') &&
1d6e5dfc 21 sanitizeAndCheckVideoTorrentObject(activity.object)
65fcc311
C
22}
23
1d6e5dfc 24function sanitizeAndCheckVideoTorrentObject (video: any) {
fbad87b0 25 if (!video || video.type !== 'Video') return false
5cf13500 26
d7a25329
C
27 if (!setValidRemoteTags(video)) {
28 logger.debug('Video has invalid tags', { video })
29 return false
30 }
31 if (!setValidRemoteVideoUrls(video)) {
32 logger.debug('Video has invalid urls', { video })
33 return false
34 }
f713f36b 35 if (!setRemoteVideoContent(video)) {
d7a25329
C
36 logger.debug('Video has invalid content', { video })
37 return false
38 }
39 if (!setValidAttributedTo(video)) {
40 logger.debug('Video has invalid attributedTo', { video })
41 return false
42 }
43 if (!setValidRemoteCaptions(video)) {
44 logger.debug('Video has invalid captions', { video })
45 return false
46 }
ca6d3622
C
47 if (!setValidRemoteIcon(video)) {
48 logger.debug('Video has invalid icons', { video })
49 return false
50 }
1d6e5dfc 51
2186386c
C
52 // Default attributes
53 if (!isVideoStateValid(video.state)) video.state = VideoState.PUBLISHED
54 if (!isBooleanValid(video.waitTranscoding)) video.waitTranscoding = false
7f2cfe3a 55 if (!isBooleanValid(video.downloadEnabled)) video.downloadEnabled = true
0bc1b31d 56 if (!isBooleanValid(video.commentsEnabled)) video.commentsEnabled = false
de6310b2 57 if (!isBooleanValid(video.isLiveBroadcast)) video.isLiveBroadcast = false
af4ae64f 58 if (!isBooleanValid(video.liveSaveReplay)) video.liveSaveReplay = false
bb4ba6d9 59 if (!isBooleanValid(video.permanentLive)) video.permanentLive = false
f443a746 60 if (!isLiveLatencyModeValid(video.latencyMode)) video.latencyMode = LiveVideoLatencyMode.DEFAULT
2186386c 61
5cf13500 62 return isActivityPubUrlValid(video.id) &&
0d0e8dd0 63 isVideoNameValid(video.name) &&
8e10cf1a 64 isActivityPubVideoDurationValid(video.duration) &&
b2111066 65 isVideoDurationValid(video.duration.replace(/[^0-9]+/g, '')) &&
0d0e8dd0 66 isUUIDValid(video.uuid) &&
9d3ef9fe
C
67 (!video.category || isRemoteNumberIdentifierValid(video.category)) &&
68 (!video.licence || isRemoteNumberIdentifierValid(video.licence)) &&
69 (!video.language || isRemoteStringIdentifierValid(video.language)) &&
efc32059 70 isVideoViewsValid(video.views) &&
0a67e28b 71 isBooleanValid(video.sensitive) &&
0d0e8dd0
C
72 isDateValid(video.published) &&
73 isDateValid(video.updated) &&
7519127b 74 (!video.originallyPublishedAt || isDateValid(video.originallyPublishedAt)) &&
f595d394 75 (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) &&
50d6de9c 76 video.attributedTo.length !== 0
65fcc311
C
77}
78
c48e82b5 79function isRemoteVideoUrlValid (url: any) {
c48e82b5 80 return url.type === 'Link' &&
d9a2a031 81 // Video file link
c48e82b5 82 (
bdd428a6 83 ACTIVITY_PUB.URL_MIME_TYPES.VIDEO.includes(url.mediaType) &&
c48e82b5
C
84 isActivityPubUrlValid(url.href) &&
85 validator.isInt(url.height + '', { min: 0 }) &&
86 validator.isInt(url.size + '', { min: 0 }) &&
a3737cbf 87 (!url.fps || validator.isInt(url.fps + '', { min: -1 }))
c48e82b5 88 ) ||
d9a2a031 89 // Torrent link
c48e82b5 90 (
bdd428a6 91 ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.includes(url.mediaType) &&
c48e82b5
C
92 isActivityPubUrlValid(url.href) &&
93 validator.isInt(url.height + '', { min: 0 })
94 ) ||
d9a2a031 95 // Magnet link
c48e82b5 96 (
bdd428a6 97 ACTIVITY_PUB.URL_MIME_TYPES.MAGNET.includes(url.mediaType) &&
c48e82b5
C
98 validator.isLength(url.href, { min: 5 }) &&
99 validator.isInt(url.height + '', { min: 0 })
09209296 100 ) ||
d9a2a031 101 // HLS playlist link
09209296
C
102 (
103 (url.mediaType || url.mimeType) === 'application/x-mpegURL' &&
104 isActivityPubUrlValid(url.href) &&
105 isArray(url.tag)
7b81edc8 106 ) ||
d9a2a031
C
107 isAPVideoTrackerUrlObject(url) ||
108 isAPVideoFileUrlMetadataObject(url)
7b81edc8
C
109}
110
d9a2a031 111function isAPVideoFileUrlMetadataObject (url: any): url is ActivityVideoFileMetadataUrlObject {
7b81edc8
C
112 return url &&
113 url.type === 'Link' &&
114 url.mediaType === 'application/json' &&
115 isArray(url.rel) && url.rel.includes('metadata')
c48e82b5
C
116}
117
d9a2a031
C
118function isAPVideoTrackerUrlObject (url: any): url is ActivityTrackerUrlObject {
119 return isArray(url.rel) &&
120 url.rel.includes('tracker') &&
121 isActivityPubUrlValid(url.href)
122}
123
65fcc311
C
124// ---------------------------------------------------------------------------
125
126export {
1d6e5dfc 127 sanitizeAndCheckVideoTorrentUpdateActivity,
9d3ef9fe 128 isRemoteStringIdentifierValid,
c48e82b5 129 sanitizeAndCheckVideoTorrentObject,
7b81edc8 130 isRemoteVideoUrlValid,
d9a2a031
C
131 isAPVideoFileUrlMetadataObject,
132 isAPVideoTrackerUrlObject
65fcc311
C
133}
134
135// ---------------------------------------------------------------------------
136
0d0e8dd0
C
137function setValidRemoteTags (video: any) {
138 if (Array.isArray(video.tag) === false) return false
65fcc311 139
a2431b7d 140 video.tag = video.tag.filter(t => {
0d0e8dd0
C
141 return t.type === 'Hashtag' &&
142 isVideoTagValid(t.name)
143 })
72c7248b 144
0d0e8dd0 145 return true
72c7248b
C
146}
147
40e87e9e
C
148function setValidRemoteCaptions (video: any) {
149 if (!video.subtitleLanguage) video.subtitleLanguage = []
150
151 if (Array.isArray(video.subtitleLanguage) === false) return false
152
153 video.subtitleLanguage = video.subtitleLanguage.filter(caption => {
ca6d3622
C
154 if (!isActivityPubUrlValid(caption.url)) caption.url = null
155
40e87e9e
C
156 return isRemoteStringIdentifierValid(caption)
157 })
158
159 return true
160}
161
9d3ef9fe 162function isRemoteNumberIdentifierValid (data: any) {
0d0e8dd0 163 return validator.isInt(data.identifier, { min: 0 })
72c7248b
C
164}
165
9d3ef9fe
C
166function isRemoteStringIdentifierValid (data: any) {
167 return typeof data.identifier === 'string'
168}
169
0d0e8dd0 170function isRemoteVideoContentValid (mediaType: string, content: string) {
f713f36b 171 return mediaType === 'text/markdown' && isVideoDescriptionValid(content)
72c7248b
C
172}
173
ca6d3622
C
174function setValidRemoteIcon (video: any) {
175 if (video.icon && !isArray(video.icon)) video.icon = [ video.icon ]
176 if (!video.icon) video.icon = []
177
178 video.icon = video.icon.filter(icon => {
179 return icon.type === 'Image' &&
180 isActivityPubUrlValid(icon.url) &&
181 icon.mediaType === 'image/jpeg' &&
182 validator.isInt(icon.width + '', { min: 0 }) &&
183 validator.isInt(icon.height + '', { min: 0 })
184 })
185
186 return video.icon.length !== 0
72c7248b
C
187}
188
0d0e8dd0
C
189function setValidRemoteVideoUrls (video: any) {
190 if (Array.isArray(video.url) === false) return false
65fcc311 191
a2431b7d 192 video.url = video.url.filter(u => isRemoteVideoUrlValid(u))
65fcc311 193
0d0e8dd0 194 return true
65fcc311
C
195}
196
f713f36b 197function setRemoteVideoContent (video: any) {
c73e83da 198 if (video.content) {
f713f36b 199 video.content = peertubeTruncate(video.content, { length: CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max })
c73e83da
C
200 }
201
202 return true
203}