aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/middlewares/validators
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2022-10-19 10:43:53 +0200
committerChocobozzz <chocobozzz@cpy.re>2022-10-24 14:48:24 +0200
commit9ab330b90decf4edf152ff8e1d2948c065766b2c (patch)
tree29d924f50f7307e8e828a57ecb9ea78623487ce0 /server/middlewares/validators
parent3545e72c686ff1725bbdfd8d16d693e2f4aa75a3 (diff)
downloadPeerTube-9ab330b90decf4edf152ff8e1d2948c065766b2c.tar.gz
PeerTube-9ab330b90decf4edf152ff8e1d2948c065766b2c.tar.zst
PeerTube-9ab330b90decf4edf152ff8e1d2948c065766b2c.zip
Use private ACL for private videos in s3
Diffstat (limited to 'server/middlewares/validators')
-rw-r--r--server/middlewares/validators/shared/videos.ts6
-rw-r--r--server/middlewares/validators/static.ts72
2 files changed, 58 insertions, 20 deletions
diff --git a/server/middlewares/validators/shared/videos.ts b/server/middlewares/validators/shared/videos.ts
index c29751eca..ebbfc0a0a 100644
--- a/server/middlewares/validators/shared/videos.ts
+++ b/server/middlewares/validators/shared/videos.ts
@@ -111,7 +111,7 @@ async function checkCanSeeVideo (options: {
111}) { 111}) {
112 const { req, res, video, paramId } = options 112 const { req, res, video, paramId } = options
113 113
114 if (video.requiresAuth(paramId)) { 114 if (video.requiresAuth({ urlParamId: paramId, checkBlacklist: true })) {
115 return checkCanSeeAuthVideo(req, res, video) 115 return checkCanSeeAuthVideo(req, res, video)
116 } 116 }
117 117
@@ -174,13 +174,13 @@ async function checkCanAccessVideoStaticFiles (options: {
174 res: Response 174 res: Response
175 paramId: string 175 paramId: string
176}) { 176}) {
177 const { video, req, res, paramId } = options 177 const { video, req, res } = options
178 178
179 if (res.locals.oauth?.token.User) { 179 if (res.locals.oauth?.token.User) {
180 return checkCanSeeVideo(options) 180 return checkCanSeeVideo(options)
181 } 181 }
182 182
183 if (!video.requiresAuth(paramId)) return true 183 if (!video.hasPrivateStaticPath()) return true
184 184
185 const videoFileToken = req.query.videoFileToken 185 const videoFileToken = req.query.videoFileToken
186 if (!videoFileToken) { 186 if (!videoFileToken) {
diff --git a/server/middlewares/validators/static.ts b/server/middlewares/validators/static.ts
index ff9e6ae6e..13fde6dd1 100644
--- a/server/middlewares/validators/static.ts
+++ b/server/middlewares/validators/static.ts
@@ -7,10 +7,17 @@ import { logger } from '@server/helpers/logger'
7import { LRU_CACHE } from '@server/initializers/constants' 7import { LRU_CACHE } from '@server/initializers/constants'
8import { VideoModel } from '@server/models/video/video' 8import { VideoModel } from '@server/models/video/video'
9import { VideoFileModel } from '@server/models/video/video-file' 9import { VideoFileModel } from '@server/models/video/video-file'
10import { MStreamingPlaylist, MVideoFile, MVideoThumbnail } from '@server/types/models'
10import { HttpStatusCode } from '@shared/models' 11import { HttpStatusCode } from '@shared/models'
11import { areValidationErrors, checkCanAccessVideoStaticFiles } from './shared' 12import { areValidationErrors, checkCanAccessVideoStaticFiles } from './shared'
12 13
13const staticFileTokenBypass = new LRUCache<string, boolean>({ 14type LRUValue = {
15 allowed: boolean
16 video?: MVideoThumbnail
17 file?: MVideoFile
18 playlist?: MStreamingPlaylist }
19
20const staticFileTokenBypass = new LRUCache<string, LRUValue>({
14 max: LRU_CACHE.STATIC_VIDEO_FILES_RIGHTS_CHECK.MAX_SIZE, 21 max: LRU_CACHE.STATIC_VIDEO_FILES_RIGHTS_CHECK.MAX_SIZE,
15 ttl: LRU_CACHE.STATIC_VIDEO_FILES_RIGHTS_CHECK.TTL 22 ttl: LRU_CACHE.STATIC_VIDEO_FILES_RIGHTS_CHECK.TTL
16}) 23})
@@ -27,18 +34,26 @@ const ensureCanAccessVideoPrivateWebTorrentFiles = [
27 const cacheKey = token + '-' + req.originalUrl 34 const cacheKey = token + '-' + req.originalUrl
28 35
29 if (staticFileTokenBypass.has(cacheKey)) { 36 if (staticFileTokenBypass.has(cacheKey)) {
30 const allowedFromCache = staticFileTokenBypass.get(cacheKey) 37 const { allowed, file, video } = staticFileTokenBypass.get(cacheKey)
38
39 if (allowed === true) {
40 res.locals.onlyVideo = video
41 res.locals.videoFile = file
31 42
32 if (allowedFromCache === true) return next() 43 return next()
44 }
33 45
34 return res.sendStatus(HttpStatusCode.FORBIDDEN_403) 46 return res.sendStatus(HttpStatusCode.FORBIDDEN_403)
35 } 47 }
36 48
37 const allowed = await isWebTorrentAllowed(req, res) 49 const result = await isWebTorrentAllowed(req, res)
50
51 staticFileTokenBypass.set(cacheKey, result)
38 52
39 staticFileTokenBypass.set(cacheKey, allowed) 53 if (result.allowed !== true) return
40 54
41 if (allowed !== true) return 55 res.locals.onlyVideo = result.video
56 res.locals.videoFile = result.file
42 57
43 return next() 58 return next()
44 } 59 }
@@ -64,18 +79,28 @@ const ensureCanAccessPrivateVideoHLSFiles = [
64 const cacheKey = token + '-' + videoUUID 79 const cacheKey = token + '-' + videoUUID
65 80
66 if (staticFileTokenBypass.has(cacheKey)) { 81 if (staticFileTokenBypass.has(cacheKey)) {
67 const allowedFromCache = staticFileTokenBypass.get(cacheKey) 82 const { allowed, file, playlist, video } = staticFileTokenBypass.get(cacheKey)
68 83
69 if (allowedFromCache === true) return next() 84 if (allowed === true) {
85 res.locals.onlyVideo = video
86 res.locals.videoFile = file
87 res.locals.videoStreamingPlaylist = playlist
88
89 return next()
90 }
70 91
71 return res.sendStatus(HttpStatusCode.FORBIDDEN_403) 92 return res.sendStatus(HttpStatusCode.FORBIDDEN_403)
72 } 93 }
73 94
74 const allowed = await isHLSAllowed(req, res, videoUUID) 95 const result = await isHLSAllowed(req, res, videoUUID)
96
97 staticFileTokenBypass.set(cacheKey, result)
75 98
76 staticFileTokenBypass.set(cacheKey, allowed) 99 if (result.allowed !== true) return
77 100
78 if (allowed !== true) return 101 res.locals.onlyVideo = result.video
102 res.locals.videoFile = result.file
103 res.locals.videoStreamingPlaylist = result.playlist
79 104
80 return next() 105 return next()
81 } 106 }
@@ -96,25 +121,38 @@ async function isWebTorrentAllowed (req: express.Request, res: express.Response)
96 logger.debug('Unknown static file %s to serve', req.originalUrl, { filename }) 121 logger.debug('Unknown static file %s to serve', req.originalUrl, { filename })
97 122
98 res.sendStatus(HttpStatusCode.FORBIDDEN_403) 123 res.sendStatus(HttpStatusCode.FORBIDDEN_403)
99 return false 124 return { allowed: false }
100 } 125 }
101 126
102 const video = file.getVideo() 127 const video = await VideoModel.load(file.getVideo().id)
103 128
104 return checkCanAccessVideoStaticFiles({ req, res, video, paramId: video.uuid }) 129 return {
130 file,
131 video,
132 allowed: await checkCanAccessVideoStaticFiles({ req, res, video, paramId: video.uuid })
133 }
105} 134}
106 135
107async function isHLSAllowed (req: express.Request, res: express.Response, videoUUID: string) { 136async function isHLSAllowed (req: express.Request, res: express.Response, videoUUID: string) {
108 const video = await VideoModel.load(videoUUID) 137 const filename = basename(req.path)
138
139 const video = await VideoModel.loadWithFiles(videoUUID)
109 140
110 if (!video) { 141 if (!video) {
111 logger.debug('Unknown static file %s to serve', req.originalUrl, { videoUUID }) 142 logger.debug('Unknown static file %s to serve', req.originalUrl, { videoUUID })
112 143
113 res.sendStatus(HttpStatusCode.FORBIDDEN_403) 144 res.sendStatus(HttpStatusCode.FORBIDDEN_403)
114 return false 145 return { allowed: false }
115 } 146 }
116 147
117 return checkCanAccessVideoStaticFiles({ req, res, video, paramId: video.uuid }) 148 const file = await VideoFileModel.loadByFilename(filename)
149
150 return {
151 file,
152 video,
153 playlist: video.getHLSPlaylist(),
154 allowed: await checkCanAccessVideoStaticFiles({ req, res, video, paramId: video.uuid })
155 }
118} 156}
119 157
120function extractTokenOrDie (req: express.Request, res: express.Response) { 158function extractTokenOrDie (req: express.Request, res: express.Response) {