diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2018-05-22 19:43:13 +0200 |
---|---|---|
committer | Rigel Kent <par@rigelk.eu> | 2018-05-22 19:44:34 +0200 |
commit | ff2c1fe8133f9556f6aaa52058cd8b83c40085e6 (patch) | |
tree | bc92cde25bf5a1d74b1413d7145179ef7abfd670 | |
parent | e2f1dad83607aa610ee33b234a81b07664f4304c (diff) | |
download | PeerTube-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.ts | 3 | ||||
-rw-r--r-- | client/src/app/menu/menu.component.ts | 3 | ||||
-rw-r--r-- | config/default.yaml | 4 | ||||
-rw-r--r-- | config/production.yaml.example | 4 | ||||
-rw-r--r-- | package.json | 2 | ||||
-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 | ||||
-rw-r--r-- | shared/models/server/server-config.model.ts | 3 | ||||
-rw-r--r-- | yarn.lock | 20 |
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: | |||
60 | signup: | 60 | signup: |
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 | ||
64 | user: | 68 | user: |
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: | |||
76 | signup: | 76 | signup: |
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 | ||
80 | user: | 84 | user: |
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' | |||
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, |
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: { |
@@ -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 | ||
1297 | cidr-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 | |||
1297 | circular-json@^0.3.1: | 1303 | circular-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 | ||
3680 | ip-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 | |||
3674 | ip-set@^1.0.0: | 3684 | ip-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 | |||
3696 | ipv6-normalize@^1.0.1: | 3710 | ipv6-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 | ||
3764 | is-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 | |||
3750 | is-data-descriptor@^0.1.4: | 3770 | is-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" |