@verdaccio/middleware 8.0.0-next-8.10 → 8.0.0-next-8.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/build/middlewares/antiLoop.js +16 -5
- package/build/middlewares/antiLoop.js.map +1 -1
- package/build/middlewares/web/render-web.js +5 -4
- package/build/middlewares/web/render-web.js.map +1 -1
- package/build/middlewares/web/web-middleware.js +4 -3
- package/build/middlewares/web/web-middleware.js.map +1 -1
- package/build/middlewares/web/web-urls.d.ts +4 -1
- package/build/middlewares/web/web-urls.js +4 -1
- package/build/middlewares/web/web-urls.js.map +1 -1
- package/package.json +6 -6
- package/src/middlewares/antiLoop.ts +16 -5
- package/src/middlewares/web/render-web.ts +5 -4
- package/src/middlewares/web/web-middleware.ts +4 -3
- package/src/middlewares/web/web-urls.ts +4 -1
- package/test/antiLoop.spec.ts +90 -0
- package/test/loop.spec.ts +0 -32
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @verdaccio/middleware
|
|
2
2
|
|
|
3
|
+
## 8.0.0-next-8.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4110873: chore(middleware): improve loop detection
|
|
8
|
+
- 66bc284: chore: middleware package update
|
|
9
|
+
- Updated dependencies [85e0e13]
|
|
10
|
+
- @verdaccio/utils@8.1.0-next-8.11
|
|
11
|
+
- @verdaccio/config@8.0.0-next-8.11
|
|
12
|
+
- @verdaccio/core@8.0.0-next-8.11
|
|
13
|
+
- @verdaccio/url@13.0.0-next-8.11
|
|
14
|
+
|
|
3
15
|
## 8.0.0-next-8.10
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -16,13 +16,24 @@ function antiLoop(config) {
|
|
|
16
16
|
const arr = req.get('via')?.split(',');
|
|
17
17
|
if (Array.isArray(arr)) {
|
|
18
18
|
for (let i = 0; i < arr.length; i++) {
|
|
19
|
-
// the "via" header must
|
|
19
|
+
// the "via" header must contain a specific value, this has to be in sync
|
|
20
20
|
// with the proxy request
|
|
21
21
|
// match eg: Server 1 or Server 2
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
|
|
23
|
+
// RFC 7230: Via = 1*( "," OWS Via-value )
|
|
24
|
+
// Via-value = received-protocol RWS received-by [ RWS comment ]
|
|
25
|
+
// received-protocol = [ protocol-name "/" ] protocol-version
|
|
26
|
+
// received-by = ( uri-host [ ":" port ] ) / pseudonym
|
|
27
|
+
|
|
28
|
+
// Split the trimmed header value into parts
|
|
29
|
+
const parts = arr[i].trim().split(/\s+/);
|
|
30
|
+
// Check if we have at least protocol/version and received-by parts
|
|
31
|
+
if (parts.length >= 2) {
|
|
32
|
+
// Get the received-by value (server id), removing any comment
|
|
33
|
+
const serverId = parts[1].split('(')[0].trim();
|
|
34
|
+
if (serverId === config.server_id) {
|
|
35
|
+
return next(_core.errorUtils.getCode(_core.HTTP_STATUS.LOOP_DETECTED, 'loop detected'));
|
|
36
|
+
}
|
|
26
37
|
}
|
|
27
38
|
}
|
|
28
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"antiLoop.js","names":["_core","require","antiLoop","config","req","res","next","headers","via","arr","get","split","Array","isArray","i","length","
|
|
1
|
+
{"version":3,"file":"antiLoop.js","names":["_core","require","antiLoop","config","req","res","next","headers","via","arr","get","split","Array","isArray","i","length","parts","trim","serverId","server_id","errorUtils","getCode","HTTP_STATUS","LOOP_DETECTED"],"sources":["../../src/middlewares/antiLoop.ts"],"sourcesContent":["import { HTTP_STATUS, errorUtils } from '@verdaccio/core';\nimport { Config } from '@verdaccio/types';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\n/**\n * A middleware that avoid a registry points itself as proxy and avoid create infinite loops.\n * @param config\n * @returns\n */\nexport function antiLoop(config: Config) {\n return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n if (req?.headers?.via != null) {\n const arr = req.get('via')?.split(',');\n if (Array.isArray(arr)) {\n for (let i = 0; i < arr.length; i++) {\n // the \"via\" header must contain a specific value, this has to be in sync\n // with the proxy request\n // match eg: Server 1 or Server 2\n\n // RFC 7230: Via = 1*( \",\" OWS Via-value )\n // Via-value = received-protocol RWS received-by [ RWS comment ]\n // received-protocol = [ protocol-name \"/\" ] protocol-version\n // received-by = ( uri-host [ \":\" port ] ) / pseudonym\n\n // Split the trimmed header value into parts\n const parts = arr[i].trim().split(/\\s+/);\n // Check if we have at least protocol/version and received-by parts\n if (parts.length >= 2) {\n // Get the received-by value (server id), removing any comment\n const serverId = parts[1].split('(')[0].trim();\n if (serverId === config.server_id) {\n return next(errorUtils.getCode(HTTP_STATUS.LOOP_DETECTED, 'loop detected'));\n }\n }\n }\n }\n }\n next();\n };\n}\n"],"mappings":";;;;;;AAAA,IAAAA,KAAA,GAAAC,OAAA;AAKA;AACA;AACA;AACA;AACA;AACO,SAASC,QAAQA,CAACC,MAAc,EAAE;EACvC,OAAO,UAAUC,GAAmB,EAAEC,GAAoB,EAAEC,IAAsB,EAAQ;IACxF,IAAIF,GAAG,EAAEG,OAAO,EAAEC,GAAG,IAAI,IAAI,EAAE;MAC7B,MAAMC,GAAG,GAAGL,GAAG,CAACM,GAAG,CAAC,KAAK,CAAC,EAAEC,KAAK,CAAC,GAAG,CAAC;MACtC,IAAIC,KAAK,CAACC,OAAO,CAACJ,GAAG,CAAC,EAAE;QACtB,KAAK,IAAIK,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGL,GAAG,CAACM,MAAM,EAAED,CAAC,EAAE,EAAE;UACnC;UACA;UACA;;UAEA;UACA;UACA;UACA;;UAEA;UACA,MAAME,KAAK,GAAGP,GAAG,CAACK,CAAC,CAAC,CAACG,IAAI,CAAC,CAAC,CAACN,KAAK,CAAC,KAAK,CAAC;UACxC;UACA,IAAIK,KAAK,CAACD,MAAM,IAAI,CAAC,EAAE;YACrB;YACA,MAAMG,QAAQ,GAAGF,KAAK,CAAC,CAAC,CAAC,CAACL,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAACM,IAAI,CAAC,CAAC;YAC9C,IAAIC,QAAQ,KAAKf,MAAM,CAACgB,SAAS,EAAE;cACjC,OAAOb,IAAI,CAACc,gBAAU,CAACC,OAAO,CAACC,iBAAW,CAACC,aAAa,EAAE,eAAe,CAAC,CAAC;YAC7E;UACF;QACF;MACF;IACF;IACAjB,IAAI,CAAC,CAAC;EACR,CAAC;AACH","ignoreList":[]}
|
|
@@ -12,6 +12,7 @@ var _core = require("@verdaccio/core");
|
|
|
12
12
|
var _url = require("@verdaccio/url");
|
|
13
13
|
var _security = require("./security");
|
|
14
14
|
var _renderHTML = _interopRequireDefault(require("./utils/renderHTML"));
|
|
15
|
+
var _webUrls = require("./web-urls");
|
|
15
16
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
17
|
const debug = (0, _debug.default)('verdaccio:web:render');
|
|
17
18
|
const sendFileCallback = next => err => {
|
|
@@ -40,7 +41,7 @@ function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
|
|
|
40
41
|
router.use(_security.setSecurityWebHeaders);
|
|
41
42
|
|
|
42
43
|
// any match within the static is routed to the file system
|
|
43
|
-
router.get(
|
|
44
|
+
router.get(_webUrls.WebUrlsNamespace.static + '*', function (req, res, next) {
|
|
44
45
|
const filename = req.params[0];
|
|
45
46
|
let file = `${staticPath}/${filename}`;
|
|
46
47
|
if (filename === 'favicon.ico' && config?.web?.favicon) {
|
|
@@ -65,7 +66,7 @@ function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
|
|
|
65
66
|
if (_fs.default.existsSync(absoluteLocalFile) && typeof _fs.default.accessSync(absoluteLocalFile, _fs.default.constants.R_OK) === 'undefined') {
|
|
66
67
|
// Note: `path.join` will break on Windows, because it transforms `/` to `\`
|
|
67
68
|
// Use POSIX version `path.posix.join` instead.
|
|
68
|
-
logo = _path.default.posix.join(
|
|
69
|
+
logo = _path.default.posix.join(_webUrls.WebUrlsNamespace.static, _path.default.basename(logo));
|
|
69
70
|
router.get(logo, function (_req, res, next) {
|
|
70
71
|
// @ts-ignore
|
|
71
72
|
debug('serve custom logo web:%s - local:%s', logo, absoluteLocalFile);
|
|
@@ -91,11 +92,11 @@ function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
|
|
|
91
92
|
if (config?.web?.logoDark) {
|
|
92
93
|
config.web.logoDark = logoDark;
|
|
93
94
|
}
|
|
94
|
-
router.get('
|
|
95
|
+
router.get(_webUrls.WebUrlsNamespace.web + ':section/*', function (req, res) {
|
|
95
96
|
(0, _renderHTML.default)(config, manifest, manifestFiles, req, res);
|
|
96
97
|
debug('render html section');
|
|
97
98
|
});
|
|
98
|
-
router.get(
|
|
99
|
+
router.get(_webUrls.WebUrlsNamespace.root, function (req, res) {
|
|
99
100
|
(0, _renderHTML.default)(config, manifest, manifestFiles, req, res);
|
|
100
101
|
debug('render root');
|
|
101
102
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-web.js","names":["_debug","_interopRequireDefault","require","_express","_fs","_path","_core","_url","_security","_renderHTML","e","__esModule","default","debug","buildDebug","sendFileCallback","next","err","status","HTTP_STATUS","NOT_FOUND","renderWebMiddleware","config","tokenMiddleware","pluginOptions","staticPath","manifest","manifestFiles","router","express","Router","use","setSecurityWebHeaders","get","req","res","filename","params","file","web","favicon","isURLhasValidProtocol","url","sendFile","renderLogo","logo","absoluteLocalFile","path","posix","resolve","fs","existsSync","accessSync","constants","R_OK","join","basename","_req","undefined","logoDark","renderHTML"],"sources":["../../../src/middlewares/web/render-web.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport express from 'express';\nimport fs from 'fs';\nimport path from 'path';\n\nimport { HTTP_STATUS } from '@verdaccio/core';\nimport { isURLhasValidProtocol } from '@verdaccio/url';\n\nimport { setSecurityWebHeaders } from './security';\nimport renderHTML from './utils/renderHTML';\n\nconst debug = buildDebug('verdaccio:web:render');\n\nconst sendFileCallback = (next) => (err) => {\n if (!err) {\n return;\n }\n if (err.status === HTTP_STATUS.NOT_FOUND) {\n next();\n } else {\n next(err);\n }\n};\n\nexport function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {\n const { staticPath, manifest, manifestFiles } = pluginOptions;\n debug('static path %o', staticPath);\n\n /* eslint new-cap:off */\n const router = express.Router();\n if (typeof tokenMiddleware === 'function') {\n router.use(tokenMiddleware);\n }\n\n router.use(setSecurityWebHeaders);\n\n // any match within the static is routed to the file system\n router.get(
|
|
1
|
+
{"version":3,"file":"render-web.js","names":["_debug","_interopRequireDefault","require","_express","_fs","_path","_core","_url","_security","_renderHTML","_webUrls","e","__esModule","default","debug","buildDebug","sendFileCallback","next","err","status","HTTP_STATUS","NOT_FOUND","renderWebMiddleware","config","tokenMiddleware","pluginOptions","staticPath","manifest","manifestFiles","router","express","Router","use","setSecurityWebHeaders","get","WebUrlsNamespace","static","req","res","filename","params","file","web","favicon","isURLhasValidProtocol","url","sendFile","renderLogo","logo","absoluteLocalFile","path","posix","resolve","fs","existsSync","accessSync","constants","R_OK","join","basename","_req","undefined","logoDark","renderHTML","root"],"sources":["../../../src/middlewares/web/render-web.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport express from 'express';\nimport fs from 'fs';\nimport path from 'path';\n\nimport { HTTP_STATUS } from '@verdaccio/core';\nimport { isURLhasValidProtocol } from '@verdaccio/url';\n\nimport { setSecurityWebHeaders } from './security';\nimport renderHTML from './utils/renderHTML';\nimport { WebUrlsNamespace } from './web-urls';\n\nconst debug = buildDebug('verdaccio:web:render');\n\nconst sendFileCallback = (next) => (err) => {\n if (!err) {\n return;\n }\n if (err.status === HTTP_STATUS.NOT_FOUND) {\n next();\n } else {\n next(err);\n }\n};\n\nexport function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {\n const { staticPath, manifest, manifestFiles } = pluginOptions;\n debug('static path %o', staticPath);\n\n /* eslint new-cap:off */\n const router = express.Router();\n if (typeof tokenMiddleware === 'function') {\n router.use(tokenMiddleware);\n }\n\n router.use(setSecurityWebHeaders);\n\n // any match within the static is routed to the file system\n router.get(WebUrlsNamespace.static + '*', function (req, res, next) {\n const filename = req.params[0];\n let file = `${staticPath}/${filename}`;\n if (filename === 'favicon.ico' && config?.web?.favicon) {\n file = config?.web?.favicon;\n if (isURLhasValidProtocol(file)) {\n debug('redirect to favicon %s', file);\n req.url = file;\n return next();\n }\n }\n debug('render static file %o', file);\n res.sendFile(file, sendFileCallback(next));\n });\n\n function renderLogo(logo: string | undefined): string | undefined {\n // check the origin of the logo\n if (logo && !isURLhasValidProtocol(logo)) {\n // URI related to a local file\n const absoluteLocalFile = path.posix.resolve(logo);\n debug('serve local logo %s', absoluteLocalFile);\n try {\n // TODO: replace existsSync by async alternative\n if (\n fs.existsSync(absoluteLocalFile) &&\n typeof fs.accessSync(absoluteLocalFile, fs.constants.R_OK) === 'undefined'\n ) {\n // Note: `path.join` will break on Windows, because it transforms `/` to `\\`\n // Use POSIX version `path.posix.join` instead.\n logo = path.posix.join(WebUrlsNamespace.static, path.basename(logo));\n router.get(logo, function (_req, res, next) {\n // @ts-ignore\n debug('serve custom logo web:%s - local:%s', logo, absoluteLocalFile);\n res.sendFile(absoluteLocalFile, sendFileCallback(next));\n });\n debug('enabled custom logo %s', logo);\n } else {\n logo = undefined;\n debug(`web logo is wrong, path ${absoluteLocalFile} does not exist or is not readable`);\n }\n } catch {\n logo = undefined;\n debug(`web logo is wrong, path ${absoluteLocalFile} does not exist or is not readable`);\n }\n }\n return logo;\n }\n\n const logo = renderLogo(config?.web?.logo);\n if (config?.web?.logo) {\n config.web.logo = logo;\n }\n const logoDark = renderLogo(config?.web?.logoDark);\n if (config?.web?.logoDark) {\n config.web.logoDark = logoDark;\n }\n\n router.get(WebUrlsNamespace.web + ':section/*', function (req, res) {\n renderHTML(config, manifest, manifestFiles, req, res);\n debug('render html section');\n });\n\n router.get(WebUrlsNamespace.root, function (req, res) {\n renderHTML(config, manifest, manifestFiles, req, res);\n debug('render root');\n });\n\n return router;\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,QAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,GAAA,GAAAH,sBAAA,CAAAC,OAAA;AACA,IAAAG,KAAA,GAAAJ,sBAAA,CAAAC,OAAA;AAEA,IAAAI,KAAA,GAAAJ,OAAA;AACA,IAAAK,IAAA,GAAAL,OAAA;AAEA,IAAAM,SAAA,GAAAN,OAAA;AACA,IAAAO,WAAA,GAAAR,sBAAA,CAAAC,OAAA;AACA,IAAAQ,QAAA,GAAAR,OAAA;AAA8C,SAAAD,uBAAAU,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAE9C,MAAMG,KAAK,GAAG,IAAAC,cAAU,EAAC,sBAAsB,CAAC;AAEhD,MAAMC,gBAAgB,GAAIC,IAAI,IAAMC,GAAG,IAAK;EAC1C,IAAI,CAACA,GAAG,EAAE;IACR;EACF;EACA,IAAIA,GAAG,CAACC,MAAM,KAAKC,iBAAW,CAACC,SAAS,EAAE;IACxCJ,IAAI,CAAC,CAAC;EACR,CAAC,MAAM;IACLA,IAAI,CAACC,GAAG,CAAC;EACX;AACF,CAAC;AAEM,SAASI,mBAAmBA,CAACC,MAAM,EAAEC,eAAe,EAAEC,aAAa,EAAE;EAC1E,MAAM;IAAEC,UAAU;IAAEC,QAAQ;IAAEC;EAAc,CAAC,GAAGH,aAAa;EAC7DX,KAAK,CAAC,gBAAgB,EAAEY,UAAU,CAAC;;EAEnC;EACA,MAAMG,MAAM,GAAGC,gBAAO,CAACC,MAAM,CAAC,CAAC;EAC/B,IAAI,OAAOP,eAAe,KAAK,UAAU,EAAE;IACzCK,MAAM,CAACG,GAAG,CAACR,eAAe,CAAC;EAC7B;EAEAK,MAAM,CAACG,GAAG,CAACC,+BAAqB,CAAC;;EAEjC;EACAJ,MAAM,CAACK,GAAG,CAACC,yBAAgB,CAACC,MAAM,GAAG,GAAG,EAAE,UAAUC,GAAG,EAAEC,GAAG,EAAErB,IAAI,EAAE;IAClE,MAAMsB,QAAQ,GAAGF,GAAG,CAACG,MAAM,CAAC,CAAC,CAAC;IAC9B,IAAIC,IAAI,GAAG,GAAGf,UAAU,IAAIa,QAAQ,EAAE;IACtC,IAAIA,QAAQ,KAAK,aAAa,IAAIhB,MAAM,EAAEmB,GAAG,EAAEC,OAAO,EAAE;MACtDF,IAAI,GAAGlB,MAAM,EAAEmB,GAAG,EAAEC,OAAO;MAC3B,IAAI,IAAAC,0BAAqB,EAACH,IAAI,CAAC,EAAE;QAC/B3B,KAAK,CAAC,wBAAwB,EAAE2B,IAAI,CAAC;QACrCJ,GAAG,CAACQ,GAAG,GAAGJ,IAAI;QACd,OAAOxB,IAAI,CAAC,CAAC;MACf;IACF;IACAH,KAAK,CAAC,uBAAuB,EAAE2B,IAAI,CAAC;IACpCH,GAAG,CAACQ,QAAQ,CAACL,IAAI,EAAEzB,gBAAgB,CAACC,IAAI,CAAC,CAAC;EAC5C,CAAC,CAAC;EAEF,SAAS8B,UAAUA,CAACC,IAAwB,EAAsB;IAChE;IACA,IAAIA,IAAI,IAAI,CAAC,IAAAJ,0BAAqB,EAACI,IAAI,CAAC,EAAE;MACxC;MACA,MAAMC,iBAAiB,GAAGC,aAAI,CAACC,KAAK,CAACC,OAAO,CAACJ,IAAI,CAAC;MAClDlC,KAAK,CAAC,qBAAqB,EAAEmC,iBAAiB,CAAC;MAC/C,IAAI;QACF;QACA,IACEI,WAAE,CAACC,UAAU,CAACL,iBAAiB,CAAC,IAChC,OAAOI,WAAE,CAACE,UAAU,CAACN,iBAAiB,EAAEI,WAAE,CAACG,SAAS,CAACC,IAAI,CAAC,KAAK,WAAW,EAC1E;UACA;UACA;UACAT,IAAI,GAAGE,aAAI,CAACC,KAAK,CAACO,IAAI,CAACvB,yBAAgB,CAACC,MAAM,EAAEc,aAAI,CAACS,QAAQ,CAACX,IAAI,CAAC,CAAC;UACpEnB,MAAM,CAACK,GAAG,CAACc,IAAI,EAAE,UAAUY,IAAI,EAAEtB,GAAG,EAAErB,IAAI,EAAE;YAC1C;YACAH,KAAK,CAAC,sCAAsC,EAAEkC,IAAI,EAAEC,iBAAiB,CAAC;YACtEX,GAAG,CAACQ,QAAQ,CAACG,iBAAiB,EAAEjC,gBAAgB,CAACC,IAAI,CAAC,CAAC;UACzD,CAAC,CAAC;UACFH,KAAK,CAAC,wBAAwB,EAAEkC,IAAI,CAAC;QACvC,CAAC,MAAM;UACLA,IAAI,GAAGa,SAAS;UAChB/C,KAAK,CAAC,2BAA2BmC,iBAAiB,oCAAoC,CAAC;QACzF;MACF,CAAC,CAAC,MAAM;QACND,IAAI,GAAGa,SAAS;QAChB/C,KAAK,CAAC,2BAA2BmC,iBAAiB,oCAAoC,CAAC;MACzF;IACF;IACA,OAAOD,IAAI;EACb;EAEA,MAAMA,IAAI,GAAGD,UAAU,CAACxB,MAAM,EAAEmB,GAAG,EAAEM,IAAI,CAAC;EAC1C,IAAIzB,MAAM,EAAEmB,GAAG,EAAEM,IAAI,EAAE;IACrBzB,MAAM,CAACmB,GAAG,CAACM,IAAI,GAAGA,IAAI;EACxB;EACA,MAAMc,QAAQ,GAAGf,UAAU,CAACxB,MAAM,EAAEmB,GAAG,EAAEoB,QAAQ,CAAC;EAClD,IAAIvC,MAAM,EAAEmB,GAAG,EAAEoB,QAAQ,EAAE;IACzBvC,MAAM,CAACmB,GAAG,CAACoB,QAAQ,GAAGA,QAAQ;EAChC;EAEAjC,MAAM,CAACK,GAAG,CAACC,yBAAgB,CAACO,GAAG,GAAG,YAAY,EAAE,UAAUL,GAAG,EAAEC,GAAG,EAAE;IAClE,IAAAyB,mBAAU,EAACxC,MAAM,EAAEI,QAAQ,EAAEC,aAAa,EAAES,GAAG,EAAEC,GAAG,CAAC;IACrDxB,KAAK,CAAC,qBAAqB,CAAC;EAC9B,CAAC,CAAC;EAEFe,MAAM,CAACK,GAAG,CAACC,yBAAgB,CAAC6B,IAAI,EAAE,UAAU3B,GAAG,EAAEC,GAAG,EAAE;IACpD,IAAAyB,mBAAU,EAACxC,MAAM,EAAEI,QAAQ,EAAEC,aAAa,EAAES,GAAG,EAAEC,GAAG,CAAC;IACrDxB,KAAK,CAAC,aAAa,CAAC;EACtB,CAAC,CAAC;EAEF,OAAOe,MAAM;AACf","ignoreList":[]}
|
|
@@ -7,6 +7,7 @@ exports.default = void 0;
|
|
|
7
7
|
var _express = _interopRequireDefault(require("express"));
|
|
8
8
|
var _renderWeb = require("./render-web");
|
|
9
9
|
var _webApi = require("./web-api");
|
|
10
|
+
var _webUrls = require("./web-urls");
|
|
10
11
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
12
|
var _default = (config, middlewares, pluginOptions) => {
|
|
12
13
|
// eslint-disable-next-line new-cap
|
|
@@ -16,9 +17,9 @@ var _default = (config, middlewares, pluginOptions) => {
|
|
|
16
17
|
webEndpointsApi
|
|
17
18
|
} = middlewares;
|
|
18
19
|
// render web
|
|
19
|
-
router.use(
|
|
20
|
-
// web endpoints
|
|
21
|
-
router.use(
|
|
20
|
+
router.use(_webUrls.WebUrlsNamespace.root, (0, _renderWeb.renderWebMiddleware)(config, tokenMiddleware, pluginOptions));
|
|
21
|
+
// web endpoints: search, packages, readme, sidebar, etc
|
|
22
|
+
router.use(_webUrls.WebUrlsNamespace.endpoints, (0, _webApi.webAPIMiddleware)(tokenMiddleware, webEndpointsApi));
|
|
22
23
|
return router;
|
|
23
24
|
};
|
|
24
25
|
exports.default = _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-middleware.js","names":["_express","_interopRequireDefault","require","_renderWeb","_webApi","e","__esModule","default","_default","config","middlewares","pluginOptions","router","express","Router","tokenMiddleware","webEndpointsApi","use","renderWebMiddleware","webAPIMiddleware","exports"],"sources":["../../../src/middlewares/web/web-middleware.ts"],"sourcesContent":["import express from 'express';\n\nimport { renderWebMiddleware } from './render-web';\nimport { webAPIMiddleware } from './web-api';\n\nexport default (config, middlewares, pluginOptions): any => {\n // eslint-disable-next-line new-cap\n const router = express.Router();\n const { tokenMiddleware, webEndpointsApi } = middlewares;\n // render web\n router.use(
|
|
1
|
+
{"version":3,"file":"web-middleware.js","names":["_express","_interopRequireDefault","require","_renderWeb","_webApi","_webUrls","e","__esModule","default","_default","config","middlewares","pluginOptions","router","express","Router","tokenMiddleware","webEndpointsApi","use","WebUrlsNamespace","root","renderWebMiddleware","endpoints","webAPIMiddleware","exports"],"sources":["../../../src/middlewares/web/web-middleware.ts"],"sourcesContent":["import express from 'express';\n\nimport { renderWebMiddleware } from './render-web';\nimport { webAPIMiddleware } from './web-api';\nimport { WebUrlsNamespace } from './web-urls';\n\nexport default (config, middlewares, pluginOptions): any => {\n // eslint-disable-next-line new-cap\n const router = express.Router();\n const { tokenMiddleware, webEndpointsApi } = middlewares;\n // render web\n router.use(WebUrlsNamespace.root, renderWebMiddleware(config, tokenMiddleware, pluginOptions));\n // web endpoints: search, packages, readme, sidebar, etc\n router.use(WebUrlsNamespace.endpoints, webAPIMiddleware(tokenMiddleware, webEndpointsApi));\n return router;\n};\n"],"mappings":";;;;;;AAAA,IAAAA,QAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,UAAA,GAAAD,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AACA,IAAAG,QAAA,GAAAH,OAAA;AAA8C,SAAAD,uBAAAK,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAAA,IAAAG,QAAA,GAE/BA,CAACC,MAAM,EAAEC,WAAW,EAAEC,aAAa,KAAU;EAC1D;EACA,MAAMC,MAAM,GAAGC,gBAAO,CAACC,MAAM,CAAC,CAAC;EAC/B,MAAM;IAAEC,eAAe;IAAEC;EAAgB,CAAC,GAAGN,WAAW;EACxD;EACAE,MAAM,CAACK,GAAG,CAACC,yBAAgB,CAACC,IAAI,EAAE,IAAAC,8BAAmB,EAACX,MAAM,EAAEM,eAAe,EAAEJ,aAAa,CAAC,CAAC;EAC9F;EACAC,MAAM,CAACK,GAAG,CAACC,yBAAgB,CAACG,SAAS,EAAE,IAAAC,wBAAgB,EAACP,eAAe,EAAEC,eAAe,CAAC,CAAC;EAC1F,OAAOJ,MAAM;AACf,CAAC;AAAAW,OAAA,CAAAhB,OAAA,GAAAC,QAAA","ignoreList":[]}
|
|
@@ -15,7 +15,10 @@ export declare enum WebUrls {
|
|
|
15
15
|
* Enum for web urls namespace, used on the web middleware
|
|
16
16
|
*/
|
|
17
17
|
export declare enum WebUrlsNamespace {
|
|
18
|
-
root = "
|
|
18
|
+
root = "/",
|
|
19
|
+
static = "/-/static/",
|
|
20
|
+
endpoints = "/-/verdaccio/",
|
|
21
|
+
web = "/-/web/",
|
|
19
22
|
data = "/data/",
|
|
20
23
|
sec = "/sec/"
|
|
21
24
|
}
|
|
@@ -22,7 +22,10 @@ let WebUrls = exports.WebUrls = /*#__PURE__*/function (WebUrls) {
|
|
|
22
22
|
* Enum for web urls namespace, used on the web middleware
|
|
23
23
|
*/
|
|
24
24
|
let WebUrlsNamespace = exports.WebUrlsNamespace = /*#__PURE__*/function (WebUrlsNamespace) {
|
|
25
|
-
WebUrlsNamespace["root"] = "
|
|
25
|
+
WebUrlsNamespace["root"] = "/";
|
|
26
|
+
WebUrlsNamespace["static"] = "/-/static/";
|
|
27
|
+
WebUrlsNamespace["endpoints"] = "/-/verdaccio/";
|
|
28
|
+
WebUrlsNamespace["web"] = "/-/web/";
|
|
26
29
|
WebUrlsNamespace["data"] = "/data/";
|
|
27
30
|
WebUrlsNamespace["sec"] = "/sec/";
|
|
28
31
|
return WebUrlsNamespace;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-urls.js","names":["WebUrls","exports","WebUrlsNamespace"],"sources":["../../../src/middlewares/web/web-urls.ts"],"sourcesContent":["/**\n * Enum for web urls, used on the web middleware\n */\nexport enum WebUrls {\n sidebar_scopped_package = '/sidebar/:scope/:package',\n sidebar_package = '/sidebar/:package',\n readme_package_scoped_version = '/package/readme/:scope/:package/:version?',\n readme_package_version = '/package/readme/:package/:version?',\n packages_all = '/packages',\n user_login = '/login',\n search = '/search/:anything',\n reset_password = '/reset_password',\n}\n\n/**\n * Enum for web urls namespace, used on the web middleware\n */\nexport enum WebUrlsNamespace {\n root = '/-/verdaccio/',\n data = '/data/',\n sec = '/sec/',\n}\n"],"mappings":";;;;;;AAAA;AACA;AACA;AAFA,IAGYA,OAAO,GAAAC,OAAA,CAAAD,OAAA,0BAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAA,OAAPA,OAAO;AAAA;AAWnB;AACA;AACA;AAFA,IAGYE,gBAAgB,GAAAD,OAAA,CAAAC,gBAAA,0BAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAA,OAAhBA,gBAAgB;AAAA","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"web-urls.js","names":["WebUrls","exports","WebUrlsNamespace"],"sources":["../../../src/middlewares/web/web-urls.ts"],"sourcesContent":["/**\n * Enum for web urls, used on the web middleware\n */\nexport enum WebUrls {\n sidebar_scopped_package = '/sidebar/:scope/:package',\n sidebar_package = '/sidebar/:package',\n readme_package_scoped_version = '/package/readme/:scope/:package/:version?',\n readme_package_version = '/package/readme/:package/:version?',\n packages_all = '/packages',\n user_login = '/login',\n search = '/search/:anything',\n reset_password = '/reset_password',\n}\n\n/**\n * Enum for web urls namespace, used on the web middleware\n */\nexport enum WebUrlsNamespace {\n root = '/',\n static = '/-/static/',\n endpoints = '/-/verdaccio/',\n web = '/-/web/',\n data = '/data/',\n sec = '/sec/',\n}\n"],"mappings":";;;;;;AAAA;AACA;AACA;AAFA,IAGYA,OAAO,GAAAC,OAAA,CAAAD,OAAA,0BAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAPA,OAAO;EAAA,OAAPA,OAAO;AAAA;AAWnB;AACA;AACA;AAFA,IAGYE,gBAAgB,GAAAD,OAAA,CAAAC,gBAAA,0BAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAA,OAAhBA,gBAAgB;AAAA","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdaccio/middleware",
|
|
3
|
-
"version": "8.0.0-next-8.
|
|
3
|
+
"version": "8.0.0-next-8.11",
|
|
4
4
|
"description": "express middleware utils",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"node": ">=18"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@verdaccio/config": "8.0.0-next-8.
|
|
33
|
-
"@verdaccio/core": "8.0.0-next-8.
|
|
34
|
-
"@verdaccio/url": "13.0.0-next-8.
|
|
35
|
-
"@verdaccio/utils": "8.1.0-next-8.
|
|
32
|
+
"@verdaccio/config": "8.0.0-next-8.11",
|
|
33
|
+
"@verdaccio/core": "8.0.0-next-8.11",
|
|
34
|
+
"@verdaccio/url": "13.0.0-next-8.11",
|
|
35
|
+
"@verdaccio/utils": "8.1.0-next-8.11",
|
|
36
36
|
"debug": "4.4.0",
|
|
37
37
|
"express": "4.21.2",
|
|
38
38
|
"express-rate-limit": "5.5.1",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"url": "https://opencollective.com/verdaccio"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@verdaccio/logger": "8.0.0-next-8.
|
|
48
|
+
"@verdaccio/logger": "8.0.0-next-8.11",
|
|
49
49
|
"body-parser": "1.20.3",
|
|
50
50
|
"supertest": "7.0.0",
|
|
51
51
|
"jsdom": "25.0.1"
|
|
@@ -14,13 +14,24 @@ export function antiLoop(config: Config) {
|
|
|
14
14
|
const arr = req.get('via')?.split(',');
|
|
15
15
|
if (Array.isArray(arr)) {
|
|
16
16
|
for (let i = 0; i < arr.length; i++) {
|
|
17
|
-
// the "via" header must
|
|
17
|
+
// the "via" header must contain a specific value, this has to be in sync
|
|
18
18
|
// with the proxy request
|
|
19
19
|
// match eg: Server 1 or Server 2
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
|
|
21
|
+
// RFC 7230: Via = 1*( "," OWS Via-value )
|
|
22
|
+
// Via-value = received-protocol RWS received-by [ RWS comment ]
|
|
23
|
+
// received-protocol = [ protocol-name "/" ] protocol-version
|
|
24
|
+
// received-by = ( uri-host [ ":" port ] ) / pseudonym
|
|
25
|
+
|
|
26
|
+
// Split the trimmed header value into parts
|
|
27
|
+
const parts = arr[i].trim().split(/\s+/);
|
|
28
|
+
// Check if we have at least protocol/version and received-by parts
|
|
29
|
+
if (parts.length >= 2) {
|
|
30
|
+
// Get the received-by value (server id), removing any comment
|
|
31
|
+
const serverId = parts[1].split('(')[0].trim();
|
|
32
|
+
if (serverId === config.server_id) {
|
|
33
|
+
return next(errorUtils.getCode(HTTP_STATUS.LOOP_DETECTED, 'loop detected'));
|
|
34
|
+
}
|
|
24
35
|
}
|
|
25
36
|
}
|
|
26
37
|
}
|
|
@@ -8,6 +8,7 @@ import { isURLhasValidProtocol } from '@verdaccio/url';
|
|
|
8
8
|
|
|
9
9
|
import { setSecurityWebHeaders } from './security';
|
|
10
10
|
import renderHTML from './utils/renderHTML';
|
|
11
|
+
import { WebUrlsNamespace } from './web-urls';
|
|
11
12
|
|
|
12
13
|
const debug = buildDebug('verdaccio:web:render');
|
|
13
14
|
|
|
@@ -35,7 +36,7 @@ export function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
|
|
|
35
36
|
router.use(setSecurityWebHeaders);
|
|
36
37
|
|
|
37
38
|
// any match within the static is routed to the file system
|
|
38
|
-
router.get(
|
|
39
|
+
router.get(WebUrlsNamespace.static + '*', function (req, res, next) {
|
|
39
40
|
const filename = req.params[0];
|
|
40
41
|
let file = `${staticPath}/${filename}`;
|
|
41
42
|
if (filename === 'favicon.ico' && config?.web?.favicon) {
|
|
@@ -64,7 +65,7 @@ export function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
|
|
|
64
65
|
) {
|
|
65
66
|
// Note: `path.join` will break on Windows, because it transforms `/` to `\`
|
|
66
67
|
// Use POSIX version `path.posix.join` instead.
|
|
67
|
-
logo = path.posix.join(
|
|
68
|
+
logo = path.posix.join(WebUrlsNamespace.static, path.basename(logo));
|
|
68
69
|
router.get(logo, function (_req, res, next) {
|
|
69
70
|
// @ts-ignore
|
|
70
71
|
debug('serve custom logo web:%s - local:%s', logo, absoluteLocalFile);
|
|
@@ -92,12 +93,12 @@ export function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
|
|
|
92
93
|
config.web.logoDark = logoDark;
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
router.get('
|
|
96
|
+
router.get(WebUrlsNamespace.web + ':section/*', function (req, res) {
|
|
96
97
|
renderHTML(config, manifest, manifestFiles, req, res);
|
|
97
98
|
debug('render html section');
|
|
98
99
|
});
|
|
99
100
|
|
|
100
|
-
router.get(
|
|
101
|
+
router.get(WebUrlsNamespace.root, function (req, res) {
|
|
101
102
|
renderHTML(config, manifest, manifestFiles, req, res);
|
|
102
103
|
debug('render root');
|
|
103
104
|
});
|
|
@@ -2,14 +2,15 @@ import express from 'express';
|
|
|
2
2
|
|
|
3
3
|
import { renderWebMiddleware } from './render-web';
|
|
4
4
|
import { webAPIMiddleware } from './web-api';
|
|
5
|
+
import { WebUrlsNamespace } from './web-urls';
|
|
5
6
|
|
|
6
7
|
export default (config, middlewares, pluginOptions): any => {
|
|
7
8
|
// eslint-disable-next-line new-cap
|
|
8
9
|
const router = express.Router();
|
|
9
10
|
const { tokenMiddleware, webEndpointsApi } = middlewares;
|
|
10
11
|
// render web
|
|
11
|
-
router.use(
|
|
12
|
-
// web endpoints
|
|
13
|
-
router.use(
|
|
12
|
+
router.use(WebUrlsNamespace.root, renderWebMiddleware(config, tokenMiddleware, pluginOptions));
|
|
13
|
+
// web endpoints: search, packages, readme, sidebar, etc
|
|
14
|
+
router.use(WebUrlsNamespace.endpoints, webAPIMiddleware(tokenMiddleware, webEndpointsApi));
|
|
14
15
|
return router;
|
|
15
16
|
};
|
|
@@ -16,7 +16,10 @@ export enum WebUrls {
|
|
|
16
16
|
* Enum for web urls namespace, used on the web middleware
|
|
17
17
|
*/
|
|
18
18
|
export enum WebUrlsNamespace {
|
|
19
|
-
root = '
|
|
19
|
+
root = '/',
|
|
20
|
+
static = '/-/static/',
|
|
21
|
+
endpoints = '/-/verdaccio/',
|
|
22
|
+
web = '/-/web/',
|
|
20
23
|
data = '/data/',
|
|
21
24
|
sec = '/sec/',
|
|
22
25
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import request from 'supertest';
|
|
2
|
+
import { test } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { HTTP_STATUS } from '@verdaccio/core';
|
|
5
|
+
|
|
6
|
+
import { antiLoop } from '../src';
|
|
7
|
+
import { getApp } from './helper';
|
|
8
|
+
|
|
9
|
+
test('should not be a loop', async () => {
|
|
10
|
+
const app = getApp([]);
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
app.use(antiLoop({ server_id: '1' }));
|
|
13
|
+
app.get('/sec', (req, res) => {
|
|
14
|
+
res.status(HTTP_STATUS.OK).json({});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return request(app).get('/sec').set('via', 'Server 2').expect(HTTP_STATUS.OK);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('should be a loop', async () => {
|
|
21
|
+
const app = getApp([]);
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
app.use(antiLoop({ server_id: '1' }));
|
|
24
|
+
app.get('/sec', (req, res) => {
|
|
25
|
+
res.status(HTTP_STATUS.OK).json({});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return request(app)
|
|
29
|
+
.get('/sec')
|
|
30
|
+
.set('via', 'Server 1, Server 2')
|
|
31
|
+
.expect(HTTP_STATUS.LOOP_DETECTED);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should detect loop with protocol name in via header', async () => {
|
|
35
|
+
const app = getApp([]);
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
app.use(antiLoop({ server_id: '1' }));
|
|
38
|
+
app.get('/sec', (req, res) => {
|
|
39
|
+
res.status(HTTP_STATUS.OK).json({});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return request(app).get('/sec').set('via', 'HTTP/1.1 1').expect(HTTP_STATUS.LOOP_DETECTED);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('should detect loop with comment in via header', async () => {
|
|
46
|
+
const app = getApp([]);
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
app.use(antiLoop({ server_id: '1' }));
|
|
49
|
+
app.get('/sec', (req, res) => {
|
|
50
|
+
res.status(HTTP_STATUS.OK).json({});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return request(app).get('/sec').set('via', '1.1 1 (Verdaccio)').expect(HTTP_STATUS.LOOP_DETECTED);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('should detect loop in multiple via entries', async () => {
|
|
57
|
+
const app = getApp([]);
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
app.use(antiLoop({ server_id: '1' }));
|
|
60
|
+
app.get('/sec', (req, res) => {
|
|
61
|
+
res.status(HTTP_STATUS.OK).json({});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return request(app)
|
|
65
|
+
.get('/sec')
|
|
66
|
+
.set('via', '1.1 server-a, 1.1 1, 1.1 server-b')
|
|
67
|
+
.expect(HTTP_STATUS.LOOP_DETECTED);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('should handle malformed via header gracefully', async () => {
|
|
71
|
+
const app = getApp([]);
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
app.use(antiLoop({ server_id: '1' }));
|
|
74
|
+
app.get('/sec', (req, res) => {
|
|
75
|
+
res.status(HTTP_STATUS.OK).json({});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return request(app).get('/sec').set('via', 'malformed-header').expect(HTTP_STATUS.OK);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('should handle via header with unexpected format', async () => {
|
|
82
|
+
const app = getApp([]);
|
|
83
|
+
// @ts-ignore
|
|
84
|
+
app.use(antiLoop({ server_id: '1' }));
|
|
85
|
+
app.get('/sec', (req, res) => {
|
|
86
|
+
res.status(HTTP_STATUS.OK).json({});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return request(app).get('/sec').set('via', 'unexpected format').expect(HTTP_STATUS.OK);
|
|
90
|
+
});
|
package/test/loop.spec.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import request from 'supertest';
|
|
2
|
-
import { test } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import { HTTP_STATUS } from '@verdaccio/core';
|
|
5
|
-
|
|
6
|
-
import { antiLoop } from '../src';
|
|
7
|
-
import { getApp } from './helper';
|
|
8
|
-
|
|
9
|
-
test('should not be a loop', async () => {
|
|
10
|
-
const app = getApp([]);
|
|
11
|
-
// @ts-ignore
|
|
12
|
-
app.use(antiLoop({ server_id: '1' }));
|
|
13
|
-
app.get('/sec', (req, res) => {
|
|
14
|
-
res.status(HTTP_STATUS.OK).json({});
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
return request(app).get('/sec').set('via', 'Server 2').expect(HTTP_STATUS.OK);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('should be a loop', async () => {
|
|
21
|
-
const app = getApp([]);
|
|
22
|
-
// @ts-ignore
|
|
23
|
-
app.use(antiLoop({ server_id: '1' }));
|
|
24
|
-
app.get('/sec', (req, res) => {
|
|
25
|
-
res.status(HTTP_STATUS.OK).json({});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
return request(app)
|
|
29
|
-
.get('/sec')
|
|
30
|
-
.set('via', 'Server 1, Server 2')
|
|
31
|
-
.expect(HTTP_STATUS.LOOP_DETECTED);
|
|
32
|
-
});
|