aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers')
-rw-r--r--server/controllers/activitypub/client.ts15
-rw-r--r--server/controllers/api/config.ts8
-rw-r--r--server/controllers/api/users/index.ts19
-rw-r--r--server/controllers/api/users/me.ts2
-rw-r--r--server/controllers/api/videos/index.ts19
-rw-r--r--server/controllers/static.ts9
-rw-r--r--server/controllers/tracker.ts25
7 files changed, 63 insertions, 34 deletions
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts
index 7e87f6f3b..31c0a5fbd 100644
--- a/server/controllers/activitypub/client.ts
+++ b/server/controllers/activitypub/client.ts
@@ -33,7 +33,7 @@ import {
33 getVideoSharesActivityPubUrl 33 getVideoSharesActivityPubUrl
34} from '../../lib/activitypub' 34} from '../../lib/activitypub'
35import { VideoCaptionModel } from '../../models/video/video-caption' 35import { VideoCaptionModel } from '../../models/video/video-caption'
36import { videoRedundancyGetValidator } from '../../middlewares/validators/redundancy' 36import { videoFileRedundancyGetValidator, videoPlaylistRedundancyGetValidator } from '../../middlewares/validators/redundancy'
37import { getServerActor } from '../../helpers/utils' 37import { getServerActor } from '../../helpers/utils'
38import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' 38import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy'
39import { buildDislikeActivity } from '../../lib/activitypub/send/send-dislike' 39import { buildDislikeActivity } from '../../lib/activitypub/send/send-dislike'
@@ -63,11 +63,11 @@ activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId',
63 63
64activityPubClientRouter.get('/videos/watch/:id', 64activityPubClientRouter.get('/videos/watch/:id',
65 executeIfActivityPub(asyncMiddleware(cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS))), 65 executeIfActivityPub(asyncMiddleware(cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS))),
66 executeIfActivityPub(asyncMiddleware(videosGetValidator)), 66 executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video-with-rights'))),
67 executeIfActivityPub(asyncMiddleware(videoController)) 67 executeIfActivityPub(asyncMiddleware(videoController))
68) 68)
69activityPubClientRouter.get('/videos/watch/:id/activity', 69activityPubClientRouter.get('/videos/watch/:id/activity',
70 executeIfActivityPub(asyncMiddleware(videosGetValidator)), 70 executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video-with-rights'))),
71 executeIfActivityPub(asyncMiddleware(videoController)) 71 executeIfActivityPub(asyncMiddleware(videoController))
72) 72)
73activityPubClientRouter.get('/videos/watch/:id/announces', 73activityPubClientRouter.get('/videos/watch/:id/announces',
@@ -113,7 +113,11 @@ activityPubClientRouter.get('/video-channels/:name/following',
113) 113)
114 114
115activityPubClientRouter.get('/redundancy/videos/:videoId/:resolution([0-9]+)(-:fps([0-9]+))?', 115activityPubClientRouter.get('/redundancy/videos/:videoId/:resolution([0-9]+)(-:fps([0-9]+))?',
116 executeIfActivityPub(asyncMiddleware(videoRedundancyGetValidator)), 116 executeIfActivityPub(asyncMiddleware(videoFileRedundancyGetValidator)),
117 executeIfActivityPub(asyncMiddleware(videoRedundancyController))
118)
119activityPubClientRouter.get('/redundancy/video-playlists/:streamingPlaylistType/:videoId',
120 executeIfActivityPub(asyncMiddleware(videoPlaylistRedundancyGetValidator)),
117 executeIfActivityPub(asyncMiddleware(videoRedundancyController)) 121 executeIfActivityPub(asyncMiddleware(videoRedundancyController))
118) 122)
119 123
@@ -160,7 +164,8 @@ function getAccountVideoRate (rateType: VideoRateType) {
160} 164}
161 165
162async function videoController (req: express.Request, res: express.Response) { 166async function videoController (req: express.Request, res: express.Response) {
163 const video: VideoModel = res.locals.video 167 // We need more attributes
168 const video: VideoModel = await VideoModel.loadForGetAPI(res.locals.video.id)
164 169
165 if (video.url.startsWith(CONFIG.WEBSERVER.URL) === false) return res.redirect(video.url) 170 if (video.url.startsWith(CONFIG.WEBSERVER.URL) === false) return res.redirect(video.url)
166 171
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index 255026f46..1f3341bc0 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -1,5 +1,5 @@
1import * as express from 'express' 1import * as express from 'express'
2import { omit, snakeCase } from 'lodash' 2import { snakeCase } from 'lodash'
3import { ServerConfig, UserRight } from '../../../shared' 3import { ServerConfig, UserRight } from '../../../shared'
4import { About } from '../../../shared/models/server/about.model' 4import { About } from '../../../shared/models/server/about.model'
5import { CustomConfig } from '../../../shared/models/server/custom-config.model' 5import { CustomConfig } from '../../../shared/models/server/custom-config.model'
@@ -78,6 +78,9 @@ async function getConfig (req: express.Request, res: express.Response) {
78 requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION 78 requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION
79 }, 79 },
80 transcoding: { 80 transcoding: {
81 hls: {
82 enabled: CONFIG.TRANSCODING.HLS.ENABLED
83 },
81 enabledResolutions 84 enabledResolutions
82 }, 85 },
83 import: { 86 import: {
@@ -246,6 +249,9 @@ function customConfig (): CustomConfig {
246 '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ], 249 '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ],
247 '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], 250 '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ],
248 '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ] 251 '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ]
252 },
253 hls: {
254 enabled: CONFIG.TRANSCODING.HLS.ENABLED
249 } 255 }
250 }, 256 },
251 import: { 257 import: {
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts
index dbe0718d4..e3533a7f6 100644
--- a/server/controllers/api/users/index.ts
+++ b/server/controllers/api/users/index.ts
@@ -229,7 +229,7 @@ async function unblockUser (req: express.Request, res: express.Response, next: e
229 return res.status(204).end() 229 return res.status(204).end()
230} 230}
231 231
232async function blockUser (req: express.Request, res: express.Response, next: express.NextFunction) { 232async function blockUser (req: express.Request, res: express.Response) {
233 const user: UserModel = res.locals.user 233 const user: UserModel = res.locals.user
234 const reason = req.body.reason 234 const reason = req.body.reason
235 235
@@ -238,23 +238,23 @@ async function blockUser (req: express.Request, res: express.Response, next: exp
238 return res.status(204).end() 238 return res.status(204).end()
239} 239}
240 240
241function getUser (req: express.Request, res: express.Response, next: express.NextFunction) { 241function getUser (req: express.Request, res: express.Response) {
242 return res.json((res.locals.user as UserModel).toFormattedJSON()) 242 return res.json((res.locals.user as UserModel).toFormattedJSON())
243} 243}
244 244
245async function autocompleteUsers (req: express.Request, res: express.Response, next: express.NextFunction) { 245async function autocompleteUsers (req: express.Request, res: express.Response) {
246 const resultList = await UserModel.autoComplete(req.query.search as string) 246 const resultList = await UserModel.autoComplete(req.query.search as string)
247 247
248 return res.json(resultList) 248 return res.json(resultList)
249} 249}
250 250
251async function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) { 251async function listUsers (req: express.Request, res: express.Response) {
252 const resultList = await UserModel.listForApi(req.query.start, req.query.count, req.query.sort, req.query.search) 252 const resultList = await UserModel.listForApi(req.query.start, req.query.count, req.query.sort, req.query.search)
253 253
254 return res.json(getFormattedObjects(resultList.data, resultList.total)) 254 return res.json(getFormattedObjects(resultList.data, resultList.total))
255} 255}
256 256
257async function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) { 257async function removeUser (req: express.Request, res: express.Response) {
258 const user: UserModel = res.locals.user 258 const user: UserModel = res.locals.user
259 259
260 await user.destroy() 260 await user.destroy()
@@ -264,12 +264,13 @@ async function removeUser (req: express.Request, res: express.Response, next: ex
264 return res.sendStatus(204) 264 return res.sendStatus(204)
265} 265}
266 266
267async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) { 267async function updateUser (req: express.Request, res: express.Response) {
268 const body: UserUpdate = req.body 268 const body: UserUpdate = req.body
269 const userToUpdate = res.locals.user as UserModel 269 const userToUpdate = res.locals.user as UserModel
270 const oldUserAuditView = new UserAuditView(userToUpdate.toFormattedJSON()) 270 const oldUserAuditView = new UserAuditView(userToUpdate.toFormattedJSON())
271 const roleChanged = body.role !== undefined && body.role !== userToUpdate.role 271 const roleChanged = body.role !== undefined && body.role !== userToUpdate.role
272 272
273 if (body.password !== undefined) userToUpdate.password = body.password
273 if (body.email !== undefined) userToUpdate.email = body.email 274 if (body.email !== undefined) userToUpdate.email = body.email
274 if (body.emailVerified !== undefined) userToUpdate.emailVerified = body.emailVerified 275 if (body.emailVerified !== undefined) userToUpdate.emailVerified = body.emailVerified
275 if (body.videoQuota !== undefined) userToUpdate.videoQuota = body.videoQuota 276 if (body.videoQuota !== undefined) userToUpdate.videoQuota = body.videoQuota
@@ -279,11 +280,11 @@ async function updateUser (req: express.Request, res: express.Response, next: ex
279 const user = await userToUpdate.save() 280 const user = await userToUpdate.save()
280 281
281 // Destroy user token to refresh rights 282 // Destroy user token to refresh rights
282 if (roleChanged) await deleteUserToken(userToUpdate.id) 283 if (roleChanged || body.password !== undefined) await deleteUserToken(userToUpdate.id)
283 284
284 auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView) 285 auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView)
285 286
286 // Don't need to send this update to followers, these attributes are not propagated 287 // Don't need to send this update to followers, these attributes are not federated
287 288
288 return res.sendStatus(204) 289 return res.sendStatus(204)
289} 290}
@@ -293,7 +294,7 @@ async function askResetUserPassword (req: express.Request, res: express.Response
293 294
294 const verificationString = await Redis.Instance.setResetPasswordVerificationString(user.id) 295 const verificationString = await Redis.Instance.setResetPasswordVerificationString(user.id)
295 const url = CONFIG.WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString 296 const url = CONFIG.WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString
296 await Emailer.Instance.addForgetPasswordEmailJob(user.email, url) 297 await Emailer.Instance.addPasswordResetEmailJob(user.email, url)
297 298
298 return res.status(204).end() 299 return res.status(204).end()
299} 300}
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts
index 94a2b8732..d5e154869 100644
--- a/server/controllers/api/users/me.ts
+++ b/server/controllers/api/users/me.ts
@@ -167,7 +167,7 @@ async function deleteMe (req: express.Request, res: express.Response) {
167 return res.sendStatus(204) 167 return res.sendStatus(204)
168} 168}
169 169
170async function updateMe (req: express.Request, res: express.Response, next: express.NextFunction) { 170async function updateMe (req: express.Request, res: express.Response) {
171 const body: UserUpdateMe = req.body 171 const body: UserUpdateMe = req.body
172 172
173 const user: UserModel = res.locals.oauth.token.user 173 const user: UserModel = res.locals.oauth.token.user
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index 8414ca42c..3b1c2d255 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -36,6 +36,7 @@ import {
36 setDefaultPagination, 36 setDefaultPagination,
37 setDefaultSort, 37 setDefaultSort,
38 videosAddValidator, 38 videosAddValidator,
39 videosCustomGetValidator,
39 videosGetValidator, 40 videosGetValidator,
40 videosRemoveValidator, 41 videosRemoveValidator,
41 videosSortValidator, 42 videosSortValidator,
@@ -123,9 +124,9 @@ videosRouter.get('/:id/description',
123) 124)
124videosRouter.get('/:id', 125videosRouter.get('/:id',
125 optionalAuthenticate, 126 optionalAuthenticate,
126 asyncMiddleware(videosGetValidator), 127 asyncMiddleware(videosCustomGetValidator('only-video-with-rights')),
127 asyncMiddleware(checkVideoFollowConstraints), 128 asyncMiddleware(checkVideoFollowConstraints),
128 getVideo 129 asyncMiddleware(getVideo)
129) 130)
130videosRouter.post('/:id/views', 131videosRouter.post('/:id/views',
131 asyncMiddleware(videosGetValidator), 132 asyncMiddleware(videosGetValidator),
@@ -395,15 +396,17 @@ async function updateVideo (req: express.Request, res: express.Response) {
395 return res.type('json').status(204).end() 396 return res.type('json').status(204).end()
396} 397}
397 398
398function getVideo (req: express.Request, res: express.Response) { 399async function getVideo (req: express.Request, res: express.Response) {
399 const videoInstance = res.locals.video 400 // We need more attributes
401 const userId: number = res.locals.oauth ? res.locals.oauth.token.User.id : null
402 const video: VideoModel = await VideoModel.loadForGetAPI(res.locals.video.id, undefined, userId)
400 403
401 if (videoInstance.isOutdated()) { 404 if (video.isOutdated()) {
402 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: videoInstance.url } }) 405 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } })
403 .catch(err => logger.error('Cannot create AP refresher job for video %s.', videoInstance.url, { err })) 406 .catch(err => logger.error('Cannot create AP refresher job for video %s.', video.url, { err }))
404 } 407 }
405 408
406 return res.json(videoInstance.toFormattedDetailsJSON()) 409 return res.json(video.toFormattedDetailsJSON())
407} 410}
408 411
409async function viewVideo (req: express.Request, res: express.Response) { 412async function viewVideo (req: express.Request, res: express.Response) {
diff --git a/server/controllers/static.ts b/server/controllers/static.ts
index 4fd58f70c..b21f9da00 100644
--- a/server/controllers/static.ts
+++ b/server/controllers/static.ts
@@ -1,6 +1,6 @@
1import * as cors from 'cors' 1import * as cors from 'cors'
2import * as express from 'express' 2import * as express from 'express'
3import { CONFIG, ROUTE_CACHE_LIFETIME, STATIC_DOWNLOAD_PATHS, STATIC_MAX_AGE, STATIC_PATHS } from '../initializers' 3import { CONFIG, HLS_PLAYLIST_DIRECTORY, ROUTE_CACHE_LIFETIME, STATIC_DOWNLOAD_PATHS, STATIC_MAX_AGE, STATIC_PATHS } from '../initializers'
4import { VideosPreviewCache } from '../lib/cache' 4import { VideosPreviewCache } from '../lib/cache'
5import { cacheRoute } from '../middlewares/cache' 5import { cacheRoute } from '../middlewares/cache'
6import { asyncMiddleware, videosGetValidator } from '../middlewares' 6import { asyncMiddleware, videosGetValidator } from '../middlewares'
@@ -51,6 +51,13 @@ staticRouter.use(
51 asyncMiddleware(downloadVideoFile) 51 asyncMiddleware(downloadVideoFile)
52) 52)
53 53
54// HLS
55staticRouter.use(
56 STATIC_PATHS.PLAYLISTS.HLS,
57 cors(),
58 express.static(HLS_PLAYLIST_DIRECTORY, { fallthrough: false }) // 404 if the file does not exist
59)
60
54// Thumbnails path for express 61// Thumbnails path for express
55const thumbnailsPhysicalPath = CONFIG.STORAGE.THUMBNAILS_DIR 62const thumbnailsPhysicalPath = CONFIG.STORAGE.THUMBNAILS_DIR
56staticRouter.use( 63staticRouter.use(
diff --git a/server/controllers/tracker.ts b/server/controllers/tracker.ts
index 1deb8c402..8b77d9de7 100644
--- a/server/controllers/tracker.ts
+++ b/server/controllers/tracker.ts
@@ -7,6 +7,7 @@ import { Server as WebSocketServer } from 'ws'
7import { CONFIG, TRACKER_RATE_LIMITS } from '../initializers/constants' 7import { CONFIG, TRACKER_RATE_LIMITS } from '../initializers/constants'
8import { VideoFileModel } from '../models/video/video-file' 8import { VideoFileModel } from '../models/video/video-file'
9import { parse } from 'url' 9import { parse } from 'url'
10import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
10 11
11const TrackerServer = bitTorrentTracker.Server 12const TrackerServer = bitTorrentTracker.Server
12 13
@@ -21,7 +22,7 @@ const trackerServer = new TrackerServer({
21 udp: false, 22 udp: false,
22 ws: false, 23 ws: false,
23 dht: false, 24 dht: false,
24 filter: function (infoHash, params, cb) { 25 filter: async function (infoHash, params, cb) {
25 let ip: string 26 let ip: string
26 27
27 if (params.type === 'ws') { 28 if (params.type === 'ws') {
@@ -32,19 +33,25 @@ const trackerServer = new TrackerServer({
32 33
33 const key = ip + '-' + infoHash 34 const key = ip + '-' + infoHash
34 35
35 peersIps[ip] = peersIps[ip] ? peersIps[ip] + 1 : 1 36 peersIps[ ip ] = peersIps[ ip ] ? peersIps[ ip ] + 1 : 1
36 peersIpInfoHash[key] = peersIpInfoHash[key] ? peersIpInfoHash[key] + 1 : 1 37 peersIpInfoHash[ key ] = peersIpInfoHash[ key ] ? peersIpInfoHash[ key ] + 1 : 1
37 38
38 if (peersIpInfoHash[key] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) { 39 if (peersIpInfoHash[ key ] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) {
39 return cb(new Error(`Too many requests (${peersIpInfoHash[ key ]} of ip ${ip} for torrent ${infoHash}`)) 40 return cb(new Error(`Too many requests (${peersIpInfoHash[ key ]} of ip ${ip} for torrent ${infoHash}`))
40 } 41 }
41 42
42 VideoFileModel.isInfohashExists(infoHash) 43 try {
43 .then(exists => { 44 const videoFileExists = await VideoFileModel.doesInfohashExist(infoHash)
44 if (exists === false) return cb(new Error(`Unknown infoHash ${infoHash}`)) 45 if (videoFileExists === true) return cb()
45 46
46 return cb() 47 const playlistExists = await VideoStreamingPlaylistModel.doesInfohashExist(infoHash)
47 }) 48 if (playlistExists === true) return cb()
49
50 return cb(new Error(`Unknown infoHash ${infoHash}`))
51 } catch (err) {
52 logger.error('Error in tracker filter.', { err })
53 return cb(err)
54 }
48 } 55 }
49}) 56})
50 57