block supports now CIDR and wildcard

Massimo Melina committed Apr 19, 2022 at 17:18 UTC 3332e72fe8268b29af6760ddd80c2846db3b93b9
7 files changed +254 -21
README.md
+2 -1
@@ -239,11 +239,12 @@ Supported entries are:
239 - `cert` use this file for https certificate. Minimum to start https is to give a cert and a private_key. Default is none.
240 - `private_key` use this file for https private key. Default is none.
241 - `allowed_referer` you can decide what domains can link to your files. Wildcards supported. Default is any.
242 -- `block` a list of rules that will block connections. At the moment only `ip` rules are supported. E.g.:
242 +- `block` a list of rules that will block connections. E.g.:
243 ```
244 block:
245 - ip: 192.168.0.90
246 ```
247 + Syntax supports, other than simple address, `*` as wildcard and CIDR format.
248 - `plugins_config` this is a generic place where you can find/put configuration for each plugin, at least those that need configuration.
249 - `custom_header` provide HTML code to be put at the top of your Frontend. Default is none.
250 - `localhost_admin` should Admin be accessed without credentials when on localhost. Default is true.
admin/src/ConfigPage.ts
+1 -1
@@ -109,7 +109,7 @@ export default function ConfigPage() {
109 keyLabel: "Files", keyWidth: 7,
110 valueLabel: "Mime type", valueWidth: 4
111 },
112 - { k: 'block', label: "Blocked IPs", multiline: true, minRows:3, helperText: "Enter an IP address for each line",
112 + { k: 'block', label: "Blocked IPs", multiline: true, minRows:3, helperText: "Enter an IP address for each line. CIDR and * are supported.",
113 fromField: (all:string) => all.split('\n').map(s => s.trim()).filter(Boolean).map(ip => ({ ip })),
114 toField: (all: any) => !Array.isArray(all) ? '' : all.map(x => x?.ip).filter(Boolean).join('\n')
115 },
package-lock.json
+212 -4
@@ -6136,6 +6136,34 @@
6136 "dev": true,
6137 "license": "MIT"
6138 },
6139 + "node_modules/cidr-regex": {
6140 + "version": "3.1.1",
6141 + "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-3.1.1.tgz",
6142 + "integrity": "sha512-RBqYd32aDwbCMFJRL6wHOlDNYJsPNTt8vC82ErHF5vKt8QQzxm1FrkW8s/R5pVrXMf17sba09Uoy91PKiddAsw==",
6143 + "dependencies": {
6144 + "ip-regex": "^4.1.0"
6145 + },
6146 + "engines": {
6147 + "node": ">=10"
6148 + }
6149 + },
6150 + "node_modules/cidr-tools": {
6151 + "version": "4.3.0",
6152 + "resolved": "https://registry.npmjs.org/cidr-tools/-/cidr-tools-4.3.0.tgz",
6153 + "integrity": "sha512-Conidfn8svry8txRhW63SkaRMYJWJSvCT5kRCovIzlD0A3wzaV3gVFNxmAFJo5rxx3KHeYnJxCe7bUKFr1wxHA==",
6154 + "dependencies": {
6155 + "ip-address": "^8.1.0",
6156 + "ip-cidr": "^3.0.4",
6157 + "ipv6-normalize": "^1.0.1",
6158 + "is-cidr": "^4.0.2",
6159 + "is-ip": "^3.1.0",
6160 + "jsbn": "^1.1.0",
6161 + "string-natural-compare": "^3.0.1"
6162 + },
6163 + "engines": {
6164 + "node": ">=10"
6165 + }
6166 + },
6167 "node_modules/cjs-module-lexer": {
6168 "version": "1.2.2",
6169 "dev": true,
@@ -9834,6 +9862,60 @@
9862 "dev": true,
9863 "license": "MIT"
9864 },
9865 + "node_modules/ip-address": {
9866 + "version": "8.1.0",
9867 + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-8.1.0.tgz",
9868 + "integrity": "sha512-Wz91gZKpNKoXtqvY8ScarKYwhXoK4r/b5QuT+uywe/azv0/nUCo7Bh0IRRI7F9DHR06kJNWtzMGLIbXavngbKA==",
9869 + "dependencies": {
9870 + "jsbn": "1.1.0",
9871 + "sprintf-js": "1.1.2"
9872 + },
9873 + "engines": {
9874 + "node": ">= 12"
9875 + }
9876 + },
9877 + "node_modules/ip-address/node_modules/sprintf-js": {
9878 + "version": "1.1.2",
9879 + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
9880 + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
9881 + },
9882 + "node_modules/ip-cidr": {
9883 + "version": "3.0.7",
9884 + "resolved": "https://registry.npmjs.org/ip-cidr/-/ip-cidr-3.0.7.tgz",
9885 + "integrity": "sha512-0cBBICDnmmpAdULMbMVdi4f0mSG+VWY/QBPL/OIIjuom14x7Y63VhpS/uSAOycasXOeGXah5y0eu//PDU51aNw==",
9886 + "dependencies": {
9887 + "ip-address": "^7.1.0",
9888 + "jsbn": "^1.1.0"
9889 + },
9890 + "engines": {
9891 + "node": ">=10.0.0"
9892 + }
9893 + },
9894 + "node_modules/ip-cidr/node_modules/ip-address": {
9895 + "version": "7.1.0",
9896 + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-7.1.0.tgz",
9897 + "integrity": "sha512-V9pWC/VJf2lsXqP7IWJ+pe3P1/HCYGBMZrrnT62niLGjAfCbeiwXMUxaeHvnVlz19O27pvXP4azs+Pj/A0x+SQ==",
9898 + "dependencies": {
9899 + "jsbn": "1.1.0",
9900 + "sprintf-js": "1.1.2"
9901 + },
9902 + "engines": {
9903 + "node": ">= 10"
9904 + }
9905 + },
9906 + "node_modules/ip-cidr/node_modules/sprintf-js": {
9907 + "version": "1.1.2",
9908 + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
9909 + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
9910 + },
9911 + "node_modules/ip-regex": {
9912 + "version": "4.3.0",
9913 + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
9914 + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==",
9915 + "engines": {
9916 + "node": ">=8"
9917 + }
9918 + },
9919 "node_modules/ipaddr.js": {
9920 "version": "2.0.1",
9921 "dev": true,
@@ -9842,6 +9924,11 @@
9924 "node": ">= 10"
9925 }
9926 },
9927 + "node_modules/ipv6-normalize": {
9928 + "version": "1.0.1",
9929 + "resolved": "https://registry.npmjs.org/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz",
9930 + "integrity": "sha1-GzJYKQ02X6gyOeiZB93kWS52IKg="
9931 + },
9932 "node_modules/is-arrayish": {
9933 "version": "0.2.1",
9934 "license": "MIT"
@@ -9905,6 +9992,17 @@
9992 "is-ci": "bin.js"
9993 }
9994 },
9995 + "node_modules/is-cidr": {
9996 + "version": "4.0.2",
9997 + "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-4.0.2.tgz",
9998 + "integrity": "sha512-z4a1ENUajDbEl/Q6/pVBpTR1nBjjEE1X7qb7bmWYanNnPoKAvUCPFKeXV6Fe4mgTkWKBqiHIcwsI3SndiO5FeA==",
9999 + "dependencies": {
10000 + "cidr-regex": "^3.1.1"
10001 + },
10002 + "engines": {
10003 + "node": ">=10"
10004 + }
10005 + },
10006 "node_modules/is-class-hotfix": {
10007 "version": "0.0.6",
10008 "license": "MIT"
@@ -10011,6 +10109,17 @@
10109 "url": "https://github.com/sponsors/sindresorhus"
10110 }
10111 },
10112 + "node_modules/is-ip": {
10113 + "version": "3.1.0",
10114 + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz",
10115 + "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==",
10116 + "dependencies": {
10117 + "ip-regex": "^4.0.0"
10118 + },
10119 + "engines": {
10120 + "node": ">=8"
10121 + }
10122 + },
10123 "node_modules/is-module": {
10124 "version": "1.0.0",
10125 "dev": true,
@@ -11829,6 +11938,11 @@
11938 "js-yaml": "bin/js-yaml.js"
11939 }
11940 },
11941 + "node_modules/jsbn": {
11942 + "version": "1.1.0",
11943 + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
11944 + "integrity": "sha1-sBMHyym2GKHtJux56RH4A8TaAEA="
11945 + },
11946 "node_modules/jsdom": {
11947 "version": "16.7.0",
11948 "dev": true,
@@ -16446,8 +16560,7 @@
16560 "node_modules/string-natural-compare": {
16561 "version": "3.0.1",
16562 "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz",
16449 - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==",
16450 - "dev": true
16563 + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw=="
16564 },
16565 "node_modules/string-width": {
16566 "version": "4.2.3",
@@ -18662,6 +18775,7 @@
18775 "@koa/router": "^10.1.1",
18776 "@node-rs/crc32": "^1.3.1",
18777 "buffer-crc32": "https://github.com/rejetto/buffer-crc32.git",
18778 + "cidr-tools": "^4.3.0",
18779 "fast-glob": "^3.2.7",
18780 "find-process": "^1.4.7",
18781 "koa": "^2.13.4",
@@ -20160,6 +20274,7 @@
20274 "@types/node": "^16.11.12",
20275 "axios": "^0.24.0",
20276 "buffer-crc32": "https://github.com/rejetto/buffer-crc32.git",
20277 + "cidr-tools": "^4.3.0",
20278 "fast-glob": "^3.2.7",
20279 "find-process": "^1.4.7",
20280 "koa": "^2.13.4",
@@ -22655,6 +22770,28 @@
22770 "version": "2.0.0",
22771 "dev": true
22772 },
22773 + "cidr-regex": {
22774 + "version": "3.1.1",
22775 + "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-3.1.1.tgz",
22776 + "integrity": "sha512-RBqYd32aDwbCMFJRL6wHOlDNYJsPNTt8vC82ErHF5vKt8QQzxm1FrkW8s/R5pVrXMf17sba09Uoy91PKiddAsw==",
22777 + "requires": {
22778 + "ip-regex": "^4.1.0"
22779 + }
22780 + },
22781 + "cidr-tools": {
22782 + "version": "4.3.0",
22783 + "resolved": "https://registry.npmjs.org/cidr-tools/-/cidr-tools-4.3.0.tgz",
22784 + "integrity": "sha512-Conidfn8svry8txRhW63SkaRMYJWJSvCT5kRCovIzlD0A3wzaV3gVFNxmAFJo5rxx3KHeYnJxCe7bUKFr1wxHA==",
22785 + "requires": {
22786 + "ip-address": "^8.1.0",
22787 + "ip-cidr": "^3.0.4",
22788 + "ipv6-normalize": "^1.0.1",
22789 + "is-cidr": "^4.0.2",
22790 + "is-ip": "^3.1.0",
22791 + "jsbn": "^1.1.0",
22792 + "string-natural-compare": "^3.0.1"
22793 + }
22794 + },
22795 "cjs-module-lexer": {
22796 "version": "1.2.2",
22797 "dev": true
@@ -25070,10 +25207,61 @@
25207 "version": "1.1.5",
25208 "dev": true
25209 },
25210 + "ip-address": {
25211 + "version": "8.1.0",
25212 + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-8.1.0.tgz",
25213 + "integrity": "sha512-Wz91gZKpNKoXtqvY8ScarKYwhXoK4r/b5QuT+uywe/azv0/nUCo7Bh0IRRI7F9DHR06kJNWtzMGLIbXavngbKA==",
25214 + "requires": {
25215 + "jsbn": "1.1.0",
25216 + "sprintf-js": "1.1.2"
25217 + },
25218 + "dependencies": {
25219 + "sprintf-js": {
25220 + "version": "1.1.2",
25221 + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
25222 + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
25223 + }
25224 + }
25225 + },
25226 + "ip-cidr": {
25227 + "version": "3.0.7",
25228 + "resolved": "https://registry.npmjs.org/ip-cidr/-/ip-cidr-3.0.7.tgz",
25229 + "integrity": "sha512-0cBBICDnmmpAdULMbMVdi4f0mSG+VWY/QBPL/OIIjuom14x7Y63VhpS/uSAOycasXOeGXah5y0eu//PDU51aNw==",
25230 + "requires": {
25231 + "ip-address": "^7.1.0",
25232 + "jsbn": "^1.1.0"
25233 + },
25234 + "dependencies": {
25235 + "ip-address": {
25236 + "version": "7.1.0",
25237 + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-7.1.0.tgz",
25238 + "integrity": "sha512-V9pWC/VJf2lsXqP7IWJ+pe3P1/HCYGBMZrrnT62niLGjAfCbeiwXMUxaeHvnVlz19O27pvXP4azs+Pj/A0x+SQ==",
25239 + "requires": {
25240 + "jsbn": "1.1.0",
25241 + "sprintf-js": "1.1.2"
25242 + }
25243 + },
25244 + "sprintf-js": {
25245 + "version": "1.1.2",
25246 + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
25247 + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
25248 + }
25249 + }
25250 + },
25251 + "ip-regex": {
25252 + "version": "4.3.0",
25253 + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
25254 + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q=="
25255 + },
25256 "ipaddr.js": {
25257 "version": "2.0.1",
25258 "dev": true
25259 },
25260 + "ipv6-normalize": {
25261 + "version": "1.0.1",
25262 + "resolved": "https://registry.npmjs.org/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz",
25263 + "integrity": "sha1-GzJYKQ02X6gyOeiZB93kWS52IKg="
25264 + },
25265 "is-arrayish": {
25266 "version": "0.2.1"
25267 },
@@ -25110,6 +25298,14 @@
25298 "ci-info": "^2.0.0"
25299 }
25300 },
25301 + "is-cidr": {
25302 + "version": "4.0.2",
25303 + "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-4.0.2.tgz",
25304 + "integrity": "sha512-z4a1ENUajDbEl/Q6/pVBpTR1nBjjEE1X7qb7bmWYanNnPoKAvUCPFKeXV6Fe4mgTkWKBqiHIcwsI3SndiO5FeA==",
25305 + "requires": {
25306 + "cidr-regex": "^3.1.1"
25307 + }
25308 + },
25309 "is-class-hotfix": {
25310 "version": "0.0.6"
25311 },
@@ -25163,6 +25359,14 @@
25359 "is-path-inside": "^3.0.2"
25360 }
25361 },
25362 + "is-ip": {
25363 + "version": "3.1.0",
25364 + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz",
25365 + "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==",
25366 + "requires": {
25367 + "ip-regex": "^4.0.0"
25368 + }
25369 + },
25370 "is-module": {
25371 "version": "1.0.0",
25372 "dev": true
@@ -26426,6 +26630,11 @@
26630 "esprima": "^4.0.0"
26631 }
26632 },
26633 + "jsbn": {
26634 + "version": "1.1.0",
26635 + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
26636 + "integrity": "sha1-sBMHyym2GKHtJux56RH4A8TaAEA="
26637 + },
26638 "jsdom": {
26639 "version": "16.7.0",
26640 "dev": true,
@@ -29328,8 +29537,7 @@
29537 "string-natural-compare": {
29538 "version": "3.0.1",
29539 "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz",
29331 - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==",
29332 - "dev": true
29540 + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw=="
29541 },
29542 "string-width": {
29543 "version": "4.2.3",
server/package.json
+1
@@ -13,6 +13,7 @@
13 "@koa/router": "^10.1.1",
14 "@node-rs/crc32": "^1.3.1",
15 "buffer-crc32": "https://github.com/rejetto/buffer-crc32.git",
16 + "cidr-tools": "^4.3.0",
17 "fast-glob": "^3.2.7",
18 "find-process": "^1.4.7",
19 "koa": "^2.13.4",
server/src/block.ts new
+36
@@ -0,0 +1,36 @@
1 +import { subscribeConfig } from './config'
2 +import { getConnections } from './connections'
3 +import { onlyTruthy, with_ } from './misc'
4 +import cidr from 'cidr-tools'
5 +import _ from 'lodash'
6 +import { Socket } from 'net'
7 +
8 +subscribeConfig({ k: 'block', defaultValue: [] }, (rules: any) => {
9 + compileBlock(rules)
10 + for (const { socket } of getConnections())
11 + applyBlock(socket)
12 +})
13 +
14 +type BlockFun = (x: string) => boolean
15 +let blockFunctions: BlockFun[] = [] // "compiled" versions of the rules in config.block
16 +
17 +function compileBlock(rules: any) {
18 + blockFunctions = !Array.isArray(rules) ? []
19 + : onlyTruthy(rules.map(rule => !rule ? null
20 + : with_(rule.ip, ip => typeof ip !== 'string' ? null
21 + : ip.includes('/') ? x => cidr.contains(ip, x)
22 + : ip.includes('*') ? with_(ipMask2regExp(ip), re => x => re.test(x) )
23 + : x => x === ip
24 + )
25 + ))
26 +
27 + function ipMask2regExp(ipMask: string) {
28 + return new RegExp(_.escapeRegExp(ipMask).replace(/\\\*/g, '.*'))
29 + }
30 +}
31 +
32 +export function applyBlock(socket: Socket) {
33 + const ip = socket.remoteAddress
34 + if (ip && blockFunctions.find(rule => rule(ip)))
35 + return socket.destroy()
36 +}
server/src/middlewares.ts
+2 -14
@@ -13,10 +13,9 @@ import { serveFileNode } from './serveFile'
13 import { serveGuiFiles } from './serveGuiFiles'
14 import mount from 'koa-mount'
15 import { Readable } from 'stream'
16 +import { applyBlock } from './block'
17 import { getAccount, getCurrentUsername } from './perm'
17 -import { getConfig, subscribeConfig } from './config'
18 -import { getConnections, socket2connection, updateConnection } from './connections'
19 -import { Socket } from 'net'
18 +import { socket2connection, updateConnection } from './connections'
19
20 export const gzipper = compress({
21 threshold: 2048,
@@ -115,17 +114,6 @@ export const someSecurity: Koa.Middleware = async (ctx, next) => {
114 export function getProxyDetected() {
115 return proxyDetected
116 }
118 -
119 -subscribeConfig({ k: 'block', defaultValue: [] }, () => {
120 - for (const { socket } of getConnections())
121 - applyBlock(socket)
122 -})
123 -
124 -function applyBlock(socket: Socket) {
125 - if (getConfig('block').find((rule:any) => rule.ip === socket.remoteAddress))
126 - return socket.destroy()
127 -}
128 -
117 export const prepareState: Koa.Middleware = async (ctx, next) => {
118 // calculate these once and for all
119 ctx.state.account = getAccount(getCurrentUsername(ctx))
todo.md
-1
@@ -17,7 +17,6 @@
17 - command line help --help
18 - download-counter: expose results on admin
19 - frontend: make a "login" route, and link it in side the 404's suggest-login message
20 -- block to support masks and CIDR
20 - whitelist di ip
21 - plugin to show country by ip in admin/monitor
22 - log filter option