@verdaccio/middleware 8.0.0-next-8.3 → 8.0.0-next-8.5

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 CHANGED
@@ -1,5 +1,34 @@
1
1
  # @verdaccio/middleware
2
2
 
3
+ ## 8.0.0-next-8.5
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [ba71932]
8
+ - Updated dependencies [64a7fc0]
9
+ - Updated dependencies [4adaa83]
10
+ - Updated dependencies [5cbee6f]
11
+ - Updated dependencies [a049bba]
12
+ - @verdaccio/config@8.0.0-next-8.5
13
+ - @verdaccio/core@8.0.0-next-8.5
14
+ - @verdaccio/url@13.0.0-next-8.5
15
+ - @verdaccio/utils@8.1.0-next-8.5
16
+
17
+ ## 8.0.0-next-8.4
18
+
19
+ ### Patch Changes
20
+
21
+ - 48aa89f: chore: request header constants
22
+ - 58e0d95: fix(middleware): error 404 when getting scoped tarballs
23
+ - 1076a89: chore(middleware): fix syntax of test files
24
+ - e93d6a3: chore: auth package requires logger as parameter
25
+ - Updated dependencies [48aa89f]
26
+ - Updated dependencies [58e0d95]
27
+ - @verdaccio/core@8.0.0-next-8.4
28
+ - @verdaccio/config@8.0.0-next-8.4
29
+ - @verdaccio/url@13.0.0-next-8.4
30
+ - @verdaccio/utils@8.1.0-next-8.4
31
+
3
32
  ## 8.0.0-next-8.3
4
33
 
5
34
  ### Patch Changes
package/build/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { match } from './middlewares/match';
2
2
  export { setSecurityWebHeaders } from './middlewares/security-headers';
3
3
  export { validateName, validatePackage } from './middlewares/validation';
4
4
  export { media } from './middlewares/media';
5
+ export { makeURLrelative } from './middlewares/make-url-relative';
5
6
  export { encodeScopePackage } from './middlewares/encode-pkg';
6
7
  export { expectJson } from './middlewares/json';
7
8
  export { antiLoop } from './middlewares/antiLoop';
package/build/index.js CHANGED
@@ -9,6 +9,7 @@ var _exportNames = {
9
9
  validateName: true,
10
10
  validatePackage: true,
11
11
  media: true,
12
+ makeURLrelative: true,
12
13
  encodeScopePackage: true,
13
14
  expectJson: true,
14
15
  antiLoop: true,
@@ -91,6 +92,12 @@ Object.defineProperty(exports, "log", {
91
92
  return _log.log;
92
93
  }
93
94
  });
95
+ Object.defineProperty(exports, "makeURLrelative", {
96
+ enumerable: true,
97
+ get: function () {
98
+ return _makeUrlRelative.makeURLrelative;
99
+ }
100
+ });
94
101
  Object.defineProperty(exports, "match", {
95
102
  enumerable: true,
96
103
  get: function () {
@@ -149,6 +156,7 @@ var _match = require("./middlewares/match");
149
156
  var _securityHeaders = require("./middlewares/security-headers");
150
157
  var _validation = require("./middlewares/validation");
151
158
  var _media = require("./middlewares/media");
159
+ var _makeUrlRelative = require("./middlewares/make-url-relative");
152
160
  var _encodePkg = require("./middlewares/encode-pkg");
153
161
  var _json = require("./middlewares/json");
154
162
  var _antiLoop = require("./middlewares/antiLoop");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_match","require","_securityHeaders","_validation","_media","_encodePkg","_json","_antiLoop","_final","_allow","_rateLimit","_userAgent","_web","_error","_log","_types","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get"],"sources":["../src/index.ts"],"sourcesContent":["export { match } from './middlewares/match';\nexport { setSecurityWebHeaders } from './middlewares/security-headers';\nexport { validateName, validatePackage } from './middlewares/validation';\nexport { media } from './middlewares/media';\nexport { encodeScopePackage } from './middlewares/encode-pkg';\nexport { expectJson } from './middlewares/json';\nexport { antiLoop } from './middlewares/antiLoop';\nexport { final } from './middlewares/final';\nexport { allow } from './middlewares/allow';\nexport { rateLimit } from './middlewares/rate-limit';\nexport { userAgent } from './middlewares/user-agent';\nexport { webMiddleware, renderWebMiddleware } from './middlewares/web';\nexport { errorReportingMiddleware, handleError } from './middlewares/error';\nexport {\n log,\n LOG_STATUS_MESSAGE,\n LOG_VERDACCIO_BYTES,\n LOG_VERDACCIO_ERROR,\n} from './middlewares/log';\nexport * from './types';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,gBAAA,GAAAD,OAAA;AACA,IAAAE,WAAA,GAAAF,OAAA;AACA,IAAAG,MAAA,GAAAH,OAAA;AACA,IAAAI,UAAA,GAAAJ,OAAA;AACA,IAAAK,KAAA,GAAAL,OAAA;AACA,IAAAM,SAAA,GAAAN,OAAA;AACA,IAAAO,MAAA,GAAAP,OAAA;AACA,IAAAQ,MAAA,GAAAR,OAAA;AACA,IAAAS,UAAA,GAAAT,OAAA;AACA,IAAAU,UAAA,GAAAV,OAAA;AACA,IAAAW,IAAA,GAAAX,OAAA;AACA,IAAAY,MAAA,GAAAZ,OAAA;AACA,IAAAa,IAAA,GAAAb,OAAA;AAMA,IAAAc,MAAA,GAAAd,OAAA;AAAAe,MAAA,CAAAC,IAAA,CAAAF,MAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,MAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,MAAA,CAAAI,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["_match","require","_securityHeaders","_validation","_media","_makeUrlRelative","_encodePkg","_json","_antiLoop","_final","_allow","_rateLimit","_userAgent","_web","_error","_log","_types","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get"],"sources":["../src/index.ts"],"sourcesContent":["export { match } from './middlewares/match';\nexport { setSecurityWebHeaders } from './middlewares/security-headers';\nexport { validateName, validatePackage } from './middlewares/validation';\nexport { media } from './middlewares/media';\nexport { makeURLrelative } from './middlewares/make-url-relative';\nexport { encodeScopePackage } from './middlewares/encode-pkg';\nexport { expectJson } from './middlewares/json';\nexport { antiLoop } from './middlewares/antiLoop';\nexport { final } from './middlewares/final';\nexport { allow } from './middlewares/allow';\nexport { rateLimit } from './middlewares/rate-limit';\nexport { userAgent } from './middlewares/user-agent';\nexport { webMiddleware, renderWebMiddleware } from './middlewares/web';\nexport { errorReportingMiddleware, handleError } from './middlewares/error';\nexport {\n log,\n LOG_STATUS_MESSAGE,\n LOG_VERDACCIO_BYTES,\n LOG_VERDACCIO_ERROR,\n} from './middlewares/log';\nexport * from './types';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,gBAAA,GAAAD,OAAA;AACA,IAAAE,WAAA,GAAAF,OAAA;AACA,IAAAG,MAAA,GAAAH,OAAA;AACA,IAAAI,gBAAA,GAAAJ,OAAA;AACA,IAAAK,UAAA,GAAAL,OAAA;AACA,IAAAM,KAAA,GAAAN,OAAA;AACA,IAAAO,SAAA,GAAAP,OAAA;AACA,IAAAQ,MAAA,GAAAR,OAAA;AACA,IAAAS,MAAA,GAAAT,OAAA;AACA,IAAAU,UAAA,GAAAV,OAAA;AACA,IAAAW,UAAA,GAAAX,OAAA;AACA,IAAAY,IAAA,GAAAZ,OAAA;AACA,IAAAa,MAAA,GAAAb,OAAA;AACA,IAAAc,IAAA,GAAAd,OAAA;AAMA,IAAAe,MAAA,GAAAf,OAAA;AAAAgB,MAAA,CAAAC,IAAA,CAAAF,MAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,MAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,MAAA,CAAAI,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.encodeScopePackage = encodeScopePackage;
7
7
  var _debug = _interopRequireDefault(require("debug"));
8
+ var _core = require("@verdaccio/core");
8
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
10
  const debug = (0, _debug.default)('verdaccio:middleware:encode');
10
11
 
@@ -16,16 +17,22 @@ const debug = (0, _debug.default)('verdaccio:middleware:encode');
16
17
  */
17
18
  function encodeScopePackage(req, res, next) {
18
19
  const original = req.url;
20
+
21
+ // Expect relative URLs i.e. should call makeURLrelative before this middleware
22
+ if (!req.url.startsWith('/')) {
23
+ return next(_core.errorUtils.getBadRequest(`Invalid URL: ${req.url} (must be relative)`));
24
+ }
25
+
19
26
  // If the @ sign is encoded, we need to decode it first
20
27
  // e.g.: /%40org/pkg/1.2.3 -> /@org/pkg/1.2.3
21
- if (req.url.indexOf('%40') !== -1) {
22
- req.url = req.url.replace(/^\/%40/, '/@');
23
- }
24
- if (req.url.indexOf('@') !== -1) {
25
- // e.g.: /@org/pkg/1.2.3 -> /@org%2Fpkg/1.2.3, /@org%2Fpkg/1.2.3 -> /@org%2Fpkg/1.2.3
26
- req.url = req.url.replace(/^(\/@[^\/%]+)\/(?!$)/, '$1%2F');
28
+ // For scoped packages, encode the slash to make it a single path segment/parameter
29
+ // e.g.: /@org/pkg/1.2.3 -> /@org%2Fpkg/1.2.3, /@org%2Fpkg/1.2.3 -> /@org%2Fpkg/1.2.3
30
+ req.url = req.url.replace(/^\/%40/, '/@').replace(/^(\/@[^\/%]+)\/(?!$)/, '$1%2F');
31
+ if (original !== req.url) {
32
+ debug('encodeScopePackage: %o -> %o', original, req.url);
33
+ } else {
34
+ debug('encodeScopePackage: %o (unchanged)', original);
27
35
  }
28
- debug('encodeScopePackage: %o -> %o', original, req.url);
29
36
  next();
30
37
  }
31
38
  //# sourceMappingURL=encode-pkg.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"encode-pkg.js","names":["_debug","_interopRequireDefault","require","e","__esModule","default","debug","buildDebug","encodeScopePackage","req","res","next","original","url","indexOf","replace"],"sources":["../../src/middlewares/encode-pkg.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:encode');\n\n/**\n * Encode / in a scoped package name to be matched as a single parameter in routes\n * @param req\n * @param res\n * @param next\n */\nexport function encodeScopePackage(\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n): void {\n const original = req.url;\n // If the @ sign is encoded, we need to decode it first\n // e.g.: /%40org/pkg/1.2.3 -> /@org/pkg/1.2.3\n if (req.url.indexOf('%40') !== -1) {\n req.url = req.url.replace(/^\\/%40/, '/@');\n }\n if (req.url.indexOf('@') !== -1) {\n // e.g.: /@org/pkg/1.2.3 -> /@org%2Fpkg/1.2.3, /@org%2Fpkg/1.2.3 -> /@org%2Fpkg/1.2.3\n req.url = req.url.replace(/^(\\/@[^\\/%]+)\\/(?!$)/, '$1%2F');\n }\n debug('encodeScopePackage: %o -> %o', original, req.url);\n next();\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAA+B,SAAAD,uBAAAE,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAI/B,MAAMG,KAAK,GAAG,IAAAC,cAAU,EAAC,6BAA6B,CAAC;;AAEvD;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,kBAAkBA,CAChCC,GAAmB,EACnBC,GAAoB,EACpBC,IAAsB,EAChB;EACN,MAAMC,QAAQ,GAAGH,GAAG,CAACI,GAAG;EACxB;EACA;EACA,IAAIJ,GAAG,CAACI,GAAG,CAACC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE;IACjCL,GAAG,CAACI,GAAG,GAAGJ,GAAG,CAACI,GAAG,CAACE,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC;EAC3C;EACA,IAAIN,GAAG,CAACI,GAAG,CAACC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE;IAC/B;IACAL,GAAG,CAACI,GAAG,GAAGJ,GAAG,CAACI,GAAG,CAACE,OAAO,CAAC,sBAAsB,EAAE,OAAO,CAAC;EAC5D;EACAT,KAAK,CAAC,8BAA8B,EAAEM,QAAQ,EAAEH,GAAG,CAACI,GAAG,CAAC;EACxDF,IAAI,CAAC,CAAC;AACR","ignoreList":[]}
1
+ {"version":3,"file":"encode-pkg.js","names":["_debug","_interopRequireDefault","require","_core","e","__esModule","default","debug","buildDebug","encodeScopePackage","req","res","next","original","url","startsWith","errorUtils","getBadRequest","replace"],"sources":["../../src/middlewares/encode-pkg.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { errorUtils } from '@verdaccio/core';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:encode');\n\n/**\n * Encode / in a scoped package name to be matched as a single parameter in routes\n * @param req\n * @param res\n * @param next\n */\nexport function encodeScopePackage(\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n): void {\n const original = req.url;\n\n // Expect relative URLs i.e. should call makeURLrelative before this middleware\n if (!req.url.startsWith('/')) {\n return next(errorUtils.getBadRequest(`Invalid URL: ${req.url} (must be relative)`));\n }\n\n // If the @ sign is encoded, we need to decode it first\n // e.g.: /%40org/pkg/1.2.3 -> /@org/pkg/1.2.3\n // For scoped packages, encode the slash to make it a single path segment/parameter\n // e.g.: /@org/pkg/1.2.3 -> /@org%2Fpkg/1.2.3, /@org%2Fpkg/1.2.3 -> /@org%2Fpkg/1.2.3\n req.url = req.url.replace(/^\\/%40/, '/@').replace(/^(\\/@[^\\/%]+)\\/(?!$)/, '$1%2F');\n\n if (original !== req.url) {\n debug('encodeScopePackage: %o -> %o', original, req.url);\n } else {\n debug('encodeScopePackage: %o (unchanged)', original);\n }\n next();\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,KAAA,GAAAD,OAAA;AAA6C,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAI7C,MAAMG,KAAK,GAAG,IAAAC,cAAU,EAAC,6BAA6B,CAAC;;AAEvD;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,kBAAkBA,CAChCC,GAAmB,EACnBC,GAAoB,EACpBC,IAAsB,EAChB;EACN,MAAMC,QAAQ,GAAGH,GAAG,CAACI,GAAG;;EAExB;EACA,IAAI,CAACJ,GAAG,CAACI,GAAG,CAACC,UAAU,CAAC,GAAG,CAAC,EAAE;IAC5B,OAAOH,IAAI,CAACI,gBAAU,CAACC,aAAa,CAAC,gBAAgBP,GAAG,CAACI,GAAG,qBAAqB,CAAC,CAAC;EACrF;;EAEA;EACA;EACA;EACA;EACAJ,GAAG,CAACI,GAAG,GAAGJ,GAAG,CAACI,GAAG,CAACI,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAACA,OAAO,CAAC,sBAAsB,EAAE,OAAO,CAAC;EAElF,IAAIL,QAAQ,KAAKH,GAAG,CAACI,GAAG,EAAE;IACxBP,KAAK,CAAC,8BAA8B,EAAEM,QAAQ,EAAEH,GAAG,CAACI,GAAG,CAAC;EAC1D,CAAC,MAAM;IACLP,KAAK,CAAC,oCAAoC,EAAEM,QAAQ,CAAC;EACvD;EACAD,IAAI,CAAC,CAAC;AACR","ignoreList":[]}
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.log = exports.LOG_VERDACCIO_ERROR = exports.LOG_VERDACCIO_BYTES = exports.LOG_STATUS_MESSAGE = void 0;
7
7
  var _lodash = _interopRequireDefault(require("lodash"));
8
+ var _core = require("@verdaccio/core");
8
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
10
  // FIXME: deprecated, moved to @verdaccio/dev-commons
10
11
  const LOG_STATUS_MESSAGE = exports.LOG_STATUS_MESSAGE = "@{status}, user: @{user}(@{remoteIP}), req: '@{request.method} @{request.url}'";
@@ -51,7 +52,7 @@ const log = logger => {
51
52
  _write.apply(res, arguments);
52
53
  };
53
54
  const log = function () {
54
- const forwardedFor = req.get('x-forwarded-for');
55
+ const forwardedFor = req.get(_core.HEADERS.FORWARDED_FOR);
55
56
  const remoteAddress = req.connection.remoteAddress;
56
57
  const remoteIP = forwardedFor ? `${forwardedFor} via ${remoteAddress}` : remoteAddress;
57
58
  let message;
@@ -1 +1 @@
1
- {"version":3,"file":"log.js","names":["_lodash","_interopRequireDefault","require","e","__esModule","default","LOG_STATUS_MESSAGE","exports","LOG_VERDACCIO_ERROR","LOG_VERDACCIO_BYTES","log","logger","req","res","next","child","sub","_auth","headers","authorization","_","isNil","_cookie","get","cookie","url","originalUrl","info","ip","bytesin","on","chunk","length","bytesout","_write","write","buf","apply","arguments","forwardedFor","remoteAddress","connection","remoteIP","message","locals","_verdaccio_error","http","request","method","user","remote_user","name","status","statusCode","error","bytes","in","out","_end","end"],"sources":["../../src/middlewares/log.ts"],"sourcesContent":["import _ from 'lodash';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\n// FIXME: deprecated, moved to @verdaccio/dev-commons\nexport const LOG_STATUS_MESSAGE =\n \"@{status}, user: @{user}(@{remoteIP}), req: '@{request.method} @{request.url}'\";\nexport const LOG_VERDACCIO_ERROR = `${LOG_STATUS_MESSAGE}, error: @{!error}`;\nexport const LOG_VERDACCIO_BYTES = `${LOG_STATUS_MESSAGE}, bytes: @{bytes.in}/@{bytes.out}`;\n\nexport const log = (logger) => {\n return function log(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n // logger\n req.log = logger.child({ sub: 'in' });\n\n const _auth = req.headers.authorization;\n if (_.isNil(_auth) === false) {\n req.headers.authorization = '<Classified>';\n }\n\n const _cookie = req.get('cookie');\n if (_.isNil(_cookie) === false) {\n req.headers.cookie = '<Classified>';\n }\n\n req.url = req.originalUrl;\n req.log.info({ req: req, ip: req.ip }, \"@{ip} requested '@{req.method} @{req.url}'\");\n req.originalUrl = req.url;\n\n if (_.isNil(_auth) === false) {\n req.headers.authorization = _auth;\n }\n\n if (_.isNil(_cookie) === false) {\n req.headers.cookie = _cookie;\n }\n\n let bytesin = 0;\n req.on('data', function (chunk): void {\n bytesin += chunk.length;\n });\n\n let bytesout = 0;\n const _write = res.write;\n // FIXME: res.write should return boolean\n // @ts-ignore\n res.write = function (buf): boolean {\n bytesout += buf.length;\n /* eslint prefer-rest-params: \"off\" */\n // @ts-ignore\n _write.apply(res, arguments);\n };\n\n const log = function (): void {\n const forwardedFor = req.get('x-forwarded-for');\n const remoteAddress = req.connection.remoteAddress;\n const remoteIP = forwardedFor ? `${forwardedFor} via ${remoteAddress}` : remoteAddress;\n let message;\n if (res.locals._verdaccio_error) {\n message = LOG_VERDACCIO_ERROR;\n } else {\n message = LOG_VERDACCIO_BYTES;\n }\n\n req.url = req.originalUrl;\n req.log.http(\n {\n request: {\n method: req.method,\n url: req.url,\n },\n user: req.remote_user?.name || null,\n remoteIP,\n status: res.statusCode,\n error: res.locals._verdaccio_error,\n bytes: {\n in: bytesin,\n out: bytesout,\n },\n },\n message\n );\n req.originalUrl = req.url;\n };\n\n req.on('close', function (): void {\n log();\n });\n\n const _end = res.end;\n // @ts-ignore\n res.end = function (buf): void {\n if (buf) {\n bytesout += buf.length;\n }\n /* eslint prefer-rest-params: \"off\" */\n // @ts-ignore\n _end.apply(res, arguments);\n log();\n };\n next();\n };\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"log.js","names":["_lodash","_interopRequireDefault","require","_core","e","__esModule","default","LOG_STATUS_MESSAGE","exports","LOG_VERDACCIO_ERROR","LOG_VERDACCIO_BYTES","log","logger","req","res","next","child","sub","_auth","headers","authorization","_","isNil","_cookie","get","cookie","url","originalUrl","info","ip","bytesin","on","chunk","length","bytesout","_write","write","buf","apply","arguments","forwardedFor","HEADERS","FORWARDED_FOR","remoteAddress","connection","remoteIP","message","locals","_verdaccio_error","http","request","method","user","remote_user","name","status","statusCode","error","bytes","in","out","_end","end"],"sources":["../../src/middlewares/log.ts"],"sourcesContent":["import _ from 'lodash';\n\nimport { HEADERS } from '@verdaccio/core';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\n// FIXME: deprecated, moved to @verdaccio/dev-commons\nexport const LOG_STATUS_MESSAGE =\n \"@{status}, user: @{user}(@{remoteIP}), req: '@{request.method} @{request.url}'\";\nexport const LOG_VERDACCIO_ERROR = `${LOG_STATUS_MESSAGE}, error: @{!error}`;\nexport const LOG_VERDACCIO_BYTES = `${LOG_STATUS_MESSAGE}, bytes: @{bytes.in}/@{bytes.out}`;\n\nexport const log = (logger) => {\n return function log(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n // logger\n req.log = logger.child({ sub: 'in' });\n\n const _auth = req.headers.authorization;\n if (_.isNil(_auth) === false) {\n req.headers.authorization = '<Classified>';\n }\n\n const _cookie = req.get('cookie');\n if (_.isNil(_cookie) === false) {\n req.headers.cookie = '<Classified>';\n }\n\n req.url = req.originalUrl;\n req.log.info({ req: req, ip: req.ip }, \"@{ip} requested '@{req.method} @{req.url}'\");\n req.originalUrl = req.url;\n\n if (_.isNil(_auth) === false) {\n req.headers.authorization = _auth;\n }\n\n if (_.isNil(_cookie) === false) {\n req.headers.cookie = _cookie;\n }\n\n let bytesin = 0;\n req.on('data', function (chunk): void {\n bytesin += chunk.length;\n });\n\n let bytesout = 0;\n const _write = res.write;\n // FIXME: res.write should return boolean\n // @ts-ignore\n res.write = function (buf): boolean {\n bytesout += buf.length;\n /* eslint prefer-rest-params: \"off\" */\n // @ts-ignore\n _write.apply(res, arguments);\n };\n\n const log = function (): void {\n const forwardedFor = req.get(HEADERS.FORWARDED_FOR);\n const remoteAddress = req.connection.remoteAddress;\n const remoteIP = forwardedFor ? `${forwardedFor} via ${remoteAddress}` : remoteAddress;\n let message;\n if (res.locals._verdaccio_error) {\n message = LOG_VERDACCIO_ERROR;\n } else {\n message = LOG_VERDACCIO_BYTES;\n }\n\n req.url = req.originalUrl;\n req.log.http(\n {\n request: {\n method: req.method,\n url: req.url,\n },\n user: req.remote_user?.name || null,\n remoteIP,\n status: res.statusCode,\n error: res.locals._verdaccio_error,\n bytes: {\n in: bytesin,\n out: bytesout,\n },\n },\n message\n );\n req.originalUrl = req.url;\n };\n\n req.on('close', function (): void {\n log();\n });\n\n const _end = res.end;\n // @ts-ignore\n res.end = function (buf): void {\n if (buf) {\n bytesout += buf.length;\n }\n /* eslint prefer-rest-params: \"off\" */\n // @ts-ignore\n _end.apply(res, arguments);\n log();\n };\n next();\n };\n};\n"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,KAAA,GAAAD,OAAA;AAA0C,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAI1C;AACO,MAAMG,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,GAC7B,gFAAgF;AAC3E,MAAME,mBAAmB,GAAAD,OAAA,CAAAC,mBAAA,GAAG,GAAGF,kBAAkB,oBAAoB;AACrE,MAAMG,mBAAmB,GAAAF,OAAA,CAAAE,mBAAA,GAAG,GAAGH,kBAAkB,mCAAmC;AAEpF,MAAMI,GAAG,GAAIC,MAAM,IAAK;EAC7B,OAAO,SAASD,GAAGA,CAACE,GAAmB,EAAEC,GAAoB,EAAEC,IAAsB,EAAQ;IAC3F;IACAF,GAAG,CAACF,GAAG,GAAGC,MAAM,CAACI,KAAK,CAAC;MAAEC,GAAG,EAAE;IAAK,CAAC,CAAC;IAErC,MAAMC,KAAK,GAAGL,GAAG,CAACM,OAAO,CAACC,aAAa;IACvC,IAAIC,eAAC,CAACC,KAAK,CAACJ,KAAK,CAAC,KAAK,KAAK,EAAE;MAC5BL,GAAG,CAACM,OAAO,CAACC,aAAa,GAAG,cAAc;IAC5C;IAEA,MAAMG,OAAO,GAAGV,GAAG,CAACW,GAAG,CAAC,QAAQ,CAAC;IACjC,IAAIH,eAAC,CAACC,KAAK,CAACC,OAAO,CAAC,KAAK,KAAK,EAAE;MAC9BV,GAAG,CAACM,OAAO,CAACM,MAAM,GAAG,cAAc;IACrC;IAEAZ,GAAG,CAACa,GAAG,GAAGb,GAAG,CAACc,WAAW;IACzBd,GAAG,CAACF,GAAG,CAACiB,IAAI,CAAC;MAAEf,GAAG,EAAEA,GAAG;MAAEgB,EAAE,EAAEhB,GAAG,CAACgB;IAAG,CAAC,EAAE,4CAA4C,CAAC;IACpFhB,GAAG,CAACc,WAAW,GAAGd,GAAG,CAACa,GAAG;IAEzB,IAAIL,eAAC,CAACC,KAAK,CAACJ,KAAK,CAAC,KAAK,KAAK,EAAE;MAC5BL,GAAG,CAACM,OAAO,CAACC,aAAa,GAAGF,KAAK;IACnC;IAEA,IAAIG,eAAC,CAACC,KAAK,CAACC,OAAO,CAAC,KAAK,KAAK,EAAE;MAC9BV,GAAG,CAACM,OAAO,CAACM,MAAM,GAAGF,OAAO;IAC9B;IAEA,IAAIO,OAAO,GAAG,CAAC;IACfjB,GAAG,CAACkB,EAAE,CAAC,MAAM,EAAE,UAAUC,KAAK,EAAQ;MACpCF,OAAO,IAAIE,KAAK,CAACC,MAAM;IACzB,CAAC,CAAC;IAEF,IAAIC,QAAQ,GAAG,CAAC;IAChB,MAAMC,MAAM,GAAGrB,GAAG,CAACsB,KAAK;IACxB;IACA;IACAtB,GAAG,CAACsB,KAAK,GAAG,UAAUC,GAAG,EAAW;MAClCH,QAAQ,IAAIG,GAAG,CAACJ,MAAM;MACtB;MACA;MACAE,MAAM,CAACG,KAAK,CAACxB,GAAG,EAAEyB,SAAS,CAAC;IAC9B,CAAC;IAED,MAAM5B,GAAG,GAAG,SAAAA,CAAA,EAAkB;MAC5B,MAAM6B,YAAY,GAAG3B,GAAG,CAACW,GAAG,CAACiB,aAAO,CAACC,aAAa,CAAC;MACnD,MAAMC,aAAa,GAAG9B,GAAG,CAAC+B,UAAU,CAACD,aAAa;MAClD,MAAME,QAAQ,GAAGL,YAAY,GAAG,GAAGA,YAAY,QAAQG,aAAa,EAAE,GAAGA,aAAa;MACtF,IAAIG,OAAO;MACX,IAAIhC,GAAG,CAACiC,MAAM,CAACC,gBAAgB,EAAE;QAC/BF,OAAO,GAAGrC,mBAAmB;MAC/B,CAAC,MAAM;QACLqC,OAAO,GAAGpC,mBAAmB;MAC/B;MAEAG,GAAG,CAACa,GAAG,GAAGb,GAAG,CAACc,WAAW;MACzBd,GAAG,CAACF,GAAG,CAACsC,IAAI,CACV;QACEC,OAAO,EAAE;UACPC,MAAM,EAAEtC,GAAG,CAACsC,MAAM;UAClBzB,GAAG,EAAEb,GAAG,CAACa;QACX,CAAC;QACD0B,IAAI,EAAEvC,GAAG,CAACwC,WAAW,EAAEC,IAAI,IAAI,IAAI;QACnCT,QAAQ;QACRU,MAAM,EAAEzC,GAAG,CAAC0C,UAAU;QACtBC,KAAK,EAAE3C,GAAG,CAACiC,MAAM,CAACC,gBAAgB;QAClCU,KAAK,EAAE;UACLC,EAAE,EAAE7B,OAAO;UACX8B,GAAG,EAAE1B;QACP;MACF,CAAC,EACDY,OACF,CAAC;MACDjC,GAAG,CAACc,WAAW,GAAGd,GAAG,CAACa,GAAG;IAC3B,CAAC;IAEDb,GAAG,CAACkB,EAAE,CAAC,OAAO,EAAE,YAAkB;MAChCpB,GAAG,CAAC,CAAC;IACP,CAAC,CAAC;IAEF,MAAMkD,IAAI,GAAG/C,GAAG,CAACgD,GAAG;IACpB;IACAhD,GAAG,CAACgD,GAAG,GAAG,UAAUzB,GAAG,EAAQ;MAC7B,IAAIA,GAAG,EAAE;QACPH,QAAQ,IAAIG,GAAG,CAACJ,MAAM;MACxB;MACA;MACA;MACA4B,IAAI,CAACvB,KAAK,CAACxB,GAAG,EAAEyB,SAAS,CAAC;MAC1B5B,GAAG,CAAC,CAAC;IACP,CAAC;IACDI,IAAI,CAAC,CAAC;EACR,CAAC;AACH,CAAC;AAACP,OAAA,CAAAG,GAAA,GAAAA,GAAA","ignoreList":[]}
@@ -0,0 +1,8 @@
1
+ import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';
2
+ /**
3
+ * Removes the host from the URL and turns it into a relative URL.
4
+ * @param req
5
+ * @param res
6
+ * @param next
7
+ */
8
+ export declare function makeURLrelative(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.makeURLrelative = makeURLrelative;
7
+ var _debug = _interopRequireDefault(require("debug"));
8
+ var _nodeUrl = require("node:url");
9
+ var _core = require("@verdaccio/core");
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ const debug = (0, _debug.default)('verdaccio:middleware:make-url-relative');
12
+
13
+ /**
14
+ * Removes the host from the URL and turns it into a relative URL.
15
+ * @param req
16
+ * @param res
17
+ * @param next
18
+ */
19
+ function makeURLrelative(req, res, next) {
20
+ const original = req.url;
21
+
22
+ // npm requests can contain the full URL, including the hostname, for example:
23
+ // tarball downloads. Removing the hostname makes the URL relative and allows
24
+ // the application to handle requests in a more consistent way.
25
+
26
+ let url;
27
+ try {
28
+ // In productive use, the URL is absolute (and base will be ignored)
29
+ // In tests, the URL might brelative (and base will be used)
30
+ // https://nodejs.org/docs/latest/api/url.html#new-urlinput-base
31
+ url = new _nodeUrl.URL(req.url, `${req.protocol}://${req.headers.host}/`);
32
+ } catch (error) {
33
+ return next(_core.errorUtils.getBadRequest(`Invalid URL: ${req.url} (${error})`));
34
+ }
35
+
36
+ // Rebuild the URL without hostname
37
+ req.url = url.pathname + url.search + url.hash;
38
+ if (original !== req.url) {
39
+ debug('makeURLrelative: %o -> %o', original, req.url);
40
+ } else {
41
+ debug('makeURLrelative: %o (unchanged)', original);
42
+ }
43
+ next();
44
+ }
45
+ //# sourceMappingURL=make-url-relative.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make-url-relative.js","names":["_debug","_interopRequireDefault","require","_nodeUrl","_core","e","__esModule","default","debug","buildDebug","makeURLrelative","req","res","next","original","url","URL","protocol","headers","host","error","errorUtils","getBadRequest","pathname","search","hash"],"sources":["../../src/middlewares/make-url-relative.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { URL } from 'node:url';\n\nimport { errorUtils } from '@verdaccio/core';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:make-url-relative');\n\n/**\n * Removes the host from the URL and turns it into a relative URL.\n * @param req\n * @param res\n * @param next\n */\nexport function makeURLrelative(\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n): void {\n const original = req.url;\n\n // npm requests can contain the full URL, including the hostname, for example:\n // tarball downloads. Removing the hostname makes the URL relative and allows\n // the application to handle requests in a more consistent way.\n\n let url;\n try {\n // In productive use, the URL is absolute (and base will be ignored)\n // In tests, the URL might brelative (and base will be used)\n // https://nodejs.org/docs/latest/api/url.html#new-urlinput-base\n url = new URL(req.url, `${req.protocol}://${req.headers.host}/`);\n } catch (error) {\n return next(errorUtils.getBadRequest(`Invalid URL: ${req.url} (${error})`));\n }\n\n // Rebuild the URL without hostname\n req.url = url.pathname + url.search + url.hash;\n\n if (original !== req.url) {\n debug('makeURLrelative: %o -> %o', original, req.url);\n } else {\n debug('makeURLrelative: %o (unchanged)', original);\n }\n next();\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,QAAA,GAAAD,OAAA;AAEA,IAAAE,KAAA,GAAAF,OAAA;AAA6C,SAAAD,uBAAAI,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAI7C,MAAMG,KAAK,GAAG,IAAAC,cAAU,EAAC,wCAAwC,CAAC;;AAElE;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,eAAeA,CAC7BC,GAAmB,EACnBC,GAAoB,EACpBC,IAAsB,EAChB;EACN,MAAMC,QAAQ,GAAGH,GAAG,CAACI,GAAG;;EAExB;EACA;EACA;;EAEA,IAAIA,GAAG;EACP,IAAI;IACF;IACA;IACA;IACAA,GAAG,GAAG,IAAIC,YAAG,CAACL,GAAG,CAACI,GAAG,EAAE,GAAGJ,GAAG,CAACM,QAAQ,MAAMN,GAAG,CAACO,OAAO,CAACC,IAAI,GAAG,CAAC;EAClE,CAAC,CAAC,OAAOC,KAAK,EAAE;IACd,OAAOP,IAAI,CAACQ,gBAAU,CAACC,aAAa,CAAC,gBAAgBX,GAAG,CAACI,GAAG,KAAKK,KAAK,GAAG,CAAC,CAAC;EAC7E;;EAEA;EACAT,GAAG,CAACI,GAAG,GAAGA,GAAG,CAACQ,QAAQ,GAAGR,GAAG,CAACS,MAAM,GAAGT,GAAG,CAACU,IAAI;EAE9C,IAAIX,QAAQ,KAAKH,GAAG,CAACI,GAAG,EAAE;IACxBP,KAAK,CAAC,2BAA2B,EAAEM,QAAQ,EAAEH,GAAG,CAACI,GAAG,CAAC;EACvD,CAAC,MAAM;IACLP,KAAK,CAAC,iCAAiC,EAAEM,QAAQ,CAAC;EACpD;EACAD,IAAI,CAAC,CAAC;AACR","ignoreList":[]}
@@ -5,9 +5,10 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.userAgent = userAgent;
7
7
  var _config = require("@verdaccio/config");
8
+ var _core = require("@verdaccio/core");
8
9
  function userAgent(config) {
9
10
  return function (_req, res, next) {
10
- res.setHeader('x-powered-by', (0, _config.getUserAgent)(config?.user_agent));
11
+ res.setHeader(_core.HEADERS.POWERED_BY, (0, _config.getUserAgent)(config?.user_agent));
11
12
  next();
12
13
  };
13
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"user-agent.js","names":["_config","require","userAgent","config","_req","res","next","setHeader","getUserAgent","user_agent"],"sources":["../../src/middlewares/user-agent.ts"],"sourcesContent":["import { getUserAgent } from '@verdaccio/config';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nexport function userAgent(config) {\n return function (_req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n res.setHeader('x-powered-by', getUserAgent(config?.user_agent));\n next();\n };\n}\n"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAIO,SAASC,SAASA,CAACC,MAAM,EAAE;EAChC,OAAO,UAAUC,IAAoB,EAAEC,GAAoB,EAAEC,IAAsB,EAAQ;IACzFD,GAAG,CAACE,SAAS,CAAC,cAAc,EAAE,IAAAC,oBAAY,EAACL,MAAM,EAAEM,UAAU,CAAC,CAAC;IAC/DH,IAAI,CAAC,CAAC;EACR,CAAC;AACH","ignoreList":[]}
1
+ {"version":3,"file":"user-agent.js","names":["_config","require","_core","userAgent","config","_req","res","next","setHeader","HEADERS","POWERED_BY","getUserAgent","user_agent"],"sources":["../../src/middlewares/user-agent.ts"],"sourcesContent":["import { getUserAgent } from '@verdaccio/config';\nimport { HEADERS } from '@verdaccio/core';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nexport function userAgent(config) {\n return function (_req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n res.setHeader(HEADERS.POWERED_BY, getUserAgent(config?.user_agent));\n next();\n };\n}\n"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAD,OAAA;AAIO,SAASE,SAASA,CAACC,MAAM,EAAE;EAChC,OAAO,UAAUC,IAAoB,EAAEC,GAAoB,EAAEC,IAAsB,EAAQ;IACzFD,GAAG,CAACE,SAAS,CAACC,aAAO,CAACC,UAAU,EAAE,IAAAC,oBAAY,EAACP,MAAM,EAAEQ,UAAU,CAAC,CAAC;IACnEL,IAAI,CAAC,CAAC;EACR,CAAC;AACH","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/middleware",
3
- "version": "8.0.0-next-8.3",
3
+ "version": "8.0.0-next-8.5",
4
4
  "description": "express middleware utils",
5
5
  "main": "./build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -29,12 +29,12 @@
29
29
  "node": ">=18"
30
30
  },
31
31
  "dependencies": {
32
- "@verdaccio/config": "8.0.0-next-8.3",
33
- "@verdaccio/core": "8.0.0-next-8.3",
34
- "@verdaccio/url": "13.0.0-next-8.3",
35
- "@verdaccio/utils": "8.1.0-next-8.3",
32
+ "@verdaccio/config": "8.0.0-next-8.5",
33
+ "@verdaccio/core": "8.0.0-next-8.5",
34
+ "@verdaccio/url": "13.0.0-next-8.5",
35
+ "@verdaccio/utils": "8.1.0-next-8.5",
36
36
  "debug": "4.3.7",
37
- "express": "4.21.0",
37
+ "express": "4.21.1",
38
38
  "express-rate-limit": "5.5.1",
39
39
  "lodash": "4.17.21",
40
40
  "lru-cache": "7.18.3",
@@ -45,7 +45,7 @@
45
45
  "url": "https://opencollective.com/verdaccio"
46
46
  },
47
47
  "devDependencies": {
48
- "@verdaccio/logger": "8.0.0-next-8.3",
48
+ "@verdaccio/logger": "8.0.0-next-8.5",
49
49
  "body-parser": "1.20.3",
50
50
  "supertest": "7.0.0",
51
51
  "jsdom": "25.0.1"
@@ -57,7 +57,6 @@
57
57
  "build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
58
58
  "watch": "pnpm build:js -- --watch",
59
59
  "test": "vitest run",
60
- "test:snap": "jest --updateSnapshot",
61
60
  "build": "pnpm run build:js && pnpm run build:types"
62
61
  }
63
62
  }
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export { match } from './middlewares/match';
2
2
  export { setSecurityWebHeaders } from './middlewares/security-headers';
3
3
  export { validateName, validatePackage } from './middlewares/validation';
4
4
  export { media } from './middlewares/media';
5
+ export { makeURLrelative } from './middlewares/make-url-relative';
5
6
  export { encodeScopePackage } from './middlewares/encode-pkg';
6
7
  export { expectJson } from './middlewares/json';
7
8
  export { antiLoop } from './middlewares/antiLoop';
@@ -1,5 +1,7 @@
1
1
  import buildDebug from 'debug';
2
2
 
3
+ import { errorUtils } from '@verdaccio/core';
4
+
3
5
  import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';
4
6
 
5
7
  const debug = buildDebug('verdaccio:middleware:encode');
@@ -16,15 +18,22 @@ export function encodeScopePackage(
16
18
  next: $NextFunctionVer
17
19
  ): void {
18
20
  const original = req.url;
21
+
22
+ // Expect relative URLs i.e. should call makeURLrelative before this middleware
23
+ if (!req.url.startsWith('/')) {
24
+ return next(errorUtils.getBadRequest(`Invalid URL: ${req.url} (must be relative)`));
25
+ }
26
+
19
27
  // If the @ sign is encoded, we need to decode it first
20
28
  // e.g.: /%40org/pkg/1.2.3 -> /@org/pkg/1.2.3
21
- if (req.url.indexOf('%40') !== -1) {
22
- req.url = req.url.replace(/^\/%40/, '/@');
23
- }
24
- if (req.url.indexOf('@') !== -1) {
25
- // e.g.: /@org/pkg/1.2.3 -> /@org%2Fpkg/1.2.3, /@org%2Fpkg/1.2.3 -> /@org%2Fpkg/1.2.3
26
- req.url = req.url.replace(/^(\/@[^\/%]+)\/(?!$)/, '$1%2F');
29
+ // For scoped packages, encode the slash to make it a single path segment/parameter
30
+ // e.g.: /@org/pkg/1.2.3 -> /@org%2Fpkg/1.2.3, /@org%2Fpkg/1.2.3 -> /@org%2Fpkg/1.2.3
31
+ req.url = req.url.replace(/^\/%40/, '/@').replace(/^(\/@[^\/%]+)\/(?!$)/, '$1%2F');
32
+
33
+ if (original !== req.url) {
34
+ debug('encodeScopePackage: %o -> %o', original, req.url);
35
+ } else {
36
+ debug('encodeScopePackage: %o (unchanged)', original);
27
37
  }
28
- debug('encodeScopePackage: %o -> %o', original, req.url);
29
38
  next();
30
39
  }
@@ -1,5 +1,7 @@
1
1
  import _ from 'lodash';
2
2
 
3
+ import { HEADERS } from '@verdaccio/core';
4
+
3
5
  import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';
4
6
 
5
7
  // FIXME: deprecated, moved to @verdaccio/dev-commons
@@ -52,7 +54,7 @@ export const log = (logger) => {
52
54
  };
53
55
 
54
56
  const log = function (): void {
55
- const forwardedFor = req.get('x-forwarded-for');
57
+ const forwardedFor = req.get(HEADERS.FORWARDED_FOR);
56
58
  const remoteAddress = req.connection.remoteAddress;
57
59
  const remoteIP = forwardedFor ? `${forwardedFor} via ${remoteAddress}` : remoteAddress;
58
60
  let message;
@@ -0,0 +1,46 @@
1
+ import buildDebug from 'debug';
2
+ import { URL } from 'node:url';
3
+
4
+ import { errorUtils } from '@verdaccio/core';
5
+
6
+ import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';
7
+
8
+ const debug = buildDebug('verdaccio:middleware:make-url-relative');
9
+
10
+ /**
11
+ * Removes the host from the URL and turns it into a relative URL.
12
+ * @param req
13
+ * @param res
14
+ * @param next
15
+ */
16
+ export function makeURLrelative(
17
+ req: $RequestExtend,
18
+ res: $ResponseExtend,
19
+ next: $NextFunctionVer
20
+ ): void {
21
+ const original = req.url;
22
+
23
+ // npm requests can contain the full URL, including the hostname, for example:
24
+ // tarball downloads. Removing the hostname makes the URL relative and allows
25
+ // the application to handle requests in a more consistent way.
26
+
27
+ let url;
28
+ try {
29
+ // In productive use, the URL is absolute (and base will be ignored)
30
+ // In tests, the URL might brelative (and base will be used)
31
+ // https://nodejs.org/docs/latest/api/url.html#new-urlinput-base
32
+ url = new URL(req.url, `${req.protocol}://${req.headers.host}/`);
33
+ } catch (error) {
34
+ return next(errorUtils.getBadRequest(`Invalid URL: ${req.url} (${error})`));
35
+ }
36
+
37
+ // Rebuild the URL without hostname
38
+ req.url = url.pathname + url.search + url.hash;
39
+
40
+ if (original !== req.url) {
41
+ debug('makeURLrelative: %o -> %o', original, req.url);
42
+ } else {
43
+ debug('makeURLrelative: %o (unchanged)', original);
44
+ }
45
+ next();
46
+ }
@@ -1,10 +1,11 @@
1
1
  import { getUserAgent } from '@verdaccio/config';
2
+ import { HEADERS } from '@verdaccio/core';
2
3
 
3
4
  import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';
4
5
 
5
6
  export function userAgent(config) {
6
7
  return function (_req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {
7
- res.setHeader('x-powered-by', getUserAgent(config?.user_agent));
8
+ res.setHeader(HEADERS.POWERED_BY, getUserAgent(config?.user_agent));
8
9
  next();
9
10
  };
10
11
  }
@@ -1,16 +1,15 @@
1
1
  import request from 'supertest';
2
- import { expect, test } from 'vitest';
2
+ import { describe, expect, test } from 'vitest';
3
3
 
4
4
  import { HTTP_STATUS } from '@verdaccio/core';
5
5
 
6
6
  import { encodeScopePackage } from '../src';
7
7
  import { getApp } from './helper';
8
8
 
9
- test('encode is json', async () => {
9
+ test('encode is json with relative path', async () => {
10
10
  const app = getApp([]);
11
11
  // @ts-ignore
12
12
  app.use(encodeScopePackage);
13
- // @ts-ignore
14
13
  app.get('/:id', (req, res) => {
15
14
  const { id } = req.params;
16
15
  res.status(HTTP_STATUS.OK).json({ id });
@@ -21,84 +20,112 @@ test('encode is json', async () => {
21
20
  expect(res.status).toEqual(HTTP_STATUS.OK);
22
21
  });
23
22
 
24
- test('packages with version/scope', async () => {
23
+ describe('packages requests', () => {
25
24
  const app = getApp([]);
26
25
  // @ts-ignore
27
26
  app.use(encodeScopePackage);
28
- // @ts-ignore
29
27
  app.get('/:package/:version?', (req, res) => {
30
28
  const { package: pkg, version } = req.params;
31
29
  res.status(HTTP_STATUS.OK).json({ package: pkg, version });
32
30
  });
33
31
 
34
- const res = await request(app).get('/foo');
35
- expect(res.body).toEqual({ package: 'foo' });
36
- expect(res.status).toEqual(HTTP_STATUS.OK);
32
+ test('just package', async () => {
33
+ const res = await request(app).get('/foo');
34
+ expect(res.body).toEqual({ package: 'foo' });
35
+ expect(res.status).toEqual(HTTP_STATUS.OK);
36
+ });
37
37
 
38
- const res2 = await request(app).get('/foo/1.0.0');
39
- expect(res2.body).toEqual({ package: 'foo', version: '1.0.0' });
40
- expect(res2.status).toEqual(HTTP_STATUS.OK);
38
+ test('package with version', async () => {
39
+ const res = await request(app).get('/foo/1.0.0');
40
+ expect(res.body).toEqual({ package: 'foo', version: '1.0.0' });
41
+ expect(res.status).toEqual(HTTP_STATUS.OK);
42
+ });
41
43
 
42
- const res3 = await request(app).get('/@scope/foo');
43
- expect(res3.body).toEqual({ package: '@scope/foo' });
44
- expect(res3.status).toEqual(HTTP_STATUS.OK);
44
+ test('scoped package', async () => {
45
+ const res = await request(app).get('/@scope/foo');
46
+ expect(res.body).toEqual({ package: '@scope/foo' });
47
+ expect(res.status).toEqual(HTTP_STATUS.OK);
48
+ });
45
49
 
46
- const res4 = await request(app).get('/@scope/foo/1.0.0');
47
- expect(res4.body).toEqual({ package: '@scope/foo', version: '1.0.0' });
48
- expect(res4.status).toEqual(HTTP_STATUS.OK);
50
+ test('scoped package with version', async () => {
51
+ const res = await request(app).get('/@scope/foo/1.0.0');
52
+ expect(res.body).toEqual({ package: '@scope/foo', version: '1.0.0' });
53
+ expect(res.status).toEqual(HTTP_STATUS.OK);
54
+ });
49
55
 
50
- const res5 = await request(app).get('/@scope%2ffoo');
51
- expect(res5.body).toEqual({ package: '@scope/foo' });
52
- expect(res5.status).toEqual(HTTP_STATUS.OK);
56
+ test('scoped package with encoded path', async () => {
57
+ const res = await request(app).get('/@scope%2ffoo');
58
+ expect(res.body).toEqual({ package: '@scope/foo' });
59
+ expect(res.status).toEqual(HTTP_STATUS.OK);
60
+ });
53
61
 
54
- const res6 = await request(app).get('/@scope%2ffoo/1.0.0');
55
- expect(res6.body).toEqual({ package: '@scope/foo', version: '1.0.0' });
56
- expect(res6.status).toEqual(HTTP_STATUS.OK);
62
+ test('scoped package and version with encoded path', async () => {
63
+ const res = await request(app).get('/@scope%2ffoo/1.0.0');
64
+ expect(res.body).toEqual({ package: '@scope/foo', version: '1.0.0' });
65
+ expect(res.status).toEqual(HTTP_STATUS.OK);
66
+ });
57
67
 
58
- const res7 = await request(app).get('/%40scope%2ffoo');
59
- expect(res7.body).toEqual({ package: '@scope/foo' });
60
- expect(res7.status).toEqual(HTTP_STATUS.OK);
68
+ test('scoped package with encoded @ and path ', async () => {
69
+ const res = await request(app).get('/%40scope%2ffoo');
70
+ expect(res.body).toEqual({ package: '@scope/foo' });
71
+ expect(res.status).toEqual(HTTP_STATUS.OK);
72
+ });
61
73
 
62
- const res8 = await request(app).get('/%40scope%2ffoo/1.0.0');
63
- expect(res8.body).toEqual({ package: '@scope/foo', version: '1.0.0' });
64
- expect(res8.status).toEqual(HTTP_STATUS.OK);
74
+ test('scoped package and version with encoded @ and path', async () => {
75
+ const res = await request(app).get('/%40scope%2ffoo/1.0.0');
76
+ expect(res.body).toEqual({ package: '@scope/foo', version: '1.0.0' });
77
+ expect(res.status).toEqual(HTTP_STATUS.OK);
78
+ });
65
79
 
66
- const res9 = await request(app).get('/%40scope/foo');
67
- expect(res9.body).toEqual({ package: '@scope/foo' });
68
- expect(res9.status).toEqual(HTTP_STATUS.OK);
80
+ test('scoped package with encoded @', async () => {
81
+ const res = await request(app).get('/%40scope/foo');
82
+ expect(res.body).toEqual({ package: '@scope/foo' });
83
+ expect(res.status).toEqual(HTTP_STATUS.OK);
84
+ });
69
85
 
70
- const res10 = await request(app).get('/%40scope/foo/1.0.0');
71
- expect(res10.body).toEqual({ package: '@scope/foo', version: '1.0.0' });
72
- expect(res10.status).toEqual(HTTP_STATUS.OK);
86
+ test('scoped package and version with encoded @', async () => {
87
+ const res = await request(app).get('/%40scope/foo/1.0.0');
88
+ expect(res.body).toEqual({ package: '@scope/foo', version: '1.0.0' });
89
+ expect(res.status).toEqual(HTTP_STATUS.OK);
90
+ });
73
91
  });
74
92
 
75
- test('tarballs with and without scope', async () => {
93
+ describe('tarball requests', () => {
76
94
  const app = getApp([]);
77
95
  // @ts-ignore
78
96
  app.use(encodeScopePackage);
79
- // @ts-ignore
80
97
  app.get('/:package/-/:filename', (req, res) => {
81
98
  const { package: pkg, filename } = req.params;
82
99
  res.status(HTTP_STATUS.OK).json({ package: pkg, filename });
83
100
  });
84
101
 
85
- const res = await request(app).get('/foo/-/foo-1.2.3.tgz');
86
- expect(res.body).toEqual({ package: 'foo', filename: 'foo-1.2.3.tgz' });
87
- expect(res.status).toEqual(HTTP_STATUS.OK);
102
+ test('just package', async () => {
103
+ const res = await request(app).get('/foo/-/foo-1.2.3.tgz');
104
+ expect(res.body).toEqual({ package: 'foo', filename: 'foo-1.2.3.tgz' });
105
+ expect(res.status).toEqual(HTTP_STATUS.OK);
106
+ });
88
107
 
89
- const res2 = await request(app).get('/@scope/foo/-/foo-1.2.3.tgz');
90
- expect(res2.body).toEqual({ package: '@scope/foo', filename: 'foo-1.2.3.tgz' });
91
- expect(res2.status).toEqual(HTTP_STATUS.OK);
108
+ test('scoped package', async () => {
109
+ const res = await request(app).get('/@scope/foo/-/foo-1.2.3.tgz');
110
+ expect(res.body).toEqual({ package: '@scope/foo', filename: 'foo-1.2.3.tgz' });
111
+ expect(res.status).toEqual(HTTP_STATUS.OK);
112
+ });
92
113
 
93
- const res3 = await request(app).get('/@scope%2ffoo/-/foo-1.2.3.tgz');
94
- expect(res3.body).toEqual({ package: '@scope/foo', filename: 'foo-1.2.3.tgz' });
95
- expect(res3.status).toEqual(HTTP_STATUS.OK);
114
+ test('scoped package with encoded path', async () => {
115
+ const res = await request(app).get('/@scope%2ffoo/-/foo-1.2.3.tgz');
116
+ expect(res.body).toEqual({ package: '@scope/foo', filename: 'foo-1.2.3.tgz' });
117
+ expect(res.status).toEqual(HTTP_STATUS.OK);
118
+ });
96
119
 
97
- const res4 = await request(app).get('/%40scope%2ffoo/-/foo-1.2.3.tgz');
98
- expect(res4.body).toEqual({ package: '@scope/foo', filename: 'foo-1.2.3.tgz' });
99
- expect(res4.status).toEqual(HTTP_STATUS.OK);
120
+ test('scoped package with encoded @ and path', async () => {
121
+ const res = await request(app).get('/%40scope%2ffoo/-/foo-1.2.3.tgz');
122
+ expect(res.body).toEqual({ package: '@scope/foo', filename: 'foo-1.2.3.tgz' });
123
+ expect(res.status).toEqual(HTTP_STATUS.OK);
124
+ });
100
125
 
101
- const res5 = await request(app).get('/%40scope/foo/-/foo-1.2.3.tgz');
102
- expect(res5.body).toEqual({ package: '@scope/foo', filename: 'foo-1.2.3.tgz' });
103
- expect(res5.status).toEqual(HTTP_STATUS.OK);
126
+ test('scoped package with encoded @', async () => {
127
+ const res = await request(app).get('/%40scope/foo/-/foo-1.2.3.tgz');
128
+ expect(res.body).toEqual({ package: '@scope/foo', filename: 'foo-1.2.3.tgz' });
129
+ expect(res.status).toEqual(HTTP_STATUS.OK);
130
+ });
104
131
  });
@@ -0,0 +1,42 @@
1
+ import request from 'supertest';
2
+ import { expect, test } from 'vitest';
3
+
4
+ import { HEADERS, HTTP_STATUS } from '@verdaccio/core';
5
+
6
+ import { makeURLrelative } from '../src';
7
+ import { getApp } from './helper';
8
+
9
+ const testHosts = [
10
+ 'localhost:4873', // with port
11
+ 'myregistry.com', // no port
12
+ '42.42.42.42', // ip
13
+ '[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443', // ip6
14
+ ];
15
+
16
+ test.each([testHosts])('remove host from url', async (host) => {
17
+ const app = getApp([]);
18
+ // @ts-ignore
19
+ app.use(makeURLrelative);
20
+ app.get('/:id', (req, res) => {
21
+ const { id } = req.params;
22
+ res.status(HTTP_STATUS.OK).json({ id, url: req.url });
23
+ });
24
+
25
+ const res = await request(app).get('/foo').set(HEADERS.HOST, host);
26
+ expect(res.body).toEqual({ id: 'foo', url: '/foo' });
27
+ expect(res.status).toEqual(HTTP_STATUS.OK);
28
+ });
29
+
30
+ test('invalid url', async () => {
31
+ const app = getApp([]);
32
+ // @ts-ignore
33
+ app.use(makeURLrelative);
34
+ app.get('/:id', (req, res) => {
35
+ const { id } = req.params;
36
+ res.status(HTTP_STATUS.OK).json({ id });
37
+ });
38
+
39
+ const res = await request(app).get('/foo').set(HEADERS.HOST, 'invalid::host');
40
+ expect(res.status).toEqual(HTTP_STATUS.BAD_REQUEST);
41
+ expect(res.text).toContain('Invalid URL');
42
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ runtime: '';
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ vendors: '';
3
+ }
@@ -1,3 +0,0 @@
1
- {
2
- 'vendors': '';
3
- }