aboutsummaryrefslogtreecommitdiffhomepage
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
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
-rw-r--r--client/src/app/core/server/server.service.ts3
-rw-r--r--client/src/app/menu/menu.component.ts3
-rw-r--r--config/default.yaml4
-rw-r--r--config/production.yaml.example4
-rw-r--r--package.json2
-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
-rw-r--r--shared/models/server/server-config.model.ts3
-rw-r--r--yarn.lock20
13 files changed, 105 insertions, 9 deletions
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index c5353023b..ccae5a151 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -34,7 +34,8 @@ export class ServerService {
34 }, 34 },
35 serverVersion: 'Unknown', 35 serverVersion: 'Unknown',
36 signup: { 36 signup: {
37 allowed: false 37 allowed: false,
38 allowedForCurrentIP: false
38 }, 39 },
39 transcoding: { 40 transcoding: {
40 enabledResolutions: [] 41 enabledResolutions: []
diff --git a/client/src/app/menu/menu.component.ts b/client/src/app/menu/menu.component.ts
index 4c35bb3a5..69216e215 100644
--- a/client/src/app/menu/menu.component.ts
+++ b/client/src/app/menu/menu.component.ts
@@ -52,7 +52,8 @@ export class MenuComponent implements OnInit {
52 } 52 }
53 53
54 isRegistrationAllowed () { 54 isRegistrationAllowed () {
55 return this.serverService.getConfig().signup.allowed 55 return this.serverService.getConfig().signup.allowed &&
56 this.serverService.getConfig().signup.allowedForCurrentIP
56 } 57 }
57 58
58 getFirstAdminRightAvailable () { 59 getFirstAdminRightAvailable () {
diff --git a/config/default.yaml b/config/default.yaml
index 387acf43d..f43cbaf4b 100644
--- a/config/default.yaml
+++ b/config/default.yaml
@@ -60,6 +60,10 @@ admin:
60signup: 60signup:
61 enabled: false 61 enabled: false
62 limit: 10 # When the limit is reached, registrations are disabled. -1 == unlimited 62 limit: 10 # When the limit is reached, registrations are disabled. -1 == unlimited
63 filters:
64 cidr: # You can specify CIDR ranges to whitelist (empty = no filtering) or blacklist
65 whitelist: []
66 blacklist: []
63 67
64user: 68user:
65 # Default value of maximum video BYTES the user can upload (does not take into account transcoded files). 69 # Default value of maximum video BYTES the user can upload (does not take into account transcoded files).
diff --git a/config/production.yaml.example b/config/production.yaml.example
index 2f80beede..a9d2c3b80 100644
--- a/config/production.yaml.example
+++ b/config/production.yaml.example
@@ -76,6 +76,10 @@ admin:
76signup: 76signup:
77 enabled: false 77 enabled: false
78 limit: 10 # When the limit is reached, registrations are disabled. -1 == unlimited 78 limit: 10 # When the limit is reached, registrations are disabled. -1 == unlimited
79 filters:
80 cidr: # You can specify CIDR ranges to whitelist (empty = no filtering) or blacklist
81 whitelist: []
82 blacklist: []
79 83
80user: 84user:
81 # Default value of maximum video BYTES the user can upload (does not take into account transcoded files). 85 # Default value of maximum video BYTES the user can upload (does not take into account transcoded files).
diff --git a/package.json b/package.json
index 4123c55ec..bf69c4ce0 100644
--- a/package.json
+++ b/package.json
@@ -84,6 +84,8 @@
84 "express-rate-limit": "^2.11.0", 84 "express-rate-limit": "^2.11.0",
85 "express-validator": "^5.0.0", 85 "express-validator": "^5.0.0",
86 "fluent-ffmpeg": "^2.1.0", 86 "fluent-ffmpeg": "^2.1.0",
87 "ipaddr.js": "https://github.com/whitequark/ipaddr.js.git#8e69afeb4053ee32447a101845f860848280eca5",
88 "is-cidr": "^2.0.5",
87 "iso-639-3": "^1.0.1", 89 "iso-639-3": "^1.0.1",
88 "js-yaml": "^3.5.4", 90 "js-yaml": "^3.5.4",
89 "jsonld": "^1.0.1", 91 "jsonld": "^1.0.1",
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,
diff --git a/shared/models/server/server-config.model.ts b/shared/models/server/server-config.model.ts
index d1f956163..da0996dae 100644
--- a/shared/models/server/server-config.model.ts
+++ b/shared/models/server/server-config.model.ts
@@ -15,7 +15,8 @@ export interface ServerConfig {
15 } 15 }
16 16
17 signup: { 17 signup: {
18 allowed: boolean 18 allowed: boolean,
19 allowedForCurrentIP: boolean
19 } 20 }
20 21
21 transcoding: { 22 transcoding: {
diff --git a/yarn.lock b/yarn.lock
index 5a66a665c..49af4df03 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1294,6 +1294,12 @@ ci-info@^1.0.0:
1294 version "1.1.3" 1294 version "1.1.3"
1295 resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" 1295 resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2"
1296 1296
1297cidr-regex@^2.0.8:
1298 version "2.0.8"
1299 resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-2.0.8.tgz#c79bae6223d241c0860d93bfde1fb1c1c4fdcab6"
1300 dependencies:
1301 ip-regex "^2.1.0"
1302
1297circular-json@^0.3.1: 1303circular-json@^0.3.1:
1298 version "0.3.3" 1304 version "0.3.3"
1299 resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" 1305 resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
@@ -3671,6 +3677,10 @@ invert-kv@^1.0.0:
3671 version "1.0.0" 3677 version "1.0.0"
3672 resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" 3678 resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
3673 3679
3680ip-regex@^2.1.0:
3681 version "2.1.0"
3682 resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
3683
3674ip-set@^1.0.0: 3684ip-set@^1.0.0:
3675 version "1.0.1" 3685 version "1.0.1"
3676 resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.1.tgz#633b66d0bd6c8d0de968d053263c9120d3b6727e" 3686 resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.1.tgz#633b66d0bd6c8d0de968d053263c9120d3b6727e"
@@ -3693,6 +3703,10 @@ ipaddr.js@1.6.0:
3693 version "1.7.0" 3703 version "1.7.0"
3694 resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.7.0.tgz#2206ed334afc32e01fed3ee838b6b2521068b9d2" 3704 resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.7.0.tgz#2206ed334afc32e01fed3ee838b6b2521068b9d2"
3695 3705
3706"ipaddr.js@https://github.com/whitequark/ipaddr.js.git#8e69afeb4053ee32447a101845f860848280eca5":
3707 version "1.7.0"
3708 resolved "https://github.com/whitequark/ipaddr.js.git#8e69afeb4053ee32447a101845f860848280eca5"
3709
3696ipv6-normalize@^1.0.1: 3710ipv6-normalize@^1.0.1:
3697 version "1.0.1" 3711 version "1.0.1"
3698 resolved "https://registry.yarnpkg.com/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz#1b3258290d365fa83239e89907dde4592e7620a8" 3712 resolved "https://registry.yarnpkg.com/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz#1b3258290d365fa83239e89907dde4592e7620a8"
@@ -3747,6 +3761,12 @@ is-ci@^1.0.10, is-ci@^1.1.0:
3747 dependencies: 3761 dependencies:
3748 ci-info "^1.0.0" 3762 ci-info "^1.0.0"
3749 3763
3764is-cidr@^2.0.5:
3765 version "2.0.5"
3766 resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-2.0.5.tgz#13227927d71865d1177fe0e5b60e6ddd3dee0034"
3767 dependencies:
3768 cidr-regex "^2.0.8"
3769
3750is-data-descriptor@^0.1.4: 3770is-data-descriptor@^0.1.4:
3751 version "0.1.4" 3771 version "0.1.4"
3752 resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" 3772 resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"