@verdaccio/middleware 8.1.1 → 8.1.3

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.
Files changed (37) hide show
  1. package/build/middlewares/allow.js.map +1 -1
  2. package/build/middlewares/allow.mjs.map +1 -1
  3. package/build/middlewares/antiLoop.js.map +1 -1
  4. package/build/middlewares/antiLoop.mjs.map +1 -1
  5. package/build/middlewares/body-parser.js.map +1 -1
  6. package/build/middlewares/body-parser.mjs.map +1 -1
  7. package/build/middlewares/encode-pkg.js.map +1 -1
  8. package/build/middlewares/encode-pkg.mjs.map +1 -1
  9. package/build/middlewares/error.js.map +1 -1
  10. package/build/middlewares/error.mjs.map +1 -1
  11. package/build/middlewares/final.js.map +1 -1
  12. package/build/middlewares/make-url-relative.js.map +1 -1
  13. package/build/middlewares/media.js.map +1 -1
  14. package/build/middlewares/media.mjs.map +1 -1
  15. package/build/middlewares/request-options.js.map +1 -1
  16. package/build/middlewares/token-auth.js +1 -1
  17. package/build/middlewares/token-auth.js.map +1 -1
  18. package/build/middlewares/token-auth.mjs +1 -1
  19. package/build/middlewares/token-auth.mjs.map +1 -1
  20. package/build/middlewares/user-agent.js.map +1 -1
  21. package/build/middlewares/web/index.js +6 -3
  22. package/build/middlewares/web/index.mjs +4 -3
  23. package/build/middlewares/web/render-web.js +4 -2
  24. package/build/middlewares/web/render-web.js.map +1 -1
  25. package/build/middlewares/web/render-web.mjs +4 -2
  26. package/build/middlewares/web/render-web.mjs.map +1 -1
  27. package/build/middlewares/web/security.js.map +1 -1
  28. package/build/middlewares/web/utils/manifest.js.map +1 -1
  29. package/build/middlewares/web/utils/renderHTML.js.map +1 -1
  30. package/build/middlewares/web/utils/renderHTML.mjs.map +1 -1
  31. package/build/middlewares/web/utils/template.js.map +1 -1
  32. package/build/middlewares/web/utils/template.mjs.map +1 -1
  33. package/build/middlewares/web/utils/ui-options.js.map +1 -1
  34. package/build/middlewares/web/utils/ui-options.mjs.map +1 -1
  35. package/build/middlewares/web/utils/web-utils.js.map +1 -1
  36. package/build/middlewares/web/web-api.js.map +1 -1
  37. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"allow.js","names":[],"sources":["../../src/middlewares/allow.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { API_ERROR, errorUtils, tarballUtils } from '@verdaccio/core';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:allow');\n\nexport function allow<T>(\n auth: T,\n options = {\n beforeAll: (_a: any, _b: any) => {},\n\n afterAll: (_a: any, _b: any) => {},\n }\n): Function {\n const { beforeAll, afterAll } = options;\n return function (action: string): Function {\n return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n req.pause();\n const packageName = req.params.scope\n ? `${req.params.scope}/${req.params.package}`\n : req.params.package;\n const packageVersion = req.params.filename\n ? tarballUtils.getVersionFromTarball(req.params.filename)\n : req.params.version\n ? req.params.version\n : undefined;\n const remote_user = req.remote_user;\n debug(\n 'check if user %o can %o package %o version %o',\n remote_user?.name,\n action,\n packageName,\n packageVersion\n );\n beforeAll?.(\n { action, user: remote_user?.name },\n `[middleware/allow][@{action}] allow for @{user}`\n );\n auth['allow_' + action](\n { packageName, packageVersion },\n remote_user,\n function (error, allowed): void {\n req.resume();\n if (error) {\n debug('user is NOT allowed to %o', action);\n next(error);\n } else if (allowed) {\n debug('user is allowed to %o', action);\n afterAll?.(\n { action, user: remote_user?.name },\n `[middleware/allow][@{action}] allowed for @{user}`\n );\n next();\n } else {\n // last plugin (that's our built-in one) returns either\n // cb(err) or cb(null, true), so this should never happen\n throw errorUtils.getInternalError(API_ERROR.PLUGIN_ERROR);\n }\n }\n );\n };\n };\n}\n"],"mappings":";;;;;AAMA,IAAM,WAAA,GAAA,MAAA,SAAmB,4BAA4B;AAErD,SAAgB,MACd,MACA,UAAU;CACR,YAAY,IAAS,OAAY,CAAC;CAElC,WAAW,IAAS,OAAY,CAAC;AACnC,GACU;CACV,MAAM,EAAE,WAAW,aAAa;CAChC,OAAO,SAAU,QAA0B;EACzC,OAAO,SAAU,KAAqB,KAAsB,MAA8B;GACxF,IAAI,MAAM;GACV,MAAM,cAAc,IAAI,OAAO,QAC3B,GAAG,IAAI,OAAO,MAAM,GAAG,IAAI,OAAO,YAClC,IAAI,OAAO;GACf,MAAM,iBAAiB,IAAI,OAAO,WAC9B,gBAAA,aAAa,sBAAsB,IAAI,OAAO,QAAQ,IACtD,IAAI,OAAO,UACT,IAAI,OAAO,UACX,KAAA;GACN,MAAM,cAAc,IAAI;GACxB,QACE,iDACA,aAAa,MACb,QACA,aACA,cACF;GACA,YACE;IAAE;IAAQ,MAAM,aAAa;GAAK,GAClC,iDACF;GACA,KAAK,WAAW,QACd;IAAE;IAAa;GAAe,GAC9B,aACA,SAAU,OAAO,SAAe;IAC9B,IAAI,OAAO;IACX,IAAI,OAAO;KACT,QAAM,6BAA6B,MAAM;KACzC,KAAK,KAAK;IACZ,OAAO,IAAI,SAAS;KAClB,QAAM,yBAAyB,MAAM;KACrC,WACE;MAAE;MAAQ,MAAM,aAAa;KAAK,GAClC,mDACF;KACA,KAAK;IACP,OAGE,MAAM,gBAAA,WAAW,iBAAiB,gBAAA,UAAU,YAAY;GAE5D,CACF;EACF;CACF;AACF"}
1
+ {"version":3,"file":"allow.js","names":[],"sources":["../../src/middlewares/allow.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { API_ERROR, errorUtils, tarballUtils } from '@verdaccio/core';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:allow');\n\nexport function allow<T>(\n auth: T,\n options = {\n beforeAll: (_a: any, _b: any) => {},\n\n afterAll: (_a: any, _b: any) => {},\n }\n): Function {\n const { beforeAll, afterAll } = options;\n return function (action: string): Function {\n return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n req.pause();\n const packageName = req.params.scope\n ? `${req.params.scope}/${req.params.package}`\n : req.params.package;\n const packageVersion = req.params.filename\n ? tarballUtils.getVersionFromTarball(req.params.filename)\n : req.params.version\n ? req.params.version\n : undefined;\n const remote_user = req.remote_user;\n debug(\n 'check if user %o can %o package %o version %o',\n remote_user?.name,\n action,\n packageName,\n packageVersion\n );\n beforeAll?.(\n { action, user: remote_user?.name },\n `[middleware/allow][@{action}] allow for @{user}`\n );\n auth['allow_' + action](\n { packageName, packageVersion },\n remote_user,\n function (error, allowed): void {\n req.resume();\n if (error) {\n debug('user is NOT allowed to %o', action);\n next(error);\n } else if (allowed) {\n debug('user is allowed to %o', action);\n afterAll?.(\n { action, user: remote_user?.name },\n `[middleware/allow][@{action}] allowed for @{user}`\n );\n next();\n } else {\n // last plugin (that's our built-in one) returns either\n // cb(err) or cb(null, true), so this should never happen\n throw errorUtils.getInternalError(API_ERROR.PLUGIN_ERROR);\n }\n }\n );\n };\n };\n}\n"],"mappings":";;;;;AAMA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,4BAA4B;AAErD,SAAgB,MACd,MACA,UAAU;CACR,YAAY,IAAS,OAAY,CAAC;CAElC,WAAW,IAAS,OAAY,CAAC;AACnC,GACU;CACV,MAAM,EAAE,WAAW,aAAa;CAChC,OAAO,SAAU,QAA0B;EACzC,OAAO,SAAU,KAAqB,KAAsB,MAA8B;GACxF,IAAI,MAAM;GACV,MAAM,cAAc,IAAI,OAAO,QAC3B,GAAG,IAAI,OAAO,MAAM,GAAG,IAAI,OAAO,YAClC,IAAI,OAAO;GACf,MAAM,iBAAiB,IAAI,OAAO,WAC9B,gBAAA,aAAa,sBAAsB,IAAI,OAAO,QAAQ,IACtD,IAAI,OAAO,UACT,IAAI,OAAO,UACX,KAAA;GACN,MAAM,cAAc,IAAI;GACxB,QACE,iDACA,aAAa,MACb,QACA,aACA,cACF;GACA,YACE;IAAE;IAAQ,MAAM,aAAa;GAAK,GAClC,iDACF;GACA,KAAK,WAAW,OAAO,CACrB;IAAE;IAAa;GAAe,GAC9B,aACA,SAAU,OAAO,SAAe;IAC9B,IAAI,OAAO;IACX,IAAI,OAAO;KACT,QAAM,6BAA6B,MAAM;KACzC,KAAK,KAAK;IACZ,OAAO,IAAI,SAAS;KAClB,QAAM,yBAAyB,MAAM;KACrC,WACE;MAAE;MAAQ,MAAM,aAAa;KAAK,GAClC,mDACF;KACA,KAAK;IACP,OAGE,MAAM,gBAAA,WAAW,iBAAiB,gBAAA,UAAU,YAAY;GAE5D,CACF;EACF;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"allow.mjs","names":[],"sources":["../../src/middlewares/allow.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { API_ERROR, errorUtils, tarballUtils } from '@verdaccio/core';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:allow');\n\nexport function allow<T>(\n auth: T,\n options = {\n beforeAll: (_a: any, _b: any) => {},\n\n afterAll: (_a: any, _b: any) => {},\n }\n): Function {\n const { beforeAll, afterAll } = options;\n return function (action: string): Function {\n return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n req.pause();\n const packageName = req.params.scope\n ? `${req.params.scope}/${req.params.package}`\n : req.params.package;\n const packageVersion = req.params.filename\n ? tarballUtils.getVersionFromTarball(req.params.filename)\n : req.params.version\n ? req.params.version\n : undefined;\n const remote_user = req.remote_user;\n debug(\n 'check if user %o can %o package %o version %o',\n remote_user?.name,\n action,\n packageName,\n packageVersion\n );\n beforeAll?.(\n { action, user: remote_user?.name },\n `[middleware/allow][@{action}] allow for @{user}`\n );\n auth['allow_' + action](\n { packageName, packageVersion },\n remote_user,\n function (error, allowed): void {\n req.resume();\n if (error) {\n debug('user is NOT allowed to %o', action);\n next(error);\n } else if (allowed) {\n debug('user is allowed to %o', action);\n afterAll?.(\n { action, user: remote_user?.name },\n `[middleware/allow][@{action}] allowed for @{user}`\n );\n next();\n } else {\n // last plugin (that's our built-in one) returns either\n // cb(err) or cb(null, true), so this should never happen\n throw errorUtils.getInternalError(API_ERROR.PLUGIN_ERROR);\n }\n }\n );\n };\n };\n}\n"],"mappings":";;;AAMA,IAAM,QAAQ,WAAW,4BAA4B;AAErD,SAAgB,MACd,MACA,UAAU;CACR,YAAY,IAAS,OAAY,CAAC;CAElC,WAAW,IAAS,OAAY,CAAC;AACnC,GACU;CACV,MAAM,EAAE,WAAW,aAAa;CAChC,OAAO,SAAU,QAA0B;EACzC,OAAO,SAAU,KAAqB,KAAsB,MAA8B;GACxF,IAAI,MAAM;GACV,MAAM,cAAc,IAAI,OAAO,QAC3B,GAAG,IAAI,OAAO,MAAM,GAAG,IAAI,OAAO,YAClC,IAAI,OAAO;GACf,MAAM,iBAAiB,IAAI,OAAO,WAC9B,aAAa,sBAAsB,IAAI,OAAO,QAAQ,IACtD,IAAI,OAAO,UACT,IAAI,OAAO,UACX,KAAA;GACN,MAAM,cAAc,IAAI;GACxB,MACE,iDACA,aAAa,MACb,QACA,aACA,cACF;GACA,YACE;IAAE;IAAQ,MAAM,aAAa;GAAK,GAClC,iDACF;GACA,KAAK,WAAW,QACd;IAAE;IAAa;GAAe,GAC9B,aACA,SAAU,OAAO,SAAe;IAC9B,IAAI,OAAO;IACX,IAAI,OAAO;KACT,MAAM,6BAA6B,MAAM;KACzC,KAAK,KAAK;IACZ,OAAO,IAAI,SAAS;KAClB,MAAM,yBAAyB,MAAM;KACrC,WACE;MAAE;MAAQ,MAAM,aAAa;KAAK,GAClC,mDACF;KACA,KAAK;IACP,OAGE,MAAM,WAAW,iBAAiB,UAAU,YAAY;GAE5D,CACF;EACF;CACF;AACF"}
1
+ {"version":3,"file":"allow.mjs","names":[],"sources":["../../src/middlewares/allow.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { API_ERROR, errorUtils, tarballUtils } from '@verdaccio/core';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:allow');\n\nexport function allow<T>(\n auth: T,\n options = {\n beforeAll: (_a: any, _b: any) => {},\n\n afterAll: (_a: any, _b: any) => {},\n }\n): Function {\n const { beforeAll, afterAll } = options;\n return function (action: string): Function {\n return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n req.pause();\n const packageName = req.params.scope\n ? `${req.params.scope}/${req.params.package}`\n : req.params.package;\n const packageVersion = req.params.filename\n ? tarballUtils.getVersionFromTarball(req.params.filename)\n : req.params.version\n ? req.params.version\n : undefined;\n const remote_user = req.remote_user;\n debug(\n 'check if user %o can %o package %o version %o',\n remote_user?.name,\n action,\n packageName,\n packageVersion\n );\n beforeAll?.(\n { action, user: remote_user?.name },\n `[middleware/allow][@{action}] allow for @{user}`\n );\n auth['allow_' + action](\n { packageName, packageVersion },\n remote_user,\n function (error, allowed): void {\n req.resume();\n if (error) {\n debug('user is NOT allowed to %o', action);\n next(error);\n } else if (allowed) {\n debug('user is allowed to %o', action);\n afterAll?.(\n { action, user: remote_user?.name },\n `[middleware/allow][@{action}] allowed for @{user}`\n );\n next();\n } else {\n // last plugin (that's our built-in one) returns either\n // cb(err) or cb(null, true), so this should never happen\n throw errorUtils.getInternalError(API_ERROR.PLUGIN_ERROR);\n }\n }\n );\n };\n };\n}\n"],"mappings":";;;AAMA,IAAM,QAAQ,WAAW,4BAA4B;AAErD,SAAgB,MACd,MACA,UAAU;CACR,YAAY,IAAS,OAAY,CAAC;CAElC,WAAW,IAAS,OAAY,CAAC;AACnC,GACU;CACV,MAAM,EAAE,WAAW,aAAa;CAChC,OAAO,SAAU,QAA0B;EACzC,OAAO,SAAU,KAAqB,KAAsB,MAA8B;GACxF,IAAI,MAAM;GACV,MAAM,cAAc,IAAI,OAAO,QAC3B,GAAG,IAAI,OAAO,MAAM,GAAG,IAAI,OAAO,YAClC,IAAI,OAAO;GACf,MAAM,iBAAiB,IAAI,OAAO,WAC9B,aAAa,sBAAsB,IAAI,OAAO,QAAQ,IACtD,IAAI,OAAO,UACT,IAAI,OAAO,UACX,KAAA;GACN,MAAM,cAAc,IAAI;GACxB,MACE,iDACA,aAAa,MACb,QACA,aACA,cACF;GACA,YACE;IAAE;IAAQ,MAAM,aAAa;GAAK,GAClC,iDACF;GACA,KAAK,WAAW,OAAO,CACrB;IAAE;IAAa;GAAe,GAC9B,aACA,SAAU,OAAO,SAAe;IAC9B,IAAI,OAAO;IACX,IAAI,OAAO;KACT,MAAM,6BAA6B,MAAM;KACzC,KAAK,KAAK;IACZ,OAAO,IAAI,SAAS;KAClB,MAAM,yBAAyB,MAAM;KACrC,WACE;MAAE;MAAQ,MAAM,aAAa;KAAK,GAClC,mDACF;KACA,KAAK;IACP,OAGE,MAAM,WAAW,iBAAiB,UAAU,YAAY;GAE5D,CACF;EACF;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"antiLoop.js","names":[],"sources":["../../src/middlewares/antiLoop.ts"],"sourcesContent":["import { HTTP_STATUS, errorUtils } from '@verdaccio/core';\nimport type { Config } from '@verdaccio/types';\n\nimport type { $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":";;;;;;;AAUA,SAAgB,SAAS,QAAgB;CACvC,OAAO,SAAU,KAAqB,KAAsB,MAA8B;EACxF,IAAI,KAAK,SAAS,OAAO,MAAM;GAC7B,MAAM,MAAM,IAAI,IAAI,KAAK,GAAG,MAAM,GAAG;GACrC,IAAI,MAAM,QAAQ,GAAG,GACnB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;IAWnC,MAAM,QAAQ,IAAI,GAAG,KAAK,EAAE,MAAM,KAAK;IAEvC,IAAI,MAAM,UAAU;SAED,MAAM,GAAG,MAAM,GAAG,EAAE,GAAG,KACpC,MAAa,OAAO,WACtB,OAAO,KAAK,gBAAA,WAAW,QAAQ,gBAAA,YAAY,eAAe,eAAe,CAAC;IAAA;GAGhF;EAEJ;EACA,KAAK;CACP;AACF"}
1
+ {"version":3,"file":"antiLoop.js","names":[],"sources":["../../src/middlewares/antiLoop.ts"],"sourcesContent":["import { HTTP_STATUS, errorUtils } from '@verdaccio/core';\nimport type { Config } from '@verdaccio/types';\n\nimport type { $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":";;;;;;;AAUA,SAAgB,SAAS,QAAgB;CACvC,OAAO,SAAU,KAAqB,KAAsB,MAA8B;EACxF,IAAI,KAAK,SAAS,OAAO,MAAM;GAC7B,MAAM,MAAM,IAAI,IAAI,KAAK,CAAC,EAAE,MAAM,GAAG;GACrC,IAAI,MAAM,QAAQ,GAAG,GACnB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;IAWnC,MAAM,QAAQ,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK;IAEvC,IAAI,MAAM,UAAU;SAED,MAAM,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,KACpC,MAAa,OAAO,WACtB,OAAO,KAAK,gBAAA,WAAW,QAAQ,gBAAA,YAAY,eAAe,eAAe,CAAC;IAAA;GAGhF;EAEJ;EACA,KAAK;CACP;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"antiLoop.mjs","names":[],"sources":["../../src/middlewares/antiLoop.ts"],"sourcesContent":["import { HTTP_STATUS, errorUtils } from '@verdaccio/core';\nimport type { Config } from '@verdaccio/types';\n\nimport type { $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":";;;;;;;AAUA,SAAgB,SAAS,QAAgB;CACvC,OAAO,SAAU,KAAqB,KAAsB,MAA8B;EACxF,IAAI,KAAK,SAAS,OAAO,MAAM;GAC7B,MAAM,MAAM,IAAI,IAAI,KAAK,GAAG,MAAM,GAAG;GACrC,IAAI,MAAM,QAAQ,GAAG,GACnB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;IAWnC,MAAM,QAAQ,IAAI,GAAG,KAAK,EAAE,MAAM,KAAK;IAEvC,IAAI,MAAM,UAAU;SAED,MAAM,GAAG,MAAM,GAAG,EAAE,GAAG,KACpC,MAAa,OAAO,WACtB,OAAO,KAAK,WAAW,QAAQ,YAAY,eAAe,eAAe,CAAC;IAAA;GAGhF;EAEJ;EACA,KAAK;CACP;AACF"}
1
+ {"version":3,"file":"antiLoop.mjs","names":[],"sources":["../../src/middlewares/antiLoop.ts"],"sourcesContent":["import { HTTP_STATUS, errorUtils } from '@verdaccio/core';\nimport type { Config } from '@verdaccio/types';\n\nimport type { $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":";;;;;;;AAUA,SAAgB,SAAS,QAAgB;CACvC,OAAO,SAAU,KAAqB,KAAsB,MAA8B;EACxF,IAAI,KAAK,SAAS,OAAO,MAAM;GAC7B,MAAM,MAAM,IAAI,IAAI,KAAK,CAAC,EAAE,MAAM,GAAG;GACrC,IAAI,MAAM,QAAQ,GAAG,GACnB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;IAWnC,MAAM,QAAQ,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK;IAEvC,IAAI,MAAM,UAAU;SAED,MAAM,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,KACpC,MAAa,OAAO,WACtB,OAAO,KAAK,WAAW,QAAQ,YAAY,eAAe,eAAe,CAAC;IAAA;GAGhF;EAEJ;EACA,KAAK;CACP;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"body-parser.js","names":[],"sources":["../../src/middlewares/body-parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Application, Router } from 'express';\nimport express from 'express';\n\nimport type { Config } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:middleware:body-parser');\n\n/**\n * Check if a body parser is already registered on the router\n */\nfunction hasBodyParser(app: Router | Application): boolean {\n // @ts-ignore - Express internals: app.stack is not part of the public API\n const stack = (app as any).stack || (app as any)._router?.stack || [];\n return stack.some((middleware: any) => {\n return middleware.handle?.name === 'jsonParser' || middleware.name === 'jsonParser';\n });\n}\n\n/**\n * Register JSON body parser on a router if not already registered\n * @param app Express router instance\n * @param config Verdaccio config\n */\nexport function registerBodyParser(app: Router | Application, config: Config): void {\n // middleware might have registered a json parser already\n if (hasBodyParser(app)) {\n debug('json parser already registered');\n } else {\n app.use(\n express.json({\n strict: false,\n limit: config.max_body_size || '10mb',\n })\n );\n }\n}\n"],"mappings":";;;;;;AAMA,IAAM,WAAA,GAAA,MAAA,SAAmB,kCAAkC;;;;AAK3D,SAAS,cAAc,KAAoC;CAGzD,QADe,IAAY,SAAU,IAAY,SAAS,SAAS,CAAC,GACvD,MAAM,eAAoB;EACrC,OAAO,WAAW,QAAQ,SAAS,gBAAgB,WAAW,SAAS;CACzE,CAAC;AACH;;;;;;AAOA,SAAgB,mBAAmB,KAA2B,QAAsB;CAElF,IAAI,cAAc,GAAG,GACnB,QAAM,gCAAgC;MAEtC,IAAI,IACF,QAAA,QAAQ,KAAK;EACX,QAAQ;EACR,OAAO,OAAO,iBAAiB;CACjC,CAAC,CACH;AAEJ"}
1
+ {"version":3,"file":"body-parser.js","names":[],"sources":["../../src/middlewares/body-parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Application, Router } from 'express';\nimport express from 'express';\n\nimport type { Config } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:middleware:body-parser');\n\n/**\n * Check if a body parser is already registered on the router\n */\nfunction hasBodyParser(app: Router | Application): boolean {\n // @ts-ignore - Express internals: app.stack is not part of the public API\n const stack = (app as any).stack || (app as any)._router?.stack || [];\n return stack.some((middleware: any) => {\n return middleware.handle?.name === 'jsonParser' || middleware.name === 'jsonParser';\n });\n}\n\n/**\n * Register JSON body parser on a router if not already registered\n * @param app Express router instance\n * @param config Verdaccio config\n */\nexport function registerBodyParser(app: Router | Application, config: Config): void {\n // middleware might have registered a json parser already\n if (hasBodyParser(app)) {\n debug('json parser already registered');\n } else {\n app.use(\n express.json({\n strict: false,\n limit: config.max_body_size || '10mb',\n })\n );\n }\n}\n"],"mappings":";;;;;;AAMA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,kCAAkC;;;;AAK3D,SAAS,cAAc,KAAoC;CAGzD,QADe,IAAY,SAAU,IAAY,SAAS,SAAS,CAAC,EAAA,CACvD,MAAM,eAAoB;EACrC,OAAO,WAAW,QAAQ,SAAS,gBAAgB,WAAW,SAAS;CACzE,CAAC;AACH;;;;;;AAOA,SAAgB,mBAAmB,KAA2B,QAAsB;CAElF,IAAI,cAAc,GAAG,GACnB,QAAM,gCAAgC;MAEtC,IAAI,IACF,QAAA,QAAQ,KAAK;EACX,QAAQ;EACR,OAAO,OAAO,iBAAiB;CACjC,CAAC,CACH;AAEJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"body-parser.mjs","names":[],"sources":["../../src/middlewares/body-parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Application, Router } from 'express';\nimport express from 'express';\n\nimport type { Config } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:middleware:body-parser');\n\n/**\n * Check if a body parser is already registered on the router\n */\nfunction hasBodyParser(app: Router | Application): boolean {\n // @ts-ignore - Express internals: app.stack is not part of the public API\n const stack = (app as any).stack || (app as any)._router?.stack || [];\n return stack.some((middleware: any) => {\n return middleware.handle?.name === 'jsonParser' || middleware.name === 'jsonParser';\n });\n}\n\n/**\n * Register JSON body parser on a router if not already registered\n * @param app Express router instance\n * @param config Verdaccio config\n */\nexport function registerBodyParser(app: Router | Application, config: Config): void {\n // middleware might have registered a json parser already\n if (hasBodyParser(app)) {\n debug('json parser already registered');\n } else {\n app.use(\n express.json({\n strict: false,\n limit: config.max_body_size || '10mb',\n })\n );\n }\n}\n"],"mappings":";;;AAMA,IAAM,QAAQ,WAAW,kCAAkC;;;;AAK3D,SAAS,cAAc,KAAoC;CAGzD,QADe,IAAY,SAAU,IAAY,SAAS,SAAS,CAAC,GACvD,MAAM,eAAoB;EACrC,OAAO,WAAW,QAAQ,SAAS,gBAAgB,WAAW,SAAS;CACzE,CAAC;AACH;;;;;;AAOA,SAAgB,mBAAmB,KAA2B,QAAsB;CAElF,IAAI,cAAc,GAAG,GACnB,MAAM,gCAAgC;MAEtC,IAAI,IACF,QAAQ,KAAK;EACX,QAAQ;EACR,OAAO,OAAO,iBAAiB;CACjC,CAAC,CACH;AAEJ"}
1
+ {"version":3,"file":"body-parser.mjs","names":[],"sources":["../../src/middlewares/body-parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Application, Router } from 'express';\nimport express from 'express';\n\nimport type { Config } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:middleware:body-parser');\n\n/**\n * Check if a body parser is already registered on the router\n */\nfunction hasBodyParser(app: Router | Application): boolean {\n // @ts-ignore - Express internals: app.stack is not part of the public API\n const stack = (app as any).stack || (app as any)._router?.stack || [];\n return stack.some((middleware: any) => {\n return middleware.handle?.name === 'jsonParser' || middleware.name === 'jsonParser';\n });\n}\n\n/**\n * Register JSON body parser on a router if not already registered\n * @param app Express router instance\n * @param config Verdaccio config\n */\nexport function registerBodyParser(app: Router | Application, config: Config): void {\n // middleware might have registered a json parser already\n if (hasBodyParser(app)) {\n debug('json parser already registered');\n } else {\n app.use(\n express.json({\n strict: false,\n limit: config.max_body_size || '10mb',\n })\n );\n }\n}\n"],"mappings":";;;AAMA,IAAM,QAAQ,WAAW,kCAAkC;;;;AAK3D,SAAS,cAAc,KAAoC;CAGzD,QADe,IAAY,SAAU,IAAY,SAAS,SAAS,CAAC,EAAA,CACvD,MAAM,eAAoB;EACrC,OAAO,WAAW,QAAQ,SAAS,gBAAgB,WAAW,SAAS;CACzE,CAAC;AACH;;;;;;AAOA,SAAgB,mBAAmB,KAA2B,QAAsB;CAElF,IAAI,cAAc,GAAG,GACnB,MAAM,gCAAgC;MAEtC,IAAI,IACF,QAAQ,KAAK;EACX,QAAQ;EACR,OAAO,OAAO,iBAAiB;CACjC,CAAC,CACH;AAEJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"encode-pkg.js","names":[],"sources":["../../src/middlewares/encode-pkg.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { errorUtils } from '@verdaccio/core';\n\nimport type { $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 // also handle cases for dist-tags where package is in the middle of the path and not at the beginning\n // e.g.: /-/package/@org/pkg/dist-tags/latest -> /-/package/@org%2Fpkg/dist-tags/latest\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":";;;;;AAMA,IAAM,WAAA,GAAA,MAAA,SAAmB,6BAA6B;;;;;;;AAQtD,SAAgB,mBACd,KACA,KACA,MACM;CACN,MAAM,WAAW,IAAI;CAGrB,IAAI,CAAC,IAAI,IAAI,WAAW,GAAG,GACzB,OAAO,KAAK,gBAAA,WAAW,cAAc,gBAAgB,IAAI,IAAI,oBAAoB,CAAC;CASpF,IAAI,MAAM,IAAI,IAAI,QAAQ,SAAS,IAAI,EAAE,QAAQ,uBAAuB,OAAO;CAE/E,IAAI,aAAa,IAAI,KACnB,QAAM,gCAAgC,UAAU,IAAI,GAAG;MAEvD,QAAM,sCAAsC,QAAQ;CAEtD,KAAK;AACP"}
1
+ {"version":3,"file":"encode-pkg.js","names":[],"sources":["../../src/middlewares/encode-pkg.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { errorUtils } from '@verdaccio/core';\n\nimport type { $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 // also handle cases for dist-tags where package is in the middle of the path and not at the beginning\n // e.g.: /-/package/@org/pkg/dist-tags/latest -> /-/package/@org%2Fpkg/dist-tags/latest\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":";;;;;AAMA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,6BAA6B;;;;;;;AAQtD,SAAgB,mBACd,KACA,KACA,MACM;CACN,MAAM,WAAW,IAAI;CAGrB,IAAI,CAAC,IAAI,IAAI,WAAW,GAAG,GACzB,OAAO,KAAK,gBAAA,WAAW,cAAc,gBAAgB,IAAI,IAAI,oBAAoB,CAAC;CASpF,IAAI,MAAM,IAAI,IAAI,QAAQ,SAAS,IAAI,CAAC,CAAC,QAAQ,uBAAuB,OAAO;CAE/E,IAAI,aAAa,IAAI,KACnB,QAAM,gCAAgC,UAAU,IAAI,GAAG;MAEvD,QAAM,sCAAsC,QAAQ;CAEtD,KAAK;AACP"}
@@ -1 +1 @@
1
- {"version":3,"file":"encode-pkg.mjs","names":[],"sources":["../../src/middlewares/encode-pkg.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { errorUtils } from '@verdaccio/core';\n\nimport type { $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 // also handle cases for dist-tags where package is in the middle of the path and not at the beginning\n // e.g.: /-/package/@org/pkg/dist-tags/latest -> /-/package/@org%2Fpkg/dist-tags/latest\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":";;;AAMA,IAAM,QAAQ,WAAW,6BAA6B;;;;;;;AAQtD,SAAgB,mBACd,KACA,KACA,MACM;CACN,MAAM,WAAW,IAAI;CAGrB,IAAI,CAAC,IAAI,IAAI,WAAW,GAAG,GACzB,OAAO,KAAK,WAAW,cAAc,gBAAgB,IAAI,IAAI,oBAAoB,CAAC;CASpF,IAAI,MAAM,IAAI,IAAI,QAAQ,SAAS,IAAI,EAAE,QAAQ,uBAAuB,OAAO;CAE/E,IAAI,aAAa,IAAI,KACnB,MAAM,gCAAgC,UAAU,IAAI,GAAG;MAEvD,MAAM,sCAAsC,QAAQ;CAEtD,KAAK;AACP"}
1
+ {"version":3,"file":"encode-pkg.mjs","names":[],"sources":["../../src/middlewares/encode-pkg.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { errorUtils } from '@verdaccio/core';\n\nimport type { $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 // also handle cases for dist-tags where package is in the middle of the path and not at the beginning\n // e.g.: /-/package/@org/pkg/dist-tags/latest -> /-/package/@org%2Fpkg/dist-tags/latest\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":";;;AAMA,IAAM,QAAQ,WAAW,6BAA6B;;;;;;;AAQtD,SAAgB,mBACd,KACA,KACA,MACM;CACN,MAAM,WAAW,IAAI;CAGrB,IAAI,CAAC,IAAI,IAAI,WAAW,GAAG,GACzB,OAAO,KAAK,WAAW,cAAc,gBAAgB,IAAI,IAAI,oBAAoB,CAAC;CASpF,IAAI,MAAM,IAAI,IAAI,QAAQ,SAAS,IAAI,CAAC,CAAC,QAAQ,uBAAuB,OAAO;CAE/E,IAAI,aAAa,IAAI,KACnB,MAAM,gCAAgC,UAAU,IAAI,GAAG;MAEvD,MAAM,sCAAsC,QAAQ;CAEtD,KAAK;AACP"}
@@ -1 +1 @@
1
- {"version":3,"file":"error.js","names":[],"sources":["../../src/middlewares/error.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { HttpError } from 'http-errors';\nimport _ from 'lodash';\n\nimport type { VerdaccioError } from '@verdaccio/core';\nimport { API_ERROR, HTTP_STATUS } from '@verdaccio/core';\nimport type { Logger } from '@verdaccio/types';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:error');\n\nexport const handleError = (logger: Logger) =>\n function handleError(\n err: HttpError,\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ) {\n debug('error handler init');\n if (_.isError(err)) {\n debug('is native error');\n if (err.code === 'ECONNABORT' && res.statusCode === HTTP_STATUS.NOT_MODIFIED) {\n return next();\n }\n if (_.isFunction(res.locals.report_error) === false) {\n debug('is locals error report ref');\n // in case of very early error this middleware may not be loaded before error is generated\n // fixing that\n errorReportingMiddleware(logger)(req, res, _.noop);\n }\n debug('set locals error report ref');\n res.locals.report_error(err);\n } else {\n // Fall to Middleware.final\n debug('no error to report, jump next layer');\n return next(err);\n }\n };\n\n// Middleware\nexport const errorReportingMiddleware = (logger: Logger) =>\n function errorReportingMiddleware(\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): void {\n debug('error report middleware start');\n res.locals.report_error =\n res.locals.report_error ||\n function (err: VerdaccioError): void {\n if (err.status && err.status >= HTTP_STATUS.BAD_REQUEST && err.status < 600) {\n debug('is error > 409 %o', err?.status);\n if (_.isNil(res.headersSent) === false) {\n debug('send status %o', err?.status);\n res.status(err.status);\n debug('next layer %o', err?.message);\n next({ error: err.message || API_ERROR.UNKNOWN_ERROR });\n }\n } else {\n debug('is error < 409 %o', err?.status);\n logger.error({ err: err }, 'unexpected error: @{!err.message}\\n@{err.stack}');\n if (!res.status || !res.send) {\n // TODO: decide which debug keep\n logger.error('this is an error in express.js, please report this');\n debug('this is an error in express.js, please report this, destroy response %o', err);\n res.destroy();\n } else if (!res.headersSent) {\n debug('send internal error %o', err);\n res.status(HTTP_STATUS.INTERNAL_ERROR);\n next({ error: API_ERROR.INTERNAL_SERVER_ERROR });\n } else {\n // socket should be already closed\n debug('this should not happen, otherwise report %o', err);\n }\n }\n };\n\n debug('error report middleware end (skip next layer) next()');\n next();\n };\n"],"mappings":";;;;;;;AAUA,IAAM,WAAA,GAAA,MAAA,SAAmB,4BAA4B;AAErD,IAAa,eAAe,WAC1B,SAAS,YACP,KACA,KACA,KACA,MACA;CACA,QAAM,oBAAoB;CAC1B,IAAI,OAAA,QAAE,QAAQ,GAAG,GAAG;EAClB,QAAM,iBAAiB;EACvB,IAAI,IAAI,SAAS,gBAAgB,IAAI,eAAe,gBAAA,YAAY,cAC9D,OAAO,KAAK;EAEd,IAAI,OAAA,QAAE,WAAW,IAAI,OAAO,YAAY,MAAM,OAAO;GACnD,QAAM,4BAA4B;GAGlC,yBAAyB,MAAM,EAAE,KAAK,KAAK,OAAA,QAAE,IAAI;EACnD;EACA,QAAM,6BAA6B;EACnC,IAAI,OAAO,aAAa,GAAG;CAC7B,OAAO;EAEL,QAAM,qCAAqC;EAC3C,OAAO,KAAK,GAAG;CACjB;AACF;AAGF,IAAa,4BAA4B,WACvC,SAAS,yBACP,KACA,KACA,MACM;CACN,QAAM,+BAA+B;CACrC,IAAI,OAAO,eACT,IAAI,OAAO,gBACX,SAAU,KAA2B;EACnC,IAAI,IAAI,UAAU,IAAI,UAAU,gBAAA,YAAY,eAAe,IAAI,SAAS,KAAK;GAC3E,QAAM,qBAAqB,KAAK,MAAM;GACtC,IAAI,OAAA,QAAE,MAAM,IAAI,WAAW,MAAM,OAAO;IACtC,QAAM,kBAAkB,KAAK,MAAM;IACnC,IAAI,OAAO,IAAI,MAAM;IACrB,QAAM,iBAAiB,KAAK,OAAO;IACnC,KAAK,EAAE,OAAO,IAAI,WAAW,gBAAA,UAAU,cAAc,CAAC;GACxD;EACF,OAAO;GACL,QAAM,qBAAqB,KAAK,MAAM;GACtC,OAAO,MAAM,EAAO,IAAI,GAAG,iDAAiD;GAC5E,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,MAAM;IAE5B,OAAO,MAAM,oDAAoD;IACjE,QAAM,2EAA2E,GAAG;IACpF,IAAI,QAAQ;GACd,OAAO,IAAI,CAAC,IAAI,aAAa;IAC3B,QAAM,0BAA0B,GAAG;IACnC,IAAI,OAAO,gBAAA,YAAY,cAAc;IACrC,KAAK,EAAE,OAAO,gBAAA,UAAU,sBAAsB,CAAC;GACjD,OAEE,QAAM,+CAA+C,GAAG;EAE5D;CACF;CAEF,QAAM,sDAAsD;CAC5D,KAAK;AACP"}
1
+ {"version":3,"file":"error.js","names":[],"sources":["../../src/middlewares/error.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { HttpError } from 'http-errors';\nimport _ from 'lodash';\n\nimport type { VerdaccioError } from '@verdaccio/core';\nimport { API_ERROR, HTTP_STATUS } from '@verdaccio/core';\nimport type { Logger } from '@verdaccio/types';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:error');\n\nexport const handleError = (logger: Logger) =>\n function handleError(\n err: HttpError,\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ) {\n debug('error handler init');\n if (_.isError(err)) {\n debug('is native error');\n if (err.code === 'ECONNABORT' && res.statusCode === HTTP_STATUS.NOT_MODIFIED) {\n return next();\n }\n if (_.isFunction(res.locals.report_error) === false) {\n debug('is locals error report ref');\n // in case of very early error this middleware may not be loaded before error is generated\n // fixing that\n errorReportingMiddleware(logger)(req, res, _.noop);\n }\n debug('set locals error report ref');\n res.locals.report_error(err);\n } else {\n // Fall to Middleware.final\n debug('no error to report, jump next layer');\n return next(err);\n }\n };\n\n// Middleware\nexport const errorReportingMiddleware = (logger: Logger) =>\n function errorReportingMiddleware(\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): void {\n debug('error report middleware start');\n res.locals.report_error =\n res.locals.report_error ||\n function (err: VerdaccioError): void {\n if (err.status && err.status >= HTTP_STATUS.BAD_REQUEST && err.status < 600) {\n debug('is error > 409 %o', err?.status);\n if (_.isNil(res.headersSent) === false) {\n debug('send status %o', err?.status);\n res.status(err.status);\n debug('next layer %o', err?.message);\n next({ error: err.message || API_ERROR.UNKNOWN_ERROR });\n }\n } else {\n debug('is error < 409 %o', err?.status);\n logger.error({ err: err }, 'unexpected error: @{!err.message}\\n@{err.stack}');\n if (!res.status || !res.send) {\n // TODO: decide which debug keep\n logger.error('this is an error in express.js, please report this');\n debug('this is an error in express.js, please report this, destroy response %o', err);\n res.destroy();\n } else if (!res.headersSent) {\n debug('send internal error %o', err);\n res.status(HTTP_STATUS.INTERNAL_ERROR);\n next({ error: API_ERROR.INTERNAL_SERVER_ERROR });\n } else {\n // socket should be already closed\n debug('this should not happen, otherwise report %o', err);\n }\n }\n };\n\n debug('error report middleware end (skip next layer) next()');\n next();\n };\n"],"mappings":";;;;;;;AAUA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,4BAA4B;AAErD,IAAa,eAAe,WAC1B,SAAS,YACP,KACA,KACA,KACA,MACA;CACA,QAAM,oBAAoB;CAC1B,IAAI,OAAA,QAAE,QAAQ,GAAG,GAAG;EAClB,QAAM,iBAAiB;EACvB,IAAI,IAAI,SAAS,gBAAgB,IAAI,eAAe,gBAAA,YAAY,cAC9D,OAAO,KAAK;EAEd,IAAI,OAAA,QAAE,WAAW,IAAI,OAAO,YAAY,MAAM,OAAO;GACnD,QAAM,4BAA4B;GAGlC,yBAAyB,MAAM,CAAC,CAAC,KAAK,KAAK,OAAA,QAAE,IAAI;EACnD;EACA,QAAM,6BAA6B;EACnC,IAAI,OAAO,aAAa,GAAG;CAC7B,OAAO;EAEL,QAAM,qCAAqC;EAC3C,OAAO,KAAK,GAAG;CACjB;AACF;AAGF,IAAa,4BAA4B,WACvC,SAAS,yBACP,KACA,KACA,MACM;CACN,QAAM,+BAA+B;CACrC,IAAI,OAAO,eACT,IAAI,OAAO,gBACX,SAAU,KAA2B;EACnC,IAAI,IAAI,UAAU,IAAI,UAAU,gBAAA,YAAY,eAAe,IAAI,SAAS,KAAK;GAC3E,QAAM,qBAAqB,KAAK,MAAM;GACtC,IAAI,OAAA,QAAE,MAAM,IAAI,WAAW,MAAM,OAAO;IACtC,QAAM,kBAAkB,KAAK,MAAM;IACnC,IAAI,OAAO,IAAI,MAAM;IACrB,QAAM,iBAAiB,KAAK,OAAO;IACnC,KAAK,EAAE,OAAO,IAAI,WAAW,gBAAA,UAAU,cAAc,CAAC;GACxD;EACF,OAAO;GACL,QAAM,qBAAqB,KAAK,MAAM;GACtC,OAAO,MAAM,EAAO,IAAI,GAAG,iDAAiD;GAC5E,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,MAAM;IAE5B,OAAO,MAAM,oDAAoD;IACjE,QAAM,2EAA2E,GAAG;IACpF,IAAI,QAAQ;GACd,OAAO,IAAI,CAAC,IAAI,aAAa;IAC3B,QAAM,0BAA0B,GAAG;IACnC,IAAI,OAAO,gBAAA,YAAY,cAAc;IACrC,KAAK,EAAE,OAAO,gBAAA,UAAU,sBAAsB,CAAC;GACjD,OAEE,QAAM,+CAA+C,GAAG;EAE5D;CACF;CAEF,QAAM,sDAAsD;CAC5D,KAAK;AACP"}
@@ -1 +1 @@
1
- {"version":3,"file":"error.mjs","names":[],"sources":["../../src/middlewares/error.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { HttpError } from 'http-errors';\nimport _ from 'lodash';\n\nimport type { VerdaccioError } from '@verdaccio/core';\nimport { API_ERROR, HTTP_STATUS } from '@verdaccio/core';\nimport type { Logger } from '@verdaccio/types';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:error');\n\nexport const handleError = (logger: Logger) =>\n function handleError(\n err: HttpError,\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ) {\n debug('error handler init');\n if (_.isError(err)) {\n debug('is native error');\n if (err.code === 'ECONNABORT' && res.statusCode === HTTP_STATUS.NOT_MODIFIED) {\n return next();\n }\n if (_.isFunction(res.locals.report_error) === false) {\n debug('is locals error report ref');\n // in case of very early error this middleware may not be loaded before error is generated\n // fixing that\n errorReportingMiddleware(logger)(req, res, _.noop);\n }\n debug('set locals error report ref');\n res.locals.report_error(err);\n } else {\n // Fall to Middleware.final\n debug('no error to report, jump next layer');\n return next(err);\n }\n };\n\n// Middleware\nexport const errorReportingMiddleware = (logger: Logger) =>\n function errorReportingMiddleware(\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): void {\n debug('error report middleware start');\n res.locals.report_error =\n res.locals.report_error ||\n function (err: VerdaccioError): void {\n if (err.status && err.status >= HTTP_STATUS.BAD_REQUEST && err.status < 600) {\n debug('is error > 409 %o', err?.status);\n if (_.isNil(res.headersSent) === false) {\n debug('send status %o', err?.status);\n res.status(err.status);\n debug('next layer %o', err?.message);\n next({ error: err.message || API_ERROR.UNKNOWN_ERROR });\n }\n } else {\n debug('is error < 409 %o', err?.status);\n logger.error({ err: err }, 'unexpected error: @{!err.message}\\n@{err.stack}');\n if (!res.status || !res.send) {\n // TODO: decide which debug keep\n logger.error('this is an error in express.js, please report this');\n debug('this is an error in express.js, please report this, destroy response %o', err);\n res.destroy();\n } else if (!res.headersSent) {\n debug('send internal error %o', err);\n res.status(HTTP_STATUS.INTERNAL_ERROR);\n next({ error: API_ERROR.INTERNAL_SERVER_ERROR });\n } else {\n // socket should be already closed\n debug('this should not happen, otherwise report %o', err);\n }\n }\n };\n\n debug('error report middleware end (skip next layer) next()');\n next();\n };\n"],"mappings":";;;;AAUA,IAAM,QAAQ,WAAW,4BAA4B;AAErD,IAAa,eAAe,WAC1B,SAAS,YACP,KACA,KACA,KACA,MACA;CACA,MAAM,oBAAoB;CAC1B,IAAI,EAAE,QAAQ,GAAG,GAAG;EAClB,MAAM,iBAAiB;EACvB,IAAI,IAAI,SAAS,gBAAgB,IAAI,eAAe,YAAY,cAC9D,OAAO,KAAK;EAEd,IAAI,EAAE,WAAW,IAAI,OAAO,YAAY,MAAM,OAAO;GACnD,MAAM,4BAA4B;GAGlC,yBAAyB,MAAM,EAAE,KAAK,KAAK,EAAE,IAAI;EACnD;EACA,MAAM,6BAA6B;EACnC,IAAI,OAAO,aAAa,GAAG;CAC7B,OAAO;EAEL,MAAM,qCAAqC;EAC3C,OAAO,KAAK,GAAG;CACjB;AACF;AAGF,IAAa,4BAA4B,WACvC,SAAS,yBACP,KACA,KACA,MACM;CACN,MAAM,+BAA+B;CACrC,IAAI,OAAO,eACT,IAAI,OAAO,gBACX,SAAU,KAA2B;EACnC,IAAI,IAAI,UAAU,IAAI,UAAU,YAAY,eAAe,IAAI,SAAS,KAAK;GAC3E,MAAM,qBAAqB,KAAK,MAAM;GACtC,IAAI,EAAE,MAAM,IAAI,WAAW,MAAM,OAAO;IACtC,MAAM,kBAAkB,KAAK,MAAM;IACnC,IAAI,OAAO,IAAI,MAAM;IACrB,MAAM,iBAAiB,KAAK,OAAO;IACnC,KAAK,EAAE,OAAO,IAAI,WAAW,UAAU,cAAc,CAAC;GACxD;EACF,OAAO;GACL,MAAM,qBAAqB,KAAK,MAAM;GACtC,OAAO,MAAM,EAAO,IAAI,GAAG,iDAAiD;GAC5E,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,MAAM;IAE5B,OAAO,MAAM,oDAAoD;IACjE,MAAM,2EAA2E,GAAG;IACpF,IAAI,QAAQ;GACd,OAAO,IAAI,CAAC,IAAI,aAAa;IAC3B,MAAM,0BAA0B,GAAG;IACnC,IAAI,OAAO,YAAY,cAAc;IACrC,KAAK,EAAE,OAAO,UAAU,sBAAsB,CAAC;GACjD,OAEE,MAAM,+CAA+C,GAAG;EAE5D;CACF;CAEF,MAAM,sDAAsD;CAC5D,KAAK;AACP"}
1
+ {"version":3,"file":"error.mjs","names":[],"sources":["../../src/middlewares/error.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { HttpError } from 'http-errors';\nimport _ from 'lodash';\n\nimport type { VerdaccioError } from '@verdaccio/core';\nimport { API_ERROR, HTTP_STATUS } from '@verdaccio/core';\nimport type { Logger } from '@verdaccio/types';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:error');\n\nexport const handleError = (logger: Logger) =>\n function handleError(\n err: HttpError,\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ) {\n debug('error handler init');\n if (_.isError(err)) {\n debug('is native error');\n if (err.code === 'ECONNABORT' && res.statusCode === HTTP_STATUS.NOT_MODIFIED) {\n return next();\n }\n if (_.isFunction(res.locals.report_error) === false) {\n debug('is locals error report ref');\n // in case of very early error this middleware may not be loaded before error is generated\n // fixing that\n errorReportingMiddleware(logger)(req, res, _.noop);\n }\n debug('set locals error report ref');\n res.locals.report_error(err);\n } else {\n // Fall to Middleware.final\n debug('no error to report, jump next layer');\n return next(err);\n }\n };\n\n// Middleware\nexport const errorReportingMiddleware = (logger: Logger) =>\n function errorReportingMiddleware(\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): void {\n debug('error report middleware start');\n res.locals.report_error =\n res.locals.report_error ||\n function (err: VerdaccioError): void {\n if (err.status && err.status >= HTTP_STATUS.BAD_REQUEST && err.status < 600) {\n debug('is error > 409 %o', err?.status);\n if (_.isNil(res.headersSent) === false) {\n debug('send status %o', err?.status);\n res.status(err.status);\n debug('next layer %o', err?.message);\n next({ error: err.message || API_ERROR.UNKNOWN_ERROR });\n }\n } else {\n debug('is error < 409 %o', err?.status);\n logger.error({ err: err }, 'unexpected error: @{!err.message}\\n@{err.stack}');\n if (!res.status || !res.send) {\n // TODO: decide which debug keep\n logger.error('this is an error in express.js, please report this');\n debug('this is an error in express.js, please report this, destroy response %o', err);\n res.destroy();\n } else if (!res.headersSent) {\n debug('send internal error %o', err);\n res.status(HTTP_STATUS.INTERNAL_ERROR);\n next({ error: API_ERROR.INTERNAL_SERVER_ERROR });\n } else {\n // socket should be already closed\n debug('this should not happen, otherwise report %o', err);\n }\n }\n };\n\n debug('error report middleware end (skip next layer) next()');\n next();\n };\n"],"mappings":";;;;AAUA,IAAM,QAAQ,WAAW,4BAA4B;AAErD,IAAa,eAAe,WAC1B,SAAS,YACP,KACA,KACA,KACA,MACA;CACA,MAAM,oBAAoB;CAC1B,IAAI,EAAE,QAAQ,GAAG,GAAG;EAClB,MAAM,iBAAiB;EACvB,IAAI,IAAI,SAAS,gBAAgB,IAAI,eAAe,YAAY,cAC9D,OAAO,KAAK;EAEd,IAAI,EAAE,WAAW,IAAI,OAAO,YAAY,MAAM,OAAO;GACnD,MAAM,4BAA4B;GAGlC,yBAAyB,MAAM,CAAC,CAAC,KAAK,KAAK,EAAE,IAAI;EACnD;EACA,MAAM,6BAA6B;EACnC,IAAI,OAAO,aAAa,GAAG;CAC7B,OAAO;EAEL,MAAM,qCAAqC;EAC3C,OAAO,KAAK,GAAG;CACjB;AACF;AAGF,IAAa,4BAA4B,WACvC,SAAS,yBACP,KACA,KACA,MACM;CACN,MAAM,+BAA+B;CACrC,IAAI,OAAO,eACT,IAAI,OAAO,gBACX,SAAU,KAA2B;EACnC,IAAI,IAAI,UAAU,IAAI,UAAU,YAAY,eAAe,IAAI,SAAS,KAAK;GAC3E,MAAM,qBAAqB,KAAK,MAAM;GACtC,IAAI,EAAE,MAAM,IAAI,WAAW,MAAM,OAAO;IACtC,MAAM,kBAAkB,KAAK,MAAM;IACnC,IAAI,OAAO,IAAI,MAAM;IACrB,MAAM,iBAAiB,KAAK,OAAO;IACnC,KAAK,EAAE,OAAO,IAAI,WAAW,UAAU,cAAc,CAAC;GACxD;EACF,OAAO;GACL,MAAM,qBAAqB,KAAK,MAAM;GACtC,OAAO,MAAM,EAAO,IAAI,GAAG,iDAAiD;GAC5E,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,MAAM;IAE5B,OAAO,MAAM,oDAAoD;IACjE,MAAM,2EAA2E,GAAG;IACpF,IAAI,QAAQ;GACd,OAAO,IAAI,CAAC,IAAI,aAAa;IAC3B,MAAM,0BAA0B,GAAG;IACnC,IAAI,OAAO,YAAY,cAAc;IACrC,KAAK,EAAE,OAAO,UAAU,sBAAsB,CAAC;GACjD,OAEE,MAAM,+CAA+C,GAAG;EAE5D;CACF;CAEF,MAAM,sDAAsD;CAC5D,KAAK;AACP"}
@@ -1 +1 @@
1
- {"version":3,"file":"final.js","names":[],"sources":["../../src/middlewares/final.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport _ from 'lodash';\n\nimport { HEADERS, HTTP_STATUS, TOKEN_BASIC, TOKEN_BEARER, cryptoUtils } from '@verdaccio/core';\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend, MiddlewareError } from '../types';\n\nexport type FinalBody = Manifest | MiddlewareError | string;\n\nconst debug = buildDebug('verdaccio:middleware:final');\n\nexport function final(\n body: FinalBody,\n req: $RequestExtend,\n res: $ResponseExtend,\n // if we remove `next` breaks test\n next: $NextFunctionVer\n): void {\n void next;\n\n if (res.statusCode === HTTP_STATUS.UNAUTHORIZED && !res.getHeader(HEADERS.WWW_AUTH)) {\n debug('set auth header support');\n res.header(HEADERS.WWW_AUTH, `${TOKEN_BASIC}, ${TOKEN_BEARER}`);\n }\n\n try {\n if (_.isString(body) || _.isObject(body)) {\n if (!res.get(HEADERS.CONTENT_TYPE)) {\n debug('set json type header support');\n res.header(HEADERS.CONTENT_TYPE, HEADERS.JSON);\n }\n\n if (typeof body === 'object' && _.isNil(body) === false) {\n if (typeof (body as MiddlewareError).error === 'string') {\n debug('set verdaccio_error method');\n res.locals._verdaccio_error = (body as MiddlewareError).error;\n }\n body = JSON.stringify(body, undefined, ' ') + '\\n';\n }\n\n // don't send etags with errors\n if (\n !res.statusCode ||\n (res.statusCode >= HTTP_STATUS.OK && res.statusCode < HTTP_STATUS.MULTIPLE_CHOICES)\n ) {\n const etag = cryptoUtils.stringToMD5(body as string);\n debug('set etag header %s', etag);\n res.header(HEADERS.ETAG, '\"' + etag + '\"');\n }\n } else {\n debug('this line should never be visible, if does report');\n // send(null), send(204), etc.\n }\n } catch (err: any) {\n // if verdaccio sends headers first, and then calls res.send()\n // as an error handler, we can't report error properly,\n // and should just close socket\n if (err.message.match(/set headers after they are sent/)) {\n debug('set headers after they are sent');\n if (_.isNil(res.socket) === false) {\n debug('force destroy socket');\n res.socket?.destroy();\n }\n return;\n }\n throw err;\n }\n\n res.send(body);\n}\n"],"mappings":";;;;;;;AAUA,IAAM,WAAA,GAAA,MAAA,SAAmB,4BAA4B;AAErD,SAAgB,MACd,MACA,KACA,KAEA,MACM;CAGN,IAAI,IAAI,eAAe,gBAAA,YAAY,gBAAgB,CAAC,IAAI,UAAU,gBAAA,QAAQ,QAAQ,GAAG;EACnF,QAAM,yBAAyB;EAC/B,IAAI,OAAO,gBAAA,QAAQ,UAAU,GAAG,gBAAA,YAAY,IAAI,gBAAA,cAAc;CAChE;CAEA,IAAI;EACF,IAAI,OAAA,QAAE,SAAS,IAAI,KAAK,OAAA,QAAE,SAAS,IAAI,GAAG;GACxC,IAAI,CAAC,IAAI,IAAI,gBAAA,QAAQ,YAAY,GAAG;IAClC,QAAM,8BAA8B;IACpC,IAAI,OAAO,gBAAA,QAAQ,cAAc,gBAAA,QAAQ,IAAI;GAC/C;GAEA,IAAI,OAAO,SAAS,YAAY,OAAA,QAAE,MAAM,IAAI,MAAM,OAAO;IACvD,IAAI,OAAQ,KAAyB,UAAU,UAAU;KACvD,QAAM,4BAA4B;KAClC,IAAI,OAAO,mBAAoB,KAAyB;IAC1D;IACA,OAAO,KAAK,UAAU,MAAM,KAAA,GAAW,IAAI,IAAI;GACjD;GAGA,IACE,CAAC,IAAI,cACJ,IAAI,cAAc,gBAAA,YAAY,MAAM,IAAI,aAAa,gBAAA,YAAY,kBAClE;IACA,MAAM,OAAO,gBAAA,YAAY,YAAY,IAAc;IACnD,QAAM,sBAAsB,IAAI;IAChC,IAAI,OAAO,gBAAA,QAAQ,MAAM,OAAM,OAAO,IAAG;GAC3C;EACF,OACE,QAAM,mDAAmD;CAG7D,SAAS,KAAU;EAIjB,IAAI,IAAI,QAAQ,MAAM,iCAAiC,GAAG;GACxD,QAAM,iCAAiC;GACvC,IAAI,OAAA,QAAE,MAAM,IAAI,MAAM,MAAM,OAAO;IACjC,QAAM,sBAAsB;IAC5B,IAAI,QAAQ,QAAQ;GACtB;GACA;EACF;EACA,MAAM;CACR;CAEA,IAAI,KAAK,IAAI;AACf"}
1
+ {"version":3,"file":"final.js","names":[],"sources":["../../src/middlewares/final.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport _ from 'lodash';\n\nimport { HEADERS, HTTP_STATUS, TOKEN_BASIC, TOKEN_BEARER, cryptoUtils } from '@verdaccio/core';\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend, MiddlewareError } from '../types';\n\nexport type FinalBody = Manifest | MiddlewareError | string;\n\nconst debug = buildDebug('verdaccio:middleware:final');\n\nexport function final(\n body: FinalBody,\n req: $RequestExtend,\n res: $ResponseExtend,\n // if we remove `next` breaks test\n next: $NextFunctionVer\n): void {\n void next;\n\n if (res.statusCode === HTTP_STATUS.UNAUTHORIZED && !res.getHeader(HEADERS.WWW_AUTH)) {\n debug('set auth header support');\n res.header(HEADERS.WWW_AUTH, `${TOKEN_BASIC}, ${TOKEN_BEARER}`);\n }\n\n try {\n if (_.isString(body) || _.isObject(body)) {\n if (!res.get(HEADERS.CONTENT_TYPE)) {\n debug('set json type header support');\n res.header(HEADERS.CONTENT_TYPE, HEADERS.JSON);\n }\n\n if (typeof body === 'object' && _.isNil(body) === false) {\n if (typeof (body as MiddlewareError).error === 'string') {\n debug('set verdaccio_error method');\n res.locals._verdaccio_error = (body as MiddlewareError).error;\n }\n body = JSON.stringify(body, undefined, ' ') + '\\n';\n }\n\n // don't send etags with errors\n if (\n !res.statusCode ||\n (res.statusCode >= HTTP_STATUS.OK && res.statusCode < HTTP_STATUS.MULTIPLE_CHOICES)\n ) {\n const etag = cryptoUtils.stringToMD5(body as string);\n debug('set etag header %s', etag);\n res.header(HEADERS.ETAG, '\"' + etag + '\"');\n }\n } else {\n debug('this line should never be visible, if does report');\n // send(null), send(204), etc.\n }\n } catch (err: any) {\n // if verdaccio sends headers first, and then calls res.send()\n // as an error handler, we can't report error properly,\n // and should just close socket\n if (err.message.match(/set headers after they are sent/)) {\n debug('set headers after they are sent');\n if (_.isNil(res.socket) === false) {\n debug('force destroy socket');\n res.socket?.destroy();\n }\n return;\n }\n throw err;\n }\n\n res.send(body);\n}\n"],"mappings":";;;;;;;AAUA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,4BAA4B;AAErD,SAAgB,MACd,MACA,KACA,KAEA,MACM;CAGN,IAAI,IAAI,eAAe,gBAAA,YAAY,gBAAgB,CAAC,IAAI,UAAU,gBAAA,QAAQ,QAAQ,GAAG;EACnF,QAAM,yBAAyB;EAC/B,IAAI,OAAO,gBAAA,QAAQ,UAAU,GAAG,gBAAA,YAAY,IAAI,gBAAA,cAAc;CAChE;CAEA,IAAI;EACF,IAAI,OAAA,QAAE,SAAS,IAAI,KAAK,OAAA,QAAE,SAAS,IAAI,GAAG;GACxC,IAAI,CAAC,IAAI,IAAI,gBAAA,QAAQ,YAAY,GAAG;IAClC,QAAM,8BAA8B;IACpC,IAAI,OAAO,gBAAA,QAAQ,cAAc,gBAAA,QAAQ,IAAI;GAC/C;GAEA,IAAI,OAAO,SAAS,YAAY,OAAA,QAAE,MAAM,IAAI,MAAM,OAAO;IACvD,IAAI,OAAQ,KAAyB,UAAU,UAAU;KACvD,QAAM,4BAA4B;KAClC,IAAI,OAAO,mBAAoB,KAAyB;IAC1D;IACA,OAAO,KAAK,UAAU,MAAM,KAAA,GAAW,IAAI,IAAI;GACjD;GAGA,IACE,CAAC,IAAI,cACJ,IAAI,cAAc,gBAAA,YAAY,MAAM,IAAI,aAAa,gBAAA,YAAY,kBAClE;IACA,MAAM,OAAO,gBAAA,YAAY,YAAY,IAAc;IACnD,QAAM,sBAAsB,IAAI;IAChC,IAAI,OAAO,gBAAA,QAAQ,MAAM,OAAM,OAAO,IAAG;GAC3C;EACF,OACE,QAAM,mDAAmD;CAG7D,SAAS,KAAU;EAIjB,IAAI,IAAI,QAAQ,MAAM,iCAAiC,GAAG;GACxD,QAAM,iCAAiC;GACvC,IAAI,OAAA,QAAE,MAAM,IAAI,MAAM,MAAM,OAAO;IACjC,QAAM,sBAAsB;IAC5B,IAAI,QAAQ,QAAQ;GACtB;GACA;EACF;EACA,MAAM;CACR;CAEA,IAAI,KAAK,IAAI;AACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"make-url-relative.js","names":[],"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 type { $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":";;;;;;AAOA,IAAM,WAAA,GAAA,MAAA,SAAmB,wCAAwC;;;;;;;AAQjE,SAAgB,gBACd,KACA,KACA,MACM;CACN,MAAM,WAAW,IAAI;CAMrB,IAAI;CACJ,IAAI;EAIF,MAAM,IAAI,SAAA,IAAI,IAAI,KAAK,GAAG,IAAI,SAAS,KAAK,IAAI,QAAQ,KAAK,EAAE;CACjE,SAAS,OAAO;EACd,OAAO,KAAK,gBAAA,WAAW,cAAc,gBAAgB,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;CAC5E;CAGA,IAAI,MAAM,IAAI,WAAW,IAAI,SAAS,IAAI;CAE1C,IAAI,aAAa,IAAI,KACnB,QAAM,6BAA6B,UAAU,IAAI,GAAG;MAEpD,QAAM,mCAAmC,QAAQ;CAEnD,KAAK;AACP"}
1
+ {"version":3,"file":"make-url-relative.js","names":[],"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 type { $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":";;;;;;AAOA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,wCAAwC;;;;;;;AAQjE,SAAgB,gBACd,KACA,KACA,MACM;CACN,MAAM,WAAW,IAAI;CAMrB,IAAI;CACJ,IAAI;EAIF,MAAM,IAAI,SAAA,IAAI,IAAI,KAAK,GAAG,IAAI,SAAS,KAAK,IAAI,QAAQ,KAAK,EAAE;CACjE,SAAS,OAAO;EACd,OAAO,KAAK,gBAAA,WAAW,cAAc,gBAAgB,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;CAC5E;CAGA,IAAI,MAAM,IAAI,WAAW,IAAI,SAAS,IAAI;CAE1C,IAAI,aAAa,IAAI,KACnB,QAAM,6BAA6B,UAAU,IAAI,GAAG;MAEpD,QAAM,mCAAmC,QAAQ;CAEnD,KAAK;AACP"}
@@ -1 +1 @@
1
- {"version":3,"file":"media.js","names":[],"sources":["../../src/middlewares/media.ts"],"sourcesContent":["import { HEADER_TYPE, HTTP_STATUS, errorUtils } from '@verdaccio/core';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nexport function media(expect: string | null): any {\n return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n const header = req.headers[HEADER_TYPE.CONTENT_TYPE];\n if (!header) {\n next(\n errorUtils.getCode(\n HTTP_STATUS.UNSUPPORTED_MEDIA,\n 'content-type is missing, expect: ' + expect\n )\n );\n return;\n }\n\n if (typeof header !== 'string' || header.split(';')[0].trim() !== expect) {\n next(\n errorUtils.getCode(\n HTTP_STATUS.UNSUPPORTED_MEDIA,\n 'wrong content-type, expect: ' + expect + ', got: ' + req.get[HEADER_TYPE.CONTENT_TYPE]\n )\n );\n } else {\n next();\n }\n };\n}\n"],"mappings":";;AAIA,SAAgB,MAAM,QAA4B;CAChD,OAAO,SAAU,KAAqB,KAAsB,MAA8B;EACxF,MAAM,SAAS,IAAI,QAAQ,gBAAA,YAAY;EACvC,IAAI,CAAC,QAAQ;GACX,KACE,gBAAA,WAAW,QACT,gBAAA,YAAY,mBACZ,sCAAsC,MACxC,CACF;GACA;EACF;EAEA,IAAI,OAAO,WAAW,YAAY,OAAO,MAAM,GAAG,EAAE,GAAG,KAAK,MAAM,QAChE,KACE,gBAAA,WAAW,QACT,gBAAA,YAAY,mBACZ,iCAAiC,SAAS,YAAY,IAAI,IAAI,gBAAA,YAAY,aAC5E,CACF;OAEA,KAAK;CAET;AACF"}
1
+ {"version":3,"file":"media.js","names":[],"sources":["../../src/middlewares/media.ts"],"sourcesContent":["import { HEADER_TYPE, HTTP_STATUS, errorUtils } from '@verdaccio/core';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nexport function media(expect: string | null): any {\n return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n const header = req.headers[HEADER_TYPE.CONTENT_TYPE];\n if (!header) {\n next(\n errorUtils.getCode(\n HTTP_STATUS.UNSUPPORTED_MEDIA,\n 'content-type is missing, expect: ' + expect\n )\n );\n return;\n }\n\n if (typeof header !== 'string' || header.split(';')[0].trim() !== expect) {\n next(\n errorUtils.getCode(\n HTTP_STATUS.UNSUPPORTED_MEDIA,\n 'wrong content-type, expect: ' + expect + ', got: ' + req.get[HEADER_TYPE.CONTENT_TYPE]\n )\n );\n } else {\n next();\n }\n };\n}\n"],"mappings":";;AAIA,SAAgB,MAAM,QAA4B;CAChD,OAAO,SAAU,KAAqB,KAAsB,MAA8B;EACxF,MAAM,SAAS,IAAI,QAAQ,gBAAA,YAAY;EACvC,IAAI,CAAC,QAAQ;GACX,KACE,gBAAA,WAAW,QACT,gBAAA,YAAY,mBACZ,sCAAsC,MACxC,CACF;GACA;EACF;EAEA,IAAI,OAAO,WAAW,YAAY,OAAO,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,QAChE,KACE,gBAAA,WAAW,QACT,gBAAA,YAAY,mBACZ,iCAAiC,SAAS,YAAY,IAAI,IAAI,gBAAA,YAAY,aAC5E,CACF;OAEA,KAAK;CAET;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"media.mjs","names":[],"sources":["../../src/middlewares/media.ts"],"sourcesContent":["import { HEADER_TYPE, HTTP_STATUS, errorUtils } from '@verdaccio/core';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nexport function media(expect: string | null): any {\n return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n const header = req.headers[HEADER_TYPE.CONTENT_TYPE];\n if (!header) {\n next(\n errorUtils.getCode(\n HTTP_STATUS.UNSUPPORTED_MEDIA,\n 'content-type is missing, expect: ' + expect\n )\n );\n return;\n }\n\n if (typeof header !== 'string' || header.split(';')[0].trim() !== expect) {\n next(\n errorUtils.getCode(\n HTTP_STATUS.UNSUPPORTED_MEDIA,\n 'wrong content-type, expect: ' + expect + ', got: ' + req.get[HEADER_TYPE.CONTENT_TYPE]\n )\n );\n } else {\n next();\n }\n };\n}\n"],"mappings":";;AAIA,SAAgB,MAAM,QAA4B;CAChD,OAAO,SAAU,KAAqB,KAAsB,MAA8B;EACxF,MAAM,SAAS,IAAI,QAAQ,YAAY;EACvC,IAAI,CAAC,QAAQ;GACX,KACE,WAAW,QACT,YAAY,mBACZ,sCAAsC,MACxC,CACF;GACA;EACF;EAEA,IAAI,OAAO,WAAW,YAAY,OAAO,MAAM,GAAG,EAAE,GAAG,KAAK,MAAM,QAChE,KACE,WAAW,QACT,YAAY,mBACZ,iCAAiC,SAAS,YAAY,IAAI,IAAI,YAAY,aAC5E,CACF;OAEA,KAAK;CAET;AACF"}
1
+ {"version":3,"file":"media.mjs","names":[],"sources":["../../src/middlewares/media.ts"],"sourcesContent":["import { HEADER_TYPE, HTTP_STATUS, errorUtils } from '@verdaccio/core';\n\nimport type { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types';\n\nexport function media(expect: string | null): any {\n return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {\n const header = req.headers[HEADER_TYPE.CONTENT_TYPE];\n if (!header) {\n next(\n errorUtils.getCode(\n HTTP_STATUS.UNSUPPORTED_MEDIA,\n 'content-type is missing, expect: ' + expect\n )\n );\n return;\n }\n\n if (typeof header !== 'string' || header.split(';')[0].trim() !== expect) {\n next(\n errorUtils.getCode(\n HTTP_STATUS.UNSUPPORTED_MEDIA,\n 'wrong content-type, expect: ' + expect + ', got: ' + req.get[HEADER_TYPE.CONTENT_TYPE]\n )\n );\n } else {\n next();\n }\n };\n}\n"],"mappings":";;AAIA,SAAgB,MAAM,QAA4B;CAChD,OAAO,SAAU,KAAqB,KAAsB,MAA8B;EACxF,MAAM,SAAS,IAAI,QAAQ,YAAY;EACvC,IAAI,CAAC,QAAQ;GACX,KACE,WAAW,QACT,YAAY,mBACZ,sCAAsC,MACxC,CACF;GACA;EACF;EAEA,IAAI,OAAO,WAAW,YAAY,OAAO,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,QAChE,KACE,WAAW,QACT,YAAY,mBACZ,iCAAiC,SAAS,YAAY,IAAI,IAAI,YAAY,aAC5E,CACF;OAEA,KAAK;CAET;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"request-options.js","names":[],"sources":["../../src/middlewares/request-options.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { IncomingHttpHeaders } from 'node:http';\n\nimport type { RequestOptions } from '@verdaccio/url';\n\nimport type { $RequestExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:request-options');\n\nexport function getRequestOptions(req: $RequestExtend): RequestOptions {\n const requestOptions = {\n // FIXME: decide if host should contain port or not\n //\n // Express 4:\n // - req.host is marked as deprecated since it does not include the port\n // - use req.headers['host'] instead, which includes the port\n // Express 5:\n // - req.host is fully supported and includes the port\n // - https://expressjs.com/en/api.html#req.host\n host: req.host,\n protocol: req.protocol,\n headers: req.headers as IncomingHttpHeaders,\n remoteAddress: req.socket.remoteAddress,\n byPassCache: req.query.write === 'true',\n username: req.remote_user?.name ?? undefined,\n };\n\n debug('request options: %o', requestOptions);\n\n return requestOptions;\n}\n"],"mappings":";;;;AAOA,IAAM,WAAA,GAAA,MAAA,SAAmB,sCAAsC;AAE/D,SAAgB,kBAAkB,KAAqC;CACrE,MAAM,iBAAiB;EASrB,MAAM,IAAI;EACV,UAAU,IAAI;EACd,SAAS,IAAI;EACb,eAAe,IAAI,OAAO;EAC1B,aAAa,IAAI,MAAM,UAAU;EACjC,UAAU,IAAI,aAAa,QAAQ,KAAA;CACrC;CAEA,QAAM,uBAAuB,cAAc;CAE3C,OAAO;AACT"}
1
+ {"version":3,"file":"request-options.js","names":[],"sources":["../../src/middlewares/request-options.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { IncomingHttpHeaders } from 'node:http';\n\nimport type { RequestOptions } from '@verdaccio/url';\n\nimport type { $RequestExtend } from '../types';\n\nconst debug = buildDebug('verdaccio:middleware:request-options');\n\nexport function getRequestOptions(req: $RequestExtend): RequestOptions {\n const requestOptions = {\n // FIXME: decide if host should contain port or not\n //\n // Express 4:\n // - req.host is marked as deprecated since it does not include the port\n // - use req.headers['host'] instead, which includes the port\n // Express 5:\n // - req.host is fully supported and includes the port\n // - https://expressjs.com/en/api.html#req.host\n host: req.host,\n protocol: req.protocol,\n headers: req.headers as IncomingHttpHeaders,\n remoteAddress: req.socket.remoteAddress,\n byPassCache: req.query.write === 'true',\n username: req.remote_user?.name ?? undefined,\n };\n\n debug('request options: %o', requestOptions);\n\n return requestOptions;\n}\n"],"mappings":";;;;AAOA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,sCAAsC;AAE/D,SAAgB,kBAAkB,KAAqC;CACrE,MAAM,iBAAiB;EASrB,MAAM,IAAI;EACV,UAAU,IAAI;EACd,SAAS,IAAI;EACb,eAAe,IAAI,OAAO;EAC1B,aAAa,IAAI,MAAM,UAAU;EACjC,UAAU,IAAI,aAAa,QAAQ,KAAA;CACrC;CAEA,QAAM,uBAAuB,cAAc;CAE3C,OAAO;AACT"}
@@ -1,6 +1,6 @@
1
1
  let _verdaccio_core = require("@verdaccio/core");
2
2
  //#region src/middlewares/token-auth.ts
3
- var WRITE_METHODS = new Set([
3
+ var WRITE_METHODS = /* @__PURE__ */ new Set([
4
4
  "DELETE",
5
5
  "PATCH",
6
6
  "POST",
@@ -1 +1 @@
1
- {"version":3,"file":"token-auth.js","names":[],"sources":["../../src/middlewares/token-auth.ts"],"sourcesContent":["import type { NextFunction, Request, RequestHandler, Response } from 'express';\n\nimport { API_ERROR, errorUtils, ipUtils } from '@verdaccio/core';\nimport type { Logger, Token } from '@verdaccio/types';\n\nimport type { $RequestExtend } from '../types';\n\nconst WRITE_METHODS = new Set(['DELETE', 'PATCH', 'POST', 'PUT']);\n\n/**\n * Minimal storage surface required to enforce generated token metadata. Typed\n * structurally so this package does not need to depend on `@verdaccio/store`.\n */\nexport interface TokenReadableStorage {\n /**\n * Load the generated tokens stored for a user.\n *\n * @param filter narrows the lookup to a single `user`\n * @returns the user's persisted tokens\n */\n readTokens(filter: { user: string }): Promise<Token[]>;\n}\n\n/**\n * Resolve the client address of an incoming request for CIDR matching.\n *\n * Uses Express' `req.ip`, which already honors the application's `trust proxy`\n * setting (`config.server.trustProxy`): when the operator has declared trusted\n * proxies, `req.ip` is the upstream-most untrusted address parsed from\n * `X-Forwarded-For`; otherwise it is the direct socket peer and the forwarded\n * header is ignored entirely.\n *\n * The middleware must NOT read `X-Forwarded-For` on its own — doing so\n * unconditionally would let any client spoof its address (and bypass a token's\n * CIDR whitelist) simply by sending the header. Falls back to the raw socket\n * address and is normalized (trimmed, IPv4-mapped IPv6 prefix stripped) via\n * {@link ipUtils.normalizeAddress}.\n *\n * @param req the incoming Express request\n * @returns the normalized client address, or `undefined` when none can be determined\n */\nfunction getClientAddress(req: Request): string | undefined {\n return ipUtils.normalizeAddress(req.ip || req.socket.remoteAddress);\n}\n\n/**\n * Find the stored token whose `key` matches the key carried by the request.\n *\n * @param tokens the tokens persisted for the authenticated user\n * @param tokenKey the key extracted from the presented generated token\n * @returns the matching {@link Token}, or `undefined` when it has been revoked / never existed\n */\nfunction findToken(tokens: Token[], tokenKey: string): Token | undefined {\n return tokens.find(({ key }) => key === tokenKey);\n}\n\n/**\n * Express middleware that enforces the metadata of npm-style generated tokens\n * (created via `POST /-/npm/v1/tokens`).\n *\n * A generated token embeds a server-issued `key` that is recovered from the\n * verified credentials as `remote_user.token.key`. This middleware looks that\n * key up in storage and rejects the request when the token:\n * - is missing from storage (revoked or never issued);\n * - is used from a client address outside its `cidr` whitelist;\n * - is `readonly` and the request uses a write method (`DELETE`/`PATCH`/`POST`/`PUT`).\n *\n * Requests that do not carry a generated token key (e.g. interactive logins)\n * pass through untouched. It must run after the JWT/auth middleware has\n * populated `remote_user`. Failures fail closed: a storage lookup error yields\n * an internal error rather than allowing the request.\n *\n * @param storage storage exposing {@link TokenReadableStorage.readTokens} to load the user's tokens\n * @param logger logger used to record rejected attempts and lookup failures\n * @returns an Express {@link RequestHandler} that calls `next()` to allow or `next(error)` to reject\n */\nexport function enforceGeneratedTokenMetadata(\n storage: TokenReadableStorage,\n logger: Logger\n): RequestHandler {\n return async function (req: Request, _res: Response, next: NextFunction): Promise<void> {\n const remoteUser = (req as $RequestExtend).remote_user;\n const tokenKey = remoteUser?.token?.key;\n\n if (!tokenKey) {\n return next();\n }\n\n const user = remoteUser?.name;\n\n if (typeof user !== 'string') {\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n try {\n const token = findToken(await storage.readTokens({ user }), tokenKey);\n\n if (!token) {\n logger.warn({ tokenKey, user }, 'generated token @{tokenKey} for user @{user} is missing');\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n if (!ipUtils.isAddressAllowed(getClientAddress(req), token.cidr)) {\n logger.warn(\n { tokenKey, user },\n 'generated token @{tokenKey} for user @{user} was used outside its CIDR whitelist'\n );\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n if (token.readonly && WRITE_METHODS.has(req.method)) {\n logger.warn(\n { tokenKey, user },\n 'readonly generated token @{tokenKey} for user @{user} was used for a write request'\n );\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n return next();\n } catch (error: any) {\n logger.error({ error: error.msg }, 'generated token metadata lookup failed: @{error}');\n return next(errorUtils.getInternalError(error.message));\n }\n };\n}\n"],"mappings":";;AAOA,IAAM,gBAAgB,IAAI,IAAI;CAAC;CAAU;CAAS;CAAQ;AAAK,CAAC;;;;;;;;;;;;;;;;;;;AAkChE,SAAS,iBAAiB,KAAkC;CAC1D,OAAO,gBAAA,QAAQ,iBAAiB,IAAI,MAAM,IAAI,OAAO,aAAa;AACpE;;;;;;;;AASA,SAAS,UAAU,QAAiB,UAAqC;CACvE,OAAO,OAAO,MAAM,EAAE,UAAU,QAAQ,QAAQ;AAClD;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,8BACd,SACA,QACgB;CAChB,OAAO,eAAgB,KAAc,MAAgB,MAAmC;EACtF,MAAM,aAAc,IAAuB;EAC3C,MAAM,WAAW,YAAY,OAAO;EAEpC,IAAI,CAAC,UACH,OAAO,KAAK;EAGd,MAAM,OAAO,YAAY;EAEzB,IAAI,OAAO,SAAS,UAClB,OAAO,KAAK,gBAAA,WAAW,aAAa,gBAAA,UAAU,mBAAmB,CAAC;EAGpE,IAAI;GACF,MAAM,QAAQ,UAAU,MAAM,QAAQ,WAAW,EAAE,KAAK,CAAC,GAAG,QAAQ;GAEpE,IAAI,CAAC,OAAO;IACV,OAAO,KAAK;KAAE;KAAU;IAAK,GAAG,yDAAyD;IACzF,OAAO,KAAK,gBAAA,WAAW,aAAa,gBAAA,UAAU,mBAAmB,CAAC;GACpE;GAEA,IAAI,CAAC,gBAAA,QAAQ,iBAAiB,iBAAiB,GAAG,GAAG,MAAM,IAAI,GAAG;IAChE,OAAO,KACL;KAAE;KAAU;IAAK,GACjB,kFACF;IACA,OAAO,KAAK,gBAAA,WAAW,aAAa,gBAAA,UAAU,mBAAmB,CAAC;GACpE;GAEA,IAAI,MAAM,YAAY,cAAc,IAAI,IAAI,MAAM,GAAG;IACnD,OAAO,KACL;KAAE;KAAU;IAAK,GACjB,oFACF;IACA,OAAO,KAAK,gBAAA,WAAW,aAAa,gBAAA,UAAU,mBAAmB,CAAC;GACpE;GAEA,OAAO,KAAK;EACd,SAAS,OAAY;GACnB,OAAO,MAAM,EAAE,OAAO,MAAM,IAAI,GAAG,kDAAkD;GACrF,OAAO,KAAK,gBAAA,WAAW,iBAAiB,MAAM,OAAO,CAAC;EACxD;CACF;AACF"}
1
+ {"version":3,"file":"token-auth.js","names":[],"sources":["../../src/middlewares/token-auth.ts"],"sourcesContent":["import type { NextFunction, Request, RequestHandler, Response } from 'express';\n\nimport { API_ERROR, errorUtils, ipUtils } from '@verdaccio/core';\nimport type { Logger, Token } from '@verdaccio/types';\n\nimport type { $RequestExtend } from '../types';\n\nconst WRITE_METHODS = new Set(['DELETE', 'PATCH', 'POST', 'PUT']);\n\n/**\n * Minimal storage surface required to enforce generated token metadata. Typed\n * structurally so this package does not need to depend on `@verdaccio/store`.\n */\nexport interface TokenReadableStorage {\n /**\n * Load the generated tokens stored for a user.\n *\n * @param filter narrows the lookup to a single `user`\n * @returns the user's persisted tokens\n */\n readTokens(filter: { user: string }): Promise<Token[]>;\n}\n\n/**\n * Resolve the client address of an incoming request for CIDR matching.\n *\n * Uses Express' `req.ip`, which already honors the application's `trust proxy`\n * setting (`config.server.trustProxy`): when the operator has declared trusted\n * proxies, `req.ip` is the upstream-most untrusted address parsed from\n * `X-Forwarded-For`; otherwise it is the direct socket peer and the forwarded\n * header is ignored entirely.\n *\n * The middleware must NOT read `X-Forwarded-For` on its own — doing so\n * unconditionally would let any client spoof its address (and bypass a token's\n * CIDR whitelist) simply by sending the header. Falls back to the raw socket\n * address and is normalized (trimmed, IPv4-mapped IPv6 prefix stripped) via\n * {@link ipUtils.normalizeAddress}.\n *\n * @param req the incoming Express request\n * @returns the normalized client address, or `undefined` when none can be determined\n */\nfunction getClientAddress(req: Request): string | undefined {\n return ipUtils.normalizeAddress(req.ip || req.socket.remoteAddress);\n}\n\n/**\n * Find the stored token whose `key` matches the key carried by the request.\n *\n * @param tokens the tokens persisted for the authenticated user\n * @param tokenKey the key extracted from the presented generated token\n * @returns the matching {@link Token}, or `undefined` when it has been revoked / never existed\n */\nfunction findToken(tokens: Token[], tokenKey: string): Token | undefined {\n return tokens.find(({ key }) => key === tokenKey);\n}\n\n/**\n * Express middleware that enforces the metadata of npm-style generated tokens\n * (created via `POST /-/npm/v1/tokens`).\n *\n * A generated token embeds a server-issued `key` that is recovered from the\n * verified credentials as `remote_user.token.key`. This middleware looks that\n * key up in storage and rejects the request when the token:\n * - is missing from storage (revoked or never issued);\n * - is used from a client address outside its `cidr` whitelist;\n * - is `readonly` and the request uses a write method (`DELETE`/`PATCH`/`POST`/`PUT`).\n *\n * Requests that do not carry a generated token key (e.g. interactive logins)\n * pass through untouched. It must run after the JWT/auth middleware has\n * populated `remote_user`. Failures fail closed: a storage lookup error yields\n * an internal error rather than allowing the request.\n *\n * @param storage storage exposing {@link TokenReadableStorage.readTokens} to load the user's tokens\n * @param logger logger used to record rejected attempts and lookup failures\n * @returns an Express {@link RequestHandler} that calls `next()` to allow or `next(error)` to reject\n */\nexport function enforceGeneratedTokenMetadata(\n storage: TokenReadableStorage,\n logger: Logger\n): RequestHandler {\n return async function (req: Request, _res: Response, next: NextFunction): Promise<void> {\n const remoteUser = (req as $RequestExtend).remote_user;\n const tokenKey = remoteUser?.token?.key;\n\n if (!tokenKey) {\n return next();\n }\n\n const user = remoteUser?.name;\n\n if (typeof user !== 'string') {\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n try {\n const token = findToken(await storage.readTokens({ user }), tokenKey);\n\n if (!token) {\n logger.warn({ tokenKey, user }, 'generated token @{tokenKey} for user @{user} is missing');\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n if (!ipUtils.isAddressAllowed(getClientAddress(req), token.cidr)) {\n logger.warn(\n { tokenKey, user },\n 'generated token @{tokenKey} for user @{user} was used outside its CIDR whitelist'\n );\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n if (token.readonly && WRITE_METHODS.has(req.method)) {\n logger.warn(\n { tokenKey, user },\n 'readonly generated token @{tokenKey} for user @{user} was used for a write request'\n );\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n return next();\n } catch (error: any) {\n logger.error({ error: error.msg }, 'generated token metadata lookup failed: @{error}');\n return next(errorUtils.getInternalError(error.message));\n }\n };\n}\n"],"mappings":";;AAOA,IAAM,gCAAgB,IAAI,IAAI;CAAC;CAAU;CAAS;CAAQ;AAAK,CAAC;;;;;;;;;;;;;;;;;;;AAkChE,SAAS,iBAAiB,KAAkC;CAC1D,OAAO,gBAAA,QAAQ,iBAAiB,IAAI,MAAM,IAAI,OAAO,aAAa;AACpE;;;;;;;;AASA,SAAS,UAAU,QAAiB,UAAqC;CACvE,OAAO,OAAO,MAAM,EAAE,UAAU,QAAQ,QAAQ;AAClD;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,8BACd,SACA,QACgB;CAChB,OAAO,eAAgB,KAAc,MAAgB,MAAmC;EACtF,MAAM,aAAc,IAAuB;EAC3C,MAAM,WAAW,YAAY,OAAO;EAEpC,IAAI,CAAC,UACH,OAAO,KAAK;EAGd,MAAM,OAAO,YAAY;EAEzB,IAAI,OAAO,SAAS,UAClB,OAAO,KAAK,gBAAA,WAAW,aAAa,gBAAA,UAAU,mBAAmB,CAAC;EAGpE,IAAI;GACF,MAAM,QAAQ,UAAU,MAAM,QAAQ,WAAW,EAAE,KAAK,CAAC,GAAG,QAAQ;GAEpE,IAAI,CAAC,OAAO;IACV,OAAO,KAAK;KAAE;KAAU;IAAK,GAAG,yDAAyD;IACzF,OAAO,KAAK,gBAAA,WAAW,aAAa,gBAAA,UAAU,mBAAmB,CAAC;GACpE;GAEA,IAAI,CAAC,gBAAA,QAAQ,iBAAiB,iBAAiB,GAAG,GAAG,MAAM,IAAI,GAAG;IAChE,OAAO,KACL;KAAE;KAAU;IAAK,GACjB,kFACF;IACA,OAAO,KAAK,gBAAA,WAAW,aAAa,gBAAA,UAAU,mBAAmB,CAAC;GACpE;GAEA,IAAI,MAAM,YAAY,cAAc,IAAI,IAAI,MAAM,GAAG;IACnD,OAAO,KACL;KAAE;KAAU;IAAK,GACjB,oFACF;IACA,OAAO,KAAK,gBAAA,WAAW,aAAa,gBAAA,UAAU,mBAAmB,CAAC;GACpE;GAEA,OAAO,KAAK;EACd,SAAS,OAAY;GACnB,OAAO,MAAM,EAAE,OAAO,MAAM,IAAI,GAAG,kDAAkD;GACrF,OAAO,KAAK,gBAAA,WAAW,iBAAiB,MAAM,OAAO,CAAC;EACxD;CACF;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { API_ERROR, errorUtils, ipUtils } from "@verdaccio/core";
2
2
  //#region src/middlewares/token-auth.ts
3
- var WRITE_METHODS = new Set([
3
+ var WRITE_METHODS = /* @__PURE__ */ new Set([
4
4
  "DELETE",
5
5
  "PATCH",
6
6
  "POST",
@@ -1 +1 @@
1
- {"version":3,"file":"token-auth.mjs","names":[],"sources":["../../src/middlewares/token-auth.ts"],"sourcesContent":["import type { NextFunction, Request, RequestHandler, Response } from 'express';\n\nimport { API_ERROR, errorUtils, ipUtils } from '@verdaccio/core';\nimport type { Logger, Token } from '@verdaccio/types';\n\nimport type { $RequestExtend } from '../types';\n\nconst WRITE_METHODS = new Set(['DELETE', 'PATCH', 'POST', 'PUT']);\n\n/**\n * Minimal storage surface required to enforce generated token metadata. Typed\n * structurally so this package does not need to depend on `@verdaccio/store`.\n */\nexport interface TokenReadableStorage {\n /**\n * Load the generated tokens stored for a user.\n *\n * @param filter narrows the lookup to a single `user`\n * @returns the user's persisted tokens\n */\n readTokens(filter: { user: string }): Promise<Token[]>;\n}\n\n/**\n * Resolve the client address of an incoming request for CIDR matching.\n *\n * Uses Express' `req.ip`, which already honors the application's `trust proxy`\n * setting (`config.server.trustProxy`): when the operator has declared trusted\n * proxies, `req.ip` is the upstream-most untrusted address parsed from\n * `X-Forwarded-For`; otherwise it is the direct socket peer and the forwarded\n * header is ignored entirely.\n *\n * The middleware must NOT read `X-Forwarded-For` on its own — doing so\n * unconditionally would let any client spoof its address (and bypass a token's\n * CIDR whitelist) simply by sending the header. Falls back to the raw socket\n * address and is normalized (trimmed, IPv4-mapped IPv6 prefix stripped) via\n * {@link ipUtils.normalizeAddress}.\n *\n * @param req the incoming Express request\n * @returns the normalized client address, or `undefined` when none can be determined\n */\nfunction getClientAddress(req: Request): string | undefined {\n return ipUtils.normalizeAddress(req.ip || req.socket.remoteAddress);\n}\n\n/**\n * Find the stored token whose `key` matches the key carried by the request.\n *\n * @param tokens the tokens persisted for the authenticated user\n * @param tokenKey the key extracted from the presented generated token\n * @returns the matching {@link Token}, or `undefined` when it has been revoked / never existed\n */\nfunction findToken(tokens: Token[], tokenKey: string): Token | undefined {\n return tokens.find(({ key }) => key === tokenKey);\n}\n\n/**\n * Express middleware that enforces the metadata of npm-style generated tokens\n * (created via `POST /-/npm/v1/tokens`).\n *\n * A generated token embeds a server-issued `key` that is recovered from the\n * verified credentials as `remote_user.token.key`. This middleware looks that\n * key up in storage and rejects the request when the token:\n * - is missing from storage (revoked or never issued);\n * - is used from a client address outside its `cidr` whitelist;\n * - is `readonly` and the request uses a write method (`DELETE`/`PATCH`/`POST`/`PUT`).\n *\n * Requests that do not carry a generated token key (e.g. interactive logins)\n * pass through untouched. It must run after the JWT/auth middleware has\n * populated `remote_user`. Failures fail closed: a storage lookup error yields\n * an internal error rather than allowing the request.\n *\n * @param storage storage exposing {@link TokenReadableStorage.readTokens} to load the user's tokens\n * @param logger logger used to record rejected attempts and lookup failures\n * @returns an Express {@link RequestHandler} that calls `next()` to allow or `next(error)` to reject\n */\nexport function enforceGeneratedTokenMetadata(\n storage: TokenReadableStorage,\n logger: Logger\n): RequestHandler {\n return async function (req: Request, _res: Response, next: NextFunction): Promise<void> {\n const remoteUser = (req as $RequestExtend).remote_user;\n const tokenKey = remoteUser?.token?.key;\n\n if (!tokenKey) {\n return next();\n }\n\n const user = remoteUser?.name;\n\n if (typeof user !== 'string') {\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n try {\n const token = findToken(await storage.readTokens({ user }), tokenKey);\n\n if (!token) {\n logger.warn({ tokenKey, user }, 'generated token @{tokenKey} for user @{user} is missing');\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n if (!ipUtils.isAddressAllowed(getClientAddress(req), token.cidr)) {\n logger.warn(\n { tokenKey, user },\n 'generated token @{tokenKey} for user @{user} was used outside its CIDR whitelist'\n );\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n if (token.readonly && WRITE_METHODS.has(req.method)) {\n logger.warn(\n { tokenKey, user },\n 'readonly generated token @{tokenKey} for user @{user} was used for a write request'\n );\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n return next();\n } catch (error: any) {\n logger.error({ error: error.msg }, 'generated token metadata lookup failed: @{error}');\n return next(errorUtils.getInternalError(error.message));\n }\n };\n}\n"],"mappings":";;AAOA,IAAM,gBAAgB,IAAI,IAAI;CAAC;CAAU;CAAS;CAAQ;AAAK,CAAC;;;;;;;;;;;;;;;;;;;AAkChE,SAAS,iBAAiB,KAAkC;CAC1D,OAAO,QAAQ,iBAAiB,IAAI,MAAM,IAAI,OAAO,aAAa;AACpE;;;;;;;;AASA,SAAS,UAAU,QAAiB,UAAqC;CACvE,OAAO,OAAO,MAAM,EAAE,UAAU,QAAQ,QAAQ;AAClD;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,8BACd,SACA,QACgB;CAChB,OAAO,eAAgB,KAAc,MAAgB,MAAmC;EACtF,MAAM,aAAc,IAAuB;EAC3C,MAAM,WAAW,YAAY,OAAO;EAEpC,IAAI,CAAC,UACH,OAAO,KAAK;EAGd,MAAM,OAAO,YAAY;EAEzB,IAAI,OAAO,SAAS,UAClB,OAAO,KAAK,WAAW,aAAa,UAAU,mBAAmB,CAAC;EAGpE,IAAI;GACF,MAAM,QAAQ,UAAU,MAAM,QAAQ,WAAW,EAAE,KAAK,CAAC,GAAG,QAAQ;GAEpE,IAAI,CAAC,OAAO;IACV,OAAO,KAAK;KAAE;KAAU;IAAK,GAAG,yDAAyD;IACzF,OAAO,KAAK,WAAW,aAAa,UAAU,mBAAmB,CAAC;GACpE;GAEA,IAAI,CAAC,QAAQ,iBAAiB,iBAAiB,GAAG,GAAG,MAAM,IAAI,GAAG;IAChE,OAAO,KACL;KAAE;KAAU;IAAK,GACjB,kFACF;IACA,OAAO,KAAK,WAAW,aAAa,UAAU,mBAAmB,CAAC;GACpE;GAEA,IAAI,MAAM,YAAY,cAAc,IAAI,IAAI,MAAM,GAAG;IACnD,OAAO,KACL;KAAE;KAAU;IAAK,GACjB,oFACF;IACA,OAAO,KAAK,WAAW,aAAa,UAAU,mBAAmB,CAAC;GACpE;GAEA,OAAO,KAAK;EACd,SAAS,OAAY;GACnB,OAAO,MAAM,EAAE,OAAO,MAAM,IAAI,GAAG,kDAAkD;GACrF,OAAO,KAAK,WAAW,iBAAiB,MAAM,OAAO,CAAC;EACxD;CACF;AACF"}
1
+ {"version":3,"file":"token-auth.mjs","names":[],"sources":["../../src/middlewares/token-auth.ts"],"sourcesContent":["import type { NextFunction, Request, RequestHandler, Response } from 'express';\n\nimport { API_ERROR, errorUtils, ipUtils } from '@verdaccio/core';\nimport type { Logger, Token } from '@verdaccio/types';\n\nimport type { $RequestExtend } from '../types';\n\nconst WRITE_METHODS = new Set(['DELETE', 'PATCH', 'POST', 'PUT']);\n\n/**\n * Minimal storage surface required to enforce generated token metadata. Typed\n * structurally so this package does not need to depend on `@verdaccio/store`.\n */\nexport interface TokenReadableStorage {\n /**\n * Load the generated tokens stored for a user.\n *\n * @param filter narrows the lookup to a single `user`\n * @returns the user's persisted tokens\n */\n readTokens(filter: { user: string }): Promise<Token[]>;\n}\n\n/**\n * Resolve the client address of an incoming request for CIDR matching.\n *\n * Uses Express' `req.ip`, which already honors the application's `trust proxy`\n * setting (`config.server.trustProxy`): when the operator has declared trusted\n * proxies, `req.ip` is the upstream-most untrusted address parsed from\n * `X-Forwarded-For`; otherwise it is the direct socket peer and the forwarded\n * header is ignored entirely.\n *\n * The middleware must NOT read `X-Forwarded-For` on its own — doing so\n * unconditionally would let any client spoof its address (and bypass a token's\n * CIDR whitelist) simply by sending the header. Falls back to the raw socket\n * address and is normalized (trimmed, IPv4-mapped IPv6 prefix stripped) via\n * {@link ipUtils.normalizeAddress}.\n *\n * @param req the incoming Express request\n * @returns the normalized client address, or `undefined` when none can be determined\n */\nfunction getClientAddress(req: Request): string | undefined {\n return ipUtils.normalizeAddress(req.ip || req.socket.remoteAddress);\n}\n\n/**\n * Find the stored token whose `key` matches the key carried by the request.\n *\n * @param tokens the tokens persisted for the authenticated user\n * @param tokenKey the key extracted from the presented generated token\n * @returns the matching {@link Token}, or `undefined` when it has been revoked / never existed\n */\nfunction findToken(tokens: Token[], tokenKey: string): Token | undefined {\n return tokens.find(({ key }) => key === tokenKey);\n}\n\n/**\n * Express middleware that enforces the metadata of npm-style generated tokens\n * (created via `POST /-/npm/v1/tokens`).\n *\n * A generated token embeds a server-issued `key` that is recovered from the\n * verified credentials as `remote_user.token.key`. This middleware looks that\n * key up in storage and rejects the request when the token:\n * - is missing from storage (revoked or never issued);\n * - is used from a client address outside its `cidr` whitelist;\n * - is `readonly` and the request uses a write method (`DELETE`/`PATCH`/`POST`/`PUT`).\n *\n * Requests that do not carry a generated token key (e.g. interactive logins)\n * pass through untouched. It must run after the JWT/auth middleware has\n * populated `remote_user`. Failures fail closed: a storage lookup error yields\n * an internal error rather than allowing the request.\n *\n * @param storage storage exposing {@link TokenReadableStorage.readTokens} to load the user's tokens\n * @param logger logger used to record rejected attempts and lookup failures\n * @returns an Express {@link RequestHandler} that calls `next()` to allow or `next(error)` to reject\n */\nexport function enforceGeneratedTokenMetadata(\n storage: TokenReadableStorage,\n logger: Logger\n): RequestHandler {\n return async function (req: Request, _res: Response, next: NextFunction): Promise<void> {\n const remoteUser = (req as $RequestExtend).remote_user;\n const tokenKey = remoteUser?.token?.key;\n\n if (!tokenKey) {\n return next();\n }\n\n const user = remoteUser?.name;\n\n if (typeof user !== 'string') {\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n try {\n const token = findToken(await storage.readTokens({ user }), tokenKey);\n\n if (!token) {\n logger.warn({ tokenKey, user }, 'generated token @{tokenKey} for user @{user} is missing');\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n if (!ipUtils.isAddressAllowed(getClientAddress(req), token.cidr)) {\n logger.warn(\n { tokenKey, user },\n 'generated token @{tokenKey} for user @{user} was used outside its CIDR whitelist'\n );\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n if (token.readonly && WRITE_METHODS.has(req.method)) {\n logger.warn(\n { tokenKey, user },\n 'readonly generated token @{tokenKey} for user @{user} was used for a write request'\n );\n return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));\n }\n\n return next();\n } catch (error: any) {\n logger.error({ error: error.msg }, 'generated token metadata lookup failed: @{error}');\n return next(errorUtils.getInternalError(error.message));\n }\n };\n}\n"],"mappings":";;AAOA,IAAM,gCAAgB,IAAI,IAAI;CAAC;CAAU;CAAS;CAAQ;AAAK,CAAC;;;;;;;;;;;;;;;;;;;AAkChE,SAAS,iBAAiB,KAAkC;CAC1D,OAAO,QAAQ,iBAAiB,IAAI,MAAM,IAAI,OAAO,aAAa;AACpE;;;;;;;;AASA,SAAS,UAAU,QAAiB,UAAqC;CACvE,OAAO,OAAO,MAAM,EAAE,UAAU,QAAQ,QAAQ;AAClD;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,8BACd,SACA,QACgB;CAChB,OAAO,eAAgB,KAAc,MAAgB,MAAmC;EACtF,MAAM,aAAc,IAAuB;EAC3C,MAAM,WAAW,YAAY,OAAO;EAEpC,IAAI,CAAC,UACH,OAAO,KAAK;EAGd,MAAM,OAAO,YAAY;EAEzB,IAAI,OAAO,SAAS,UAClB,OAAO,KAAK,WAAW,aAAa,UAAU,mBAAmB,CAAC;EAGpE,IAAI;GACF,MAAM,QAAQ,UAAU,MAAM,QAAQ,WAAW,EAAE,KAAK,CAAC,GAAG,QAAQ;GAEpE,IAAI,CAAC,OAAO;IACV,OAAO,KAAK;KAAE;KAAU;IAAK,GAAG,yDAAyD;IACzF,OAAO,KAAK,WAAW,aAAa,UAAU,mBAAmB,CAAC;GACpE;GAEA,IAAI,CAAC,QAAQ,iBAAiB,iBAAiB,GAAG,GAAG,MAAM,IAAI,GAAG;IAChE,OAAO,KACL;KAAE;KAAU;IAAK,GACjB,kFACF;IACA,OAAO,KAAK,WAAW,aAAa,UAAU,mBAAmB,CAAC;GACpE;GAEA,IAAI,MAAM,YAAY,cAAc,IAAI,IAAI,MAAM,GAAG;IACnD,OAAO,KACL;KAAE;KAAU;IAAK,GACjB,oFACF;IACA,OAAO,KAAK,WAAW,aAAa,UAAU,mBAAmB,CAAC;GACpE;GAEA,OAAO,KAAK;EACd,SAAS,OAAY;GACnB,OAAO,MAAM,EAAE,OAAO,MAAM,IAAI,GAAG,kDAAkD;GACrF,OAAO,KAAK,WAAW,iBAAiB,MAAM,OAAO,CAAC;EACxD;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"user-agent.js","names":[],"sources":["../../src/middlewares/user-agent.ts"],"sourcesContent":["import { getUserAgent } from '@verdaccio/config';\nimport { HEADERS } from '@verdaccio/core';\n\nimport type { $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":";;;AAKA,SAAgB,UAAU,QAAQ;CAChC,OAAO,SAAU,MAAsB,KAAsB,MAA8B;EACzF,IAAI,UAAU,gBAAA,QAAQ,aAAA,GAAA,kBAAA,cAAyB,QAAQ,UAAU,CAAC;EAClE,KAAK;CACP;AACF"}
1
+ {"version":3,"file":"user-agent.js","names":[],"sources":["../../src/middlewares/user-agent.ts"],"sourcesContent":["import { getUserAgent } from '@verdaccio/config';\nimport { HEADERS } from '@verdaccio/core';\n\nimport type { $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":";;;AAKA,SAAgB,UAAU,QAAQ;CAChC,OAAO,SAAU,MAAsB,KAAsB,MAA8B;EACzF,IAAI,UAAU,gBAAA,QAAQ,aAAA,GAAA,kBAAA,aAAA,CAAyB,QAAQ,UAAU,CAAC;EAClE,KAAK;CACP;AACF"}
@@ -1,4 +1,7 @@
1
- require("./security.js");
2
- require("./render-web.js");
1
+ const require_security = require("./security.js");
2
+ const require_render_web = require("./render-web.js");
3
3
  require("./web-api.js");
4
- require("./web-middleware.js");
4
+ const require_web_middleware = require("./web-middleware.js");
5
+ exports.renderWebMiddleware = require_render_web.renderWebMiddleware;
6
+ exports.setSecurityWebHeaders = require_security.setSecurityWebHeaders;
7
+ exports.webMiddleware = require_web_middleware.default;
@@ -1,4 +1,5 @@
1
- import "./security.mjs";
2
- import "./render-web.mjs";
1
+ import { setSecurityWebHeaders } from "./security.mjs";
2
+ import { renderWebMiddleware } from "./render-web.mjs";
3
3
  import "./web-api.mjs";
4
- import "./web-middleware.mjs";
4
+ import web_middleware_default from "./web-middleware.mjs";
5
+ export { renderWebMiddleware, setSecurityWebHeaders, web_middleware_default as webMiddleware };
@@ -75,11 +75,13 @@ function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
75
75
  res.send(script);
76
76
  });
77
77
  router.get(require_web_urls.WebUrlsNamespace.web + "*", function(req, res) {
78
- require_renderHTML.default(config, manifest, manifestFiles, require_ui_options.getUIOptions(config, req, res), res);
78
+ const options = require_ui_options.getUIOptions(config, req, res);
79
+ require_renderHTML.default(config, manifest, manifestFiles, options, res);
79
80
  debug$1("render html section");
80
81
  });
81
82
  router.get(require_web_urls.WebUrlsNamespace.root, function(req, res) {
82
- require_renderHTML.default(config, manifest, manifestFiles, require_ui_options.getUIOptions(config, req, res), res);
83
+ const options = require_ui_options.getUIOptions(config, req, res);
84
+ require_renderHTML.default(config, manifest, manifestFiles, options, res);
83
85
  debug$1("render root");
84
86
  });
85
87
  return router;
@@ -1 +1 @@
1
- {"version":3,"file":"render-web.js","names":[],"sources":["../../../src/middlewares/web/render-web.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport express from 'express';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { HEADERS, HTTP_STATUS } from '@verdaccio/core';\nimport { isURLhasValidProtocol } from '@verdaccio/url';\n\nimport { setSecurityWebHeaders } from './security';\nimport renderHTML from './utils/renderHTML';\nimport { getUIOptions } from './utils/ui-options';\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 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 // Serve external script that loads UI options\n router.get(WebUrlsNamespace.static + 'ui-options.js', function (req, res) {\n const options = getUIOptions(config, req, res);\n const script = `window.__VERDACCIO_BASENAME_UI_OPTIONS=${JSON.stringify(options)};`;\n res.setHeader(HEADERS.CACHE_CONTROL, HEADERS.NO_CACHE);\n res.setHeader(HEADERS.CONTENT_TYPE, HEADERS.JAVASCRIPT_CHARSET);\n res.send(script);\n });\n\n // Handle all web routes including security routes\n router.get(WebUrlsNamespace.web + '*', function (req, res) {\n const options = getUIOptions(config, req, res);\n renderHTML(config, manifest, manifestFiles, options, res);\n debug('render html section');\n });\n\n router.get(WebUrlsNamespace.root, function (req, res) {\n const options = getUIOptions(config, req, res);\n renderHTML(config, manifest, manifestFiles, options, res);\n debug('render root');\n });\n\n return router;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAaA,IAAM,WAAA,GAAA,MAAA,SAAmB,sBAAsB;AAE/C,IAAM,oBAAoB,UAAU,QAAQ;CAC1C,IAAI,CAAC,KACH;CAEF,IAAI,IAAI,WAAW,gBAAA,YAAY,WAC7B,KAAK;MAEL,KAAK,GAAG;AAEZ;AAEA,SAAgB,oBAAoB,QAAQ,iBAAiB,eAAe;CAC1E,MAAM,EAAE,YAAY,UAAU,kBAAkB;CAChD,QAAM,kBAAkB,UAAU;CAElC,MAAM,SAAS,QAAA,QAAQ,OAAO;CAC9B,IAAI,OAAO,oBAAoB,YAC7B,OAAO,IAAI,eAAe;CAG5B,OAAO,IAAI,iBAAA,qBAAqB;CAGhC,OAAO,IAAI,iBAAA,iBAAiB,SAAS,KAAK,SAAU,KAAK,KAAK,MAAM;EAClE,MAAM,WAAW,IAAI,OAAO;EAC5B,IAAI,OAAO,GAAG,WAAW,GAAG;EAC5B,IAAI,aAAa,iBAAiB,QAAQ,KAAK,SAAS;GACtD,OAAO,QAAQ,KAAK;GACpB,KAAA,GAAA,eAAA,uBAA0B,IAAI,GAAG;IAC/B,QAAM,0BAA0B,IAAI;IACpC,IAAI,MAAM;IACV,OAAO,KAAK;GACd;EACF;EACA,QAAM,yBAAyB,IAAI;EACnC,IAAI,SAAS,MAAM,iBAAiB,IAAI,CAAC;CAC3C,CAAC;CAED,SAAS,WAAW,MAA8C;EAEhE,IAAI,QAAQ,EAAA,GAAA,eAAA,uBAAuB,IAAI,GAAG;GAExC,MAAM,oBAAoB,UAAA,QAAK,MAAM,QAAQ,IAAI;GACjD,QAAM,uBAAuB,iBAAiB;GAC9C,IAAI;IAEF,IACE,QAAA,QAAG,WAAW,iBAAiB,KAC/B,OAAO,QAAA,QAAG,WAAW,mBAAmB,QAAA,QAAG,UAAU,IAAI,MAAM,aAC/D;KAGA,OAAO,UAAA,QAAK,MAAM,KAAK,iBAAA,iBAAiB,QAAQ,UAAA,QAAK,SAAS,IAAI,CAAC;KACnE,OAAO,IAAI,MAAM,SAAU,MAAM,KAAK,MAAM;MAE1C,QAAM,wCAAwC,MAAM,iBAAiB;MACrE,IAAI,SAAS,mBAAmB,iBAAiB,IAAI,CAAC;KACxD,CAAC;KACD,QAAM,0BAA0B,IAAI;IACtC,OAAO;KACL,OAAO,KAAA;KACP,QAAM,2BAA2B,kBAAkB,mCAAmC;IACxF;GACF,QAAQ;IACN,OAAO,KAAA;IACP,QAAM,2BAA2B,kBAAkB,mCAAmC;GACxF;EACF;EACA,OAAO;CACT;CAEA,MAAM,OAAO,WAAW,QAAQ,KAAK,IAAI;CACzC,IAAI,QAAQ,KAAK,MACf,OAAO,IAAI,OAAO;CAEpB,MAAM,WAAW,WAAW,QAAQ,KAAK,QAAQ;CACjD,IAAI,QAAQ,KAAK,UACf,OAAO,IAAI,WAAW;CAIxB,OAAO,IAAI,iBAAA,iBAAiB,SAAS,iBAAiB,SAAU,KAAK,KAAK;EACxE,MAAM,UAAU,mBAAA,aAAa,QAAQ,KAAK,GAAG;EAC7C,MAAM,SAAS,0CAA0C,KAAK,UAAU,OAAO,EAAE;EACjF,IAAI,UAAU,gBAAA,QAAQ,eAAe,gBAAA,QAAQ,QAAQ;EACrD,IAAI,UAAU,gBAAA,QAAQ,cAAc,gBAAA,QAAQ,kBAAkB;EAC9D,IAAI,KAAK,MAAM;CACjB,CAAC;CAGD,OAAO,IAAI,iBAAA,iBAAiB,MAAM,KAAK,SAAU,KAAK,KAAK;EAEzD,mBAAA,QAAW,QAAQ,UAAU,eADb,mBAAA,aAAa,QAAQ,KAAK,GACE,GAAS,GAAG;EACxD,QAAM,qBAAqB;CAC7B,CAAC;CAED,OAAO,IAAI,iBAAA,iBAAiB,MAAM,SAAU,KAAK,KAAK;EAEpD,mBAAA,QAAW,QAAQ,UAAU,eADb,mBAAA,aAAa,QAAQ,KAAK,GACE,GAAS,GAAG;EACxD,QAAM,aAAa;CACrB,CAAC;CAED,OAAO;AACT"}
1
+ {"version":3,"file":"render-web.js","names":[],"sources":["../../../src/middlewares/web/render-web.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport express from 'express';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { HEADERS, HTTP_STATUS } from '@verdaccio/core';\nimport { isURLhasValidProtocol } from '@verdaccio/url';\n\nimport { setSecurityWebHeaders } from './security';\nimport renderHTML from './utils/renderHTML';\nimport { getUIOptions } from './utils/ui-options';\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 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 // Serve external script that loads UI options\n router.get(WebUrlsNamespace.static + 'ui-options.js', function (req, res) {\n const options = getUIOptions(config, req, res);\n const script = `window.__VERDACCIO_BASENAME_UI_OPTIONS=${JSON.stringify(options)};`;\n res.setHeader(HEADERS.CACHE_CONTROL, HEADERS.NO_CACHE);\n res.setHeader(HEADERS.CONTENT_TYPE, HEADERS.JAVASCRIPT_CHARSET);\n res.send(script);\n });\n\n // Handle all web routes including security routes\n router.get(WebUrlsNamespace.web + '*', function (req, res) {\n const options = getUIOptions(config, req, res);\n renderHTML(config, manifest, manifestFiles, options, res);\n debug('render html section');\n });\n\n router.get(WebUrlsNamespace.root, function (req, res) {\n const options = getUIOptions(config, req, res);\n renderHTML(config, manifest, manifestFiles, options, res);\n debug('render root');\n });\n\n return router;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAaA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,sBAAsB;AAE/C,IAAM,oBAAoB,UAAU,QAAQ;CAC1C,IAAI,CAAC,KACH;CAEF,IAAI,IAAI,WAAW,gBAAA,YAAY,WAC7B,KAAK;MAEL,KAAK,GAAG;AAEZ;AAEA,SAAgB,oBAAoB,QAAQ,iBAAiB,eAAe;CAC1E,MAAM,EAAE,YAAY,UAAU,kBAAkB;CAChD,QAAM,kBAAkB,UAAU;CAElC,MAAM,SAAS,QAAA,QAAQ,OAAO;CAC9B,IAAI,OAAO,oBAAoB,YAC7B,OAAO,IAAI,eAAe;CAG5B,OAAO,IAAI,iBAAA,qBAAqB;CAGhC,OAAO,IAAI,iBAAA,iBAAiB,SAAS,KAAK,SAAU,KAAK,KAAK,MAAM;EAClE,MAAM,WAAW,IAAI,OAAO;EAC5B,IAAI,OAAO,GAAG,WAAW,GAAG;EAC5B,IAAI,aAAa,iBAAiB,QAAQ,KAAK,SAAS;GACtD,OAAO,QAAQ,KAAK;GACpB,KAAA,GAAA,eAAA,sBAAA,CAA0B,IAAI,GAAG;IAC/B,QAAM,0BAA0B,IAAI;IACpC,IAAI,MAAM;IACV,OAAO,KAAK;GACd;EACF;EACA,QAAM,yBAAyB,IAAI;EACnC,IAAI,SAAS,MAAM,iBAAiB,IAAI,CAAC;CAC3C,CAAC;CAED,SAAS,WAAW,MAA8C;EAEhE,IAAI,QAAQ,EAAA,GAAA,eAAA,sBAAA,CAAuB,IAAI,GAAG;GAExC,MAAM,oBAAoB,UAAA,QAAK,MAAM,QAAQ,IAAI;GACjD,QAAM,uBAAuB,iBAAiB;GAC9C,IAAI;IAEF,IACE,QAAA,QAAG,WAAW,iBAAiB,KAC/B,OAAO,QAAA,QAAG,WAAW,mBAAmB,QAAA,QAAG,UAAU,IAAI,MAAM,aAC/D;KAGA,OAAO,UAAA,QAAK,MAAM,KAAK,iBAAA,iBAAiB,QAAQ,UAAA,QAAK,SAAS,IAAI,CAAC;KACnE,OAAO,IAAI,MAAM,SAAU,MAAM,KAAK,MAAM;MAE1C,QAAM,wCAAwC,MAAM,iBAAiB;MACrE,IAAI,SAAS,mBAAmB,iBAAiB,IAAI,CAAC;KACxD,CAAC;KACD,QAAM,0BAA0B,IAAI;IACtC,OAAO;KACL,OAAO,KAAA;KACP,QAAM,2BAA2B,kBAAkB,mCAAmC;IACxF;GACF,QAAQ;IACN,OAAO,KAAA;IACP,QAAM,2BAA2B,kBAAkB,mCAAmC;GACxF;EACF;EACA,OAAO;CACT;CAEA,MAAM,OAAO,WAAW,QAAQ,KAAK,IAAI;CACzC,IAAI,QAAQ,KAAK,MACf,OAAO,IAAI,OAAO;CAEpB,MAAM,WAAW,WAAW,QAAQ,KAAK,QAAQ;CACjD,IAAI,QAAQ,KAAK,UACf,OAAO,IAAI,WAAW;CAIxB,OAAO,IAAI,iBAAA,iBAAiB,SAAS,iBAAiB,SAAU,KAAK,KAAK;EACxE,MAAM,UAAU,mBAAA,aAAa,QAAQ,KAAK,GAAG;EAC7C,MAAM,SAAS,0CAA0C,KAAK,UAAU,OAAO,EAAE;EACjF,IAAI,UAAU,gBAAA,QAAQ,eAAe,gBAAA,QAAQ,QAAQ;EACrD,IAAI,UAAU,gBAAA,QAAQ,cAAc,gBAAA,QAAQ,kBAAkB;EAC9D,IAAI,KAAK,MAAM;CACjB,CAAC;CAGD,OAAO,IAAI,iBAAA,iBAAiB,MAAM,KAAK,SAAU,KAAK,KAAK;EACzD,MAAM,UAAU,mBAAA,aAAa,QAAQ,KAAK,GAAG;EAC7C,mBAAA,QAAW,QAAQ,UAAU,eAAe,SAAS,GAAG;EACxD,QAAM,qBAAqB;CAC7B,CAAC;CAED,OAAO,IAAI,iBAAA,iBAAiB,MAAM,SAAU,KAAK,KAAK;EACpD,MAAM,UAAU,mBAAA,aAAa,QAAQ,KAAK,GAAG;EAC7C,mBAAA,QAAW,QAAQ,UAAU,eAAe,SAAS,GAAG;EACxD,QAAM,aAAa;CACrB,CAAC;CAED,OAAO;AACT"}
@@ -70,11 +70,13 @@ function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
70
70
  res.send(script);
71
71
  });
72
72
  router.get(WebUrlsNamespace.web + "*", function(req, res) {
73
- renderHTML(config, manifest, manifestFiles, getUIOptions(config, req, res), res);
73
+ const options = getUIOptions(config, req, res);
74
+ renderHTML(config, manifest, manifestFiles, options, res);
74
75
  debug("render html section");
75
76
  });
76
77
  router.get(WebUrlsNamespace.root, function(req, res) {
77
- renderHTML(config, manifest, manifestFiles, getUIOptions(config, req, res), res);
78
+ const options = getUIOptions(config, req, res);
79
+ renderHTML(config, manifest, manifestFiles, options, res);
78
80
  debug("render root");
79
81
  });
80
82
  return router;
@@ -1 +1 @@
1
- {"version":3,"file":"render-web.mjs","names":[],"sources":["../../../src/middlewares/web/render-web.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport express from 'express';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { HEADERS, HTTP_STATUS } from '@verdaccio/core';\nimport { isURLhasValidProtocol } from '@verdaccio/url';\n\nimport { setSecurityWebHeaders } from './security';\nimport renderHTML from './utils/renderHTML';\nimport { getUIOptions } from './utils/ui-options';\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 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 // Serve external script that loads UI options\n router.get(WebUrlsNamespace.static + 'ui-options.js', function (req, res) {\n const options = getUIOptions(config, req, res);\n const script = `window.__VERDACCIO_BASENAME_UI_OPTIONS=${JSON.stringify(options)};`;\n res.setHeader(HEADERS.CACHE_CONTROL, HEADERS.NO_CACHE);\n res.setHeader(HEADERS.CONTENT_TYPE, HEADERS.JAVASCRIPT_CHARSET);\n res.send(script);\n });\n\n // Handle all web routes including security routes\n router.get(WebUrlsNamespace.web + '*', function (req, res) {\n const options = getUIOptions(config, req, res);\n renderHTML(config, manifest, manifestFiles, options, res);\n debug('render html section');\n });\n\n router.get(WebUrlsNamespace.root, function (req, res) {\n const options = getUIOptions(config, req, res);\n renderHTML(config, manifest, manifestFiles, options, res);\n debug('render root');\n });\n\n return router;\n}\n"],"mappings":";;;;;;;;;;;AAaA,IAAM,QAAQ,WAAW,sBAAsB;AAE/C,IAAM,oBAAoB,UAAU,QAAQ;CAC1C,IAAI,CAAC,KACH;CAEF,IAAI,IAAI,WAAW,YAAY,WAC7B,KAAK;MAEL,KAAK,GAAG;AAEZ;AAEA,SAAgB,oBAAoB,QAAQ,iBAAiB,eAAe;CAC1E,MAAM,EAAE,YAAY,UAAU,kBAAkB;CAChD,MAAM,kBAAkB,UAAU;CAElC,MAAM,SAAS,QAAQ,OAAO;CAC9B,IAAI,OAAO,oBAAoB,YAC7B,OAAO,IAAI,eAAe;CAG5B,OAAO,IAAI,qBAAqB;CAGhC,OAAO,IAAI,iBAAiB,SAAS,KAAK,SAAU,KAAK,KAAK,MAAM;EAClE,MAAM,WAAW,IAAI,OAAO;EAC5B,IAAI,OAAO,GAAG,WAAW,GAAG;EAC5B,IAAI,aAAa,iBAAiB,QAAQ,KAAK,SAAS;GACtD,OAAO,QAAQ,KAAK;GACpB,IAAI,sBAAsB,IAAI,GAAG;IAC/B,MAAM,0BAA0B,IAAI;IACpC,IAAI,MAAM;IACV,OAAO,KAAK;GACd;EACF;EACA,MAAM,yBAAyB,IAAI;EACnC,IAAI,SAAS,MAAM,iBAAiB,IAAI,CAAC;CAC3C,CAAC;CAED,SAAS,WAAW,MAA8C;EAEhE,IAAI,QAAQ,CAAC,sBAAsB,IAAI,GAAG;GAExC,MAAM,oBAAoB,KAAK,MAAM,QAAQ,IAAI;GACjD,MAAM,uBAAuB,iBAAiB;GAC9C,IAAI;IAEF,IACE,GAAG,WAAW,iBAAiB,KAC/B,OAAO,GAAG,WAAW,mBAAmB,GAAG,UAAU,IAAI,MAAM,aAC/D;KAGA,OAAO,KAAK,MAAM,KAAK,iBAAiB,QAAQ,KAAK,SAAS,IAAI,CAAC;KACnE,OAAO,IAAI,MAAM,SAAU,MAAM,KAAK,MAAM;MAE1C,MAAM,wCAAwC,MAAM,iBAAiB;MACrE,IAAI,SAAS,mBAAmB,iBAAiB,IAAI,CAAC;KACxD,CAAC;KACD,MAAM,0BAA0B,IAAI;IACtC,OAAO;KACL,OAAO,KAAA;KACP,MAAM,2BAA2B,kBAAkB,mCAAmC;IACxF;GACF,QAAQ;IACN,OAAO,KAAA;IACP,MAAM,2BAA2B,kBAAkB,mCAAmC;GACxF;EACF;EACA,OAAO;CACT;CAEA,MAAM,OAAO,WAAW,QAAQ,KAAK,IAAI;CACzC,IAAI,QAAQ,KAAK,MACf,OAAO,IAAI,OAAO;CAEpB,MAAM,WAAW,WAAW,QAAQ,KAAK,QAAQ;CACjD,IAAI,QAAQ,KAAK,UACf,OAAO,IAAI,WAAW;CAIxB,OAAO,IAAI,iBAAiB,SAAS,iBAAiB,SAAU,KAAK,KAAK;EACxE,MAAM,UAAU,aAAa,QAAQ,KAAK,GAAG;EAC7C,MAAM,SAAS,0CAA0C,KAAK,UAAU,OAAO,EAAE;EACjF,IAAI,UAAU,QAAQ,eAAe,QAAQ,QAAQ;EACrD,IAAI,UAAU,QAAQ,cAAc,QAAQ,kBAAkB;EAC9D,IAAI,KAAK,MAAM;CACjB,CAAC;CAGD,OAAO,IAAI,iBAAiB,MAAM,KAAK,SAAU,KAAK,KAAK;EAEzD,WAAW,QAAQ,UAAU,eADb,aAAa,QAAQ,KAAK,GACE,GAAS,GAAG;EACxD,MAAM,qBAAqB;CAC7B,CAAC;CAED,OAAO,IAAI,iBAAiB,MAAM,SAAU,KAAK,KAAK;EAEpD,WAAW,QAAQ,UAAU,eADb,aAAa,QAAQ,KAAK,GACE,GAAS,GAAG;EACxD,MAAM,aAAa;CACrB,CAAC;CAED,OAAO;AACT"}
1
+ {"version":3,"file":"render-web.mjs","names":[],"sources":["../../../src/middlewares/web/render-web.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport express from 'express';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { HEADERS, HTTP_STATUS } from '@verdaccio/core';\nimport { isURLhasValidProtocol } from '@verdaccio/url';\n\nimport { setSecurityWebHeaders } from './security';\nimport renderHTML from './utils/renderHTML';\nimport { getUIOptions } from './utils/ui-options';\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 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 // Serve external script that loads UI options\n router.get(WebUrlsNamespace.static + 'ui-options.js', function (req, res) {\n const options = getUIOptions(config, req, res);\n const script = `window.__VERDACCIO_BASENAME_UI_OPTIONS=${JSON.stringify(options)};`;\n res.setHeader(HEADERS.CACHE_CONTROL, HEADERS.NO_CACHE);\n res.setHeader(HEADERS.CONTENT_TYPE, HEADERS.JAVASCRIPT_CHARSET);\n res.send(script);\n });\n\n // Handle all web routes including security routes\n router.get(WebUrlsNamespace.web + '*', function (req, res) {\n const options = getUIOptions(config, req, res);\n renderHTML(config, manifest, manifestFiles, options, res);\n debug('render html section');\n });\n\n router.get(WebUrlsNamespace.root, function (req, res) {\n const options = getUIOptions(config, req, res);\n renderHTML(config, manifest, manifestFiles, options, res);\n debug('render root');\n });\n\n return router;\n}\n"],"mappings":";;;;;;;;;;;AAaA,IAAM,QAAQ,WAAW,sBAAsB;AAE/C,IAAM,oBAAoB,UAAU,QAAQ;CAC1C,IAAI,CAAC,KACH;CAEF,IAAI,IAAI,WAAW,YAAY,WAC7B,KAAK;MAEL,KAAK,GAAG;AAEZ;AAEA,SAAgB,oBAAoB,QAAQ,iBAAiB,eAAe;CAC1E,MAAM,EAAE,YAAY,UAAU,kBAAkB;CAChD,MAAM,kBAAkB,UAAU;CAElC,MAAM,SAAS,QAAQ,OAAO;CAC9B,IAAI,OAAO,oBAAoB,YAC7B,OAAO,IAAI,eAAe;CAG5B,OAAO,IAAI,qBAAqB;CAGhC,OAAO,IAAI,iBAAiB,SAAS,KAAK,SAAU,KAAK,KAAK,MAAM;EAClE,MAAM,WAAW,IAAI,OAAO;EAC5B,IAAI,OAAO,GAAG,WAAW,GAAG;EAC5B,IAAI,aAAa,iBAAiB,QAAQ,KAAK,SAAS;GACtD,OAAO,QAAQ,KAAK;GACpB,IAAI,sBAAsB,IAAI,GAAG;IAC/B,MAAM,0BAA0B,IAAI;IACpC,IAAI,MAAM;IACV,OAAO,KAAK;GACd;EACF;EACA,MAAM,yBAAyB,IAAI;EACnC,IAAI,SAAS,MAAM,iBAAiB,IAAI,CAAC;CAC3C,CAAC;CAED,SAAS,WAAW,MAA8C;EAEhE,IAAI,QAAQ,CAAC,sBAAsB,IAAI,GAAG;GAExC,MAAM,oBAAoB,KAAK,MAAM,QAAQ,IAAI;GACjD,MAAM,uBAAuB,iBAAiB;GAC9C,IAAI;IAEF,IACE,GAAG,WAAW,iBAAiB,KAC/B,OAAO,GAAG,WAAW,mBAAmB,GAAG,UAAU,IAAI,MAAM,aAC/D;KAGA,OAAO,KAAK,MAAM,KAAK,iBAAiB,QAAQ,KAAK,SAAS,IAAI,CAAC;KACnE,OAAO,IAAI,MAAM,SAAU,MAAM,KAAK,MAAM;MAE1C,MAAM,wCAAwC,MAAM,iBAAiB;MACrE,IAAI,SAAS,mBAAmB,iBAAiB,IAAI,CAAC;KACxD,CAAC;KACD,MAAM,0BAA0B,IAAI;IACtC,OAAO;KACL,OAAO,KAAA;KACP,MAAM,2BAA2B,kBAAkB,mCAAmC;IACxF;GACF,QAAQ;IACN,OAAO,KAAA;IACP,MAAM,2BAA2B,kBAAkB,mCAAmC;GACxF;EACF;EACA,OAAO;CACT;CAEA,MAAM,OAAO,WAAW,QAAQ,KAAK,IAAI;CACzC,IAAI,QAAQ,KAAK,MACf,OAAO,IAAI,OAAO;CAEpB,MAAM,WAAW,WAAW,QAAQ,KAAK,QAAQ;CACjD,IAAI,QAAQ,KAAK,UACf,OAAO,IAAI,WAAW;CAIxB,OAAO,IAAI,iBAAiB,SAAS,iBAAiB,SAAU,KAAK,KAAK;EACxE,MAAM,UAAU,aAAa,QAAQ,KAAK,GAAG;EAC7C,MAAM,SAAS,0CAA0C,KAAK,UAAU,OAAO,EAAE;EACjF,IAAI,UAAU,QAAQ,eAAe,QAAQ,QAAQ;EACrD,IAAI,UAAU,QAAQ,cAAc,QAAQ,kBAAkB;EAC9D,IAAI,KAAK,MAAM;CACjB,CAAC;CAGD,OAAO,IAAI,iBAAiB,MAAM,KAAK,SAAU,KAAK,KAAK;EACzD,MAAM,UAAU,aAAa,QAAQ,KAAK,GAAG;EAC7C,WAAW,QAAQ,UAAU,eAAe,SAAS,GAAG;EACxD,MAAM,qBAAqB;CAC7B,CAAC;CAED,OAAO,IAAI,iBAAiB,MAAM,SAAU,KAAK,KAAK;EACpD,MAAM,UAAU,aAAa,QAAQ,KAAK,GAAG;EAC7C,WAAW,QAAQ,UAAU,eAAe,SAAS,GAAG;EACxD,MAAM,aAAa;CACrB,CAAC;CAED,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"security.js","names":[],"sources":["../../../src/middlewares/web/security.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { HEADERS } from '@verdaccio/core';\n\nconst debug = buildDebug('verdaccio:middleware:web:security');\n\nexport function setSecurityWebHeaders(_req, res, next): void {\n // disable loading in frames (clickjacking, etc.)\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Frame-Options\n const framesOptions = res.getHeader(HEADERS.FRAMES_OPTIONS);\n if (!framesOptions || !(framesOptions === 'deny' || framesOptions === 'sameorigin')) {\n debug('Missing or invalid X-Frame-Options header; setting to \"deny\"');\n res.header(HEADERS.FRAMES_OPTIONS, 'deny');\n }\n\n // avoid establishing connections outside of domain\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy\n if (!res.getHeader(HEADERS.CSP)) {\n debug('Missing Content-Security-Policy header; setting to \"connect-src \\'self\\'\"');\n res.header(HEADERS.CSP, \"connect-src 'self'\");\n }\n\n // respect the content type of the response\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Content-Type-Options\n const cto = res.getHeader(HEADERS.CTO);\n if (!cto || cto !== 'nosniff') {\n debug('Missing or invalid X-Content-Type-Options header; setting to \"nosniff\"');\n res.header(HEADERS.CTO, 'nosniff');\n }\n\n // block rendering of the page in case of XSS attack\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-XSS-Protection\n const xss = res.getHeader(HEADERS.XSS);\n if (!xss || !(xss === '0' || xss.startsWith('1'))) {\n debug('Missing or invalid X-XSS-Protection header; setting to \"1; mode=block\"');\n res.header(HEADERS.XSS, '1; mode=block');\n }\n next();\n}\n"],"mappings":";;;;;AAIA,IAAM,WAAA,GAAA,MAAA,SAAmB,mCAAmC;AAE5D,SAAgB,sBAAsB,MAAM,KAAK,MAAY;CAG3D,MAAM,gBAAgB,IAAI,UAAU,gBAAA,QAAQ,cAAc;CAC1D,IAAI,CAAC,iBAAiB,EAAE,kBAAkB,UAAU,kBAAkB,eAAe;EACnF,QAAM,gEAA8D;EACpE,IAAI,OAAO,gBAAA,QAAQ,gBAAgB,MAAM;CAC3C;CAIA,IAAI,CAAC,IAAI,UAAU,gBAAA,QAAQ,GAAG,GAAG;EAC/B,QAAM,2EAA2E;EACjF,IAAI,OAAO,gBAAA,QAAQ,KAAK,oBAAoB;CAC9C;CAIA,MAAM,MAAM,IAAI,UAAU,gBAAA,QAAQ,GAAG;CACrC,IAAI,CAAC,OAAO,QAAQ,WAAW;EAC7B,QAAM,0EAAwE;EAC9E,IAAI,OAAO,gBAAA,QAAQ,KAAK,SAAS;CACnC;CAIA,MAAM,MAAM,IAAI,UAAU,gBAAA,QAAQ,GAAG;CACrC,IAAI,CAAC,OAAO,EAAE,QAAQ,OAAO,IAAI,WAAW,GAAG,IAAI;EACjD,QAAM,0EAAwE;EAC9E,IAAI,OAAO,gBAAA,QAAQ,KAAK,eAAe;CACzC;CACA,KAAK;AACP"}
1
+ {"version":3,"file":"security.js","names":[],"sources":["../../../src/middlewares/web/security.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { HEADERS } from '@verdaccio/core';\n\nconst debug = buildDebug('verdaccio:middleware:web:security');\n\nexport function setSecurityWebHeaders(_req, res, next): void {\n // disable loading in frames (clickjacking, etc.)\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Frame-Options\n const framesOptions = res.getHeader(HEADERS.FRAMES_OPTIONS);\n if (!framesOptions || !(framesOptions === 'deny' || framesOptions === 'sameorigin')) {\n debug('Missing or invalid X-Frame-Options header; setting to \"deny\"');\n res.header(HEADERS.FRAMES_OPTIONS, 'deny');\n }\n\n // avoid establishing connections outside of domain\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy\n if (!res.getHeader(HEADERS.CSP)) {\n debug('Missing Content-Security-Policy header; setting to \"connect-src \\'self\\'\"');\n res.header(HEADERS.CSP, \"connect-src 'self'\");\n }\n\n // respect the content type of the response\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Content-Type-Options\n const cto = res.getHeader(HEADERS.CTO);\n if (!cto || cto !== 'nosniff') {\n debug('Missing or invalid X-Content-Type-Options header; setting to \"nosniff\"');\n res.header(HEADERS.CTO, 'nosniff');\n }\n\n // block rendering of the page in case of XSS attack\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-XSS-Protection\n const xss = res.getHeader(HEADERS.XSS);\n if (!xss || !(xss === '0' || xss.startsWith('1'))) {\n debug('Missing or invalid X-XSS-Protection header; setting to \"1; mode=block\"');\n res.header(HEADERS.XSS, '1; mode=block');\n }\n next();\n}\n"],"mappings":";;;;;AAIA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,mCAAmC;AAE5D,SAAgB,sBAAsB,MAAM,KAAK,MAAY;CAG3D,MAAM,gBAAgB,IAAI,UAAU,gBAAA,QAAQ,cAAc;CAC1D,IAAI,CAAC,iBAAiB,EAAE,kBAAkB,UAAU,kBAAkB,eAAe;EACnF,QAAM,gEAA8D;EACpE,IAAI,OAAO,gBAAA,QAAQ,gBAAgB,MAAM;CAC3C;CAIA,IAAI,CAAC,IAAI,UAAU,gBAAA,QAAQ,GAAG,GAAG;EAC/B,QAAM,2EAA2E;EACjF,IAAI,OAAO,gBAAA,QAAQ,KAAK,oBAAoB;CAC9C;CAIA,MAAM,MAAM,IAAI,UAAU,gBAAA,QAAQ,GAAG;CACrC,IAAI,CAAC,OAAO,QAAQ,WAAW;EAC7B,QAAM,0EAAwE;EAC9E,IAAI,OAAO,gBAAA,QAAQ,KAAK,SAAS;CACnC;CAIA,MAAM,MAAM,IAAI,UAAU,gBAAA,QAAQ,GAAG;CACrC,IAAI,CAAC,OAAO,EAAE,QAAQ,OAAO,IAAI,WAAW,GAAG,IAAI;EACjD,QAAM,0EAAwE;EAC9E,IAAI,OAAO,gBAAA,QAAQ,KAAK,eAAe;CACzC;CACA,KAAK;AACP"}
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.js","names":[],"sources":["../../../../src/middlewares/web/utils/manifest.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nexport type Manifest = {\n // goes on first place at the header\n ico: string;\n css: string[];\n js: string[];\n};\n\nconst debug = buildDebug('verdaccio:middleware:web:render:manifest');\n\nexport function getManifestValue(\n manifestItems: string[],\n manifest,\n basePath: string = ''\n): string[] {\n return manifestItems?.map((item) => {\n debug('resolve item %o', item);\n const resolvedItem = `${stripTrailingSlash(basePath)}/${stripLeadingSlash(manifest[item])}`;\n debug('resolved item %o', resolvedItem);\n return resolvedItem;\n });\n}\n\nfunction stripTrailingSlash(path: string): string {\n return path.replace(/\\/$/, '');\n}\n\nfunction stripLeadingSlash(path: string): string {\n return path.replace(/^\\//, '');\n}\n"],"mappings":";;;;AASA,IAAM,WAAA,GAAA,MAAA,SAAmB,0CAA0C;AAEnE,SAAgB,iBACd,eACA,UACA,WAAmB,IACT;CACV,OAAO,eAAe,KAAK,SAAS;EAClC,QAAM,mBAAmB,IAAI;EAC7B,MAAM,eAAe,GAAG,mBAAmB,QAAQ,EAAE,GAAG,kBAAkB,SAAS,KAAK;EACxF,QAAM,oBAAoB,YAAY;EACtC,OAAO;CACT,CAAC;AACH;AAEA,SAAS,mBAAmB,MAAsB;CAChD,OAAO,KAAK,QAAQ,OAAO,EAAE;AAC/B;AAEA,SAAS,kBAAkB,MAAsB;CAC/C,OAAO,KAAK,QAAQ,OAAO,EAAE;AAC/B"}
1
+ {"version":3,"file":"manifest.js","names":[],"sources":["../../../../src/middlewares/web/utils/manifest.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nexport type Manifest = {\n // goes on first place at the header\n ico: string;\n css: string[];\n js: string[];\n};\n\nconst debug = buildDebug('verdaccio:middleware:web:render:manifest');\n\nexport function getManifestValue(\n manifestItems: string[],\n manifest,\n basePath: string = ''\n): string[] {\n return manifestItems?.map((item) => {\n debug('resolve item %o', item);\n const resolvedItem = `${stripTrailingSlash(basePath)}/${stripLeadingSlash(manifest[item])}`;\n debug('resolved item %o', resolvedItem);\n return resolvedItem;\n });\n}\n\nfunction stripTrailingSlash(path: string): string {\n return path.replace(/\\/$/, '');\n}\n\nfunction stripLeadingSlash(path: string): string {\n return path.replace(/^\\//, '');\n}\n"],"mappings":";;;;AASA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,0CAA0C;AAEnE,SAAgB,iBACd,eACA,UACA,WAAmB,IACT;CACV,OAAO,eAAe,KAAK,SAAS;EAClC,QAAM,mBAAmB,IAAI;EAC7B,MAAM,eAAe,GAAG,mBAAmB,QAAQ,EAAE,GAAG,kBAAkB,SAAS,KAAK;EACxF,QAAM,oBAAoB,YAAY;EACtC,OAAO;CACT,CAAC;AACH;AAEA,SAAS,mBAAmB,MAAsB;CAChD,OAAO,KAAK,QAAQ,OAAO,EAAE;AAC/B;AAEA,SAAS,kBAAkB,MAAsB;CAC/C,OAAO,KAAK,QAAQ,OAAO,EAAE;AAC/B"}
@@ -1 +1 @@
1
- {"version":3,"file":"renderHTML.js","names":[],"sources":["../../../../src/middlewares/web/utils/renderHTML.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Response } from 'express';\nimport LRUCache from 'lru-cache';\n\nimport { HEADERS } from '@verdaccio/core';\nimport type { ConfigYaml, TemplateUIOptions } from '@verdaccio/types';\n\nimport type { Manifest } from './manifest';\nimport renderTemplate from './template';\nimport type { AssetManifest } from './template';\n\n// Cache for rendered HTML templates: max 500 entries, 1 hour TTL\nconst cache = new LRUCache({ max: 500, ttl: 1000 * 60 * 60 });\n\nconst debug = buildDebug('verdaccio:web:render');\n\nconst defaultManifestFiles: Manifest = {\n js: ['vendors.js', 'main.js'],\n ico: 'favicon.ico',\n css: [],\n};\n\nexport default function renderHTML(\n config: ConfigYaml,\n manifest: AssetManifest,\n manifestFiles: Manifest | null | undefined,\n options: TemplateUIOptions,\n res: Response\n) {\n // @ts-ignore\n const needHtmlCache = [undefined, null].includes(config?.web?.html_cache)\n ? true\n : config?.web?.html_cache;\n\n const scriptsBodyBefore = config?.web?.scriptsBodyBefore || config?.web?.scriptsbodyBefore || [];\n const scriptsBodyAfter = config?.web?.scriptsBodyAfter || [];\n const metaScripts = config?.web?.metaScripts || [];\n\n let webPage;\n\n const cacheKey = `template:${JSON.stringify(options)}`;\n\n try {\n webPage = cache.get(cacheKey);\n if (!webPage) {\n webPage = renderTemplate(\n {\n manifest: manifestFiles ?? defaultManifestFiles,\n options,\n scriptsBodyAfter,\n metaScripts,\n scriptsBodyBefore,\n },\n manifest\n );\n\n if (needHtmlCache) {\n cache.set(cacheKey, webPage);\n debug('set template cache');\n }\n } else {\n debug('reuse template cache');\n }\n } catch (error: any) {\n throw new Error(`theme could not be load, stack ${error.stack}`);\n }\n res.setHeader('Content-Type', HEADERS.TEXT_HTML);\n res.send(webPage);\n debug('web rendered');\n}\n"],"mappings":";;;;;;;;AAYA,IAAM,QAAQ,IAAI,UAAA,QAAS;CAAE,KAAK;CAAK,KAAK,MAAO,KAAK;AAAG,CAAC;AAE5D,IAAM,WAAA,GAAA,MAAA,SAAmB,sBAAsB;AAE/C,IAAM,uBAAiC;CACrC,IAAI,CAAC,cAAc,SAAS;CAC5B,KAAK;CACL,KAAK,CAAC;AACR;AAEA,SAAwB,WACtB,QACA,UACA,eACA,SACA,KACA;CAEA,MAAM,gBAAgB,CAAC,KAAA,GAAW,IAAI,EAAE,SAAS,QAAQ,KAAK,UAAU,IACpE,OACA,QAAQ,KAAK;CAEjB,MAAM,oBAAoB,QAAQ,KAAK,qBAAqB,QAAQ,KAAK,qBAAqB,CAAC;CAC/F,MAAM,mBAAmB,QAAQ,KAAK,oBAAoB,CAAC;CAC3D,MAAM,cAAc,QAAQ,KAAK,eAAe,CAAC;CAEjD,IAAI;CAEJ,MAAM,WAAW,YAAY,KAAK,UAAU,OAAO;CAEnD,IAAI;EACF,UAAU,MAAM,IAAI,QAAQ;EAC5B,IAAI,CAAC,SAAS;GACZ,UAAU,iBAAA,QACR;IACE,UAAU,iBAAiB;IAC3B;IACA;IACA;IACA;GACF,GACA,QACF;GAEA,IAAI,eAAe;IACjB,MAAM,IAAI,UAAU,OAAO;IAC3B,QAAM,oBAAoB;GAC5B;EACF,OACE,QAAM,sBAAsB;CAEhC,SAAS,OAAY;EACnB,MAAM,IAAI,MAAM,kCAAkC,MAAM,OAAO;CACjE;CACA,IAAI,UAAU,gBAAgB,gBAAA,QAAQ,SAAS;CAC/C,IAAI,KAAK,OAAO;CAChB,QAAM,cAAc;AACtB"}
1
+ {"version":3,"file":"renderHTML.js","names":[],"sources":["../../../../src/middlewares/web/utils/renderHTML.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Response } from 'express';\nimport LRUCache from 'lru-cache';\n\nimport { HEADERS } from '@verdaccio/core';\nimport type { ConfigYaml, TemplateUIOptions } from '@verdaccio/types';\n\nimport type { Manifest } from './manifest';\nimport renderTemplate from './template';\nimport type { AssetManifest } from './template';\n\n// Cache for rendered HTML templates: max 500 entries, 1 hour TTL\nconst cache = new LRUCache({ max: 500, ttl: 1000 * 60 * 60 });\n\nconst debug = buildDebug('verdaccio:web:render');\n\nconst defaultManifestFiles: Manifest = {\n js: ['vendors.js', 'main.js'],\n ico: 'favicon.ico',\n css: [],\n};\n\nexport default function renderHTML(\n config: ConfigYaml,\n manifest: AssetManifest,\n manifestFiles: Manifest | null | undefined,\n options: TemplateUIOptions,\n res: Response\n) {\n // @ts-ignore\n const needHtmlCache = [undefined, null].includes(config?.web?.html_cache)\n ? true\n : config?.web?.html_cache;\n\n const scriptsBodyBefore = config?.web?.scriptsBodyBefore || config?.web?.scriptsbodyBefore || [];\n const scriptsBodyAfter = config?.web?.scriptsBodyAfter || [];\n const metaScripts = config?.web?.metaScripts || [];\n\n let webPage;\n\n const cacheKey = `template:${JSON.stringify(options)}`;\n\n try {\n webPage = cache.get(cacheKey);\n if (!webPage) {\n webPage = renderTemplate(\n {\n manifest: manifestFiles ?? defaultManifestFiles,\n options,\n scriptsBodyAfter,\n metaScripts,\n scriptsBodyBefore,\n },\n manifest\n );\n\n if (needHtmlCache) {\n cache.set(cacheKey, webPage);\n debug('set template cache');\n }\n } else {\n debug('reuse template cache');\n }\n } catch (error: any) {\n throw new Error(`theme could not be load, stack ${error.stack}`);\n }\n res.setHeader('Content-Type', HEADERS.TEXT_HTML);\n res.send(webPage);\n debug('web rendered');\n}\n"],"mappings":";;;;;;;;AAYA,IAAM,QAAQ,IAAI,UAAA,QAAS;CAAE,KAAK;CAAK,KAAK,MAAO,KAAK;AAAG,CAAC;AAE5D,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,sBAAsB;AAE/C,IAAM,uBAAiC;CACrC,IAAI,CAAC,cAAc,SAAS;CAC5B,KAAK;CACL,KAAK,CAAC;AACR;AAEA,SAAwB,WACtB,QACA,UACA,eACA,SACA,KACA;CAEA,MAAM,gBAAgB,CAAC,KAAA,GAAW,IAAI,CAAC,CAAC,SAAS,QAAQ,KAAK,UAAU,IACpE,OACA,QAAQ,KAAK;CAEjB,MAAM,oBAAoB,QAAQ,KAAK,qBAAqB,QAAQ,KAAK,qBAAqB,CAAC;CAC/F,MAAM,mBAAmB,QAAQ,KAAK,oBAAoB,CAAC;CAC3D,MAAM,cAAc,QAAQ,KAAK,eAAe,CAAC;CAEjD,IAAI;CAEJ,MAAM,WAAW,YAAY,KAAK,UAAU,OAAO;CAEnD,IAAI;EACF,UAAU,MAAM,IAAI,QAAQ;EAC5B,IAAI,CAAC,SAAS;GACZ,UAAU,iBAAA,QACR;IACE,UAAU,iBAAiB;IAC3B;IACA;IACA;IACA;GACF,GACA,QACF;GAEA,IAAI,eAAe;IACjB,MAAM,IAAI,UAAU,OAAO;IAC3B,QAAM,oBAAoB;GAC5B;EACF,OACE,QAAM,sBAAsB;CAEhC,SAAS,OAAY;EACnB,MAAM,IAAI,MAAM,kCAAkC,MAAM,OAAO;CACjE;CACA,IAAI,UAAU,gBAAgB,gBAAA,QAAQ,SAAS;CAC/C,IAAI,KAAK,OAAO;CAChB,QAAM,cAAc;AACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"renderHTML.mjs","names":[],"sources":["../../../../src/middlewares/web/utils/renderHTML.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Response } from 'express';\nimport LRUCache from 'lru-cache';\n\nimport { HEADERS } from '@verdaccio/core';\nimport type { ConfigYaml, TemplateUIOptions } from '@verdaccio/types';\n\nimport type { Manifest } from './manifest';\nimport renderTemplate from './template';\nimport type { AssetManifest } from './template';\n\n// Cache for rendered HTML templates: max 500 entries, 1 hour TTL\nconst cache = new LRUCache({ max: 500, ttl: 1000 * 60 * 60 });\n\nconst debug = buildDebug('verdaccio:web:render');\n\nconst defaultManifestFiles: Manifest = {\n js: ['vendors.js', 'main.js'],\n ico: 'favicon.ico',\n css: [],\n};\n\nexport default function renderHTML(\n config: ConfigYaml,\n manifest: AssetManifest,\n manifestFiles: Manifest | null | undefined,\n options: TemplateUIOptions,\n res: Response\n) {\n // @ts-ignore\n const needHtmlCache = [undefined, null].includes(config?.web?.html_cache)\n ? true\n : config?.web?.html_cache;\n\n const scriptsBodyBefore = config?.web?.scriptsBodyBefore || config?.web?.scriptsbodyBefore || [];\n const scriptsBodyAfter = config?.web?.scriptsBodyAfter || [];\n const metaScripts = config?.web?.metaScripts || [];\n\n let webPage;\n\n const cacheKey = `template:${JSON.stringify(options)}`;\n\n try {\n webPage = cache.get(cacheKey);\n if (!webPage) {\n webPage = renderTemplate(\n {\n manifest: manifestFiles ?? defaultManifestFiles,\n options,\n scriptsBodyAfter,\n metaScripts,\n scriptsBodyBefore,\n },\n manifest\n );\n\n if (needHtmlCache) {\n cache.set(cacheKey, webPage);\n debug('set template cache');\n }\n } else {\n debug('reuse template cache');\n }\n } catch (error: any) {\n throw new Error(`theme could not be load, stack ${error.stack}`);\n }\n res.setHeader('Content-Type', HEADERS.TEXT_HTML);\n res.send(webPage);\n debug('web rendered');\n}\n"],"mappings":";;;;;AAYA,IAAM,QAAQ,IAAI,SAAS;CAAE,KAAK;CAAK,KAAK,MAAO,KAAK;AAAG,CAAC;AAE5D,IAAM,QAAQ,WAAW,sBAAsB;AAE/C,IAAM,uBAAiC;CACrC,IAAI,CAAC,cAAc,SAAS;CAC5B,KAAK;CACL,KAAK,CAAC;AACR;AAEA,SAAwB,WACtB,QACA,UACA,eACA,SACA,KACA;CAEA,MAAM,gBAAgB,CAAC,KAAA,GAAW,IAAI,EAAE,SAAS,QAAQ,KAAK,UAAU,IACpE,OACA,QAAQ,KAAK;CAEjB,MAAM,oBAAoB,QAAQ,KAAK,qBAAqB,QAAQ,KAAK,qBAAqB,CAAC;CAC/F,MAAM,mBAAmB,QAAQ,KAAK,oBAAoB,CAAC;CAC3D,MAAM,cAAc,QAAQ,KAAK,eAAe,CAAC;CAEjD,IAAI;CAEJ,MAAM,WAAW,YAAY,KAAK,UAAU,OAAO;CAEnD,IAAI;EACF,UAAU,MAAM,IAAI,QAAQ;EAC5B,IAAI,CAAC,SAAS;GACZ,UAAU,eACR;IACE,UAAU,iBAAiB;IAC3B;IACA;IACA;IACA;GACF,GACA,QACF;GAEA,IAAI,eAAe;IACjB,MAAM,IAAI,UAAU,OAAO;IAC3B,MAAM,oBAAoB;GAC5B;EACF,OACE,MAAM,sBAAsB;CAEhC,SAAS,OAAY;EACnB,MAAM,IAAI,MAAM,kCAAkC,MAAM,OAAO;CACjE;CACA,IAAI,UAAU,gBAAgB,QAAQ,SAAS;CAC/C,IAAI,KAAK,OAAO;CAChB,MAAM,cAAc;AACtB"}
1
+ {"version":3,"file":"renderHTML.mjs","names":[],"sources":["../../../../src/middlewares/web/utils/renderHTML.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Response } from 'express';\nimport LRUCache from 'lru-cache';\n\nimport { HEADERS } from '@verdaccio/core';\nimport type { ConfigYaml, TemplateUIOptions } from '@verdaccio/types';\n\nimport type { Manifest } from './manifest';\nimport renderTemplate from './template';\nimport type { AssetManifest } from './template';\n\n// Cache for rendered HTML templates: max 500 entries, 1 hour TTL\nconst cache = new LRUCache({ max: 500, ttl: 1000 * 60 * 60 });\n\nconst debug = buildDebug('verdaccio:web:render');\n\nconst defaultManifestFiles: Manifest = {\n js: ['vendors.js', 'main.js'],\n ico: 'favicon.ico',\n css: [],\n};\n\nexport default function renderHTML(\n config: ConfigYaml,\n manifest: AssetManifest,\n manifestFiles: Manifest | null | undefined,\n options: TemplateUIOptions,\n res: Response\n) {\n // @ts-ignore\n const needHtmlCache = [undefined, null].includes(config?.web?.html_cache)\n ? true\n : config?.web?.html_cache;\n\n const scriptsBodyBefore = config?.web?.scriptsBodyBefore || config?.web?.scriptsbodyBefore || [];\n const scriptsBodyAfter = config?.web?.scriptsBodyAfter || [];\n const metaScripts = config?.web?.metaScripts || [];\n\n let webPage;\n\n const cacheKey = `template:${JSON.stringify(options)}`;\n\n try {\n webPage = cache.get(cacheKey);\n if (!webPage) {\n webPage = renderTemplate(\n {\n manifest: manifestFiles ?? defaultManifestFiles,\n options,\n scriptsBodyAfter,\n metaScripts,\n scriptsBodyBefore,\n },\n manifest\n );\n\n if (needHtmlCache) {\n cache.set(cacheKey, webPage);\n debug('set template cache');\n }\n } else {\n debug('reuse template cache');\n }\n } catch (error: any) {\n throw new Error(`theme could not be load, stack ${error.stack}`);\n }\n res.setHeader('Content-Type', HEADERS.TEXT_HTML);\n res.send(webPage);\n debug('web rendered');\n}\n"],"mappings":";;;;;AAYA,IAAM,QAAQ,IAAI,SAAS;CAAE,KAAK;CAAK,KAAK,MAAO,KAAK;AAAG,CAAC;AAE5D,IAAM,QAAQ,WAAW,sBAAsB;AAE/C,IAAM,uBAAiC;CACrC,IAAI,CAAC,cAAc,SAAS;CAC5B,KAAK;CACL,KAAK,CAAC;AACR;AAEA,SAAwB,WACtB,QACA,UACA,eACA,SACA,KACA;CAEA,MAAM,gBAAgB,CAAC,KAAA,GAAW,IAAI,CAAC,CAAC,SAAS,QAAQ,KAAK,UAAU,IACpE,OACA,QAAQ,KAAK;CAEjB,MAAM,oBAAoB,QAAQ,KAAK,qBAAqB,QAAQ,KAAK,qBAAqB,CAAC;CAC/F,MAAM,mBAAmB,QAAQ,KAAK,oBAAoB,CAAC;CAC3D,MAAM,cAAc,QAAQ,KAAK,eAAe,CAAC;CAEjD,IAAI;CAEJ,MAAM,WAAW,YAAY,KAAK,UAAU,OAAO;CAEnD,IAAI;EACF,UAAU,MAAM,IAAI,QAAQ;EAC5B,IAAI,CAAC,SAAS;GACZ,UAAU,eACR;IACE,UAAU,iBAAiB;IAC3B;IACA;IACA;IACA;GACF,GACA,QACF;GAEA,IAAI,eAAe;IACjB,MAAM,IAAI,UAAU,OAAO;IAC3B,MAAM,oBAAoB;GAC5B;EACF,OACE,MAAM,sBAAsB;CAEhC,SAAS,OAAY;EACnB,MAAM,IAAI,MAAM,kCAAkC,MAAM,OAAO;CACjE;CACA,IAAI,UAAU,gBAAgB,QAAQ,SAAS;CAC/C,IAAI,KAAK,OAAO;CAChB,MAAM,cAAc;AACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"template.js","names":[],"sources":["../../../../src/middlewares/web/utils/template.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport type { TemplateUIOptions } from '@verdaccio/types';\n\nimport type { Manifest } from './manifest';\nimport { getManifestValue } from './manifest';\n\nconst debug = buildDebug('verdaccio:web:render:template');\n\nexport type Template = {\n manifest: Manifest;\n options: TemplateUIOptions;\n metaScripts?: string[];\n scriptsBodyAfter?: string[];\n scriptsBodyBefore?: string[];\n};\n\nexport interface AssetManifest {\n [key: string]: string;\n}\n\nexport default function renderTemplate(template: Template, manifest: AssetManifest) {\n debug('template %o', template);\n debug('manifest %o', manifest);\n\n return `\n <!DOCTYPE html>\n <html lang=\"en-us\">\n <head>\n <meta charset=\"utf-8\">\n <base href=\"${template?.options.base}\">\n <title>${template?.options?.title ?? ''}</title>\n <link rel=\"icon\" href=\"${template?.options.base}-/static/favicon.ico\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script src=\"${template?.options.base}-/static/ui-options.js\"></script>\n ${\n template.manifest.css?.length\n ? getManifestValue(template.manifest.css, manifest, template?.options.base)\n .map((item) => `<link rel=\"stylesheet\" href=\"${item}\">`)\n .join('\\n ')\n : ''\n }\n ${template?.metaScripts ? template.metaScripts.join('') : ''}\n </head>\n <body class=\"body\">\n ${template?.scriptsBodyBefore ? template.scriptsBodyBefore.join('') : ''}\n <div id=\"root\"></div>\n ${getManifestValue(template.manifest.js, manifest, template?.options.base)\n .map((item) => `<script type=\"module\" src=\"${item}\"></script>`)\n .join(`\\n `)}\n ${template?.scriptsBodyAfter ? template.scriptsBodyAfter.join('') : ''}\n </body>\n </html>\n `;\n}\n"],"mappings":";;;;;AAOA,IAAM,WAAA,GAAA,MAAA,SAAmB,+BAA+B;AAcxD,SAAwB,eAAe,UAAoB,UAAyB;CAClF,QAAM,eAAe,QAAQ;CAC7B,QAAM,eAAe,QAAQ;CAE7B,OAAO;;;;;sBAKa,UAAU,QAAQ,KAAK;iBAC5B,UAAU,SAAS,SAAS,GAAG;iCACf,UAAU,QAAQ,KAAK;;uBAEjC,UAAU,QAAQ,KAAK;UAEpC,SAAS,SAAS,KAAK,SACnB,iBAAA,iBAAiB,SAAS,SAAS,KAAK,UAAU,UAAU,QAAQ,IAAI,EACrE,KAAK,SAAS,gCAAgC,KAAK,GAAG,EACtD,KAAK,YAAY,IACpB,GACL;UACC,UAAU,cAAc,SAAS,YAAY,KAAK,EAAE,IAAI,GAAG;;;UAG3D,UAAU,oBAAoB,SAAS,kBAAkB,KAAK,EAAE,IAAI,GAAG;;UAEvE,iBAAA,iBAAiB,SAAS,SAAS,IAAI,UAAU,UAAU,QAAQ,IAAI,EACtE,KAAK,SAAS,8BAA8B,KAAK,aAAY,EAC7D,KAAK,YAAY,EAAE;UACpB,UAAU,mBAAmB,SAAS,iBAAiB,KAAK,EAAE,IAAI,GAAG;;;;AAI/E"}
1
+ {"version":3,"file":"template.js","names":[],"sources":["../../../../src/middlewares/web/utils/template.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport type { TemplateUIOptions } from '@verdaccio/types';\n\nimport type { Manifest } from './manifest';\nimport { getManifestValue } from './manifest';\n\nconst debug = buildDebug('verdaccio:web:render:template');\n\nexport type Template = {\n manifest: Manifest;\n options: TemplateUIOptions;\n metaScripts?: string[];\n scriptsBodyAfter?: string[];\n scriptsBodyBefore?: string[];\n};\n\nexport interface AssetManifest {\n [key: string]: string;\n}\n\nexport default function renderTemplate(template: Template, manifest: AssetManifest) {\n debug('template %o', template);\n debug('manifest %o', manifest);\n\n return `\n <!DOCTYPE html>\n <html lang=\"en-us\">\n <head>\n <meta charset=\"utf-8\">\n <base href=\"${template?.options.base}\">\n <title>${template?.options?.title ?? ''}</title>\n <link rel=\"icon\" href=\"${template?.options.base}-/static/favicon.ico\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script src=\"${template?.options.base}-/static/ui-options.js\"></script>\n ${\n template.manifest.css?.length\n ? getManifestValue(template.manifest.css, manifest, template?.options.base)\n .map((item) => `<link rel=\"stylesheet\" href=\"${item}\">`)\n .join('\\n ')\n : ''\n }\n ${template?.metaScripts ? template.metaScripts.join('') : ''}\n </head>\n <body class=\"body\">\n ${template?.scriptsBodyBefore ? template.scriptsBodyBefore.join('') : ''}\n <div id=\"root\"></div>\n ${getManifestValue(template.manifest.js, manifest, template?.options.base)\n .map((item) => `<script type=\"module\" src=\"${item}\"></script>`)\n .join(`\\n `)}\n ${template?.scriptsBodyAfter ? template.scriptsBodyAfter.join('') : ''}\n </body>\n </html>\n `;\n}\n"],"mappings":";;;;;AAOA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,+BAA+B;AAcxD,SAAwB,eAAe,UAAoB,UAAyB;CAClF,QAAM,eAAe,QAAQ;CAC7B,QAAM,eAAe,QAAQ;CAE7B,OAAO;;;;;sBAKa,UAAU,QAAQ,KAAK;iBAC5B,UAAU,SAAS,SAAS,GAAG;iCACf,UAAU,QAAQ,KAAK;;uBAEjC,UAAU,QAAQ,KAAK;UAEpC,SAAS,SAAS,KAAK,SACnB,iBAAA,iBAAiB,SAAS,SAAS,KAAK,UAAU,UAAU,QAAQ,IAAI,CAAC,CACtE,KAAK,SAAS,gCAAgC,KAAK,GAAG,CAAC,CACvD,KAAK,YAAY,IACpB,GACL;UACC,UAAU,cAAc,SAAS,YAAY,KAAK,EAAE,IAAI,GAAG;;;UAG3D,UAAU,oBAAoB,SAAS,kBAAkB,KAAK,EAAE,IAAI,GAAG;;UAEvE,iBAAA,iBAAiB,SAAS,SAAS,IAAI,UAAU,UAAU,QAAQ,IAAI,CAAC,CACvE,KAAK,SAAS,8BAA8B,KAAK,aAAY,CAAC,CAC9D,KAAK,YAAY,EAAE;UACpB,UAAU,mBAAmB,SAAS,iBAAiB,KAAK,EAAE,IAAI,GAAG;;;;AAI/E"}
@@ -1 +1 @@
1
- {"version":3,"file":"template.mjs","names":[],"sources":["../../../../src/middlewares/web/utils/template.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport type { TemplateUIOptions } from '@verdaccio/types';\n\nimport type { Manifest } from './manifest';\nimport { getManifestValue } from './manifest';\n\nconst debug = buildDebug('verdaccio:web:render:template');\n\nexport type Template = {\n manifest: Manifest;\n options: TemplateUIOptions;\n metaScripts?: string[];\n scriptsBodyAfter?: string[];\n scriptsBodyBefore?: string[];\n};\n\nexport interface AssetManifest {\n [key: string]: string;\n}\n\nexport default function renderTemplate(template: Template, manifest: AssetManifest) {\n debug('template %o', template);\n debug('manifest %o', manifest);\n\n return `\n <!DOCTYPE html>\n <html lang=\"en-us\">\n <head>\n <meta charset=\"utf-8\">\n <base href=\"${template?.options.base}\">\n <title>${template?.options?.title ?? ''}</title>\n <link rel=\"icon\" href=\"${template?.options.base}-/static/favicon.ico\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script src=\"${template?.options.base}-/static/ui-options.js\"></script>\n ${\n template.manifest.css?.length\n ? getManifestValue(template.manifest.css, manifest, template?.options.base)\n .map((item) => `<link rel=\"stylesheet\" href=\"${item}\">`)\n .join('\\n ')\n : ''\n }\n ${template?.metaScripts ? template.metaScripts.join('') : ''}\n </head>\n <body class=\"body\">\n ${template?.scriptsBodyBefore ? template.scriptsBodyBefore.join('') : ''}\n <div id=\"root\"></div>\n ${getManifestValue(template.manifest.js, manifest, template?.options.base)\n .map((item) => `<script type=\"module\" src=\"${item}\"></script>`)\n .join(`\\n `)}\n ${template?.scriptsBodyAfter ? template.scriptsBodyAfter.join('') : ''}\n </body>\n </html>\n `;\n}\n"],"mappings":";;;AAOA,IAAM,QAAQ,WAAW,+BAA+B;AAcxD,SAAwB,eAAe,UAAoB,UAAyB;CAClF,MAAM,eAAe,QAAQ;CAC7B,MAAM,eAAe,QAAQ;CAE7B,OAAO;;;;;sBAKa,UAAU,QAAQ,KAAK;iBAC5B,UAAU,SAAS,SAAS,GAAG;iCACf,UAAU,QAAQ,KAAK;;uBAEjC,UAAU,QAAQ,KAAK;UAEpC,SAAS,SAAS,KAAK,SACnB,iBAAiB,SAAS,SAAS,KAAK,UAAU,UAAU,QAAQ,IAAI,EACrE,KAAK,SAAS,gCAAgC,KAAK,GAAG,EACtD,KAAK,YAAY,IACpB,GACL;UACC,UAAU,cAAc,SAAS,YAAY,KAAK,EAAE,IAAI,GAAG;;;UAG3D,UAAU,oBAAoB,SAAS,kBAAkB,KAAK,EAAE,IAAI,GAAG;;UAEvE,iBAAiB,SAAS,SAAS,IAAI,UAAU,UAAU,QAAQ,IAAI,EACtE,KAAK,SAAS,8BAA8B,KAAK,aAAY,EAC7D,KAAK,YAAY,EAAE;UACpB,UAAU,mBAAmB,SAAS,iBAAiB,KAAK,EAAE,IAAI,GAAG;;;;AAI/E"}
1
+ {"version":3,"file":"template.mjs","names":[],"sources":["../../../../src/middlewares/web/utils/template.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport type { TemplateUIOptions } from '@verdaccio/types';\n\nimport type { Manifest } from './manifest';\nimport { getManifestValue } from './manifest';\n\nconst debug = buildDebug('verdaccio:web:render:template');\n\nexport type Template = {\n manifest: Manifest;\n options: TemplateUIOptions;\n metaScripts?: string[];\n scriptsBodyAfter?: string[];\n scriptsBodyBefore?: string[];\n};\n\nexport interface AssetManifest {\n [key: string]: string;\n}\n\nexport default function renderTemplate(template: Template, manifest: AssetManifest) {\n debug('template %o', template);\n debug('manifest %o', manifest);\n\n return `\n <!DOCTYPE html>\n <html lang=\"en-us\">\n <head>\n <meta charset=\"utf-8\">\n <base href=\"${template?.options.base}\">\n <title>${template?.options?.title ?? ''}</title>\n <link rel=\"icon\" href=\"${template?.options.base}-/static/favicon.ico\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script src=\"${template?.options.base}-/static/ui-options.js\"></script>\n ${\n template.manifest.css?.length\n ? getManifestValue(template.manifest.css, manifest, template?.options.base)\n .map((item) => `<link rel=\"stylesheet\" href=\"${item}\">`)\n .join('\\n ')\n : ''\n }\n ${template?.metaScripts ? template.metaScripts.join('') : ''}\n </head>\n <body class=\"body\">\n ${template?.scriptsBodyBefore ? template.scriptsBodyBefore.join('') : ''}\n <div id=\"root\"></div>\n ${getManifestValue(template.manifest.js, manifest, template?.options.base)\n .map((item) => `<script type=\"module\" src=\"${item}\"></script>`)\n .join(`\\n `)}\n ${template?.scriptsBodyAfter ? template.scriptsBodyAfter.join('') : ''}\n </body>\n </html>\n `;\n}\n"],"mappings":";;;AAOA,IAAM,QAAQ,WAAW,+BAA+B;AAcxD,SAAwB,eAAe,UAAoB,UAAyB;CAClF,MAAM,eAAe,QAAQ;CAC7B,MAAM,eAAe,QAAQ;CAE7B,OAAO;;;;;sBAKa,UAAU,QAAQ,KAAK;iBAC5B,UAAU,SAAS,SAAS,GAAG;iCACf,UAAU,QAAQ,KAAK;;uBAEjC,UAAU,QAAQ,KAAK;UAEpC,SAAS,SAAS,KAAK,SACnB,iBAAiB,SAAS,SAAS,KAAK,UAAU,UAAU,QAAQ,IAAI,CAAC,CACtE,KAAK,SAAS,gCAAgC,KAAK,GAAG,CAAC,CACvD,KAAK,YAAY,IACpB,GACL;UACC,UAAU,cAAc,SAAS,YAAY,KAAK,EAAE,IAAI,GAAG;;;UAG3D,UAAU,oBAAoB,SAAS,kBAAkB,KAAK,EAAE,IAAI,GAAG;;UAEvE,iBAAiB,SAAS,SAAS,IAAI,UAAU,UAAU,QAAQ,IAAI,CAAC,CACvE,KAAK,SAAS,8BAA8B,KAAK,aAAY,CAAC,CAC9D,KAAK,YAAY,EAAE;UACpB,UAAU,mBAAmB,SAAS,iBAAiB,KAAK,EAAE,IAAI,GAAG;;;;AAI/E"}
@@ -1 +1 @@
1
- {"version":3,"file":"ui-options.js","names":[],"sources":["../../../../src/middlewares/web/utils/ui-options.ts"],"sourcesContent":["import type { Response } from 'express';\nimport path from 'node:path';\nimport { URL } from 'node:url';\n\nimport { WEB_TITLE } from '@verdaccio/config';\nimport type { ConfigYaml, TemplateUIOptions } from '@verdaccio/types';\nimport { type RequestOptions, getPublicUrl, isURLhasValidProtocol } from '@verdaccio/url';\n\nimport { hasLogin, validatePrimaryColor } from './web-utils';\n\nconst DEFAULT_LANGUAGE = 'en-US';\n\nfunction resolveLogo(\n logo: string | undefined,\n url_prefix: string | undefined,\n requestOptions: RequestOptions\n) {\n if (typeof logo !== 'string') {\n return '';\n }\n const isLocalFile = logo && !isURLhasValidProtocol(logo);\n\n if (isLocalFile) {\n return `${getPublicUrl(url_prefix, requestOptions)}-/static/${path.basename(logo)}`;\n } else if (isURLhasValidProtocol(logo)) {\n return logo;\n } else {\n return '';\n }\n}\n\nexport function getUIOptions(\n config: ConfigYaml,\n requestOptions: RequestOptions,\n res: Response\n): TemplateUIOptions {\n const { url_prefix } = config;\n const base = getPublicUrl(config?.url_prefix, requestOptions);\n const basename = URL.canParse(base) ? new URL(base).pathname : base;\n const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;\n const hideDeprecatedVersions = config?.web?.hideDeprecatedVersions ?? false;\n const darkMode = config?.web?.darkMode ?? false;\n const title = config?.web?.title ?? WEB_TITLE;\n const login = hasLogin(config);\n const scope = config?.web?.scope ?? '';\n const favicon = resolveLogo(config?.web?.favicon, config?.url_prefix, requestOptions);\n const logo = resolveLogo(config?.web?.logo, config?.url_prefix, requestOptions);\n const logoDark = resolveLogo(config?.web?.logoDark, config?.url_prefix, requestOptions);\n const pkgManagers = config?.web?.pkgManagers ?? ['yarn', 'pnpm', 'npm'];\n const version = res.locals.app_version ?? '';\n const flags = {\n ...config.flags,\n // legacy from 5.x\n ...config.experiments,\n };\n const primaryColor =\n validatePrimaryColor(config?.web?.primary_color ?? config?.web?.primaryColor) ?? '#4b5e40';\n const {\n showInfo,\n showSettings,\n showThemeSwitch,\n showFooter,\n showSearch,\n showDownloadTarball,\n showRaw,\n showUplinks,\n } = Object.assign({}, config?.web);\n\n return {\n showInfo,\n showSettings,\n showThemeSwitch,\n showFooter,\n showSearch,\n showDownloadTarball,\n showRaw,\n showUplinks,\n darkMode,\n url_prefix,\n basename,\n base,\n primaryColor,\n version,\n logo,\n logoDark,\n favicon,\n flags,\n login,\n pkgManagers,\n title,\n scope,\n language,\n hideDeprecatedVersions,\n };\n}\n"],"mappings":";;;;;;;;AAUA,IAAM,mBAAmB;AAEzB,SAAS,YACP,MACA,YACA,gBACA;CACA,IAAI,OAAO,SAAS,UAClB,OAAO;CAIT,IAFoB,QAAQ,EAAA,GAAA,eAAA,uBAAuB,IAAI,GAGrD,OAAO,IAAA,GAAA,eAAA,cAAgB,YAAY,cAAc,EAAE,WAAW,UAAA,QAAK,SAAS,IAAI;MAC3E,KAAA,GAAA,eAAA,uBAA0B,IAAI,GACnC,OAAO;MAEP,OAAO;AAEX;AAEA,SAAgB,aACd,QACA,gBACA,KACmB;CACnB,MAAM,EAAE,eAAe;CACvB,MAAM,QAAA,GAAA,eAAA,cAAoB,QAAQ,YAAY,cAAc;CAC5D,MAAM,WAAW,SAAA,IAAI,SAAS,IAAI,IAAI,IAAI,SAAA,IAAI,IAAI,EAAE,WAAW;CAC/D,MAAM,WAAW,QAAQ,MAAM,OAAO;CACtC,MAAM,yBAAyB,QAAQ,KAAK,0BAA0B;CACtE,MAAM,WAAW,QAAQ,KAAK,YAAY;CAC1C,MAAM,QAAQ,QAAQ,KAAK,SAAS,kBAAA;CACpC,MAAM,QAAQ,kBAAA,SAAS,MAAM;CAC7B,MAAM,QAAQ,QAAQ,KAAK,SAAS;CACpC,MAAM,UAAU,YAAY,QAAQ,KAAK,SAAS,QAAQ,YAAY,cAAc;CACpF,MAAM,OAAO,YAAY,QAAQ,KAAK,MAAM,QAAQ,YAAY,cAAc;CAC9E,MAAM,WAAW,YAAY,QAAQ,KAAK,UAAU,QAAQ,YAAY,cAAc;CACtF,MAAM,cAAc,QAAQ,KAAK,eAAe;EAAC;EAAQ;EAAQ;CAAK;CACtE,MAAM,UAAU,IAAI,OAAO,eAAe;CAC1C,MAAM,QAAQ;EACZ,GAAG,OAAO;EAEV,GAAG,OAAO;CACZ;CACA,MAAM,eACJ,kBAAA,qBAAqB,QAAQ,KAAK,iBAAiB,QAAQ,KAAK,YAAY,KAAK;CACnF,MAAM,EACJ,UACA,cACA,iBACA,YACA,YACA,qBACA,SACA,gBACE,OAAO,OAAO,CAAC,GAAG,QAAQ,GAAG;CAEjC,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
1
+ {"version":3,"file":"ui-options.js","names":[],"sources":["../../../../src/middlewares/web/utils/ui-options.ts"],"sourcesContent":["import type { Response } from 'express';\nimport path from 'node:path';\nimport { URL } from 'node:url';\n\nimport { WEB_TITLE } from '@verdaccio/config';\nimport type { ConfigYaml, TemplateUIOptions } from '@verdaccio/types';\nimport { type RequestOptions, getPublicUrl, isURLhasValidProtocol } from '@verdaccio/url';\n\nimport { hasLogin, validatePrimaryColor } from './web-utils';\n\nconst DEFAULT_LANGUAGE = 'en-US';\n\nfunction resolveLogo(\n logo: string | undefined,\n url_prefix: string | undefined,\n requestOptions: RequestOptions\n) {\n if (typeof logo !== 'string') {\n return '';\n }\n const isLocalFile = logo && !isURLhasValidProtocol(logo);\n\n if (isLocalFile) {\n return `${getPublicUrl(url_prefix, requestOptions)}-/static/${path.basename(logo)}`;\n } else if (isURLhasValidProtocol(logo)) {\n return logo;\n } else {\n return '';\n }\n}\n\nexport function getUIOptions(\n config: ConfigYaml,\n requestOptions: RequestOptions,\n res: Response\n): TemplateUIOptions {\n const { url_prefix } = config;\n const base = getPublicUrl(config?.url_prefix, requestOptions);\n const basename = URL.canParse(base) ? new URL(base).pathname : base;\n const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;\n const hideDeprecatedVersions = config?.web?.hideDeprecatedVersions ?? false;\n const darkMode = config?.web?.darkMode ?? false;\n const title = config?.web?.title ?? WEB_TITLE;\n const login = hasLogin(config);\n const scope = config?.web?.scope ?? '';\n const favicon = resolveLogo(config?.web?.favicon, config?.url_prefix, requestOptions);\n const logo = resolveLogo(config?.web?.logo, config?.url_prefix, requestOptions);\n const logoDark = resolveLogo(config?.web?.logoDark, config?.url_prefix, requestOptions);\n const pkgManagers = config?.web?.pkgManagers ?? ['yarn', 'pnpm', 'npm'];\n const version = res.locals.app_version ?? '';\n const flags = {\n ...config.flags,\n // legacy from 5.x\n ...config.experiments,\n };\n const primaryColor =\n validatePrimaryColor(config?.web?.primary_color ?? config?.web?.primaryColor) ?? '#4b5e40';\n const {\n showInfo,\n showSettings,\n showThemeSwitch,\n showFooter,\n showSearch,\n showDownloadTarball,\n showRaw,\n showUplinks,\n } = Object.assign({}, config?.web);\n\n return {\n showInfo,\n showSettings,\n showThemeSwitch,\n showFooter,\n showSearch,\n showDownloadTarball,\n showRaw,\n showUplinks,\n darkMode,\n url_prefix,\n basename,\n base,\n primaryColor,\n version,\n logo,\n logoDark,\n favicon,\n flags,\n login,\n pkgManagers,\n title,\n scope,\n language,\n hideDeprecatedVersions,\n };\n}\n"],"mappings":";;;;;;;;AAUA,IAAM,mBAAmB;AAEzB,SAAS,YACP,MACA,YACA,gBACA;CACA,IAAI,OAAO,SAAS,UAClB,OAAO;CAIT,IAFoB,QAAQ,EAAA,GAAA,eAAA,sBAAA,CAAuB,IAAI,GAGrD,OAAO,IAAA,GAAA,eAAA,aAAA,CAAgB,YAAY,cAAc,EAAE,WAAW,UAAA,QAAK,SAAS,IAAI;MAC3E,KAAA,GAAA,eAAA,sBAAA,CAA0B,IAAI,GACnC,OAAO;MAEP,OAAO;AAEX;AAEA,SAAgB,aACd,QACA,gBACA,KACmB;CACnB,MAAM,EAAE,eAAe;CACvB,MAAM,QAAA,GAAA,eAAA,aAAA,CAAoB,QAAQ,YAAY,cAAc;CAC5D,MAAM,WAAW,SAAA,IAAI,SAAS,IAAI,IAAI,IAAI,SAAA,IAAI,IAAI,CAAC,CAAC,WAAW;CAC/D,MAAM,WAAW,QAAQ,MAAM,OAAO;CACtC,MAAM,yBAAyB,QAAQ,KAAK,0BAA0B;CACtE,MAAM,WAAW,QAAQ,KAAK,YAAY;CAC1C,MAAM,QAAQ,QAAQ,KAAK,SAAS,kBAAA;CACpC,MAAM,QAAQ,kBAAA,SAAS,MAAM;CAC7B,MAAM,QAAQ,QAAQ,KAAK,SAAS;CACpC,MAAM,UAAU,YAAY,QAAQ,KAAK,SAAS,QAAQ,YAAY,cAAc;CACpF,MAAM,OAAO,YAAY,QAAQ,KAAK,MAAM,QAAQ,YAAY,cAAc;CAC9E,MAAM,WAAW,YAAY,QAAQ,KAAK,UAAU,QAAQ,YAAY,cAAc;CACtF,MAAM,cAAc,QAAQ,KAAK,eAAe;EAAC;EAAQ;EAAQ;CAAK;CACtE,MAAM,UAAU,IAAI,OAAO,eAAe;CAC1C,MAAM,QAAQ;EACZ,GAAG,OAAO;EAEV,GAAG,OAAO;CACZ;CACA,MAAM,eACJ,kBAAA,qBAAqB,QAAQ,KAAK,iBAAiB,QAAQ,KAAK,YAAY,KAAK;CACnF,MAAM,EACJ,UACA,cACA,iBACA,YACA,YACA,qBACA,SACA,gBACE,OAAO,OAAO,CAAC,GAAG,QAAQ,GAAG;CAEjC,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"ui-options.mjs","names":[],"sources":["../../../../src/middlewares/web/utils/ui-options.ts"],"sourcesContent":["import type { Response } from 'express';\nimport path from 'node:path';\nimport { URL } from 'node:url';\n\nimport { WEB_TITLE } from '@verdaccio/config';\nimport type { ConfigYaml, TemplateUIOptions } from '@verdaccio/types';\nimport { type RequestOptions, getPublicUrl, isURLhasValidProtocol } from '@verdaccio/url';\n\nimport { hasLogin, validatePrimaryColor } from './web-utils';\n\nconst DEFAULT_LANGUAGE = 'en-US';\n\nfunction resolveLogo(\n logo: string | undefined,\n url_prefix: string | undefined,\n requestOptions: RequestOptions\n) {\n if (typeof logo !== 'string') {\n return '';\n }\n const isLocalFile = logo && !isURLhasValidProtocol(logo);\n\n if (isLocalFile) {\n return `${getPublicUrl(url_prefix, requestOptions)}-/static/${path.basename(logo)}`;\n } else if (isURLhasValidProtocol(logo)) {\n return logo;\n } else {\n return '';\n }\n}\n\nexport function getUIOptions(\n config: ConfigYaml,\n requestOptions: RequestOptions,\n res: Response\n): TemplateUIOptions {\n const { url_prefix } = config;\n const base = getPublicUrl(config?.url_prefix, requestOptions);\n const basename = URL.canParse(base) ? new URL(base).pathname : base;\n const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;\n const hideDeprecatedVersions = config?.web?.hideDeprecatedVersions ?? false;\n const darkMode = config?.web?.darkMode ?? false;\n const title = config?.web?.title ?? WEB_TITLE;\n const login = hasLogin(config);\n const scope = config?.web?.scope ?? '';\n const favicon = resolveLogo(config?.web?.favicon, config?.url_prefix, requestOptions);\n const logo = resolveLogo(config?.web?.logo, config?.url_prefix, requestOptions);\n const logoDark = resolveLogo(config?.web?.logoDark, config?.url_prefix, requestOptions);\n const pkgManagers = config?.web?.pkgManagers ?? ['yarn', 'pnpm', 'npm'];\n const version = res.locals.app_version ?? '';\n const flags = {\n ...config.flags,\n // legacy from 5.x\n ...config.experiments,\n };\n const primaryColor =\n validatePrimaryColor(config?.web?.primary_color ?? config?.web?.primaryColor) ?? '#4b5e40';\n const {\n showInfo,\n showSettings,\n showThemeSwitch,\n showFooter,\n showSearch,\n showDownloadTarball,\n showRaw,\n showUplinks,\n } = Object.assign({}, config?.web);\n\n return {\n showInfo,\n showSettings,\n showThemeSwitch,\n showFooter,\n showSearch,\n showDownloadTarball,\n showRaw,\n showUplinks,\n darkMode,\n url_prefix,\n basename,\n base,\n primaryColor,\n version,\n logo,\n logoDark,\n favicon,\n flags,\n login,\n pkgManagers,\n title,\n scope,\n language,\n hideDeprecatedVersions,\n };\n}\n"],"mappings":";;;;;;AAUA,IAAM,mBAAmB;AAEzB,SAAS,YACP,MACA,YACA,gBACA;CACA,IAAI,OAAO,SAAS,UAClB,OAAO;CAIT,IAFoB,QAAQ,CAAC,sBAAsB,IAAI,GAGrD,OAAO,GAAG,aAAa,YAAY,cAAc,EAAE,WAAW,KAAK,SAAS,IAAI;MAC3E,IAAI,sBAAsB,IAAI,GACnC,OAAO;MAEP,OAAO;AAEX;AAEA,SAAgB,aACd,QACA,gBACA,KACmB;CACnB,MAAM,EAAE,eAAe;CACvB,MAAM,OAAO,aAAa,QAAQ,YAAY,cAAc;CAC5D,MAAM,WAAW,IAAI,SAAS,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,WAAW;CAC/D,MAAM,WAAW,QAAQ,MAAM,OAAO;CACtC,MAAM,yBAAyB,QAAQ,KAAK,0BAA0B;CACtE,MAAM,WAAW,QAAQ,KAAK,YAAY;CAC1C,MAAM,QAAQ,QAAQ,KAAK,SAAS;CACpC,MAAM,QAAQ,SAAS,MAAM;CAC7B,MAAM,QAAQ,QAAQ,KAAK,SAAS;CACpC,MAAM,UAAU,YAAY,QAAQ,KAAK,SAAS,QAAQ,YAAY,cAAc;CACpF,MAAM,OAAO,YAAY,QAAQ,KAAK,MAAM,QAAQ,YAAY,cAAc;CAC9E,MAAM,WAAW,YAAY,QAAQ,KAAK,UAAU,QAAQ,YAAY,cAAc;CACtF,MAAM,cAAc,QAAQ,KAAK,eAAe;EAAC;EAAQ;EAAQ;CAAK;CACtE,MAAM,UAAU,IAAI,OAAO,eAAe;CAC1C,MAAM,QAAQ;EACZ,GAAG,OAAO;EAEV,GAAG,OAAO;CACZ;CACA,MAAM,eACJ,qBAAqB,QAAQ,KAAK,iBAAiB,QAAQ,KAAK,YAAY,KAAK;CACnF,MAAM,EACJ,UACA,cACA,iBACA,YACA,YACA,qBACA,SACA,gBACE,OAAO,OAAO,CAAC,GAAG,QAAQ,GAAG;CAEjC,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
1
+ {"version":3,"file":"ui-options.mjs","names":[],"sources":["../../../../src/middlewares/web/utils/ui-options.ts"],"sourcesContent":["import type { Response } from 'express';\nimport path from 'node:path';\nimport { URL } from 'node:url';\n\nimport { WEB_TITLE } from '@verdaccio/config';\nimport type { ConfigYaml, TemplateUIOptions } from '@verdaccio/types';\nimport { type RequestOptions, getPublicUrl, isURLhasValidProtocol } from '@verdaccio/url';\n\nimport { hasLogin, validatePrimaryColor } from './web-utils';\n\nconst DEFAULT_LANGUAGE = 'en-US';\n\nfunction resolveLogo(\n logo: string | undefined,\n url_prefix: string | undefined,\n requestOptions: RequestOptions\n) {\n if (typeof logo !== 'string') {\n return '';\n }\n const isLocalFile = logo && !isURLhasValidProtocol(logo);\n\n if (isLocalFile) {\n return `${getPublicUrl(url_prefix, requestOptions)}-/static/${path.basename(logo)}`;\n } else if (isURLhasValidProtocol(logo)) {\n return logo;\n } else {\n return '';\n }\n}\n\nexport function getUIOptions(\n config: ConfigYaml,\n requestOptions: RequestOptions,\n res: Response\n): TemplateUIOptions {\n const { url_prefix } = config;\n const base = getPublicUrl(config?.url_prefix, requestOptions);\n const basename = URL.canParse(base) ? new URL(base).pathname : base;\n const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;\n const hideDeprecatedVersions = config?.web?.hideDeprecatedVersions ?? false;\n const darkMode = config?.web?.darkMode ?? false;\n const title = config?.web?.title ?? WEB_TITLE;\n const login = hasLogin(config);\n const scope = config?.web?.scope ?? '';\n const favicon = resolveLogo(config?.web?.favicon, config?.url_prefix, requestOptions);\n const logo = resolveLogo(config?.web?.logo, config?.url_prefix, requestOptions);\n const logoDark = resolveLogo(config?.web?.logoDark, config?.url_prefix, requestOptions);\n const pkgManagers = config?.web?.pkgManagers ?? ['yarn', 'pnpm', 'npm'];\n const version = res.locals.app_version ?? '';\n const flags = {\n ...config.flags,\n // legacy from 5.x\n ...config.experiments,\n };\n const primaryColor =\n validatePrimaryColor(config?.web?.primary_color ?? config?.web?.primaryColor) ?? '#4b5e40';\n const {\n showInfo,\n showSettings,\n showThemeSwitch,\n showFooter,\n showSearch,\n showDownloadTarball,\n showRaw,\n showUplinks,\n } = Object.assign({}, config?.web);\n\n return {\n showInfo,\n showSettings,\n showThemeSwitch,\n showFooter,\n showSearch,\n showDownloadTarball,\n showRaw,\n showUplinks,\n darkMode,\n url_prefix,\n basename,\n base,\n primaryColor,\n version,\n logo,\n logoDark,\n favicon,\n flags,\n login,\n pkgManagers,\n title,\n scope,\n language,\n hideDeprecatedVersions,\n };\n}\n"],"mappings":";;;;;;AAUA,IAAM,mBAAmB;AAEzB,SAAS,YACP,MACA,YACA,gBACA;CACA,IAAI,OAAO,SAAS,UAClB,OAAO;CAIT,IAFoB,QAAQ,CAAC,sBAAsB,IAAI,GAGrD,OAAO,GAAG,aAAa,YAAY,cAAc,EAAE,WAAW,KAAK,SAAS,IAAI;MAC3E,IAAI,sBAAsB,IAAI,GACnC,OAAO;MAEP,OAAO;AAEX;AAEA,SAAgB,aACd,QACA,gBACA,KACmB;CACnB,MAAM,EAAE,eAAe;CACvB,MAAM,OAAO,aAAa,QAAQ,YAAY,cAAc;CAC5D,MAAM,WAAW,IAAI,SAAS,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,WAAW;CAC/D,MAAM,WAAW,QAAQ,MAAM,OAAO;CACtC,MAAM,yBAAyB,QAAQ,KAAK,0BAA0B;CACtE,MAAM,WAAW,QAAQ,KAAK,YAAY;CAC1C,MAAM,QAAQ,QAAQ,KAAK,SAAS;CACpC,MAAM,QAAQ,SAAS,MAAM;CAC7B,MAAM,QAAQ,QAAQ,KAAK,SAAS;CACpC,MAAM,UAAU,YAAY,QAAQ,KAAK,SAAS,QAAQ,YAAY,cAAc;CACpF,MAAM,OAAO,YAAY,QAAQ,KAAK,MAAM,QAAQ,YAAY,cAAc;CAC9E,MAAM,WAAW,YAAY,QAAQ,KAAK,UAAU,QAAQ,YAAY,cAAc;CACtF,MAAM,cAAc,QAAQ,KAAK,eAAe;EAAC;EAAQ;EAAQ;CAAK;CACtE,MAAM,UAAU,IAAI,OAAO,eAAe;CAC1C,MAAM,QAAQ;EACZ,GAAG,OAAO;EAEV,GAAG,OAAO;CACZ;CACA,MAAM,eACJ,qBAAqB,QAAQ,KAAK,iBAAiB,QAAQ,KAAK,YAAY,KAAK;CACnF,MAAM,EACJ,UACA,cACA,iBACA,YACA,YACA,qBACA,SACA,gBACE,OAAO,OAAO,CAAC,GAAG,QAAQ,GAAG;CAEjC,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"web-utils.js","names":[],"sources":["../../../../src/middlewares/web/utils/web-utils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport _ from 'lodash';\n\nconst debug = buildDebug('verdaccio:web:middlwares');\n\nexport function validatePrimaryColor(primaryColor) {\n const isHex = /^#([0-9A-F]{3}){1,2}$/i.test(primaryColor);\n if (!isHex) {\n debug('invalid primary color %o', primaryColor);\n return;\n }\n\n return primaryColor;\n}\n\nexport function hasLogin(config: any) {\n return _.isNil(config?.web?.login) || config?.web?.login === true;\n}\n"],"mappings":";;;;;;AAGA,IAAM,WAAA,GAAA,MAAA,SAAmB,0BAA0B;AAEnD,SAAgB,qBAAqB,cAAc;CAEjD,IAAI,CADU,yBAAyB,KAAK,YACvC,GAAO;EACV,QAAM,4BAA4B,YAAY;EAC9C;CACF;CAEA,OAAO;AACT;AAEA,SAAgB,SAAS,QAAa;CACpC,OAAO,OAAA,QAAE,MAAM,QAAQ,KAAK,KAAK,KAAK,QAAQ,KAAK,UAAU;AAC/D"}
1
+ {"version":3,"file":"web-utils.js","names":[],"sources":["../../../../src/middlewares/web/utils/web-utils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport _ from 'lodash';\n\nconst debug = buildDebug('verdaccio:web:middlwares');\n\nexport function validatePrimaryColor(primaryColor) {\n const isHex = /^#([0-9A-F]{3}){1,2}$/i.test(primaryColor);\n if (!isHex) {\n debug('invalid primary color %o', primaryColor);\n return;\n }\n\n return primaryColor;\n}\n\nexport function hasLogin(config: any) {\n return _.isNil(config?.web?.login) || config?.web?.login === true;\n}\n"],"mappings":";;;;;;AAGA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,0BAA0B;AAEnD,SAAgB,qBAAqB,cAAc;CAEjD,IAAI,CADU,yBAAyB,KAAK,YACvC,GAAO;EACV,QAAM,4BAA4B,YAAY;EAC9C;CACF;CAEA,OAAO;AACT;AAEA,SAAgB,SAAS,QAAa;CACpC,OAAO,OAAA,QAAE,MAAM,QAAQ,KAAK,KAAK,KAAK,QAAQ,KAAK,UAAU;AAC/D"}
@@ -1 +1 @@
1
- {"version":3,"file":"web-api.js","names":[],"sources":["../../../src/middlewares/web/web-api.ts"],"sourcesContent":["import type { RequestHandler } from 'express';\nimport express, { Router } from 'express';\n\nimport { validateName, validatePackage } from '../validation';\nimport { setSecurityWebHeaders } from './security';\n\nexport function webAPIMiddleware(\n tokenMiddleware: RequestHandler,\n webEndpointsApi: RequestHandler\n): Router {\n const route = Router();\n // validate all of these params as a package name\n // this might be too harsh, so ask if it causes trouble=\n route.param('package', validatePackage);\n route.param('filename', validateName);\n route.param('version', validateName);\n route.use(express.urlencoded({ extended: false }));\n route.use(setSecurityWebHeaders);\n\n if (typeof tokenMiddleware === 'function') {\n route.use(tokenMiddleware);\n }\n\n if (typeof webEndpointsApi === 'function') {\n route.use(webEndpointsApi);\n }\n\n return route;\n}\n"],"mappings":";;;;;;AAMA,SAAgB,iBACd,iBACA,iBACQ;CACR,MAAM,SAAA,GAAA,QAAA,QAAe;CAGrB,MAAM,MAAM,WAAW,mBAAA,eAAe;CACtC,MAAM,MAAM,YAAY,mBAAA,YAAY;CACpC,MAAM,MAAM,WAAW,mBAAA,YAAY;CACnC,MAAM,IAAI,QAAA,QAAQ,WAAW,EAAE,UAAU,MAAM,CAAC,CAAC;CACjD,MAAM,IAAI,iBAAA,qBAAqB;CAE/B,IAAI,OAAO,oBAAoB,YAC7B,MAAM,IAAI,eAAe;CAG3B,IAAI,OAAO,oBAAoB,YAC7B,MAAM,IAAI,eAAe;CAG3B,OAAO;AACT"}
1
+ {"version":3,"file":"web-api.js","names":[],"sources":["../../../src/middlewares/web/web-api.ts"],"sourcesContent":["import type { RequestHandler } from 'express';\nimport express, { Router } from 'express';\n\nimport { validateName, validatePackage } from '../validation';\nimport { setSecurityWebHeaders } from './security';\n\nexport function webAPIMiddleware(\n tokenMiddleware: RequestHandler,\n webEndpointsApi: RequestHandler\n): Router {\n const route = Router();\n // validate all of these params as a package name\n // this might be too harsh, so ask if it causes trouble=\n route.param('package', validatePackage);\n route.param('filename', validateName);\n route.param('version', validateName);\n route.use(express.urlencoded({ extended: false }));\n route.use(setSecurityWebHeaders);\n\n if (typeof tokenMiddleware === 'function') {\n route.use(tokenMiddleware);\n }\n\n if (typeof webEndpointsApi === 'function') {\n route.use(webEndpointsApi);\n }\n\n return route;\n}\n"],"mappings":";;;;;;AAMA,SAAgB,iBACd,iBACA,iBACQ;CACR,MAAM,SAAA,GAAA,QAAA,OAAA,CAAe;CAGrB,MAAM,MAAM,WAAW,mBAAA,eAAe;CACtC,MAAM,MAAM,YAAY,mBAAA,YAAY;CACpC,MAAM,MAAM,WAAW,mBAAA,YAAY;CACnC,MAAM,IAAI,QAAA,QAAQ,WAAW,EAAE,UAAU,MAAM,CAAC,CAAC;CACjD,MAAM,IAAI,iBAAA,qBAAqB;CAE/B,IAAI,OAAO,oBAAoB,YAC7B,MAAM,IAAI,eAAe;CAG3B,IAAI,OAAO,oBAAoB,YAC7B,MAAM,IAAI,eAAe;CAG3B,OAAO;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/middleware",
3
- "version": "8.1.1",
3
+ "version": "8.1.3",
4
4
  "description": "Verdaccio Express Middleware",
5
5
  "keywords": [
6
6
  "enterprise",
@@ -48,9 +48,9 @@
48
48
  "./build/*": "./build/*"
49
49
  },
50
50
  "dependencies": {
51
- "@verdaccio/config": "8.2.1",
52
- "@verdaccio/core": "8.2.1",
53
- "@verdaccio/url": "13.1.1",
51
+ "@verdaccio/config": "8.3.0",
52
+ "@verdaccio/core": "8.3.0",
53
+ "@verdaccio/url": "13.1.3",
54
54
  "debug": "4.4.3",
55
55
  "express": "4.22.2",
56
56
  "express-rate-limit": "5.5.1",
@@ -58,13 +58,13 @@
58
58
  "lru-cache": "7.18.3"
59
59
  },
60
60
  "devDependencies": {
61
- "@verdaccio/logger": "8.1.1",
62
- "@verdaccio/types": "13.0.5",
61
+ "@verdaccio/logger": "8.1.3",
62
+ "@verdaccio/types": "13.0.6",
63
63
  "http-errors": "2.0.1",
64
64
  "jsdom": "26.1.0",
65
65
  "supertest": "7.1.4",
66
- "vite": "8.0.16",
67
- "vitest": "4.1.2"
66
+ "vite": "8.1.5",
67
+ "vitest": "4.1.10"
68
68
  },
69
69
  "engines": {
70
70
  "node": ">=22"