@verdaccio/middleware 8.0.7 → 8.1.0

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 (119) hide show
  1. package/build/_virtual/_rolldown/runtime.js +23 -0
  2. package/build/index.js +62 -229
  3. package/build/index.mjs +23 -0
  4. package/build/middlewares/allow.js +42 -50
  5. package/build/middlewares/allow.js.map +1 -1
  6. package/build/middlewares/allow.mjs +44 -0
  7. package/build/middlewares/allow.mjs.map +1 -0
  8. package/build/middlewares/antiLoop.js +21 -40
  9. package/build/middlewares/antiLoop.js.map +1 -1
  10. package/build/middlewares/antiLoop.mjs +25 -0
  11. package/build/middlewares/antiLoop.mjs.map +1 -0
  12. package/build/middlewares/api_urls.js +66 -59
  13. package/build/middlewares/api_urls.js.map +1 -1
  14. package/build/middlewares/api_urls.mjs +59 -0
  15. package/build/middlewares/api_urls.mjs.map +1 -0
  16. package/build/middlewares/body-parser.js +24 -32
  17. package/build/middlewares/body-parser.js.map +1 -1
  18. package/build/middlewares/body-parser.mjs +28 -0
  19. package/build/middlewares/body-parser.mjs.map +1 -0
  20. package/build/middlewares/encode-pkg.js +20 -36
  21. package/build/middlewares/encode-pkg.js.map +1 -1
  22. package/build/middlewares/encode-pkg.mjs +22 -0
  23. package/build/middlewares/encode-pkg.mjs.map +1 -0
  24. package/build/middlewares/error.js +53 -71
  25. package/build/middlewares/error.js.map +1 -1
  26. package/build/middlewares/error.mjs +53 -0
  27. package/build/middlewares/error.mjs.map +1 -0
  28. package/build/middlewares/final.js +46 -57
  29. package/build/middlewares/final.js.map +1 -1
  30. package/build/middlewares/final.mjs +46 -0
  31. package/build/middlewares/final.mjs.map +1 -0
  32. package/build/middlewares/json.js +7 -11
  33. package/build/middlewares/json.js.map +1 -1
  34. package/build/middlewares/json.mjs +10 -0
  35. package/build/middlewares/json.mjs.map +1 -0
  36. package/build/middlewares/log.js +73 -94
  37. package/build/middlewares/log.js.map +1 -1
  38. package/build/middlewares/log.mjs +71 -0
  39. package/build/middlewares/log.mjs.map +1 -0
  40. package/build/middlewares/make-url-relative.js +26 -41
  41. package/build/middlewares/make-url-relative.js.map +1 -1
  42. package/build/middlewares/make-url-relative.mjs +28 -0
  43. package/build/middlewares/make-url-relative.mjs.map +1 -0
  44. package/build/middlewares/match.js +8 -13
  45. package/build/middlewares/match.js.map +1 -1
  46. package/build/middlewares/match.mjs +11 -0
  47. package/build/middlewares/match.mjs.map +1 -0
  48. package/build/middlewares/media.js +14 -19
  49. package/build/middlewares/media.js.map +1 -1
  50. package/build/middlewares/media.mjs +17 -0
  51. package/build/middlewares/media.mjs.map +1 -0
  52. package/build/middlewares/rate-limit.js +8 -10
  53. package/build/middlewares/rate-limit.js.map +1 -1
  54. package/build/middlewares/rate-limit.mjs +9 -0
  55. package/build/middlewares/rate-limit.mjs.map +1 -0
  56. package/build/middlewares/request-options.js +18 -27
  57. package/build/middlewares/request-options.js.map +1 -1
  58. package/build/middlewares/request-options.mjs +19 -0
  59. package/build/middlewares/request-options.mjs.map +1 -0
  60. package/build/middlewares/token-auth.js +90 -105
  61. package/build/middlewares/token-auth.js.map +1 -1
  62. package/build/middlewares/token-auth.mjs +100 -0
  63. package/build/middlewares/token-auth.mjs.map +1 -0
  64. package/build/middlewares/user-agent.js +10 -12
  65. package/build/middlewares/user-agent.js.map +1 -1
  66. package/build/middlewares/user-agent.mjs +13 -0
  67. package/build/middlewares/user-agent.mjs.map +1 -0
  68. package/build/middlewares/validation.js +10 -18
  69. package/build/middlewares/validation.js.map +1 -1
  70. package/build/middlewares/validation.mjs +14 -0
  71. package/build/middlewares/validation.mjs.map +1 -0
  72. package/build/middlewares/web/index.js +4 -35
  73. package/build/middlewares/web/index.mjs +4 -0
  74. package/build/middlewares/web/render-web.js +86 -113
  75. package/build/middlewares/web/render-web.js.map +1 -1
  76. package/build/middlewares/web/render-web.mjs +85 -0
  77. package/build/middlewares/web/render-web.mjs.map +1 -0
  78. package/build/middlewares/web/security.js +29 -41
  79. package/build/middlewares/web/security.js.map +1 -1
  80. package/build/middlewares/web/security.mjs +30 -0
  81. package/build/middlewares/web/security.mjs.map +1 -0
  82. package/build/middlewares/web/utils/manifest.js +17 -18
  83. package/build/middlewares/web/utils/manifest.js.map +1 -1
  84. package/build/middlewares/web/utils/manifest.mjs +21 -0
  85. package/build/middlewares/web/utils/manifest.mjs.map +1 -0
  86. package/build/middlewares/web/utils/renderHTML.js +46 -50
  87. package/build/middlewares/web/utils/renderHTML.js.map +1 -1
  88. package/build/middlewares/web/utils/renderHTML.mjs +48 -0
  89. package/build/middlewares/web/utils/renderHTML.mjs.map +1 -0
  90. package/build/middlewares/web/utils/template.js +19 -20
  91. package/build/middlewares/web/utils/template.js.map +1 -1
  92. package/build/middlewares/web/utils/template.mjs +33 -0
  93. package/build/middlewares/web/utils/template.mjs.map +1 -0
  94. package/build/middlewares/web/utils/ui-options.js +66 -82
  95. package/build/middlewares/web/utils/ui-options.js.map +1 -1
  96. package/build/middlewares/web/utils/ui-options.mjs +69 -0
  97. package/build/middlewares/web/utils/ui-options.mjs.map +1 -0
  98. package/build/middlewares/web/utils/web-utils.js +17 -18
  99. package/build/middlewares/web/utils/web-utils.js.map +1 -1
  100. package/build/middlewares/web/utils/web-utils.mjs +18 -0
  101. package/build/middlewares/web/utils/web-utils.mjs.map +1 -0
  102. package/build/middlewares/web/web-api.js +18 -27
  103. package/build/middlewares/web/web-api.js.map +1 -1
  104. package/build/middlewares/web/web-api.mjs +19 -0
  105. package/build/middlewares/web/web-api.mjs.map +1 -0
  106. package/build/middlewares/web/web-middleware.d.ts +1 -1
  107. package/build/middlewares/web/web-middleware.js +16 -23
  108. package/build/middlewares/web/web-middleware.js.map +1 -1
  109. package/build/middlewares/web/web-middleware.mjs +16 -0
  110. package/build/middlewares/web/web-middleware.mjs.map +1 -0
  111. package/build/middlewares/web/web-urls.js +28 -29
  112. package/build/middlewares/web/web-urls.js.map +1 -1
  113. package/build/middlewares/web/web-urls.mjs +32 -0
  114. package/build/middlewares/web/web-urls.mjs.map +1 -0
  115. package/package.json +24 -11
  116. package/build/index.js.map +0 -1
  117. package/build/middlewares/web/index.js.map +0 -1
  118. package/build/types.js +0 -6
  119. package/build/types.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"token-auth.js","names":["_core","require","WRITE_METHODS","Set","getClientAddress","req","ipUtils","normalizeAddress","ip","socket","remoteAddress","findToken","tokens","tokenKey","find","key","enforceGeneratedTokenMetadata","storage","logger","_res","next","remoteUser","remote_user","token","user","name","errorUtils","getForbidden","API_ERROR","UNAUTHORIZED_ACCESS","readTokens","warn","isAddressAllowed","cidr","readonly","has","method","error","msg","getInternalError","message"],"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":"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","ignoreList":[]}
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"}
@@ -0,0 +1,100 @@
1
+ import { API_ERROR, errorUtils, ipUtils } from "@verdaccio/core";
2
+ //#region src/middlewares/token-auth.ts
3
+ var WRITE_METHODS = new Set([
4
+ "DELETE",
5
+ "PATCH",
6
+ "POST",
7
+ "PUT"
8
+ ]);
9
+ /**
10
+ * Resolve the client address of an incoming request for CIDR matching.
11
+ *
12
+ * Uses Express' `req.ip`, which already honors the application's `trust proxy`
13
+ * setting (`config.server.trustProxy`): when the operator has declared trusted
14
+ * proxies, `req.ip` is the upstream-most untrusted address parsed from
15
+ * `X-Forwarded-For`; otherwise it is the direct socket peer and the forwarded
16
+ * header is ignored entirely.
17
+ *
18
+ * The middleware must NOT read `X-Forwarded-For` on its own — doing so
19
+ * unconditionally would let any client spoof its address (and bypass a token's
20
+ * CIDR whitelist) simply by sending the header. Falls back to the raw socket
21
+ * address and is normalized (trimmed, IPv4-mapped IPv6 prefix stripped) via
22
+ * {@link ipUtils.normalizeAddress}.
23
+ *
24
+ * @param req the incoming Express request
25
+ * @returns the normalized client address, or `undefined` when none can be determined
26
+ */
27
+ function getClientAddress(req) {
28
+ return ipUtils.normalizeAddress(req.ip || req.socket.remoteAddress);
29
+ }
30
+ /**
31
+ * Find the stored token whose `key` matches the key carried by the request.
32
+ *
33
+ * @param tokens the tokens persisted for the authenticated user
34
+ * @param tokenKey the key extracted from the presented generated token
35
+ * @returns the matching {@link Token}, or `undefined` when it has been revoked / never existed
36
+ */
37
+ function findToken(tokens, tokenKey) {
38
+ return tokens.find(({ key }) => key === tokenKey);
39
+ }
40
+ /**
41
+ * Express middleware that enforces the metadata of npm-style generated tokens
42
+ * (created via `POST /-/npm/v1/tokens`).
43
+ *
44
+ * A generated token embeds a server-issued `key` that is recovered from the
45
+ * verified credentials as `remote_user.token.key`. This middleware looks that
46
+ * key up in storage and rejects the request when the token:
47
+ * - is missing from storage (revoked or never issued);
48
+ * - is used from a client address outside its `cidr` whitelist;
49
+ * - is `readonly` and the request uses a write method (`DELETE`/`PATCH`/`POST`/`PUT`).
50
+ *
51
+ * Requests that do not carry a generated token key (e.g. interactive logins)
52
+ * pass through untouched. It must run after the JWT/auth middleware has
53
+ * populated `remote_user`. Failures fail closed: a storage lookup error yields
54
+ * an internal error rather than allowing the request.
55
+ *
56
+ * @param storage storage exposing {@link TokenReadableStorage.readTokens} to load the user's tokens
57
+ * @param logger logger used to record rejected attempts and lookup failures
58
+ * @returns an Express {@link RequestHandler} that calls `next()` to allow or `next(error)` to reject
59
+ */
60
+ function enforceGeneratedTokenMetadata(storage, logger) {
61
+ return async function(req, _res, next) {
62
+ const remoteUser = req.remote_user;
63
+ const tokenKey = remoteUser?.token?.key;
64
+ if (!tokenKey) return next();
65
+ const user = remoteUser?.name;
66
+ if (typeof user !== "string") return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));
67
+ try {
68
+ const token = findToken(await storage.readTokens({ user }), tokenKey);
69
+ if (!token) {
70
+ logger.warn({
71
+ tokenKey,
72
+ user
73
+ }, "generated token @{tokenKey} for user @{user} is missing");
74
+ return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));
75
+ }
76
+ if (!ipUtils.isAddressAllowed(getClientAddress(req), token.cidr)) {
77
+ logger.warn({
78
+ tokenKey,
79
+ user
80
+ }, "generated token @{tokenKey} for user @{user} was used outside its CIDR whitelist");
81
+ return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));
82
+ }
83
+ if (token.readonly && WRITE_METHODS.has(req.method)) {
84
+ logger.warn({
85
+ tokenKey,
86
+ user
87
+ }, "readonly generated token @{tokenKey} for user @{user} was used for a write request");
88
+ return next(errorUtils.getForbidden(API_ERROR.UNAUTHORIZED_ACCESS));
89
+ }
90
+ return next();
91
+ } catch (error) {
92
+ logger.error({ error: error.msg }, "generated token metadata lookup failed: @{error}");
93
+ return next(errorUtils.getInternalError(error.message));
94
+ }
95
+ };
96
+ }
97
+ //#endregion
98
+ export { enforceGeneratedTokenMetadata };
99
+
100
+ //# sourceMappingURL=token-auth.mjs.map
@@ -0,0 +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,15 +1,13 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.userAgent = userAgent;
7
- var _config = require("@verdaccio/config");
8
- var _core = require("@verdaccio/core");
1
+ let _verdaccio_core = require("@verdaccio/core");
2
+ let _verdaccio_config = require("@verdaccio/config");
3
+ //#region src/middlewares/user-agent.ts
9
4
  function userAgent(config) {
10
- return function (_req, res, next) {
11
- res.setHeader(_core.HEADERS.POWERED_BY, (0, _config.getUserAgent)(config?.user_agent));
12
- next();
13
- };
5
+ return function(_req, res, next) {
6
+ res.setHeader(_verdaccio_core.HEADERS.POWERED_BY, (0, _verdaccio_config.getUserAgent)(config?.user_agent));
7
+ next();
8
+ };
14
9
  }
10
+ //#endregion
11
+ exports.userAgent = userAgent;
12
+
15
13
  //# sourceMappingURL=user-agent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-agent.js","names":["_config","require","_core","userAgent","config","_req","res","next","setHeader","HEADERS","POWERED_BY","getUserAgent","user_agent"],"sources":["../../src/middlewares/user-agent.ts"],"sourcesContent":["import { getUserAgent } from '@verdaccio/config';\nimport { HEADERS } from '@verdaccio/core';\n\nimport 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":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAD,OAAA;AAIO,SAASE,SAASA,CAACC,MAAM,EAAE;EAChC,OAAO,UAAUC,IAAoB,EAAEC,GAAoB,EAAEC,IAAsB,EAAQ;IACzFD,GAAG,CAACE,SAAS,CAACC,aAAO,CAACC,UAAU,EAAE,IAAAC,oBAAY,EAACP,MAAM,EAAEQ,UAAU,CAAC,CAAC;IACnEL,IAAI,CAAC,CAAC;EACR,CAAC;AACH","ignoreList":[]}
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"}
@@ -0,0 +1,13 @@
1
+ import { HEADERS } from "@verdaccio/core";
2
+ import { getUserAgent } from "@verdaccio/config";
3
+ //#region src/middlewares/user-agent.ts
4
+ function userAgent(config) {
5
+ return function(_req, res, next) {
6
+ res.setHeader(HEADERS.POWERED_BY, getUserAgent(config?.user_agent));
7
+ next();
8
+ };
9
+ }
10
+ //#endregion
11
+ export { userAgent };
12
+
13
+ //# sourceMappingURL=user-agent.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-agent.mjs","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,QAAQ,YAAY,aAAa,QAAQ,UAAU,CAAC;EAClE,KAAK;CACP;AACF"}
@@ -1,23 +1,15 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.validateName = validateName;
7
- exports.validatePackage = validatePackage;
8
- var _core = require("@verdaccio/core");
1
+ let _verdaccio_core = require("@verdaccio/core");
2
+ //#region src/middlewares/validation.ts
9
3
  function validateName(_req, _res, next, value, name) {
10
- if (_core.validationUtils.validateName(value)) {
11
- next();
12
- } else {
13
- next(_core.errorUtils.getBadRequest('invalid ' + name));
14
- }
4
+ if (_verdaccio_core.validationUtils.validateName(value)) next();
5
+ else next(_verdaccio_core.errorUtils.getBadRequest("invalid " + name));
15
6
  }
16
7
  function validatePackage(_req, _res, next, value, name) {
17
- if (_core.validationUtils.validatePackage(value)) {
18
- next();
19
- } else {
20
- next(_core.errorUtils.getBadRequest('invalid ' + name));
21
- }
8
+ if (_verdaccio_core.validationUtils.validatePackage(value)) next();
9
+ else next(_verdaccio_core.errorUtils.getBadRequest("invalid " + name));
22
10
  }
11
+ //#endregion
12
+ exports.validateName = validateName;
13
+ exports.validatePackage = validatePackage;
14
+
23
15
  //# sourceMappingURL=validation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","names":["_core","require","validateName","_req","_res","next","value","name","validationUtils","errorUtils","getBadRequest","validatePackage"],"sources":["../../src/middlewares/validation.ts"],"sourcesContent":["import type { NextFunction, Request, Response } from 'express';\n\nimport { errorUtils, validationUtils } from '@verdaccio/core';\n\nexport function validateName(\n _req: Request,\n _res: Response,\n next: NextFunction,\n value: string,\n name: string\n) {\n if (validationUtils.validateName(value)) {\n next();\n } else {\n next(errorUtils.getBadRequest('invalid ' + name));\n }\n}\n\nexport function validatePackage(\n _req: Request,\n _res,\n next: NextFunction,\n value: string,\n name: string\n) {\n if (validationUtils.validatePackage(value)) {\n next();\n } else {\n next(errorUtils.getBadRequest('invalid ' + name));\n }\n}\n"],"mappings":";;;;;;;AAEA,IAAAA,KAAA,GAAAC,OAAA;AAEO,SAASC,YAAYA,CAC1BC,IAAa,EACbC,IAAc,EACdC,IAAkB,EAClBC,KAAa,EACbC,IAAY,EACZ;EACA,IAAIC,qBAAe,CAACN,YAAY,CAACI,KAAK,CAAC,EAAE;IACvCD,IAAI,CAAC,CAAC;EACR,CAAC,MAAM;IACLA,IAAI,CAACI,gBAAU,CAACC,aAAa,CAAC,UAAU,GAAGH,IAAI,CAAC,CAAC;EACnD;AACF;AAEO,SAASI,eAAeA,CAC7BR,IAAa,EACbC,IAAI,EACJC,IAAkB,EAClBC,KAAa,EACbC,IAAY,EACZ;EACA,IAAIC,qBAAe,CAACG,eAAe,CAACL,KAAK,CAAC,EAAE;IAC1CD,IAAI,CAAC,CAAC;EACR,CAAC,MAAM;IACLA,IAAI,CAACI,gBAAU,CAACC,aAAa,CAAC,UAAU,GAAGH,IAAI,CAAC,CAAC;EACnD;AACF","ignoreList":[]}
1
+ {"version":3,"file":"validation.js","names":[],"sources":["../../src/middlewares/validation.ts"],"sourcesContent":["import type { NextFunction, Request, Response } from 'express';\n\nimport { errorUtils, validationUtils } from '@verdaccio/core';\n\nexport function validateName(\n _req: Request,\n _res: Response,\n next: NextFunction,\n value: string,\n name: string\n) {\n if (validationUtils.validateName(value)) {\n next();\n } else {\n next(errorUtils.getBadRequest('invalid ' + name));\n }\n}\n\nexport function validatePackage(\n _req: Request,\n _res,\n next: NextFunction,\n value: string,\n name: string\n) {\n if (validationUtils.validatePackage(value)) {\n next();\n } else {\n next(errorUtils.getBadRequest('invalid ' + name));\n }\n}\n"],"mappings":";;AAIA,SAAgB,aACd,MACA,MACA,MACA,OACA,MACA;CACA,IAAI,gBAAA,gBAAgB,aAAa,KAAK,GACpC,KAAK;MAEL,KAAK,gBAAA,WAAW,cAAc,aAAa,IAAI,CAAC;AAEpD;AAEA,SAAgB,gBACd,MACA,MACA,MACA,OACA,MACA;CACA,IAAI,gBAAA,gBAAgB,gBAAgB,KAAK,GACvC,KAAK;MAEL,KAAK,gBAAA,WAAW,cAAc,aAAa,IAAI,CAAC;AAEpD"}
@@ -0,0 +1,14 @@
1
+ import { errorUtils, validationUtils } from "@verdaccio/core";
2
+ //#region src/middlewares/validation.ts
3
+ function validateName(_req, _res, next, value, name) {
4
+ if (validationUtils.validateName(value)) next();
5
+ else next(errorUtils.getBadRequest("invalid " + name));
6
+ }
7
+ function validatePackage(_req, _res, next, value, name) {
8
+ if (validationUtils.validatePackage(value)) next();
9
+ else next(errorUtils.getBadRequest("invalid " + name));
10
+ }
11
+ //#endregion
12
+ export { validateName, validatePackage };
13
+
14
+ //# sourceMappingURL=validation.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.mjs","names":[],"sources":["../../src/middlewares/validation.ts"],"sourcesContent":["import type { NextFunction, Request, Response } from 'express';\n\nimport { errorUtils, validationUtils } from '@verdaccio/core';\n\nexport function validateName(\n _req: Request,\n _res: Response,\n next: NextFunction,\n value: string,\n name: string\n) {\n if (validationUtils.validateName(value)) {\n next();\n } else {\n next(errorUtils.getBadRequest('invalid ' + name));\n }\n}\n\nexport function validatePackage(\n _req: Request,\n _res,\n next: NextFunction,\n value: string,\n name: string\n) {\n if (validationUtils.validatePackage(value)) {\n next();\n } else {\n next(errorUtils.getBadRequest('invalid ' + name));\n }\n}\n"],"mappings":";;AAIA,SAAgB,aACd,MACA,MACA,MACA,OACA,MACA;CACA,IAAI,gBAAgB,aAAa,KAAK,GACpC,KAAK;MAEL,KAAK,WAAW,cAAc,aAAa,IAAI,CAAC;AAEpD;AAEA,SAAgB,gBACd,MACA,MACA,MACA,OACA,MACA;CACA,IAAI,gBAAgB,gBAAgB,KAAK,GACvC,KAAK;MAEL,KAAK,WAAW,cAAc,aAAa,IAAI,CAAC;AAEpD"}
@@ -1,35 +1,4 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "renderWebMiddleware", {
7
- enumerable: true,
8
- get: function () {
9
- return _renderWeb.renderWebMiddleware;
10
- }
11
- });
12
- Object.defineProperty(exports, "setSecurityWebHeaders", {
13
- enumerable: true,
14
- get: function () {
15
- return _security.setSecurityWebHeaders;
16
- }
17
- });
18
- Object.defineProperty(exports, "webAPIMiddleware", {
19
- enumerable: true,
20
- get: function () {
21
- return _webApi.webAPIMiddleware;
22
- }
23
- });
24
- Object.defineProperty(exports, "webMiddleware", {
25
- enumerable: true,
26
- get: function () {
27
- return _webMiddleware.default;
28
- }
29
- });
30
- var _webMiddleware = _interopRequireDefault(require("./web-middleware"));
31
- var _webApi = require("./web-api");
32
- var _security = require("./security");
33
- var _renderWeb = require("./render-web");
34
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
35
- //# sourceMappingURL=index.js.map
1
+ require("./security.js");
2
+ require("./render-web.js");
3
+ require("./web-api.js");
4
+ require("./web-middleware.js");
@@ -0,0 +1,4 @@
1
+ import "./security.mjs";
2
+ import "./render-web.mjs";
3
+ import "./web-api.mjs";
4
+ import "./web-middleware.mjs";
@@ -1,117 +1,90 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.renderWebMiddleware = renderWebMiddleware;
7
- var _debug = _interopRequireDefault(require("debug"));
8
- var _express = _interopRequireDefault(require("express"));
9
- var _nodeFs = _interopRequireDefault(require("node:fs"));
10
- var _nodePath = _interopRequireDefault(require("node:path"));
11
- var _core = require("@verdaccio/core");
12
- var _url = require("@verdaccio/url");
13
- var _security = require("./security");
14
- var _renderHTML = _interopRequireDefault(require("./utils/renderHTML"));
15
- var _uiOptions = require("./utils/ui-options");
16
- var _webUrls = require("./web-urls");
17
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
- const debug = (0, _debug.default)('verdaccio:web:render');
19
- const sendFileCallback = next => err => {
20
- if (!err) {
21
- return;
22
- }
23
- if (err.status === _core.HTTP_STATUS.NOT_FOUND) {
24
- next();
25
- } else {
26
- next(err);
27
- }
1
+ const require_runtime = require("../../_virtual/_rolldown/runtime.js");
2
+ const require_security = require("./security.js");
3
+ const require_renderHTML = require("./utils/renderHTML.js");
4
+ const require_ui_options = require("./utils/ui-options.js");
5
+ const require_web_urls = require("./web-urls.js");
6
+ let _verdaccio_core = require("@verdaccio/core");
7
+ let debug = require("debug");
8
+ debug = require_runtime.__toESM(debug);
9
+ let express = require("express");
10
+ express = require_runtime.__toESM(express);
11
+ let node_fs = require("node:fs");
12
+ node_fs = require_runtime.__toESM(node_fs);
13
+ let node_path = require("node:path");
14
+ node_path = require_runtime.__toESM(node_path);
15
+ let _verdaccio_url = require("@verdaccio/url");
16
+ //#region src/middlewares/web/render-web.ts
17
+ var debug$1 = (0, debug.default)("verdaccio:web:render");
18
+ var sendFileCallback = (next) => (err) => {
19
+ if (!err) return;
20
+ if (err.status === _verdaccio_core.HTTP_STATUS.NOT_FOUND) next();
21
+ else next(err);
28
22
  };
29
23
  function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
30
- const {
31
- staticPath,
32
- manifest,
33
- manifestFiles
34
- } = pluginOptions;
35
- debug('static path %o', staticPath);
36
- const router = _express.default.Router();
37
- if (typeof tokenMiddleware === 'function') {
38
- router.use(tokenMiddleware);
39
- }
40
- router.use(_security.setSecurityWebHeaders);
41
-
42
- // any match within the static is routed to the file system
43
- router.get(_webUrls.WebUrlsNamespace.static + '*', function (req, res, next) {
44
- const filename = req.params[0];
45
- let file = `${staticPath}/${filename}`;
46
- if (filename === 'favicon.ico' && config?.web?.favicon) {
47
- file = config?.web?.favicon;
48
- if ((0, _url.isURLhasValidProtocol)(file)) {
49
- debug('redirect to favicon %s', file);
50
- req.url = file;
51
- return next();
52
- }
53
- }
54
- debug('render static file %o', file);
55
- res.sendFile(file, sendFileCallback(next));
56
- });
57
- function renderLogo(logo) {
58
- // check the origin of the logo
59
- if (logo && !(0, _url.isURLhasValidProtocol)(logo)) {
60
- // URI related to a local file
61
- const absoluteLocalFile = _nodePath.default.posix.resolve(logo);
62
- debug('serve local logo %s', absoluteLocalFile);
63
- try {
64
- // TODO: replace existsSync by async alternative
65
- if (_nodeFs.default.existsSync(absoluteLocalFile) && typeof _nodeFs.default.accessSync(absoluteLocalFile, _nodeFs.default.constants.R_OK) === 'undefined') {
66
- // Note: `path.join` will break on Windows, because it transforms `/` to `\`
67
- // Use POSIX version `path.posix.join` instead.
68
- logo = _nodePath.default.posix.join(_webUrls.WebUrlsNamespace.static, _nodePath.default.basename(logo));
69
- router.get(logo, function (_req, res, next) {
70
- // @ts-ignore
71
- debug('serve custom logo web:%s - local:%s', logo, absoluteLocalFile);
72
- res.sendFile(absoluteLocalFile, sendFileCallback(next));
73
- });
74
- debug('enabled custom logo %s', logo);
75
- } else {
76
- logo = undefined;
77
- debug(`web logo is wrong, path ${absoluteLocalFile} does not exist or is not readable`);
78
- }
79
- } catch {
80
- logo = undefined;
81
- debug(`web logo is wrong, path ${absoluteLocalFile} does not exist or is not readable`);
82
- }
83
- }
84
- return logo;
85
- }
86
- const logo = renderLogo(config?.web?.logo);
87
- if (config?.web?.logo) {
88
- config.web.logo = logo;
89
- }
90
- const logoDark = renderLogo(config?.web?.logoDark);
91
- if (config?.web?.logoDark) {
92
- config.web.logoDark = logoDark;
93
- }
94
-
95
- // Serve external script that loads UI options
96
- router.get(_webUrls.WebUrlsNamespace.static + 'ui-options.js', function (req, res) {
97
- const options = (0, _uiOptions.getUIOptions)(config, req, res);
98
- const script = `window.__VERDACCIO_BASENAME_UI_OPTIONS=${JSON.stringify(options)};`;
99
- res.setHeader(_core.HEADERS.CACHE_CONTROL, _core.HEADERS.NO_CACHE);
100
- res.setHeader(_core.HEADERS.CONTENT_TYPE, _core.HEADERS.JAVASCRIPT_CHARSET);
101
- res.send(script);
102
- });
103
-
104
- // Handle all web routes including security routes
105
- router.get(_webUrls.WebUrlsNamespace.web + '*', function (req, res) {
106
- const options = (0, _uiOptions.getUIOptions)(config, req, res);
107
- (0, _renderHTML.default)(config, manifest, manifestFiles, options, res);
108
- debug('render html section');
109
- });
110
- router.get(_webUrls.WebUrlsNamespace.root, function (req, res) {
111
- const options = (0, _uiOptions.getUIOptions)(config, req, res);
112
- (0, _renderHTML.default)(config, manifest, manifestFiles, options, res);
113
- debug('render root');
114
- });
115
- return router;
24
+ const { staticPath, manifest, manifestFiles } = pluginOptions;
25
+ debug$1("static path %o", staticPath);
26
+ const router = express.default.Router();
27
+ if (typeof tokenMiddleware === "function") router.use(tokenMiddleware);
28
+ router.use(require_security.setSecurityWebHeaders);
29
+ router.get(require_web_urls.WebUrlsNamespace.static + "*", function(req, res, next) {
30
+ const filename = req.params[0];
31
+ let file = `${staticPath}/${filename}`;
32
+ if (filename === "favicon.ico" && config?.web?.favicon) {
33
+ file = config?.web?.favicon;
34
+ if ((0, _verdaccio_url.isURLhasValidProtocol)(file)) {
35
+ debug$1("redirect to favicon %s", file);
36
+ req.url = file;
37
+ return next();
38
+ }
39
+ }
40
+ debug$1("render static file %o", file);
41
+ res.sendFile(file, sendFileCallback(next));
42
+ });
43
+ function renderLogo(logo) {
44
+ if (logo && !(0, _verdaccio_url.isURLhasValidProtocol)(logo)) {
45
+ const absoluteLocalFile = node_path.default.posix.resolve(logo);
46
+ debug$1("serve local logo %s", absoluteLocalFile);
47
+ try {
48
+ if (node_fs.default.existsSync(absoluteLocalFile) && typeof node_fs.default.accessSync(absoluteLocalFile, node_fs.default.constants.R_OK) === "undefined") {
49
+ logo = node_path.default.posix.join(require_web_urls.WebUrlsNamespace.static, node_path.default.basename(logo));
50
+ router.get(logo, function(_req, res, next) {
51
+ debug$1("serve custom logo web:%s - local:%s", logo, absoluteLocalFile);
52
+ res.sendFile(absoluteLocalFile, sendFileCallback(next));
53
+ });
54
+ debug$1("enabled custom logo %s", logo);
55
+ } else {
56
+ logo = void 0;
57
+ debug$1(`web logo is wrong, path ${absoluteLocalFile} does not exist or is not readable`);
58
+ }
59
+ } catch {
60
+ logo = void 0;
61
+ debug$1(`web logo is wrong, path ${absoluteLocalFile} does not exist or is not readable`);
62
+ }
63
+ }
64
+ return logo;
65
+ }
66
+ const logo = renderLogo(config?.web?.logo);
67
+ if (config?.web?.logo) config.web.logo = logo;
68
+ const logoDark = renderLogo(config?.web?.logoDark);
69
+ if (config?.web?.logoDark) config.web.logoDark = logoDark;
70
+ router.get(require_web_urls.WebUrlsNamespace.static + "ui-options.js", function(req, res) {
71
+ const options = require_ui_options.getUIOptions(config, req, res);
72
+ const script = `window.__VERDACCIO_BASENAME_UI_OPTIONS=${JSON.stringify(options)};`;
73
+ res.setHeader(_verdaccio_core.HEADERS.CACHE_CONTROL, _verdaccio_core.HEADERS.NO_CACHE);
74
+ res.setHeader(_verdaccio_core.HEADERS.CONTENT_TYPE, _verdaccio_core.HEADERS.JAVASCRIPT_CHARSET);
75
+ res.send(script);
76
+ });
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);
79
+ debug$1("render html section");
80
+ });
81
+ 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
+ debug$1("render root");
84
+ });
85
+ return router;
116
86
  }
87
+ //#endregion
88
+ exports.renderWebMiddleware = renderWebMiddleware;
89
+
117
90
  //# sourceMappingURL=render-web.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"render-web.js","names":["_debug","_interopRequireDefault","require","_express","_nodeFs","_nodePath","_core","_url","_security","_renderHTML","_uiOptions","_webUrls","e","__esModule","default","debug","buildDebug","sendFileCallback","next","err","status","HTTP_STATUS","NOT_FOUND","renderWebMiddleware","config","tokenMiddleware","pluginOptions","staticPath","manifest","manifestFiles","router","express","Router","use","setSecurityWebHeaders","get","WebUrlsNamespace","static","req","res","filename","params","file","web","favicon","isURLhasValidProtocol","url","sendFile","renderLogo","logo","absoluteLocalFile","path","posix","resolve","fs","existsSync","accessSync","constants","R_OK","join","basename","_req","undefined","logoDark","options","getUIOptions","script","JSON","stringify","setHeader","HEADERS","CACHE_CONTROL","NO_CACHE","CONTENT_TYPE","JAVASCRIPT_CHARSET","send","renderHTML","root"],"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":"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","ignoreList":[]}
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":"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"}