@stratum-hq/lib 0.5.0 → 0.6.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 (56) hide show
  1. package/dist/__tests__/webhook-signature.test.d.ts +2 -0
  2. package/dist/__tests__/webhook-signature.test.d.ts.map +1 -0
  3. package/dist/__tests__/webhook-signature.test.js +103 -0
  4. package/dist/__tests__/webhook-signature.test.js.map +1 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +5 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/services/__tests__/api-key-service.test.d.ts +2 -0
  10. package/dist/services/__tests__/api-key-service.test.d.ts.map +1 -0
  11. package/dist/services/__tests__/api-key-service.test.js +76 -0
  12. package/dist/services/__tests__/api-key-service.test.js.map +1 -0
  13. package/dist/services/__tests__/event-service.test.js +32 -0
  14. package/dist/services/__tests__/event-service.test.js.map +1 -1
  15. package/dist/services/__tests__/key-rotation-service.test.d.ts +2 -0
  16. package/dist/services/__tests__/key-rotation-service.test.d.ts.map +1 -0
  17. package/dist/services/__tests__/key-rotation-service.test.js +132 -0
  18. package/dist/services/__tests__/key-rotation-service.test.js.map +1 -0
  19. package/dist/services/__tests__/role-service.test.js +29 -2
  20. package/dist/services/__tests__/role-service.test.js.map +1 -1
  21. package/dist/services/__tests__/tenant-service.test.js +34 -0
  22. package/dist/services/__tests__/tenant-service.test.js.map +1 -1
  23. package/dist/services/abac-service.d.ts.map +1 -1
  24. package/dist/services/abac-service.js +7 -3
  25. package/dist/services/abac-service.js.map +1 -1
  26. package/dist/services/api-key-service.d.ts +14 -0
  27. package/dist/services/api-key-service.d.ts.map +1 -1
  28. package/dist/services/api-key-service.js +13 -0
  29. package/dist/services/api-key-service.js.map +1 -1
  30. package/dist/services/event-service.d.ts.map +1 -1
  31. package/dist/services/event-service.js +34 -22
  32. package/dist/services/event-service.js.map +1 -1
  33. package/dist/services/key-rotation-service.d.ts +3 -2
  34. package/dist/services/key-rotation-service.d.ts.map +1 -1
  35. package/dist/services/key-rotation-service.js +17 -7
  36. package/dist/services/key-rotation-service.js.map +1 -1
  37. package/dist/services/permission-service.d.ts.map +1 -1
  38. package/dist/services/permission-service.js +7 -4
  39. package/dist/services/permission-service.js.map +1 -1
  40. package/dist/services/role-service.d.ts +15 -2
  41. package/dist/services/role-service.d.ts.map +1 -1
  42. package/dist/services/role-service.js +24 -5
  43. package/dist/services/role-service.js.map +1 -1
  44. package/dist/services/tenant-service.d.ts +21 -1
  45. package/dist/services/tenant-service.d.ts.map +1 -1
  46. package/dist/services/tenant-service.js +24 -3
  47. package/dist/services/tenant-service.js.map +1 -1
  48. package/dist/stratum.d.ts +21 -4
  49. package/dist/stratum.d.ts.map +1 -1
  50. package/dist/stratum.js +20 -9
  51. package/dist/stratum.js.map +1 -1
  52. package/dist/webhook-signature.d.ts +36 -0
  53. package/dist/webhook-signature.d.ts.map +1 -0
  54. package/dist/webhook-signature.js +55 -0
  55. package/dist/webhook-signature.js.map +1 -0
  56. package/package.json +3 -2
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DEFAULT_WEBHOOK_TOLERANCE_SECONDS = void 0;
7
+ exports.signWebhookPayload = signWebhookPayload;
8
+ exports.verifyWebhookSignature = verifyWebhookSignature;
9
+ const node_crypto_1 = __importDefault(require("node:crypto"));
10
+ /** Default freshness window, in seconds, for a webhook delivery timestamp. */
11
+ exports.DEFAULT_WEBHOOK_TOLERANCE_SECONDS = 300;
12
+ /**
13
+ * Compute the signature for a webhook delivery.
14
+ *
15
+ * The timestamp is bound into the signed value (`<timestamp>.<payload>`), so a
16
+ * captured delivery cannot be re-sent with a fresh timestamp to slip past the
17
+ * receiver's freshness check. Producers and {@link verifyWebhookSignature} must
18
+ * sign over the exact same string.
19
+ */
20
+ function signWebhookPayload(secret, timestamp, payload) {
21
+ return ("sha256=" +
22
+ node_crypto_1.default
23
+ .createHmac("sha256", secret)
24
+ .update(`${timestamp}.${payload}`)
25
+ .digest("hex"));
26
+ }
27
+ /**
28
+ * Verify a Stratum webhook delivery.
29
+ *
30
+ * Returns `true` only when the signature is valid AND the timestamp falls
31
+ * within the freshness window. The window is the replay defense: it rejects a
32
+ * captured, still-correctly-signed delivery once it ages out. For strict
33
+ * exactly-once handling, also de-duplicate on the `X-Stratum-Delivery-ID`
34
+ * header. The comparison is constant-time and the function never throws.
35
+ */
36
+ function verifyWebhookSignature(options) {
37
+ const { secret, payload, signature, timestamp, toleranceSeconds = exports.DEFAULT_WEBHOOK_TOLERANCE_SECONDS, now = Date.now(), } = options;
38
+ // Reject a missing or malformed timestamp (fail closed).
39
+ const sentMs = Date.parse(timestamp);
40
+ if (Number.isNaN(sentMs)) {
41
+ return false;
42
+ }
43
+ // Reject deliveries outside the freshness window in either direction.
44
+ if (Math.abs(now - sentMs) > toleranceSeconds * 1000) {
45
+ return false;
46
+ }
47
+ const expected = Buffer.from(signWebhookPayload(secret, timestamp, payload));
48
+ const provided = Buffer.from(signature);
49
+ // timingSafeEqual requires equal-length inputs; unequal length is a mismatch.
50
+ if (expected.length !== provided.length) {
51
+ return false;
52
+ }
53
+ return node_crypto_1.default.timingSafeEqual(expected, provided);
54
+ }
55
+ //# sourceMappingURL=webhook-signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-signature.js","sourceRoot":"","sources":["../src/webhook-signature.ts"],"names":[],"mappings":";;;;;;AAaA,gDAYC;AA0BD,wDA4BC;AA/ED,8DAAiC;AAEjC,8EAA8E;AACjE,QAAA,iCAAiC,GAAG,GAAG,CAAC;AAErD;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAChC,MAAc,EACd,SAAiB,EACjB,OAAe;IAEf,OAAO,CACL,SAAS;QACT,qBAAM;aACH,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;aAC5B,MAAM,CAAC,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC;aACjC,MAAM,CAAC,KAAK,CAAC,CACjB,CAAC;AACJ,CAAC;AAiBD;;;;;;;;GAQG;AACH,SAAgB,sBAAsB,CAAC,OAA6B;IAClE,MAAM,EACJ,MAAM,EACN,OAAO,EACP,SAAS,EACT,SAAS,EACT,gBAAgB,GAAG,yCAAiC,EACpD,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GACjB,GAAG,OAAO,CAAC;IAEZ,yDAAyD;IACzD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,sEAAsE;IACtE,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,gBAAgB,GAAG,IAAI,EAAE,CAAC;QACrD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7E,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,8EAA8E;IAC9E,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,qBAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACpD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratum-hq/lib",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Stratum tenant management library - framework-agnostic business logic",
5
5
  "keywords": [
6
6
  "multi-tenancy",
@@ -36,7 +36,8 @@
36
36
  "scripts": {
37
37
  "build": "tsc && cp -r src/migrations dist/migrations",
38
38
  "test": "vitest run",
39
- "lint": "tsc --noEmit",
39
+ "typecheck": "tsc --noEmit",
40
+ "lint": "eslint .",
40
41
  "clean": "rm -rf dist"
41
42
  },
42
43
  "publishConfig": {