@stratum-hq/lib 0.5.1 → 0.7.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.
- package/dist/__tests__/webhook-signature.test.d.ts +2 -0
- package/dist/__tests__/webhook-signature.test.d.ts.map +1 -0
- package/dist/__tests__/webhook-signature.test.js +103 -0
- package/dist/__tests__/webhook-signature.test.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/migrations/019_rls_policies.sql +236 -0
- package/dist/pool-helpers.d.ts.map +1 -1
- package/dist/pool-helpers.js +31 -1
- package/dist/pool-helpers.js.map +1 -1
- package/dist/services/__tests__/api-key-service.test.d.ts +2 -0
- package/dist/services/__tests__/api-key-service.test.d.ts.map +1 -0
- package/dist/services/__tests__/api-key-service.test.js +76 -0
- package/dist/services/__tests__/api-key-service.test.js.map +1 -0
- package/dist/services/__tests__/event-service.test.js +32 -0
- package/dist/services/__tests__/event-service.test.js.map +1 -1
- package/dist/services/__tests__/key-rotation-service.test.d.ts +2 -0
- package/dist/services/__tests__/key-rotation-service.test.d.ts.map +1 -0
- package/dist/services/__tests__/key-rotation-service.test.js +132 -0
- package/dist/services/__tests__/key-rotation-service.test.js.map +1 -0
- package/dist/services/__tests__/tenant-service.test.js +34 -0
- package/dist/services/__tests__/tenant-service.test.js.map +1 -1
- package/dist/services/abac-service.d.ts.map +1 -1
- package/dist/services/abac-service.js +7 -3
- package/dist/services/abac-service.js.map +1 -1
- package/dist/services/api-key-service.d.ts +14 -0
- package/dist/services/api-key-service.d.ts.map +1 -1
- package/dist/services/api-key-service.js +13 -0
- package/dist/services/api-key-service.js.map +1 -1
- package/dist/services/event-service.d.ts.map +1 -1
- package/dist/services/event-service.js +34 -22
- package/dist/services/event-service.js.map +1 -1
- package/dist/services/key-rotation-service.d.ts +3 -2
- package/dist/services/key-rotation-service.d.ts.map +1 -1
- package/dist/services/key-rotation-service.js +17 -7
- package/dist/services/key-rotation-service.js.map +1 -1
- package/dist/services/permission-service.d.ts.map +1 -1
- package/dist/services/permission-service.js +7 -4
- package/dist/services/permission-service.js.map +1 -1
- package/dist/services/tenant-service.d.ts +21 -1
- package/dist/services/tenant-service.d.ts.map +1 -1
- package/dist/services/tenant-service.js +24 -3
- package/dist/services/tenant-service.js.map +1 -1
- package/dist/stratum.d.ts +15 -1
- package/dist/stratum.d.ts.map +1 -1
- package/dist/stratum.js +12 -4
- package/dist/stratum.js.map +1 -1
- package/dist/webhook-signature.d.ts +36 -0
- package/dist/webhook-signature.d.ts.map +1 -0
- package/dist/webhook-signature.js +55 -0
- package/dist/webhook-signature.js.map +1 -0
- 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.
|
|
3
|
+
"version": "0.7.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
|
-
"
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"lint": "eslint .",
|
|
40
41
|
"clean": "rm -rf dist"
|
|
41
42
|
},
|
|
42
43
|
"publishConfig": {
|