aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers')
-rw-r--r--server/controllers/activitypub/client.ts2
-rw-r--r--server/controllers/api/config.ts1
-rw-r--r--server/controllers/api/users/email-verification.ts72
-rw-r--r--server/controllers/api/users/index.ts99
-rw-r--r--server/controllers/api/users/registrations.ts249
-rw-r--r--server/controllers/api/video-playlist.ts7
-rw-r--r--server/controllers/api/videos/comment.ts7
-rw-r--r--server/controllers/api/videos/token.ts2
-rw-r--r--server/controllers/feeds.ts4
-rw-r--r--server/controllers/tracker.ts34
10 files changed, 356 insertions, 121 deletions
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts
index 8e064fb5b..def320730 100644
--- a/server/controllers/activitypub/client.ts
+++ b/server/controllers/activitypub/client.ts
@@ -309,7 +309,7 @@ async function videoCommentsController (req: express.Request, res: express.Respo
309 if (redirectIfNotOwned(video.url, res)) return 309 if (redirectIfNotOwned(video.url, res)) return
310 310
311 const handler = async (start: number, count: number) => { 311 const handler = async (start: number, count: number) => {
312 const result = await VideoCommentModel.listAndCountByVideoForAP(video, start, count) 312 const result = await VideoCommentModel.listAndCountByVideoForAP({ video, start, count })
313 313
314 return { 314 return {
315 total: result.total, 315 total: result.total,
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index f0fb43071..86434f382 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -193,6 +193,7 @@ function customConfig (): CustomConfig {
193 signup: { 193 signup: {
194 enabled: CONFIG.SIGNUP.ENABLED, 194 enabled: CONFIG.SIGNUP.ENABLED,
195 limit: CONFIG.SIGNUP.LIMIT, 195 limit: CONFIG.SIGNUP.LIMIT,
196 requiresApproval: CONFIG.SIGNUP.REQUIRES_APPROVAL,
196 requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION, 197 requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION,
197 minimumAge: CONFIG.SIGNUP.MINIMUM_AGE 198 minimumAge: CONFIG.SIGNUP.MINIMUM_AGE
198 }, 199 },
diff --git a/server/controllers/api/users/email-verification.ts b/server/controllers/api/users/email-verification.ts
new file mode 100644
index 000000000..230aaa9af
--- /dev/null
+++ b/server/controllers/api/users/email-verification.ts
@@ -0,0 +1,72 @@
1import express from 'express'
2import { HttpStatusCode } from '@shared/models'
3import { CONFIG } from '../../../initializers/config'
4import { sendVerifyRegistrationEmail, sendVerifyUserEmail } from '../../../lib/user'
5import { asyncMiddleware, buildRateLimiter } from '../../../middlewares'
6import {
7 registrationVerifyEmailValidator,
8 usersAskSendVerifyEmailValidator,
9 usersVerifyEmailValidator
10} from '../../../middlewares/validators'
11
12const askSendEmailLimiter = buildRateLimiter({
13 windowMs: CONFIG.RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS,
14 max: CONFIG.RATES_LIMIT.ASK_SEND_EMAIL.MAX
15})
16
17const emailVerificationRouter = express.Router()
18
19emailVerificationRouter.post([ '/ask-send-verify-email', '/registrations/ask-send-verify-email' ],
20 askSendEmailLimiter,
21 asyncMiddleware(usersAskSendVerifyEmailValidator),
22 asyncMiddleware(reSendVerifyUserEmail)
23)
24
25emailVerificationRouter.post('/:id/verify-email',
26 asyncMiddleware(usersVerifyEmailValidator),
27 asyncMiddleware(verifyUserEmail)
28)
29
30emailVerificationRouter.post('/registrations/:registrationId/verify-email',
31 asyncMiddleware(registrationVerifyEmailValidator),
32 asyncMiddleware(verifyRegistrationEmail)
33)
34
35// ---------------------------------------------------------------------------
36
37export {
38 emailVerificationRouter
39}
40
41async function reSendVerifyUserEmail (req: express.Request, res: express.Response) {
42 const user = res.locals.user
43 const registration = res.locals.userRegistration
44
45 if (user) await sendVerifyUserEmail(user)
46 else if (registration) await sendVerifyRegistrationEmail(registration)
47
48 return res.status(HttpStatusCode.NO_CONTENT_204).end()
49}
50
51async function verifyUserEmail (req: express.Request, res: express.Response) {
52 const user = res.locals.user
53 user.emailVerified = true
54
55 if (req.body.isPendingEmail === true) {
56 user.email = user.pendingEmail
57 user.pendingEmail = null
58 }
59
60 await user.save()
61
62 return res.status(HttpStatusCode.NO_CONTENT_204).end()
63}
64
65async function verifyRegistrationEmail (req: express.Request, res: express.Response) {
66 const registration = res.locals.userRegistration
67 registration.emailVerified = true
68
69 await registration.save()
70
71 return res.status(HttpStatusCode.NO_CONTENT_204).end()
72}
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts
index a8677a1d3..5a5a12e82 100644
--- a/server/controllers/api/users/index.ts
+++ b/server/controllers/api/users/index.ts
@@ -4,26 +4,21 @@ import { Hooks } from '@server/lib/plugins/hooks'
4import { OAuthTokenModel } from '@server/models/oauth/oauth-token' 4import { OAuthTokenModel } from '@server/models/oauth/oauth-token'
5import { MUserAccountDefault } from '@server/types/models' 5import { MUserAccountDefault } from '@server/types/models'
6import { pick } from '@shared/core-utils' 6import { pick } from '@shared/core-utils'
7import { HttpStatusCode, UserCreate, UserCreateResult, UserRegister, UserRight, UserUpdate } from '@shared/models' 7import { HttpStatusCode, UserCreate, UserCreateResult, UserRight, UserUpdate } from '@shared/models'
8import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger' 8import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger'
9import { logger } from '../../../helpers/logger' 9import { logger } from '../../../helpers/logger'
10import { generateRandomString, getFormattedObjects } from '../../../helpers/utils' 10import { generateRandomString, getFormattedObjects } from '../../../helpers/utils'
11import { CONFIG } from '../../../initializers/config'
12import { WEBSERVER } from '../../../initializers/constants' 11import { WEBSERVER } from '../../../initializers/constants'
13import { sequelizeTypescript } from '../../../initializers/database' 12import { sequelizeTypescript } from '../../../initializers/database'
14import { Emailer } from '../../../lib/emailer' 13import { Emailer } from '../../../lib/emailer'
15import { Notifier } from '../../../lib/notifier'
16import { Redis } from '../../../lib/redis' 14import { Redis } from '../../../lib/redis'
17import { buildUser, createUserAccountAndChannelAndPlaylist, sendVerifyUserEmail } from '../../../lib/user' 15import { buildUser, createUserAccountAndChannelAndPlaylist } from '../../../lib/user'
18import { 16import {
19 adminUsersSortValidator, 17 adminUsersSortValidator,
20 asyncMiddleware, 18 asyncMiddleware,
21 asyncRetryTransactionMiddleware, 19 asyncRetryTransactionMiddleware,
22 authenticate, 20 authenticate,
23 buildRateLimiter,
24 ensureUserHasRight, 21 ensureUserHasRight,
25 ensureUserRegistrationAllowed,
26 ensureUserRegistrationAllowedForIP,
27 paginationValidator, 22 paginationValidator,
28 setDefaultPagination, 23 setDefaultPagination,
29 setDefaultSort, 24 setDefaultSort,
@@ -31,19 +26,17 @@ import {
31 usersAddValidator, 26 usersAddValidator,
32 usersGetValidator, 27 usersGetValidator,
33 usersListValidator, 28 usersListValidator,
34 usersRegisterValidator,
35 usersRemoveValidator, 29 usersRemoveValidator,
36 usersUpdateValidator 30 usersUpdateValidator
37} from '../../../middlewares' 31} from '../../../middlewares'
38import { 32import {
39 ensureCanModerateUser, 33 ensureCanModerateUser,
40 usersAskResetPasswordValidator, 34 usersAskResetPasswordValidator,
41 usersAskSendVerifyEmailValidator,
42 usersBlockingValidator, 35 usersBlockingValidator,
43 usersResetPasswordValidator, 36 usersResetPasswordValidator
44 usersVerifyEmailValidator
45} from '../../../middlewares/validators' 37} from '../../../middlewares/validators'
46import { UserModel } from '../../../models/user/user' 38import { UserModel } from '../../../models/user/user'
39import { emailVerificationRouter } from './email-verification'
47import { meRouter } from './me' 40import { meRouter } from './me'
48import { myAbusesRouter } from './my-abuses' 41import { myAbusesRouter } from './my-abuses'
49import { myBlocklistRouter } from './my-blocklist' 42import { myBlocklistRouter } from './my-blocklist'
@@ -51,22 +44,14 @@ import { myVideosHistoryRouter } from './my-history'
51import { myNotificationsRouter } from './my-notifications' 44import { myNotificationsRouter } from './my-notifications'
52import { mySubscriptionsRouter } from './my-subscriptions' 45import { mySubscriptionsRouter } from './my-subscriptions'
53import { myVideoPlaylistsRouter } from './my-video-playlists' 46import { myVideoPlaylistsRouter } from './my-video-playlists'
47import { registrationsRouter } from './registrations'
54import { twoFactorRouter } from './two-factor' 48import { twoFactorRouter } from './two-factor'
55 49
56const auditLogger = auditLoggerFactory('users') 50const auditLogger = auditLoggerFactory('users')
57 51
58const signupRateLimiter = buildRateLimiter({
59 windowMs: CONFIG.RATES_LIMIT.SIGNUP.WINDOW_MS,
60 max: CONFIG.RATES_LIMIT.SIGNUP.MAX,
61 skipFailedRequests: true
62})
63
64const askSendEmailLimiter = buildRateLimiter({
65 windowMs: CONFIG.RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS,
66 max: CONFIG.RATES_LIMIT.ASK_SEND_EMAIL.MAX
67})
68
69const usersRouter = express.Router() 52const usersRouter = express.Router()
53usersRouter.use('/', emailVerificationRouter)
54usersRouter.use('/', registrationsRouter)
70usersRouter.use('/', twoFactorRouter) 55usersRouter.use('/', twoFactorRouter)
71usersRouter.use('/', tokensRouter) 56usersRouter.use('/', tokensRouter)
72usersRouter.use('/', myNotificationsRouter) 57usersRouter.use('/', myNotificationsRouter)
@@ -122,14 +107,6 @@ usersRouter.post('/',
122 asyncRetryTransactionMiddleware(createUser) 107 asyncRetryTransactionMiddleware(createUser)
123) 108)
124 109
125usersRouter.post('/register',
126 signupRateLimiter,
127 asyncMiddleware(ensureUserRegistrationAllowed),
128 ensureUserRegistrationAllowedForIP,
129 asyncMiddleware(usersRegisterValidator),
130 asyncRetryTransactionMiddleware(registerUser)
131)
132
133usersRouter.put('/:id', 110usersRouter.put('/:id',
134 authenticate, 111 authenticate,
135 ensureUserHasRight(UserRight.MANAGE_USERS), 112 ensureUserHasRight(UserRight.MANAGE_USERS),
@@ -156,17 +133,6 @@ usersRouter.post('/:id/reset-password',
156 asyncMiddleware(resetUserPassword) 133 asyncMiddleware(resetUserPassword)
157) 134)
158 135
159usersRouter.post('/ask-send-verify-email',
160 askSendEmailLimiter,
161 asyncMiddleware(usersAskSendVerifyEmailValidator),
162 asyncMiddleware(reSendVerifyUserEmail)
163)
164
165usersRouter.post('/:id/verify-email',
166 asyncMiddleware(usersVerifyEmailValidator),
167 asyncMiddleware(verifyUserEmail)
168)
169
170// --------------------------------------------------------------------------- 136// ---------------------------------------------------------------------------
171 137
172export { 138export {
@@ -218,35 +184,6 @@ async function createUser (req: express.Request, res: express.Response) {
218 }) 184 })
219} 185}
220 186
221async function registerUser (req: express.Request, res: express.Response) {
222 const body: UserRegister = req.body
223
224 const userToCreate = buildUser({
225 ...pick(body, [ 'username', 'password', 'email' ]),
226
227 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
228 })
229
230 const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({
231 userToCreate,
232 userDisplayName: body.displayName || undefined,
233 channelNames: body.channel
234 })
235
236 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
237 logger.info('User %s with its channel and account registered.', body.username)
238
239 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
240 await sendVerifyUserEmail(user)
241 }
242
243 Notifier.Instance.notifyOnNewUserRegistration(user)
244
245 Hooks.runAction('action:api.user.registered', { body, user, account, videoChannel, req, res })
246
247 return res.type('json').status(HttpStatusCode.NO_CONTENT_204).end()
248}
249
250async function unblockUser (req: express.Request, res: express.Response) { 187async function unblockUser (req: express.Request, res: express.Response) {
251 const user = res.locals.user 188 const user = res.locals.user
252 189
@@ -360,28 +297,6 @@ async function resetUserPassword (req: express.Request, res: express.Response) {
360 return res.status(HttpStatusCode.NO_CONTENT_204).end() 297 return res.status(HttpStatusCode.NO_CONTENT_204).end()
361} 298}
362 299
363async function reSendVerifyUserEmail (req: express.Request, res: express.Response) {
364 const user = res.locals.user
365
366 await sendVerifyUserEmail(user)
367
368 return res.status(HttpStatusCode.NO_CONTENT_204).end()
369}
370
371async function verifyUserEmail (req: express.Request, res: express.Response) {
372 const user = res.locals.user
373 user.emailVerified = true
374
375 if (req.body.isPendingEmail === true) {
376 user.email = user.pendingEmail
377 user.pendingEmail = null
378 }
379
380 await user.save()
381
382 return res.status(HttpStatusCode.NO_CONTENT_204).end()
383}
384
385async function changeUserBlock (res: express.Response, user: MUserAccountDefault, block: boolean, reason?: string) { 300async function changeUserBlock (res: express.Response, user: MUserAccountDefault, block: boolean, reason?: string) {
386 const oldUserAuditView = new UserAuditView(user.toFormattedJSON()) 301 const oldUserAuditView = new UserAuditView(user.toFormattedJSON())
387 302
diff --git a/server/controllers/api/users/registrations.ts b/server/controllers/api/users/registrations.ts
new file mode 100644
index 000000000..5e213d6cc
--- /dev/null
+++ b/server/controllers/api/users/registrations.ts
@@ -0,0 +1,249 @@
1import express from 'express'
2import { Emailer } from '@server/lib/emailer'
3import { Hooks } from '@server/lib/plugins/hooks'
4import { UserRegistrationModel } from '@server/models/user/user-registration'
5import { pick } from '@shared/core-utils'
6import {
7 HttpStatusCode,
8 UserRegister,
9 UserRegistrationRequest,
10 UserRegistrationState,
11 UserRegistrationUpdateState,
12 UserRight
13} from '@shared/models'
14import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger'
15import { logger } from '../../../helpers/logger'
16import { CONFIG } from '../../../initializers/config'
17import { Notifier } from '../../../lib/notifier'
18import { buildUser, createUserAccountAndChannelAndPlaylist, sendVerifyRegistrationEmail, sendVerifyUserEmail } from '../../../lib/user'
19import {
20 acceptOrRejectRegistrationValidator,
21 asyncMiddleware,
22 asyncRetryTransactionMiddleware,
23 authenticate,
24 buildRateLimiter,
25 ensureUserHasRight,
26 ensureUserRegistrationAllowedFactory,
27 ensureUserRegistrationAllowedForIP,
28 getRegistrationValidator,
29 listRegistrationsValidator,
30 paginationValidator,
31 setDefaultPagination,
32 setDefaultSort,
33 userRegistrationsSortValidator,
34 usersDirectRegistrationValidator,
35 usersRequestRegistrationValidator
36} from '../../../middlewares'
37
38const auditLogger = auditLoggerFactory('users')
39
40const registrationRateLimiter = buildRateLimiter({
41 windowMs: CONFIG.RATES_LIMIT.SIGNUP.WINDOW_MS,
42 max: CONFIG.RATES_LIMIT.SIGNUP.MAX,
43 skipFailedRequests: true
44})
45
46const registrationsRouter = express.Router()
47
48registrationsRouter.post('/registrations/request',
49 registrationRateLimiter,
50 asyncMiddleware(ensureUserRegistrationAllowedFactory('request-registration')),
51 ensureUserRegistrationAllowedForIP,
52 asyncMiddleware(usersRequestRegistrationValidator),
53 asyncRetryTransactionMiddleware(requestRegistration)
54)
55
56registrationsRouter.post('/registrations/:registrationId/accept',
57 authenticate,
58 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
59 asyncMiddleware(acceptOrRejectRegistrationValidator),
60 asyncRetryTransactionMiddleware(acceptRegistration)
61)
62registrationsRouter.post('/registrations/:registrationId/reject',
63 authenticate,
64 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
65 asyncMiddleware(acceptOrRejectRegistrationValidator),
66 asyncRetryTransactionMiddleware(rejectRegistration)
67)
68
69registrationsRouter.delete('/registrations/:registrationId',
70 authenticate,
71 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
72 asyncMiddleware(getRegistrationValidator),
73 asyncRetryTransactionMiddleware(deleteRegistration)
74)
75
76registrationsRouter.get('/registrations',
77 authenticate,
78 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
79 paginationValidator,
80 userRegistrationsSortValidator,
81 setDefaultSort,
82 setDefaultPagination,
83 listRegistrationsValidator,
84 asyncMiddleware(listRegistrations)
85)
86
87registrationsRouter.post('/register',
88 registrationRateLimiter,
89 asyncMiddleware(ensureUserRegistrationAllowedFactory('direct-registration')),
90 ensureUserRegistrationAllowedForIP,
91 asyncMiddleware(usersDirectRegistrationValidator),
92 asyncRetryTransactionMiddleware(registerUser)
93)
94
95// ---------------------------------------------------------------------------
96
97export {
98 registrationsRouter
99}
100
101// ---------------------------------------------------------------------------
102
103async function requestRegistration (req: express.Request, res: express.Response) {
104 const body: UserRegistrationRequest = req.body
105
106 const registration = new UserRegistrationModel({
107 ...pick(body, [ 'username', 'password', 'email', 'registrationReason' ]),
108
109 accountDisplayName: body.displayName,
110 channelDisplayName: body.channel?.displayName,
111 channelHandle: body.channel?.name,
112
113 state: UserRegistrationState.PENDING,
114
115 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
116 })
117
118 await registration.save()
119
120 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
121 await sendVerifyRegistrationEmail(registration)
122 }
123
124 Notifier.Instance.notifyOnNewRegistrationRequest(registration)
125
126 Hooks.runAction('action:api.user.requested-registration', { body, registration, req, res })
127
128 return res.json(registration.toFormattedJSON())
129}
130
131// ---------------------------------------------------------------------------
132
133async function acceptRegistration (req: express.Request, res: express.Response) {
134 const registration = res.locals.userRegistration
135 const body: UserRegistrationUpdateState = req.body
136
137 const userToCreate = buildUser({
138 username: registration.username,
139 password: registration.password,
140 email: registration.email,
141 emailVerified: registration.emailVerified
142 })
143 // We already encrypted password in registration model
144 userToCreate.skipPasswordEncryption = true
145
146 // TODO: handle conflicts if someone else created a channel handle/user handle/user email between registration and approval
147
148 const { user } = await createUserAccountAndChannelAndPlaylist({
149 userToCreate,
150 userDisplayName: registration.accountDisplayName,
151 channelNames: registration.channelHandle && registration.channelDisplayName
152 ? {
153 name: registration.channelHandle,
154 displayName: registration.channelDisplayName
155 }
156 : undefined
157 })
158
159 registration.userId = user.id
160 registration.state = UserRegistrationState.ACCEPTED
161 registration.moderationResponse = body.moderationResponse
162
163 await registration.save()
164
165 logger.info('Registration of %s accepted', registration.username)
166
167 if (body.preventEmailDelivery !== true) {
168 Emailer.Instance.addUserRegistrationRequestProcessedJob(registration)
169 }
170
171 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
172}
173
174async function rejectRegistration (req: express.Request, res: express.Response) {
175 const registration = res.locals.userRegistration
176 const body: UserRegistrationUpdateState = req.body
177
178 registration.state = UserRegistrationState.REJECTED
179 registration.moderationResponse = body.moderationResponse
180
181 await registration.save()
182
183 if (body.preventEmailDelivery !== true) {
184 Emailer.Instance.addUserRegistrationRequestProcessedJob(registration)
185 }
186
187 logger.info('Registration of %s rejected', registration.username)
188
189 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
190}
191
192// ---------------------------------------------------------------------------
193
194async function deleteRegistration (req: express.Request, res: express.Response) {
195 const registration = res.locals.userRegistration
196
197 await registration.destroy()
198
199 logger.info('Registration of %s deleted', registration.username)
200
201 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
202}
203
204// ---------------------------------------------------------------------------
205
206async function listRegistrations (req: express.Request, res: express.Response) {
207 const resultList = await UserRegistrationModel.listForApi({
208 start: req.query.start,
209 count: req.query.count,
210 sort: req.query.sort,
211 search: req.query.search
212 })
213
214 return res.json({
215 total: resultList.total,
216 data: resultList.data.map(d => d.toFormattedJSON())
217 })
218}
219
220// ---------------------------------------------------------------------------
221
222async function registerUser (req: express.Request, res: express.Response) {
223 const body: UserRegister = req.body
224
225 const userToCreate = buildUser({
226 ...pick(body, [ 'username', 'password', 'email' ]),
227
228 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
229 })
230
231 const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({
232 userToCreate,
233 userDisplayName: body.displayName || undefined,
234 channelNames: body.channel
235 })
236
237 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
238 logger.info('User %s with its channel and account registered.', body.username)
239
240 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
241 await sendVerifyUserEmail(user)
242 }
243
244 Notifier.Instance.notifyOnNewDirectRegistration(user)
245
246 Hooks.runAction('action:api.user.registered', { body, user, account, videoChannel, req, res })
247
248 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
249}
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts
index f8a607170..947f7ca77 100644
--- a/server/controllers/api/video-playlist.ts
+++ b/server/controllers/api/video-playlist.ts
@@ -15,7 +15,7 @@ import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/vid
15import { VideoPlaylistReorder } from '../../../shared/models/videos/playlist/video-playlist-reorder.model' 15import { VideoPlaylistReorder } from '../../../shared/models/videos/playlist/video-playlist-reorder.model'
16import { VideoPlaylistUpdate } from '../../../shared/models/videos/playlist/video-playlist-update.model' 16import { VideoPlaylistUpdate } from '../../../shared/models/videos/playlist/video-playlist-update.model'
17import { resetSequelizeInstance } from '../../helpers/database-utils' 17import { resetSequelizeInstance } from '../../helpers/database-utils'
18import { buildNSFWFilter, createReqFiles } from '../../helpers/express-utils' 18import { createReqFiles } from '../../helpers/express-utils'
19import { logger } from '../../helpers/logger' 19import { logger } from '../../helpers/logger'
20import { getFormattedObjects } from '../../helpers/utils' 20import { getFormattedObjects } from '../../helpers/utils'
21import { CONFIG } from '../../initializers/config' 21import { CONFIG } from '../../initializers/config'
@@ -474,10 +474,7 @@ async function getVideoPlaylistVideos (req: express.Request, res: express.Respon
474 'filter:api.video-playlist.videos.list.result' 474 'filter:api.video-playlist.videos.list.result'
475 ) 475 )
476 476
477 const options = { 477 const options = { accountId: user?.Account?.id }
478 displayNSFW: buildNSFWFilter(res, req.query.nsfw),
479 accountId: user ? user.Account.id : undefined
480 }
481 return res.json(getFormattedObjects(resultList.data, resultList.total, options)) 478 return res.json(getFormattedObjects(resultList.data, resultList.total, options))
482} 479}
483 480
diff --git a/server/controllers/api/videos/comment.ts b/server/controllers/api/videos/comment.ts
index 44d64776c..70ca21500 100644
--- a/server/controllers/api/videos/comment.ts
+++ b/server/controllers/api/videos/comment.ts
@@ -1,4 +1,6 @@
1import { MCommentFormattable } from '@server/types/models'
1import express from 'express' 2import express from 'express'
3
2import { ResultList, ThreadsResultList, UserRight, VideoCommentCreate } from '../../../../shared/models' 4import { ResultList, ThreadsResultList, UserRight, VideoCommentCreate } from '../../../../shared/models'
3import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' 5import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes'
4import { VideoCommentThreads } from '../../../../shared/models/videos/comment/video-comment.model' 6import { VideoCommentThreads } from '../../../../shared/models/videos/comment/video-comment.model'
@@ -109,7 +111,7 @@ async function listVideoThreads (req: express.Request, res: express.Response) {
109 const video = res.locals.onlyVideo 111 const video = res.locals.onlyVideo
110 const user = res.locals.oauth ? res.locals.oauth.token.User : undefined 112 const user = res.locals.oauth ? res.locals.oauth.token.User : undefined
111 113
112 let resultList: ThreadsResultList<VideoCommentModel> 114 let resultList: ThreadsResultList<MCommentFormattable>
113 115
114 if (video.commentsEnabled === true) { 116 if (video.commentsEnabled === true) {
115 const apiOptions = await Hooks.wrapObject({ 117 const apiOptions = await Hooks.wrapObject({
@@ -144,12 +146,11 @@ async function listVideoThreadComments (req: express.Request, res: express.Respo
144 const video = res.locals.onlyVideo 146 const video = res.locals.onlyVideo
145 const user = res.locals.oauth ? res.locals.oauth.token.User : undefined 147 const user = res.locals.oauth ? res.locals.oauth.token.User : undefined
146 148
147 let resultList: ResultList<VideoCommentModel> 149 let resultList: ResultList<MCommentFormattable>
148 150
149 if (video.commentsEnabled === true) { 151 if (video.commentsEnabled === true) {
150 const apiOptions = await Hooks.wrapObject({ 152 const apiOptions = await Hooks.wrapObject({
151 videoId: video.id, 153 videoId: video.id,
152 isVideoOwned: video.isOwned(),
153 threadId: res.locals.videoCommentThread.id, 154 threadId: res.locals.videoCommentThread.id,
154 user 155 user
155 }, 'filter:api.video-thread-comments.list.params') 156 }, 'filter:api.video-thread-comments.list.params')
diff --git a/server/controllers/api/videos/token.ts b/server/controllers/api/videos/token.ts
index 009b6dfb6..22387c3e8 100644
--- a/server/controllers/api/videos/token.ts
+++ b/server/controllers/api/videos/token.ts
@@ -22,7 +22,7 @@ export {
22function generateToken (req: express.Request, res: express.Response) { 22function generateToken (req: express.Request, res: express.Response) {
23 const video = res.locals.onlyVideo 23 const video = res.locals.onlyVideo
24 24
25 const { token, expires } = VideoTokensManager.Instance.create(video.uuid) 25 const { token, expires } = VideoTokensManager.Instance.create({ videoUUID: video.uuid, user: res.locals.oauth.token.User })
26 26
27 return res.json({ 27 return res.json({
28 files: { 28 files: {
diff --git a/server/controllers/feeds.ts b/server/controllers/feeds.ts
index 772fe734d..ef810a842 100644
--- a/server/controllers/feeds.ts
+++ b/server/controllers/feeds.ts
@@ -285,8 +285,8 @@ function addVideosToFeed (feed: Feed, videos: VideoModel[]) {
285 content: toSafeHtml(video.description), 285 content: toSafeHtml(video.description),
286 author: [ 286 author: [
287 { 287 {
288 name: video.VideoChannel.Account.getDisplayName(), 288 name: video.VideoChannel.getDisplayName(),
289 link: video.VideoChannel.Account.Actor.url 289 link: video.VideoChannel.Actor.url
290 } 290 }
291 ], 291 ],
292 date: video.publishedAt, 292 date: video.publishedAt,
diff --git a/server/controllers/tracker.ts b/server/controllers/tracker.ts
index 19a8b2bc9..c4f3a8889 100644
--- a/server/controllers/tracker.ts
+++ b/server/controllers/tracker.ts
@@ -1,17 +1,22 @@
1import { Server as TrackerServer } from 'bittorrent-tracker' 1import { Server as TrackerServer } from 'bittorrent-tracker'
2import express from 'express' 2import express from 'express'
3import { createServer } from 'http' 3import { createServer } from 'http'
4import LRUCache from 'lru-cache'
4import proxyAddr from 'proxy-addr' 5import proxyAddr from 'proxy-addr'
5import { WebSocketServer } from 'ws' 6import { WebSocketServer } from 'ws'
6import { Redis } from '@server/lib/redis'
7import { logger } from '../helpers/logger' 7import { logger } from '../helpers/logger'
8import { CONFIG } from '../initializers/config' 8import { CONFIG } from '../initializers/config'
9import { TRACKER_RATE_LIMITS } from '../initializers/constants' 9import { LRU_CACHE, TRACKER_RATE_LIMITS } from '../initializers/constants'
10import { VideoFileModel } from '../models/video/video-file' 10import { VideoFileModel } from '../models/video/video-file'
11import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' 11import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
12 12
13const trackerRouter = express.Router() 13const trackerRouter = express.Router()
14 14
15const blockedIPs = new LRUCache<string, boolean>({
16 max: LRU_CACHE.TRACKER_IPS.MAX_SIZE,
17 ttl: TRACKER_RATE_LIMITS.BLOCK_IP_LIFETIME
18})
19
15let peersIps = {} 20let peersIps = {}
16let peersIpInfoHash = {} 21let peersIpInfoHash = {}
17runPeersChecker() 22runPeersChecker()
@@ -55,8 +60,7 @@ const trackerServer = new TrackerServer({
55 60
56 // Close socket connection and block IP for a few time 61 // Close socket connection and block IP for a few time
57 if (params.type === 'ws') { 62 if (params.type === 'ws') {
58 Redis.Instance.setTrackerBlockIP(ip) 63 blockedIPs.set(ip, true)
59 .catch(err => logger.error('Cannot set tracker block ip.', { err }))
60 64
61 // setTimeout to wait filter response 65 // setTimeout to wait filter response
62 setTimeout(() => params.socket.close(), 0) 66 setTimeout(() => params.socket.close(), 0)
@@ -102,26 +106,22 @@ function createWebsocketTrackerServer (app: express.Application) {
102 if (request.url === '/tracker/socket') { 106 if (request.url === '/tracker/socket') {
103 const ip = proxyAddr(request, CONFIG.TRUST_PROXY) 107 const ip = proxyAddr(request, CONFIG.TRUST_PROXY)
104 108
105 Redis.Instance.doesTrackerBlockIPExist(ip) 109 if (blockedIPs.has(ip)) {
106 .then(result => { 110 logger.debug('Blocking IP %s from tracker.', ip)
107 if (result === true) {
108 logger.debug('Blocking IP %s from tracker.', ip)
109 111
110 socket.write('HTTP/1.1 403 Forbidden\r\n\r\n') 112 socket.write('HTTP/1.1 403 Forbidden\r\n\r\n')
111 socket.destroy() 113 socket.destroy()
112 return 114 return
113 } 115 }
114 116
115 // FIXME: typings 117 // FIXME: typings
116 return wss.handleUpgrade(request, socket as any, head, ws => wss.emit('connection', ws, request)) 118 return wss.handleUpgrade(request, socket as any, head, ws => wss.emit('connection', ws, request))
117 })
118 .catch(err => logger.error('Cannot check if tracker block ip exists.', { err }))
119 } 119 }
120 120
121 // Don't destroy socket, we have Socket.IO too 121 // Don't destroy socket, we have Socket.IO too
122 }) 122 })
123 123
124 return server 124 return { server, trackerServer }
125} 125}
126 126
127// --------------------------------------------------------------------------- 127// ---------------------------------------------------------------------------