aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers
diff options
context:
space:
mode:
authorWicklow <123956049+wickloww@users.noreply.github.com>2023-06-29 07:48:55 +0000
committerGitHub <noreply@github.com>2023-06-29 09:48:55 +0200
commit40346ead2b0b7afa475aef057d3673b6c7574b7a (patch)
tree24ffdc23c3a9d987334842e0d400b5bd44500cf7 /server/helpers
parentae22c59f14d0d553f60b281948b6c232c2aca178 (diff)
downloadPeerTube-40346ead2b0b7afa475aef057d3673b6c7574b7a.tar.gz
PeerTube-40346ead2b0b7afa475aef057d3673b6c7574b7a.tar.zst
PeerTube-40346ead2b0b7afa475aef057d3673b6c7574b7a.zip
Feature/password protected videos (#5836)
* Add server endpoints * Refactoring test suites * Update server and add openapi documentation * fix compliation and tests * upload/import password protected video on client * add server error code * Add video password to update resolver * add custom message when sharing pw protected video * improve confirm component * Add new alert in component * Add ability to watch protected video on client * Cannot have password protected replay privacy * Add migration * Add tests * update after review * Update check params tests * Add live videos test * Add more filter test * Update static file privacy test * Update object storage tests * Add test on feeds * Add missing word * Fix tests * Fix tests on live videos * add embed support on password protected videos * fix style * Correcting data leaks * Unable to add password protected privacy on replay * Updated code based on review comments * fix validator and command * Updated code based on review comments
Diffstat (limited to 'server/helpers')
-rw-r--r--server/helpers/custom-validators/videos.ts57
1 files changed, 54 insertions, 3 deletions
diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts
index 5f75ec27c..91109217c 100644
--- a/server/helpers/custom-validators/videos.ts
+++ b/server/helpers/custom-validators/videos.ts
@@ -1,7 +1,7 @@
1import { UploadFilesForCheck } from 'express' 1import { Response, Request, UploadFilesForCheck } from 'express'
2import { decode as magnetUriDecode } from 'magnet-uri' 2import { decode as magnetUriDecode } from 'magnet-uri'
3import validator from 'validator' 3import validator from 'validator'
4import { VideoFilter, VideoInclude, VideoPrivacy, VideoRateType } from '@shared/models' 4import { HttpStatusCode, VideoFilter, VideoInclude, VideoPrivacy, VideoRateType } from '@shared/models'
5import { 5import {
6 CONSTRAINTS_FIELDS, 6 CONSTRAINTS_FIELDS,
7 MIMETYPES, 7 MIMETYPES,
@@ -13,6 +13,7 @@ import {
13 VIDEO_STATES 13 VIDEO_STATES
14} from '../../initializers/constants' 14} from '../../initializers/constants'
15import { exists, isArray, isDateValid, isFileValid } from './misc' 15import { exists, isArray, isDateValid, isFileValid } from './misc'
16import { getVideoWithAttributes } from '@server/helpers/video'
16 17
17const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS 18const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
18 19
@@ -110,6 +111,10 @@ function isVideoPrivacyValid (value: number) {
110 return VIDEO_PRIVACIES[value] !== undefined 111 return VIDEO_PRIVACIES[value] !== undefined
111} 112}
112 113
114function isVideoReplayPrivacyValid (value: number) {
115 return VIDEO_PRIVACIES[value] !== undefined && value !== VideoPrivacy.PASSWORD_PROTECTED
116}
117
113function isScheduleVideoUpdatePrivacyValid (value: number) { 118function isScheduleVideoUpdatePrivacyValid (value: number) {
114 return value === VideoPrivacy.UNLISTED || value === VideoPrivacy.PUBLIC || value === VideoPrivacy.INTERNAL 119 return value === VideoPrivacy.UNLISTED || value === VideoPrivacy.PUBLIC || value === VideoPrivacy.INTERNAL
115} 120}
@@ -141,6 +146,49 @@ function isVideoMagnetUriValid (value: string) {
141 return parsed && isVideoFileInfoHashValid(parsed.infoHash) 146 return parsed && isVideoFileInfoHashValid(parsed.infoHash)
142} 147}
143 148
149function isPasswordValid (password: string) {
150 return password.length >= CONSTRAINTS_FIELDS.VIDEO_PASSWORD.LENGTH.min &&
151 password.length < CONSTRAINTS_FIELDS.VIDEO_PASSWORD.LENGTH.max
152}
153
154function isValidPasswordProtectedPrivacy (req: Request, res: Response) {
155 const fail = (message: string) => {
156 res.fail({
157 status: HttpStatusCode.BAD_REQUEST_400,
158 message
159 })
160 return false
161 }
162
163 let privacy: VideoPrivacy
164 const video = getVideoWithAttributes(res)
165
166 if (exists(req.body?.privacy)) privacy = req.body.privacy
167 else if (exists(video?.privacy)) privacy = video.privacy
168
169 if (privacy !== VideoPrivacy.PASSWORD_PROTECTED) return true
170
171 if (!exists(req.body.videoPasswords) && !exists(req.body.passwords)) return fail('Video passwords are missing.')
172
173 const passwords = req.body.videoPasswords || req.body.passwords
174
175 if (passwords.length === 0) return fail('At least one video password is required.')
176
177 if (new Set(passwords).size !== passwords.length) return fail('Duplicate video passwords are not allowed.')
178
179 for (const password of passwords) {
180 if (typeof password !== 'string') {
181 return fail('Video password should be a string.')
182 }
183
184 if (!isPasswordValid(password)) {
185 return fail('Invalid video password. Password length should be at least 2 characters and no more than 100 characters.')
186 }
187 }
188
189 return true
190}
191
144// --------------------------------------------------------------------------- 192// ---------------------------------------------------------------------------
145 193
146export { 194export {
@@ -164,9 +212,12 @@ export {
164 isVideoDurationValid, 212 isVideoDurationValid,
165 isVideoTagValid, 213 isVideoTagValid,
166 isVideoPrivacyValid, 214 isVideoPrivacyValid,
215 isVideoReplayPrivacyValid,
167 isVideoFileResolutionValid, 216 isVideoFileResolutionValid,
168 isVideoFileSizeValid, 217 isVideoFileSizeValid,
169 isVideoImageValid, 218 isVideoImageValid,
170 isVideoSupportValid, 219 isVideoSupportValid,
171 isVideoFilterValid 220 isVideoFilterValid,
221 isPasswordValid,
222 isValidPasswordProtectedPrivacy
172} 223}