diff --git a/docs/en/install/README.md b/docs/en/install/README.md index eb265abde5..a9b7947ed9 100644 --- a/docs/en/install/README.md +++ b/docs/en/install/README.md @@ -325,7 +325,7 @@ For readers that do not support HTTP Basic authentication, please refer to [Acce ### Access Control Configuration -RSSHub supports access control via access key/code, whitelisting and blacklisting, enabling any will activate access control for all routes. +RSSHub supports access control via access key/code, whitelisting and blacklisting, enabling any will activate access control for all routes. `ALLOW_LOCALHOST: true` will grant access to all localhost IP addresses. #### White/blacklisting diff --git a/docs/install/README.md b/docs/install/README.md index 57b9233f21..c5d8a49dbb 100644 --- a/docs/install/README.md +++ b/docs/install/README.md @@ -351,7 +351,7 @@ RSSHub 支持 `memory` 和 `redis` 两种缓存方式 ### 访问控制配置 -RSSHub 支持使用访问密钥 / 码,白名单和黑名单三种方式进行访问控制。开启任意选项将会激活全局访问控制,没有访问权限将会导致访问被拒绝。 +RSSHub 支持使用访问密钥 / 码,白名单和黑名单三种方式进行访问控制。开启任意选项将会激活全局访问控制,没有访问权限将会导致访问被拒绝。同时可以通过 `ALLOW_LOCALHOST: true` 赋予所有本地 IP 访问权限。 #### 黑白名单 diff --git a/lib/config.js b/lib/config.js index c810fd344b..0e476461c6 100644 --- a/lib/config.js +++ b/lib/config.js @@ -95,6 +95,7 @@ const calculateValue = () => { }, blacklist: envs.BLACKLIST && envs.BLACKLIST.split(','), whitelist: envs.WHITELIST && envs.WHITELIST.split(','), + allowLocalhost: envs.ALLOW_LOCALHOST, accessKey: envs.ACCESS_KEY, enableCluster: envs.ENABLE_CLUSTER, email: { diff --git a/lib/middleware/access-control.js b/lib/middleware/access-control.js index a3bc50330b..bdb1be26fa 100644 --- a/lib/middleware/access-control.js +++ b/lib/middleware/access-control.js @@ -1,5 +1,6 @@ const config = require('@/config').value; const md5 = require('@/utils/md5'); +const isLocalhost = require('is-localhost-ip'); const reject = (ctx) => { ctx.response.status = 403; @@ -15,6 +16,8 @@ module.exports = async (ctx, next) => { const isControlled = config.accessKey || config.whitelist || config.blacklist; + const allowLocalhost = config.allowLocalhost && (await isLocalhost(ip)); + const grant = async () => { if (ctx.response.status !== 403) { await next(); @@ -24,7 +27,7 @@ module.exports = async (ctx, next) => { if (requestPath === '/' || requestPath === '/robots.txt') { await next(); } else { - if (!isControlled) { + if (!isControlled || allowLocalhost) { return await grant(); } diff --git a/package.json b/package.json index 4710842417..c2e89625f7 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "hooman": "1.2.5", "https-proxy-agent": "5.0.0", "iconv-lite": "0.5.1", + "is-localhost-ip": "1.4.0", "jsdom": "16.2.2", "json-bigint": "0.3.0", "json5": "2.1.3", diff --git a/yarn.lock b/yarn.lock index 89d2d1865a..8861d33c46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6699,6 +6699,11 @@ is-keyword-js@^1.0.3: resolved "https://registry.yarnpkg.com/is-keyword-js/-/is-keyword-js-1.0.3.tgz#ac30dcf35b671f4b27b17f5cb57235126021132d" integrity sha1-rDDc81tnH0snsX9ctXI1EmAhEy0= +is-localhost-ip@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/is-localhost-ip/-/is-localhost-ip-1.4.0.tgz#dd66aaabcbb5dbbc943e00adad5f715d2c3b3a1d" + integrity sha512-cN7SzlY7BVxSeoJu5equjsZaKSgD4HCfXrTwu0Jgbq5BbT1BU+D7Lyi/l1KO8H0un0JTlxcQaT/GWVapu+DIDg== + is-npm@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d"