@oxyhq/core 3.10.1 → 3.11.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 (82) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/AuthManager.js +9 -2
  3. package/dist/cjs/HttpService.js +27 -9
  4. package/dist/cjs/OxyServices.base.js +3 -2
  5. package/dist/cjs/crypto/canonicalJson.js +107 -0
  6. package/dist/cjs/crypto/keyManager.js +67 -8
  7. package/dist/cjs/crypto/signatureService.js +103 -0
  8. package/dist/cjs/index.js +15 -4
  9. package/dist/cjs/mixins/OxyServices.assets.js +16 -1
  10. package/dist/cjs/mixins/OxyServices.auth.js +190 -1
  11. package/dist/cjs/mixins/OxyServices.identity.js +291 -0
  12. package/dist/cjs/mixins/OxyServices.sso.js +28 -1
  13. package/dist/cjs/mixins/OxyServices.user.js +1 -0
  14. package/dist/cjs/mixins/index.js +3 -0
  15. package/dist/cjs/server/cors.js +20 -21
  16. package/dist/cjs/server/rateLimit.js +32 -8
  17. package/dist/cjs/utils/ssoReturn.js +1 -1
  18. package/dist/esm/.tsbuildinfo +1 -1
  19. package/dist/esm/AuthManager.js +9 -2
  20. package/dist/esm/HttpService.js +27 -9
  21. package/dist/esm/OxyServices.base.js +3 -2
  22. package/dist/esm/crypto/canonicalJson.js +104 -0
  23. package/dist/esm/crypto/keyManager.js +67 -8
  24. package/dist/esm/crypto/signatureService.js +102 -0
  25. package/dist/esm/index.js +9 -1
  26. package/dist/esm/mixins/OxyServices.assets.js +16 -1
  27. package/dist/esm/mixins/OxyServices.auth.js +190 -1
  28. package/dist/esm/mixins/OxyServices.identity.js +287 -0
  29. package/dist/esm/mixins/OxyServices.sso.js +28 -1
  30. package/dist/esm/mixins/OxyServices.user.js +1 -0
  31. package/dist/esm/mixins/index.js +3 -0
  32. package/dist/esm/server/cors.js +20 -21
  33. package/dist/esm/server/rateLimit.js +32 -8
  34. package/dist/esm/utils/ssoReturn.js +1 -1
  35. package/dist/types/.tsbuildinfo +1 -1
  36. package/dist/types/HttpService.d.ts +3 -0
  37. package/dist/types/OxyServices.d.ts +2 -2
  38. package/dist/types/crypto/canonicalJson.d.ts +44 -0
  39. package/dist/types/crypto/keyManager.d.ts +7 -0
  40. package/dist/types/crypto/signatureService.d.ts +61 -0
  41. package/dist/types/index.d.ts +6 -2
  42. package/dist/types/mixins/OxyServices.auth.d.ts +136 -0
  43. package/dist/types/mixins/OxyServices.identity.d.ts +249 -0
  44. package/dist/types/mixins/OxyServices.sso.d.ts +4 -1
  45. package/dist/types/mixins/index.d.ts +2 -1
  46. package/dist/types/models/interfaces.d.ts +3 -0
  47. package/dist/types/server/cors.d.ts +5 -5
  48. package/dist/types/utils/ssoReturn.d.ts +1 -1
  49. package/package.json +2 -2
  50. package/src/AuthManager.ts +8 -2
  51. package/src/HttpService.ts +36 -8
  52. package/src/OxyServices.base.ts +3 -2
  53. package/src/OxyServices.ts +1 -1
  54. package/src/__tests__/authManager.security.test.ts +31 -0
  55. package/src/__tests__/httpServiceCsrf.test.ts +75 -0
  56. package/src/crypto/__tests__/canonicalJson.test.ts +116 -0
  57. package/src/crypto/__tests__/keyManager.atomicity.test.ts +41 -2
  58. package/src/crypto/__tests__/signChallengeShared.test.ts +64 -0
  59. package/src/crypto/__tests__/signedRecord.test.ts +125 -0
  60. package/src/crypto/canonicalJson.ts +120 -0
  61. package/src/crypto/keyManager.ts +62 -12
  62. package/src/crypto/signatureService.ts +126 -0
  63. package/src/index.ts +27 -2
  64. package/src/mixins/OxyServices.assets.ts +16 -1
  65. package/src/mixins/OxyServices.auth.ts +309 -1
  66. package/src/mixins/OxyServices.identity.ts +445 -0
  67. package/src/mixins/OxyServices.sso.ts +30 -1
  68. package/src/mixins/OxyServices.user.ts +1 -0
  69. package/src/mixins/__tests__/OxyServices.identity.test.ts +364 -0
  70. package/src/mixins/__tests__/assetCredentials.test.ts +47 -0
  71. package/src/mixins/__tests__/commonsSignIn.test.ts +277 -0
  72. package/src/mixins/__tests__/serviceAuth.test.ts +19 -0
  73. package/src/mixins/__tests__/sso.test.ts +31 -0
  74. package/src/mixins/index.ts +4 -0
  75. package/src/models/interfaces.ts +3 -0
  76. package/src/server/__tests__/cors.test.ts +5 -1
  77. package/src/server/__tests__/rateLimit.test.ts +116 -0
  78. package/src/server/cors.ts +25 -20
  79. package/src/server/rateLimit.ts +39 -8
  80. package/src/utils/__tests__/consumeSsoReturn.test.ts +1 -1
  81. package/src/utils/__tests__/ssoReturn.test.ts +1 -1
  82. package/src/utils/ssoReturn.ts +2 -2
@@ -19,12 +19,36 @@ function isBuiltInExempt(req) {
19
19
  function ipKeyGenerator(ip) {
20
20
  return ip.replace(/:/g, '_');
21
21
  }
22
- /** Resolve the rate-limit key: per authenticated user, else per (IPv6-safe) IP. */
23
- function resolveKey(req) {
22
+ /**
23
+ * Resolve the trusted authenticated rate-limit key.
24
+ *
25
+ * `oxy.auth({ optional: true })` preserves legacy non-session user tokens by
26
+ * decoding their JWT claims locally. Those claims are not cryptographically
27
+ * verified and therefore MUST NOT influence abuse-control buckets. Only use
28
+ * identities that came from a server-validated session or a verified service
29
+ * token/delegation.
30
+ */
31
+ function resolveTrustedAuthenticatedKey(req) {
24
32
  const userId = req.userId ?? req.user?.id ?? req.user?._id;
25
- if (userId) {
33
+ if (userId && req.sessionId) {
26
34
  return `user:${userId}`;
27
35
  }
36
+ const delegatedUserId = req.serviceActingAs?.userId;
37
+ if (delegatedUserId && req.serviceApp?.appId) {
38
+ return `user:${delegatedUserId}`;
39
+ }
40
+ const serviceAppId = req.serviceApp?.appId;
41
+ if (serviceAppId) {
42
+ return `service:${serviceAppId}`;
43
+ }
44
+ return null;
45
+ }
46
+ /** Resolve the rate-limit key: per trusted authenticated identity, else per (IPv6-safe) IP. */
47
+ function resolveKey(req) {
48
+ const authenticatedKey = resolveTrustedAuthenticatedKey(req);
49
+ if (authenticatedKey) {
50
+ return authenticatedKey;
51
+ }
28
52
  const ip = req.ip || req.socket.remoteAddress || 'unknown';
29
53
  return ipKeyGenerator(ip);
30
54
  }
@@ -41,9 +65,9 @@ export function createOxyRateLimit(oxy, options = {}) {
41
65
  windowMs,
42
66
  ...(store ? { store } : {}),
43
67
  max: (req) => {
44
- const authed = req;
45
- const userId = authed.userId ?? authed.user?.id ?? authed.user?._id;
46
- return userId ? authenticatedMax : anonymousMax;
68
+ return resolveTrustedAuthenticatedKey(req)
69
+ ? authenticatedMax
70
+ : anonymousMax;
47
71
  },
48
72
  keyGenerator: (req) => resolveKey(req),
49
73
  message,
@@ -61,8 +85,8 @@ export function createOxyRateLimit(oxy, options = {}) {
61
85
  resolveSession(req, res, (err) => {
62
86
  if (err) {
63
87
  // Optional auth never rejects; a token error just means "anonymous".
64
- // Swallow the error and continue to limit as anonymous.
65
- next();
88
+ // Swallow the error and continue through the anonymous limiter.
89
+ limiter(req, res, next);
66
90
  return;
67
91
  }
68
92
  limiter(req, res, next);
@@ -237,7 +237,7 @@ export async function consumeSsoReturn(oxy, deps = {}) {
237
237
  }
238
238
  let session;
239
239
  try {
240
- session = await oxy.exchangeSsoCode(ret.code);
240
+ session = await oxy.exchangeSsoCode(ret.code, ret.state);
241
241
  }
242
242
  catch (error) {
243
243
  onExchangeError?.(error);