Add ability to limit user registrations
authorChocobozzz <florian.bigard@gmail.com>
Tue, 25 Jul 2017 18:17:28 +0000 (20:17 +0200)
committerChocobozzz <florian.bigard@gmail.com>
Tue, 25 Jul 2017 18:17:28 +0000 (20:17 +0200)
15 files changed:
client/src/app/core/config/config.service.ts
client/src/app/core/menu/menu.component.html
client/src/app/core/menu/menu.component.ts
config/default.yaml
config/test-1.yaml
server/controllers/api/config.ts
server/controllers/api/users.ts
server/helpers/utils.ts
server/initializers/constants.ts
server/middlewares/config.ts [deleted file]
server/middlewares/index.ts
server/middlewares/validators/users.ts
server/tests/api/check-params/users.js
server/tests/api/config.js
shared/models/server-config.model.ts

index b8cb15e84b8538fc7d3890e2adf0ac53f15c317f..acdc12cc66b5e60065c458161c29702c26178f08 100644 (file)
@@ -10,7 +10,7 @@ export class ConfigService {
 
   private config: ServerConfig = {
     signup: {
-      enabled: false
+      allowed: false
     }
   }
 
index 63a1c03c53290ccd8d070586e2562e31c5669321..fb4c4a6a9a5b7a97e1f437321cf4905320dcd0ae 100644 (file)
@@ -14,7 +14,7 @@
       </a>
     </div>
 
-    <a *ngIf="!isLoggedIn && isRegistrationEnabled()" routerLink="/signup" routerLinkActive="active">
+    <a *ngIf="!isLoggedIn && isRegistrationAllowed()" routerLink="/signup" routerLinkActive="active">
       <span class="hidden-xs glyphicon glyphicon-user"></span>
       Signup
     </a>
index b725f64a7dd01cfaf628af4ebfdc34d80598b411..669fc6572035600a9e9dc22fadfd254d427a6315 100644 (file)
@@ -36,8 +36,8 @@ export class MenuComponent implements OnInit {
     )
   }
 
-  isRegistrationEnabled () {
-    return this.configService.getConfig().signup.enabled
+  isRegistrationAllowed () {
+    return this.configService.getConfig().signup.allowed
   }
 
   isUserAdmin () {
index b4e7606cfb4556cde1d8e0294929eb2fa446e0dc..a97d3ff78e7bab3d0007f3b297d679a2463614e5 100644 (file)
@@ -33,6 +33,7 @@ admin:
 
 signup:
   enabled: false
+  limit: 10 # When the limit is reached, registrations are disabled. -1 == unlimited
 
 # If enabled, the video will be transcoded to mp4 (x264) with "faststart" flag
 # Uses a lot of CPU!
index e244a8797cc99b7c8ad72a0ed75c97b98114df10..d08a3bee6a741d37d5841a28016daad5fd14cbbf 100644 (file)
@@ -20,3 +20,6 @@ storage:
 
 admin:
   email: 'admin1@example.com'
+
+signup:
+  limit: 4
index 3e9aa77a5c6aac1bb7432adcac866d2abbe41b2d..f02a2bc58efb2c71a677d2fb07fc1a238f98792e 100644 (file)
@@ -1,6 +1,6 @@
 import * as express from 'express'
 
-import { CONFIG } from '../../initializers'
+import { isSignupAllowed } from '../../helpers'
 import { ServerConfig } from '../../../shared'
 
 const configRouter = express.Router()
@@ -9,12 +9,15 @@ configRouter.get('/', getConfig)
 
 // Get the client credentials for the PeerTube front end
 function getConfig (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const json: ServerConfig = {
-    signup: {
-      enabled: CONFIG.SIGNUP.ENABLED
+
+  isSignupAllowed().then(allowed => {
+    const json: ServerConfig = {
+      signup: {
+        allowed
+      }
     }
-  }
-  res.json(json)
+    res.json(json)
+  })
 }
 
 // ---------------------------------------------------------------------------
index 6c375cc5b1b1d2aeb9f017b71c4001e91d669017..f50dbc9a31a3e31833eb39fce629f08b4f291bcc 100644 (file)
@@ -6,7 +6,7 @@ import { logger, getFormatedObjects } from '../../helpers'
 import {
   authenticate,
   ensureIsAdmin,
-  ensureUserRegistrationEnabled,
+  ensureUserRegistrationAllowed,
   usersAddValidator,
   usersUpdateValidator,
   usersRemoveValidator,
@@ -48,7 +48,7 @@ usersRouter.post('/',
 )
 
 usersRouter.post('/register',
-  ensureUserRegistrationEnabled,
+  ensureUserRegistrationAllowed,
   usersAddValidator,
   createUser
 )
index 9c08afb711af7329863d0dd385608ae7f9a46b31..f326210f32886fd5136ee1511820cffeaed5bdd3 100644 (file)
@@ -1,6 +1,8 @@
 import * as express from 'express'
+import * as Promise from 'bluebird'
 
 import { pseudoRandomBytesPromise } from './core-utils'
+import { CONFIG, database as db } from '../initializers'
 import { ResultList } from '../../shared'
 
 function badRequest (req: express.Request, res: express.Response, next: express.NextFunction) {
@@ -30,10 +32,26 @@ function getFormatedObjects<U, T extends FormatableToJSON> (objects: T[], object
   return res
 }
 
+function isSignupAllowed () {
+  if (CONFIG.SIGNUP.ENABLED === false) {
+    return Promise.resolve(false)
+  }
+
+  // No limit and signup is enabled
+  if (CONFIG.SIGNUP.LIMIT === -1) {
+    return Promise.resolve(true)
+  }
+
+  return db.User.countTotal().then(totalUsers => {
+    return totalUsers < CONFIG.SIGNUP.LIMIT
+  })
+}
+
 // ---------------------------------------------------------------------------
 
 export {
   badRequest,
   generateRandomString,
-  getFormatedObjects
+  getFormatedObjects,
+  isSignupAllowed
 }
index 928a3f5704cea290dbf2c59288586250355543bf..314a05ab7a0241a021db3c75ed51414259ba6a2d 100644 (file)
@@ -76,7 +76,8 @@ const CONFIG = {
     EMAIL: config.get<string>('admin.email')
   },
   SIGNUP: {
-    ENABLED: config.get<boolean>('signup.enabled')
+    ENABLED: config.get<boolean>('signup.enabled'),
+    LIMIT: config.get<number>('signup.limit')
   },
   TRANSCODING: {
     ENABLED: config.get<boolean>('transcoding.enabled'),
diff --git a/server/middlewares/config.ts b/server/middlewares/config.ts
deleted file mode 100644 (file)
index 1481e66..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-import 'express-validator'
-import * as express from 'express'
-
-import { CONFIG } from '../initializers'
-
-function ensureUserRegistrationEnabled (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const registrationEnabled = CONFIG.SIGNUP.ENABLED
-
-  if (registrationEnabled === true) {
-    return next()
-  }
-
-  return res.status(400).send('User registration is not enabled.')
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  ensureUserRegistrationEnabled
-}
index 9a3f849a71285278ef26c5f8545fc34037432ceb..d71dd245265a6fbbebef6bf1acf2ef3188304a98 100644 (file)
@@ -1,6 +1,5 @@
 export * from './validators'
 export * from './admin'
-export * from './config'
 export * from './oauth'
 export * from './pagination'
 export * from './pods'
index 38f8aed5b05adb66e5a9282eb10bbecf8d717c89..71e529872087cb006c901b904975eafc955d5ab1 100644 (file)
@@ -5,7 +5,7 @@ import * as validator from 'validator'
 
 import { database as db } from '../../initializers/database'
 import { checkErrors } from './utils'
-import { logger } from '../../helpers'
+import { isSignupAllowed, logger } from '../../helpers'
 import { VideoInstance } from '../../models'
 
 function usersAddValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
@@ -88,11 +88,22 @@ function usersVideoRatingValidator (req: express.Request, res: express.Response,
   })
 }
 
+function ensureUserRegistrationAllowed (req: express.Request, res: express.Response, next: express.NextFunction) {
+  isSignupAllowed().then(allowed => {
+    if (allowed === false) {
+      return res.status(403).send('User registration is not enabled or user limit is reached.')
+    }
+
+    return next()
+  })
+}
+
 // ---------------------------------------------------------------------------
 
 export {
   usersAddValidator,
   usersRemoveValidator,
   usersUpdateValidator,
-  usersVideoRatingValidator
+  usersVideoRatingValidator,
+  ensureUserRegistrationAllowed
 }
index 2c1189f7a590754e239e9a353517c542b3194770..9e7115da149a53bc5c465a3d71a83e0f9f736c1c 100644 (file)
@@ -513,7 +513,13 @@ describe('Test users API validators', function () {
         password: 'my super password 4'
       }
 
-      requestsUtils.makePostBodyRequest(serverWithRegistrationDisabled.url, registrationPath, serverWithRegistrationDisabled.accessToken, data, done, 400)
+      requestsUtils.makePostBodyRequest(serverWithRegistrationDisabled.url, registrationPath, serverWithRegistrationDisabled.accessToken, data, done, 403)
+    })
+  })
+
+  describe('When registering multiple users on a server with users limit', function () {
+    it('Should fail when after 3 registrations', function (done) {
+      usersUtils.registerUser(server.url, 'user42', 'super password', 403, done)
     })
   })
 
index e79e12823b3b6fdca9259b7fe0fb9eb574f8f704..f2c00f85a94254f223a56ef3ab5807eb9a5a6fdd 100644 (file)
@@ -8,6 +8,7 @@ const series = require('async/series')
 
 const serversUtils = require('../utils/servers')
 const configUtils = require('../utils/config')
+const usersUtils = require('../utils/users')
 
 describe('Test config', function () {
   let server = null
@@ -28,18 +29,51 @@ describe('Test config', function () {
     ], done)
   })
 
-  it('Should have a correct config', function (done) {
+  it('Should have a correct config on a server with registration enabled', function (done) {
     configUtils.getConfig(server.url, function (err, res) {
       if (err) throw err
 
       const data = res.body
 
-      expect(data.signup.enabled).to.be.truthy
+      expect(data.signup.allowed).to.be.truthy
 
       done()
     })
   })
 
+  it('Should have a correct config on a server with registration enabled and a users limit', function (done) {
+    series([
+      function (next) {
+        usersUtils.registerUser(server.url, 'user1', 'super password', done)
+      },
+
+      function (next) {
+        usersUtils.registerUser(server.url, 'user2', 'super password', done)
+      },
+
+      function (next) {
+        usersUtils.registerUser(server.url, 'user3', 'super password', done)
+      },
+
+      function (next) {
+        usersUtils.registerUser(server.url, 'user4', 'super password', done)
+      }
+
+    ], function (err) {
+      if (err) throw err
+
+      configUtils.getConfig(server.url, function (err, res) {
+        if (err) throw err
+
+        const data = res.body
+
+        expect(data.signup.allowed).to.be.truthy
+
+        done()
+      })
+    })
+  })
+
   after(function (done) {
     process.kill(-server.app.pid)
 
index a391569630d1facc499f85f324b6342ac6f53954..aab842905ffc79428f0a012997bfcb74024a6020 100644 (file)
@@ -1,5 +1,5 @@
 export interface ServerConfig {
   signup: {
-    enabled: boolean
+    allowed: boolean
   }
 }