mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2024-11-28 11:34:01 -06:00
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
This commit is contained in:
parent
e2f1dad836
commit
ff2c1fe813
@ -34,7 +34,8 @@ export class ServerService {
|
||||
},
|
||||
serverVersion: 'Unknown',
|
||||
signup: {
|
||||
allowed: false
|
||||
allowed: false,
|
||||
allowedForCurrentIP: false
|
||||
},
|
||||
transcoding: {
|
||||
enabledResolutions: []
|
||||
|
@ -52,7 +52,8 @@ export class MenuComponent implements OnInit {
|
||||
}
|
||||
|
||||
isRegistrationAllowed () {
|
||||
return this.serverService.getConfig().signup.allowed
|
||||
return this.serverService.getConfig().signup.allowed &&
|
||||
this.serverService.getConfig().signup.allowedForCurrentIP
|
||||
}
|
||||
|
||||
getFirstAdminRightAvailable () {
|
||||
|
@ -60,6 +60,10 @@ admin:
|
||||
signup:
|
||||
enabled: false
|
||||
limit: 10 # When the limit is reached, registrations are disabled. -1 == unlimited
|
||||
filters:
|
||||
cidr: # You can specify CIDR ranges to whitelist (empty = no filtering) or blacklist
|
||||
whitelist: []
|
||||
blacklist: []
|
||||
|
||||
user:
|
||||
# Default value of maximum video BYTES the user can upload (does not take into account transcoded files).
|
||||
|
@ -76,6 +76,10 @@ admin:
|
||||
signup:
|
||||
enabled: false
|
||||
limit: 10 # When the limit is reached, registrations are disabled. -1 == unlimited
|
||||
filters:
|
||||
cidr: # You can specify CIDR ranges to whitelist (empty = no filtering) or blacklist
|
||||
whitelist: []
|
||||
blacklist: []
|
||||
|
||||
user:
|
||||
# Default value of maximum video BYTES the user can upload (does not take into account transcoded files).
|
||||
|
@ -84,6 +84,8 @@
|
||||
"express-rate-limit": "^2.11.0",
|
||||
"express-validator": "^5.0.0",
|
||||
"fluent-ffmpeg": "^2.1.0",
|
||||
"ipaddr.js": "https://github.com/whitequark/ipaddr.js.git#8e69afeb4053ee32447a101845f860848280eca5",
|
||||
"is-cidr": "^2.0.5",
|
||||
"iso-639-3": "^1.0.1",
|
||||
"js-yaml": "^3.5.4",
|
||||
"jsonld": "^1.0.1",
|
||||
|
@ -4,7 +4,7 @@ import { ServerConfig, UserRight } from '../../../shared'
|
||||
import { About } from '../../../shared/models/server/about.model'
|
||||
import { CustomConfig } from '../../../shared/models/server/custom-config.model'
|
||||
import { unlinkPromise, writeFilePromise } from '../../helpers/core-utils'
|
||||
import { isSignupAllowed } from '../../helpers/utils'
|
||||
import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../helpers/utils'
|
||||
import { CONFIG, CONSTRAINTS_FIELDS, reloadConfig } from '../../initializers'
|
||||
import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares'
|
||||
import { customConfigUpdateValidator } from '../../middlewares/validators/config'
|
||||
@ -36,6 +36,7 @@ configRouter.delete('/custom',
|
||||
|
||||
async function getConfig (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const allowed = await isSignupAllowed()
|
||||
const allowedForCurrentIP = isSignupAllowedForCurrentIP(req.ip)
|
||||
|
||||
const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
|
||||
.filter(key => CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
|
||||
@ -54,7 +55,8 @@ async function getConfig (req: express.Request, res: express.Response, next: exp
|
||||
},
|
||||
serverVersion: packageJSON.version,
|
||||
signup: {
|
||||
allowed
|
||||
allowed,
|
||||
allowedForCurrentIP
|
||||
},
|
||||
transcoding: {
|
||||
enabledResolutions
|
||||
|
@ -19,6 +19,7 @@ import {
|
||||
authenticate,
|
||||
ensureUserHasRight,
|
||||
ensureUserRegistrationAllowed,
|
||||
ensureUserRegistrationAllowedForIP,
|
||||
paginationValidator,
|
||||
setDefaultPagination,
|
||||
setDefaultSort,
|
||||
@ -106,6 +107,7 @@ usersRouter.post('/',
|
||||
|
||||
usersRouter.post('/register',
|
||||
asyncMiddleware(ensureUserRegistrationAllowed),
|
||||
ensureUserRegistrationAllowedForIP,
|
||||
asyncMiddleware(usersRegisterValidator),
|
||||
asyncMiddleware(registerUserRetryWrapper)
|
||||
)
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { Model } from 'sequelize-typescript'
|
||||
import * as ipaddr from 'ipaddr.js'
|
||||
const isCidr = require('is-cidr')
|
||||
import { ResultList } from '../../shared'
|
||||
import { VideoResolution } from '../../shared/models/videos'
|
||||
import { CONFIG } from '../initializers'
|
||||
@ -48,6 +50,39 @@ async function isSignupAllowed () {
|
||||
return totalUsers < CONFIG.SIGNUP.LIMIT
|
||||
}
|
||||
|
||||
function isSignupAllowedForCurrentIP (ip: string) {
|
||||
const addr = ipaddr.parse(ip)
|
||||
let excludeList = [ 'blacklist' ]
|
||||
let matched: string
|
||||
|
||||
// if there is a valid, non-empty whitelist, we exclude all unknown adresses too
|
||||
if (CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr(cidr)).length > 0) {
|
||||
excludeList.push('unknown')
|
||||
}
|
||||
|
||||
if (addr.kind() === 'ipv4') {
|
||||
const addrV4 = ipaddr.IPv4.parse(ip)
|
||||
const rangeList = {
|
||||
whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v4(cidr))
|
||||
.map(cidr => ipaddr.IPv4.parseCIDR(cidr)),
|
||||
blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v4(cidr))
|
||||
.map(cidr => ipaddr.IPv4.parseCIDR(cidr))
|
||||
}
|
||||
matched = ipaddr.subnetMatch(addrV4, rangeList, 'unknown')
|
||||
} else if (addr.kind() === 'ipv6') {
|
||||
const addrV6 = ipaddr.IPv6.parse(ip)
|
||||
const rangeList = {
|
||||
whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v6(cidr))
|
||||
.map(cidr => ipaddr.IPv6.parseCIDR(cidr)),
|
||||
blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v6(cidr))
|
||||
.map(cidr => ipaddr.IPv6.parseCIDR(cidr))
|
||||
}
|
||||
matched = ipaddr.subnetMatch(addrV6, rangeList, 'unknown')
|
||||
}
|
||||
|
||||
return !excludeList.includes(matched)
|
||||
}
|
||||
|
||||
function computeResolutionsToTranscode (videoFileHeight: number) {
|
||||
const resolutionsEnabled: number[] = []
|
||||
const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS
|
||||
@ -99,6 +134,7 @@ export {
|
||||
generateRandomString,
|
||||
getFormattedObjects,
|
||||
isSignupAllowed,
|
||||
isSignupAllowedForCurrentIP,
|
||||
computeResolutionsToTranscode,
|
||||
resetSequelizeInstance,
|
||||
getServerActor,
|
||||
|
@ -27,7 +27,9 @@ function checkMissedConfig () {
|
||||
'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache',
|
||||
'log.level',
|
||||
'user.video_quota',
|
||||
'cache.previews.size', 'admin.email', 'signup.enabled', 'signup.limit', 'transcoding.enabled', 'transcoding.threads',
|
||||
'cache.previews.size', 'admin.email',
|
||||
'signup.enabled', 'signup.limit', 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist',
|
||||
'transcoding.enabled', 'transcoding.threads',
|
||||
'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route',
|
||||
'instance.default_nsfw_policy', 'instance.robots',
|
||||
'services.twitter.username', 'services.twitter.whitelisted'
|
||||
|
@ -150,7 +150,13 @@ const CONFIG = {
|
||||
},
|
||||
SIGNUP: {
|
||||
get ENABLED () { return config.get<boolean>('signup.enabled') },
|
||||
get LIMIT () { return config.get<number>('signup.limit') }
|
||||
get LIMIT () { return config.get<number>('signup.limit') },
|
||||
FILTERS: {
|
||||
CIDR: {
|
||||
get WHITELIST () { return config.get<string[]>('signup.filters.cidr.whitelist') },
|
||||
get BLACKLIST () { return config.get<string[]>('signup.filters.cidr.blacklist') }
|
||||
}
|
||||
}
|
||||
},
|
||||
USER: {
|
||||
get VIDEO_QUOTA () { return config.get<number>('user.video_quota') }
|
||||
|
@ -16,8 +16,8 @@ import {
|
||||
} from '../../helpers/custom-validators/users'
|
||||
import { isVideoExist } from '../../helpers/custom-validators/videos'
|
||||
import { logger } from '../../helpers/logger'
|
||||
import { isSignupAllowed } from '../../helpers/utils'
|
||||
import { CONSTRAINTS_FIELDS } from '../../initializers'
|
||||
import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../helpers/utils'
|
||||
import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
|
||||
import { Redis } from '../../lib/redis'
|
||||
import { UserModel } from '../../models/account/user'
|
||||
import { areValidationErrors } from './utils'
|
||||
@ -177,6 +177,20 @@ const ensureUserRegistrationAllowed = [
|
||||
}
|
||||
]
|
||||
|
||||
const ensureUserRegistrationAllowedForIP = [
|
||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
const allowed = isSignupAllowedForCurrentIP(req.ip)
|
||||
|
||||
if (allowed === false) {
|
||||
return res.status(403)
|
||||
.send({ error: 'You are not on a network authorized for registration.' })
|
||||
.end()
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
]
|
||||
|
||||
const usersAskResetPasswordValidator = [
|
||||
body('email').isEmail().not().isEmpty().withMessage('Should have a valid email'),
|
||||
|
||||
@ -230,6 +244,7 @@ export {
|
||||
usersUpdateMeValidator,
|
||||
usersVideoRatingValidator,
|
||||
ensureUserRegistrationAllowed,
|
||||
ensureUserRegistrationAllowedForIP,
|
||||
usersGetValidator,
|
||||
usersUpdateMyAvatarValidator,
|
||||
usersAskResetPasswordValidator,
|
||||
|
@ -15,7 +15,8 @@ export interface ServerConfig {
|
||||
}
|
||||
|
||||
signup: {
|
||||
allowed: boolean
|
||||
allowed: boolean,
|
||||
allowedForCurrentIP: boolean
|
||||
}
|
||||
|
||||
transcoding: {
|
||||
|
20
yarn.lock
20
yarn.lock
@ -1294,6 +1294,12 @@ ci-info@^1.0.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2"
|
||||
|
||||
cidr-regex@^2.0.8:
|
||||
version "2.0.8"
|
||||
resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-2.0.8.tgz#c79bae6223d241c0860d93bfde1fb1c1c4fdcab6"
|
||||
dependencies:
|
||||
ip-regex "^2.1.0"
|
||||
|
||||
circular-json@^0.3.1:
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
|
||||
@ -3671,6 +3677,10 @@ invert-kv@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
|
||||
|
||||
ip-regex@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
|
||||
|
||||
ip-set@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.1.tgz#633b66d0bd6c8d0de968d053263c9120d3b6727e"
|
||||
@ -3693,6 +3703,10 @@ ipaddr.js@1.6.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.7.0.tgz#2206ed334afc32e01fed3ee838b6b2521068b9d2"
|
||||
|
||||
"ipaddr.js@https://github.com/whitequark/ipaddr.js.git#8e69afeb4053ee32447a101845f860848280eca5":
|
||||
version "1.7.0"
|
||||
resolved "https://github.com/whitequark/ipaddr.js.git#8e69afeb4053ee32447a101845f860848280eca5"
|
||||
|
||||
ipv6-normalize@^1.0.1:
|
||||
version "1.0.1"
|
||||
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:
|
||||
dependencies:
|
||||
ci-info "^1.0.0"
|
||||
|
||||
is-cidr@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-2.0.5.tgz#13227927d71865d1177fe0e5b60e6ddd3dee0034"
|
||||
dependencies:
|
||||
cidr-regex "^2.0.8"
|
||||
|
||||
is-data-descriptor@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
|
||||
|
Loading…
Reference in New Issue
Block a user