aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
authorRigel Kent <sendmemail@rigelk.eu>2018-05-22 19:43:13 +0200
committerRigel Kent <par@rigelk.eu>2018-05-22 19:44:34 +0200
commitff2c1fe8133f9556f6aaa52058cd8b83c40085e6 (patch)
treebc92cde25bf5a1d74b1413d7145179ef7abfd670 /server
parente2f1dad83607aa610ee33b234a81b07664f4304c (diff)
downloadPeerTube-ff2c1fe8133f9556f6aaa52058cd8b83c40085e6.tar.gz
PeerTube-ff2c1fe8133f9556f6aaa52058cd8b83c40085e6.tar.zst
PeerTube-ff2c1fe8133f9556f6aaa52058cd8b83c40085e6.zip
feature: IP filtering on signup page
disable registration form on IP not in range checking the CIDR list before filtering with it placing the cidr filters as an attribute object in the config
Diffstat (limited to 'server')
-rw-r--r--server/controllers/api/config.ts6
-rw-r--r--server/controllers/api/users.ts2
-rw-r--r--server/helpers/utils.ts36
-rw-r--r--server/initializers/checker.ts4
-rw-r--r--server/initializers/constants.ts8
-rw-r--r--server/middlewares/validators/users.ts19
6 files changed, 69 insertions, 6 deletions
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index 12074a80e..f678e3c4a 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -4,7 +4,7 @@ import { 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'
6import { unlinkPromise, writeFilePromise } from '../../helpers/core-utils' 6import { unlinkPromise, writeFilePromise } from '../../helpers/core-utils'
7import { isSignupAllowed } from '../../helpers/utils' 7import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../helpers/utils'
8import { CONFIG, CONSTRAINTS_FIELDS, reloadConfig } from '../../initializers' 8import { CONFIG, CONSTRAINTS_FIELDS, reloadConfig } from '../../initializers'
9import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares' 9import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares'
10import { customConfigUpdateValidator } from '../../middlewares/validators/config' 10import { customConfigUpdateValidator } from '../../middlewares/validators/config'
@@ -36,6 +36,7 @@ configRouter.delete('/custom',
36 36
37async function getConfig (req: express.Request, res: express.Response, next: express.NextFunction) { 37async function getConfig (req: express.Request, res: express.Response, next: express.NextFunction) {
38 const allowed = await isSignupAllowed() 38 const allowed = await isSignupAllowed()
39 const allowedForCurrentIP = isSignupAllowedForCurrentIP(req.ip)
39 40
40 const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) 41 const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
41 .filter(key => CONFIG.TRANSCODING.RESOLUTIONS[key] === true) 42 .filter(key => CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
@@ -54,7 +55,8 @@ async function getConfig (req: express.Request, res: express.Response, next: exp
54 }, 55 },
55 serverVersion: packageJSON.version, 56 serverVersion: packageJSON.version,
56 signup: { 57 signup: {
57 allowed 58 allowed,
59 allowedForCurrentIP
58 }, 60 },
59 transcoding: { 61 transcoding: {
60 enabledResolutions 62 enabledResolutions
diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts
index 0a591f11d..8dff4b87c 100644
--- a/server/controllers/api/users.ts
+++ b/server/controllers/api/users.ts
@@ -19,6 +19,7 @@ import {
19 authenticate, 19 authenticate,
20 ensureUserHasRight, 20 ensureUserHasRight,
21 ensureUserRegistrationAllowed, 21 ensureUserRegistrationAllowed,
22 ensureUserRegistrationAllowedForIP,
22 paginationValidator, 23 paginationValidator,
23 setDefaultPagination, 24 setDefaultPagination,
24 setDefaultSort, 25 setDefaultSort,
@@ -106,6 +107,7 @@ usersRouter.post('/',
106 107
107usersRouter.post('/register', 108usersRouter.post('/register',
108 asyncMiddleware(ensureUserRegistrationAllowed), 109 asyncMiddleware(ensureUserRegistrationAllowed),
110 ensureUserRegistrationAllowedForIP,
109 asyncMiddleware(usersRegisterValidator), 111 asyncMiddleware(usersRegisterValidator),
110 asyncMiddleware(registerUserRetryWrapper) 112 asyncMiddleware(registerUserRetryWrapper)
111) 113)
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts
index 058c3211e..e4556fa12 100644
--- a/server/helpers/utils.ts
+++ b/server/helpers/utils.ts
@@ -1,4 +1,6 @@
1import { Model } from 'sequelize-typescript' 1import { Model } from 'sequelize-typescript'
2import * as ipaddr from 'ipaddr.js'
3const isCidr = require('is-cidr')
2import { ResultList } from '../../shared' 4import { ResultList } from '../../shared'
3import { VideoResolution } from '../../shared/models/videos' 5import { VideoResolution } from '../../shared/models/videos'
4import { CONFIG } from '../initializers' 6import { CONFIG } from '../initializers'
@@ -48,6 +50,39 @@ async function isSignupAllowed () {
48 return totalUsers < CONFIG.SIGNUP.LIMIT 50 return totalUsers < CONFIG.SIGNUP.LIMIT
49} 51}
50 52
53function isSignupAllowedForCurrentIP (ip: string) {
54 const addr = ipaddr.parse(ip)
55 let excludeList = [ 'blacklist' ]
56 let matched: string
57
58 // if there is a valid, non-empty whitelist, we exclude all unknown adresses too
59 if (CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr(cidr)).length > 0) {
60 excludeList.push('unknown')
61 }
62
63 if (addr.kind() === 'ipv4') {
64 const addrV4 = ipaddr.IPv4.parse(ip)
65 const rangeList = {
66 whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v4(cidr))
67 .map(cidr => ipaddr.IPv4.parseCIDR(cidr)),
68 blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v4(cidr))
69 .map(cidr => ipaddr.IPv4.parseCIDR(cidr))
70 }
71 matched = ipaddr.subnetMatch(addrV4, rangeList, 'unknown')
72 } else if (addr.kind() === 'ipv6') {
73 const addrV6 = ipaddr.IPv6.parse(ip)
74 const rangeList = {
75 whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v6(cidr))
76 .map(cidr => ipaddr.IPv6.parseCIDR(cidr)),
77 blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v6(cidr))
78 .map(cidr => ipaddr.IPv6.parseCIDR(cidr))
79 }
80 matched = ipaddr.subnetMatch(addrV6, rangeList, 'unknown')
81 }
82
83 return !excludeList.includes(matched)
84}
85
51function computeResolutionsToTranscode (videoFileHeight: number) { 86function computeResolutionsToTranscode (videoFileHeight: number) {
52 const resolutionsEnabled: number[] = [] 87 const resolutionsEnabled: number[] = []
53 const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS 88 const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS
@@ -99,6 +134,7 @@ export {
99 generateRandomString, 134 generateRandomString,
100 getFormattedObjects, 135 getFormattedObjects,
101 isSignupAllowed, 136 isSignupAllowed,
137 isSignupAllowedForCurrentIP,
102 computeResolutionsToTranscode, 138 computeResolutionsToTranscode,
103 resetSequelizeInstance, 139 resetSequelizeInstance,
104 getServerActor, 140 getServerActor,
diff --git a/server/initializers/checker.ts b/server/initializers/checker.ts
index 5a9c603b5..6259c7b6c 100644
--- a/server/initializers/checker.ts
+++ b/server/initializers/checker.ts
@@ -27,7 +27,9 @@ function checkMissedConfig () {
27 'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache', 27 'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache',
28 'log.level', 28 'log.level',
29 'user.video_quota', 29 'user.video_quota',
30 'cache.previews.size', 'admin.email', 'signup.enabled', 'signup.limit', 'transcoding.enabled', 'transcoding.threads', 30 'cache.previews.size', 'admin.email',
31 'signup.enabled', 'signup.limit', 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist',
32 'transcoding.enabled', 'transcoding.threads',
31 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', 33 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route',
32 'instance.default_nsfw_policy', 'instance.robots', 34 'instance.default_nsfw_policy', 'instance.robots',
33 'services.twitter.username', 'services.twitter.whitelisted' 35 'services.twitter.username', 'services.twitter.whitelisted'
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 424947590..a35306730 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -150,7 +150,13 @@ const CONFIG = {
150 }, 150 },
151 SIGNUP: { 151 SIGNUP: {
152 get ENABLED () { return config.get<boolean>('signup.enabled') }, 152 get ENABLED () { return config.get<boolean>('signup.enabled') },
153 get LIMIT () { return config.get<number>('signup.limit') } 153 get LIMIT () { return config.get<number>('signup.limit') },
154 FILTERS: {
155 CIDR: {
156 get WHITELIST () { return config.get<string[]>('signup.filters.cidr.whitelist') },
157 get BLACKLIST () { return config.get<string[]>('signup.filters.cidr.blacklist') }
158 }
159 }
154 }, 160 },
155 USER: { 161 USER: {
156 get VIDEO_QUOTA () { return config.get<number>('user.video_quota') } 162 get VIDEO_QUOTA () { return config.get<number>('user.video_quota') }
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts
index 247b704c4..4ad0e33da 100644
--- a/server/middlewares/validators/users.ts
+++ b/server/middlewares/validators/users.ts
@@ -16,8 +16,8 @@ import {
16} from '../../helpers/custom-validators/users' 16} from '../../helpers/custom-validators/users'
17import { isVideoExist } from '../../helpers/custom-validators/videos' 17import { isVideoExist } from '../../helpers/custom-validators/videos'
18import { logger } from '../../helpers/logger' 18import { logger } from '../../helpers/logger'
19import { isSignupAllowed } from '../../helpers/utils' 19import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../helpers/utils'
20import { CONSTRAINTS_FIELDS } from '../../initializers' 20import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
21import { Redis } from '../../lib/redis' 21import { Redis } from '../../lib/redis'
22import { UserModel } from '../../models/account/user' 22import { UserModel } from '../../models/account/user'
23import { areValidationErrors } from './utils' 23import { areValidationErrors } from './utils'
@@ -177,6 +177,20 @@ const ensureUserRegistrationAllowed = [
177 } 177 }
178] 178]
179 179
180const ensureUserRegistrationAllowedForIP = [
181 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
182 const allowed = isSignupAllowedForCurrentIP(req.ip)
183
184 if (allowed === false) {
185 return res.status(403)
186 .send({ error: 'You are not on a network authorized for registration.' })
187 .end()
188 }
189
190 return next()
191 }
192]
193
180const usersAskResetPasswordValidator = [ 194const usersAskResetPasswordValidator = [
181 body('email').isEmail().not().isEmpty().withMessage('Should have a valid email'), 195 body('email').isEmail().not().isEmpty().withMessage('Should have a valid email'),
182 196
@@ -230,6 +244,7 @@ export {
230 usersUpdateMeValidator, 244 usersUpdateMeValidator,
231 usersVideoRatingValidator, 245 usersVideoRatingValidator,
232 ensureUserRegistrationAllowed, 246 ensureUserRegistrationAllowed,
247 ensureUserRegistrationAllowedForIP,
233 usersGetValidator, 248 usersGetValidator,
234 usersUpdateMyAvatarValidator, 249 usersUpdateMyAvatarValidator,
235 usersAskResetPasswordValidator, 250 usersAskResetPasswordValidator,