]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/helpers/custom-validators/activitypub/videos.ts
Add hls support on server
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / activitypub / videos.ts
... / ...
CommitLineData
1import * as validator from 'validator'
2import { ACTIVITY_PUB, CONSTRAINTS_FIELDS } from '../../../initializers'
3import { peertubeTruncate } from '../../core-utils'
4import { exists, isArray, isBooleanValid, isDateValid, isUUIDValid } from '../misc'
5import {
6 isVideoDurationValid,
7 isVideoNameValid,
8 isVideoStateValid,
9 isVideoTagValid,
10 isVideoTruncatedDescriptionValid,
11 isVideoViewsValid
12} from '../videos'
13import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc'
14import { VideoState } from '../../../../shared/models/videos'
15
16function sanitizeAndCheckVideoTorrentUpdateActivity (activity: any) {
17 return isBaseActivityValid(activity, 'Update') &&
18 sanitizeAndCheckVideoTorrentObject(activity.object)
19}
20
21function 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, ''))
28}
29
30function sanitizeAndCheckVideoTorrentObject (video: any) {
31 if (!video || video.type !== 'Video') return false
32
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
38
39 // Default attributes
40 if (!isVideoStateValid(video.state)) video.state = VideoState.PUBLISHED
41 if (!isBooleanValid(video.waitTranscoding)) video.waitTranscoding = false
42
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
59}
60
61function 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
64
65 return url.type === 'Link' &&
66 (
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 }))
73 ) ||
74 (
75 ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.indexOf(url.mediaType || url.mimeType) !== -1 &&
76 isActivityPubUrlValid(url.href) &&
77 validator.isInt(url.height + '', { min: 0 })
78 ) ||
79 (
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 })
83 ) ||
84 (
85 (url.mediaType || url.mimeType) === 'application/x-mpegURL' &&
86 isActivityPubUrlValid(url.href) &&
87 isArray(url.tag)
88 )
89}
90
91// ---------------------------------------------------------------------------
92
93export {
94 sanitizeAndCheckVideoTorrentUpdateActivity,
95 isRemoteStringIdentifierValid,
96 sanitizeAndCheckVideoTorrentObject,
97 isRemoteVideoUrlValid
98}
99
100// ---------------------------------------------------------------------------
101
102function setValidRemoteTags (video: any) {
103 if (Array.isArray(video.tag) === false) return false
104
105 video.tag = video.tag.filter(t => {
106 return t.type === 'Hashtag' &&
107 isVideoTagValid(t.name)
108 })
109
110 return true
111}
112
113function setValidRemoteCaptions (video: any) {
114 if (!video.subtitleLanguage) video.subtitleLanguage = []
115
116 if (Array.isArray(video.subtitleLanguage) === false) return false
117
118 video.subtitleLanguage = video.subtitleLanguage.filter(caption => {
119 return isRemoteStringIdentifierValid(caption)
120 })
121
122 return true
123}
124
125function isRemoteNumberIdentifierValid (data: any) {
126 return validator.isInt(data.identifier, { min: 0 })
127}
128
129function isRemoteStringIdentifierValid (data: any) {
130 return typeof data.identifier === 'string'
131}
132
133function isRemoteVideoContentValid (mediaType: string, content: string) {
134 return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content)
135}
136
137function 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 })
143}
144
145function setValidRemoteVideoUrls (video: any) {
146 if (Array.isArray(video.url) === false) return false
147
148 video.url = video.url.filter(u => isRemoteVideoUrlValid(u))
149
150 return true
151}
152
153function setRemoteVideoTruncatedContent (video: any) {
154 if (video.content) {
155 video.content = peertubeTruncate(video.content, CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max)
156 }
157
158 return true
159}