diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/config.ts | 6 | ||||
-rw-r--r-- | server/controllers/api/users.ts | 2 | ||||
-rw-r--r-- | server/helpers/utils.ts | 36 | ||||
-rw-r--r-- | server/initializers/checker.ts | 4 | ||||
-rw-r--r-- | server/initializers/constants.ts | 8 | ||||
-rw-r--r-- | server/middlewares/validators/users.ts | 19 |
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' | |||
4 | import { About } from '../../../shared/models/server/about.model' | 4 | import { About } from '../../../shared/models/server/about.model' |
5 | import { CustomConfig } from '../../../shared/models/server/custom-config.model' | 5 | import { CustomConfig } from '../../../shared/models/server/custom-config.model' |
6 | import { unlinkPromise, writeFilePromise } from '../../helpers/core-utils' | 6 | import { unlinkPromise, writeFilePromise } from '../../helpers/core-utils' |
7 | import { isSignupAllowed } from '../../helpers/utils' | 7 | import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../helpers/utils' |
8 | import { CONFIG, CONSTRAINTS_FIELDS, reloadConfig } from '../../initializers' | 8 | import { CONFIG, CONSTRAINTS_FIELDS, reloadConfig } from '../../initializers' |
9 | import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares' | 9 | import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares' |
10 | import { customConfigUpdateValidator } from '../../middlewares/validators/config' | 10 | import { customConfigUpdateValidator } from '../../middlewares/validators/config' |
@@ -36,6 +36,7 @@ configRouter.delete('/custom', | |||
36 | 36 | ||
37 | async function getConfig (req: express.Request, res: express.Response, next: express.NextFunction) { | 37 | async 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 | ||
107 | usersRouter.post('/register', | 108 | usersRouter.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 @@ | |||
1 | import { Model } from 'sequelize-typescript' | 1 | import { Model } from 'sequelize-typescript' |
2 | import * as ipaddr from 'ipaddr.js' | ||
3 | const isCidr = require('is-cidr') | ||
2 | import { ResultList } from '../../shared' | 4 | import { ResultList } from '../../shared' |
3 | import { VideoResolution } from '../../shared/models/videos' | 5 | import { VideoResolution } from '../../shared/models/videos' |
4 | import { CONFIG } from '../initializers' | 6 | import { 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 | ||
53 | function 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 | |||
51 | function computeResolutionsToTranscode (videoFileHeight: number) { | 86 | function 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' |
17 | import { isVideoExist } from '../../helpers/custom-validators/videos' | 17 | import { isVideoExist } from '../../helpers/custom-validators/videos' |
18 | import { logger } from '../../helpers/logger' | 18 | import { logger } from '../../helpers/logger' |
19 | import { isSignupAllowed } from '../../helpers/utils' | 19 | import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../helpers/utils' |
20 | import { CONSTRAINTS_FIELDS } from '../../initializers' | 20 | import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers' |
21 | import { Redis } from '../../lib/redis' | 21 | import { Redis } from '../../lib/redis' |
22 | import { UserModel } from '../../models/account/user' | 22 | import { UserModel } from '../../models/account/user' |
23 | import { areValidationErrors } from './utils' | 23 | import { areValidationErrors } from './utils' |
@@ -177,6 +177,20 @@ const ensureUserRegistrationAllowed = [ | |||
177 | } | 177 | } |
178 | ] | 178 | ] |
179 | 179 | ||
180 | const 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 | |||
180 | const usersAskResetPasswordValidator = [ | 194 | const 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, |