aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/controllers/api/config.ts8
-rw-r--r--server/helpers/signup.ts8
-rw-r--r--server/middlewares/validators/users.ts17
-rw-r--r--server/tests/fixtures/peertube-plugin-test/main.js11
-rw-r--r--server/tests/plugins/filter-hooks.ts21
-rw-r--r--shared/models/plugins/server-hook.model.ts5
6 files changed, 60 insertions, 10 deletions
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index 39a124fc5..113c1e9db 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -17,6 +17,7 @@ import { objectConverter } from '../../helpers/core-utils'
17import { CONFIG, reloadConfig } from '../../initializers/config' 17import { CONFIG, reloadConfig } from '../../initializers/config'
18import { PluginManager } from '../../lib/plugins/plugin-manager' 18import { PluginManager } from '../../lib/plugins/plugin-manager'
19import { getThemeOrDefault } from '../../lib/plugins/theme-utils' 19import { getThemeOrDefault } from '../../lib/plugins/theme-utils'
20import { Hooks } from '@server/lib/plugins/hooks'
20 21
21const configRouter = express.Router() 22const configRouter = express.Router()
22 23
@@ -47,7 +48,12 @@ configRouter.delete('/custom',
47let serverCommit: string 48let serverCommit: string
48 49
49async function getConfig (req: express.Request, res: express.Response) { 50async function getConfig (req: express.Request, res: express.Response) {
50 const allowed = await isSignupAllowed() 51 const { allowed } = await Hooks.wrapPromiseFun(
52 isSignupAllowed,
53 {},
54 'filter:api.user.signup.allowed.result'
55 )
56
51 const allowedForCurrentIP = isSignupAllowedForCurrentIP(req.ip) 57 const allowedForCurrentIP = isSignupAllowedForCurrentIP(req.ip)
52 const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME) 58 const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME)
53 59
diff --git a/server/helpers/signup.ts b/server/helpers/signup.ts
index 5eb56b3cf..7c73f7c5c 100644
--- a/server/helpers/signup.ts
+++ b/server/helpers/signup.ts
@@ -4,19 +4,19 @@ import { CONFIG } from '../initializers/config'
4 4
5const isCidr = require('is-cidr') 5const isCidr = require('is-cidr')
6 6
7async function isSignupAllowed () { 7async function isSignupAllowed (): Promise<{ allowed: boolean, errorMessage?: string }> {
8 if (CONFIG.SIGNUP.ENABLED === false) { 8 if (CONFIG.SIGNUP.ENABLED === false) {
9 return false 9 return { allowed: false }
10 } 10 }
11 11
12 // No limit and signup is enabled 12 // No limit and signup is enabled
13 if (CONFIG.SIGNUP.LIMIT === -1) { 13 if (CONFIG.SIGNUP.LIMIT === -1) {
14 return true 14 return { allowed: true }
15 } 15 }
16 16
17 const totalUsers = await UserModel.countTotal() 17 const totalUsers = await UserModel.countTotal()
18 18
19 return totalUsers < CONFIG.SIGNUP.LIMIT 19 return { allowed: totalUsers < CONFIG.SIGNUP.LIMIT }
20} 20}
21 21
22function isSignupAllowedForCurrentIP (ip: string) { 22function isSignupAllowedForCurrentIP (ip: string) {
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts
index 804d1410e..8615de406 100644
--- a/server/middlewares/validators/users.ts
+++ b/server/middlewares/validators/users.ts
@@ -35,6 +35,8 @@ import { isThemeRegistered } from '../../lib/plugins/theme-utils'
35import { doesVideoExist } from '../../helpers/middlewares' 35import { doesVideoExist } from '../../helpers/middlewares'
36import { UserRole } from '../../../shared/models/users' 36import { UserRole } from '../../../shared/models/users'
37import { MUserDefault } from '@server/typings/models' 37import { MUserDefault } from '@server/typings/models'
38import { Hooks } from '@server/lib/plugins/hooks'
39import { isLocalVideoAccepted } from '@server/lib/moderation'
38 40
39const usersAddValidator = [ 41const usersAddValidator = [
40 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), 42 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'),
@@ -280,10 +282,19 @@ const usersVideoRatingValidator = [
280 282
281const ensureUserRegistrationAllowed = [ 283const ensureUserRegistrationAllowed = [
282 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 284 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
283 const allowed = await isSignupAllowed() 285 const allowedParams = {
284 if (allowed === false) { 286 body: req.body
287 }
288
289 const allowedResult = await Hooks.wrapPromiseFun(
290 isSignupAllowed,
291 allowedParams,
292 'filter:api.user.signup.allowed.result'
293 )
294
295 if (allowedResult.allowed === false) {
285 return res.status(403) 296 return res.status(403)
286 .json({ error: 'User registration is not enabled or user limit is reached.' }) 297 .json({ error: allowedResult.errorMessage || 'User registration is not enabled or user limit is reached.' })
287 } 298 }
288 299
289 return next() 300 return next()
diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js
index 7c53f6afe..055884d29 100644
--- a/server/tests/fixtures/peertube-plugin-test/main.js
+++ b/server/tests/fixtures/peertube-plugin-test/main.js
@@ -86,6 +86,17 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
86 return false 86 return false
87 } 87 }
88 }) 88 })
89
90 registerHook({
91 target: 'filter:api.user.signup.allowed.result',
92 handler: (result, params) => {
93 if (params && params.body.email.includes('jma')) {
94 return { allowed: false, errorMessage: 'No jma' }
95 }
96
97 return result
98 }
99 })
89} 100}
90 101
91async function unregister () { 102async function unregister () {
diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts
index ec0679b04..b2436fb9e 100644
--- a/server/tests/plugins/filter-hooks.ts
+++ b/server/tests/plugins/filter-hooks.ts
@@ -28,11 +28,12 @@ import {
28 getVideoWithToken, 28 getVideoWithToken,
29 setDefaultVideoChannel, 29 setDefaultVideoChannel,
30 waitJobs, 30 waitJobs,
31 doubleFollow 31 doubleFollow, getConfig, registerUser
32} from '../../../shared/extra-utils' 32} from '../../../shared/extra-utils'
33import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' 33import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model'
34import { VideoDetails } from '../../../shared/models/videos' 34import { VideoDetails } from '../../../shared/models/videos'
35import { getYoutubeVideoUrl, importVideo } from '../../../shared/extra-utils/videos/video-imports' 35import { getYoutubeVideoUrl, importVideo } from '../../../shared/extra-utils/videos/video-imports'
36import { ServerConfig } from '@shared/models'
36 37
37const expect = chai.expect 38const expect = chai.expect
38 39
@@ -187,6 +188,24 @@ describe('Test plugin filter hooks', function () {
187 }) 188 })
188 }) 189 })
189 190
191 describe('Should run filter:api.user.signup.allowed.result', function () {
192
193 it('Should run on config endpoint', async function () {
194 const res = await getConfig(servers[0].url)
195 expect((res.body as ServerConfig).signup.allowed).to.be.true
196 })
197
198 it('Should allow a signup', async function () {
199 await registerUser(servers[0].url, 'john', 'password')
200 })
201
202 it('Should not allow a signup', async function () {
203 const res = await registerUser(servers[0].url, 'jma', 'password', 403)
204
205 expect(res.body.error).to.equal('No jma')
206 })
207 })
208
190 after(async function () { 209 after(async function () {
191 await cleanupTests(servers) 210 await cleanupTests(servers)
192 }) 211 })
diff --git a/shared/models/plugins/server-hook.model.ts b/shared/models/plugins/server-hook.model.ts
index 32c7f4688..41ee28097 100644
--- a/shared/models/plugins/server-hook.model.ts
+++ b/shared/models/plugins/server-hook.model.ts
@@ -29,7 +29,10 @@ export const serverFilterHookObject = {
29 29
30 // Filter result used to check if we need to auto blacklist a video 30 // Filter result used to check if we need to auto blacklist a video
31 // (fired when a local or remote video is created or updated) 31 // (fired when a local or remote video is created or updated)
32 'filter:video.auto-blacklist.result': true 32 'filter:video.auto-blacklist.result': true,
33
34 // Filter result used to check if a user can register on the instance
35 'filter:api.user.signup.allowed.result': true
33} 36}
34 37
35export type ServerFilterHookName = keyof typeof serverFilterHookObject 38export type ServerFilterHookName = keyof typeof serverFilterHookObject