@dregs/sdk 0.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.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +287 -0
- package/dist/chunk-AIUWT3Z7.js +149 -0
- package/dist/chunk-AIUWT3Z7.js.map +1 -0
- package/dist/chunk-K63AUEQR.cjs +170 -0
- package/dist/chunk-K63AUEQR.cjs.map +1 -0
- package/dist/index.cjs +645 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +576 -0
- package/dist/index.d.ts +576 -0
- package/dist/index.js +554 -0
- package/dist/index.js.map +1 -0
- package/dist/webhooks.cjs +36 -0
- package/dist/webhooks.cjs.map +1 -0
- package/dist/webhooks.d.cts +83 -0
- package/dist/webhooks.d.ts +83 -0
- package/dist/webhooks.js +3 -0
- package/dist/webhooks.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkK63AUEQR_cjs = require('./chunk-K63AUEQR.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, "DEFAULT_TOLERANCE_SECONDS", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return chunkK63AUEQR_cjs.DEFAULT_TOLERANCE_SECONDS; }
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(exports, "EVENT_HEADER", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return chunkK63AUEQR_cjs.EVENT_HEADER; }
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, "SIGNATURE_HEADER", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return chunkK63AUEQR_cjs.SIGNATURE_HEADER; }
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports, "TIMESTAMP_HEADER", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return chunkK63AUEQR_cjs.TIMESTAMP_HEADER; }
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports, "computeWebhookSignature", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return chunkK63AUEQR_cjs.computeWebhookSignature; }
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(exports, "verifyWebhook", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () { return chunkK63AUEQR_cjs.verifyWebhook; }
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(exports, "verifyWebhookSignature", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
get: function () { return chunkK63AUEQR_cjs.verifyWebhookSignature; }
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=webhooks.cjs.map
|
|
36
|
+
//# sourceMappingURL=webhooks.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"webhooks.cjs"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verifying webhooks Dregs sends you.
|
|
3
|
+
*
|
|
4
|
+
* Dregs signs every webhook with the channel's signing secret: `X-Dregs-Signature` is the
|
|
5
|
+
* hex-encoded HMAC-SHA256 of the raw request body. Verify it before you act on the payload, and
|
|
6
|
+
* verify it against the bytes you received rather than a re-serialized object, because
|
|
7
|
+
* re-serializing changes key order and whitespace and will not match.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { verifyWebhook } from '@dregs/sdk/webhooks';
|
|
11
|
+
*
|
|
12
|
+
* app.post('/webhooks/dregs', express.raw({ type: 'application/json' }), (req, res) => {
|
|
13
|
+
* const event = verifyWebhook({
|
|
14
|
+
* payload: req.body, // the Buffer, not req.body parsed as JSON
|
|
15
|
+
* signature: req.header('X-Dregs-Signature') ?? '',
|
|
16
|
+
* secret: process.env.DREGS_WEBHOOK_SECRET!,
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* handle(event);
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* The signing secret is shown once, when you create the webhook channel. It is not your API
|
|
24
|
+
* secret key: one authenticates you to Dregs, the other proves a payload came from Dregs.
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
/** The header carrying the hex-encoded HMAC-SHA256 of the raw body. */
|
|
29
|
+
declare const SIGNATURE_HEADER = "X-Dregs-Signature";
|
|
30
|
+
/** The header carrying the delivery's timestamp. */
|
|
31
|
+
declare const TIMESTAMP_HEADER = "X-Dregs-Timestamp";
|
|
32
|
+
/** The header naming the event type. */
|
|
33
|
+
declare const EVENT_HEADER = "X-Dregs-Event";
|
|
34
|
+
/** How far out of date a webhook's timestamp may be before {@link verifyWebhook} rejects it. */
|
|
35
|
+
declare const DEFAULT_TOLERANCE_SECONDS = 300;
|
|
36
|
+
/**
|
|
37
|
+
* A raw webhook body.
|
|
38
|
+
*
|
|
39
|
+
* A `Buffer` or `Uint8Array` is what you want: the bytes exactly as received. A string is
|
|
40
|
+
* accepted for frameworks that hand you the raw text, and is hashed as UTF-8.
|
|
41
|
+
*/
|
|
42
|
+
type WebhookPayload = string | Uint8Array;
|
|
43
|
+
/** A verified webhook body: `event`, `timestamp`, and the payload for that event. */
|
|
44
|
+
type WebhookEvent = Record<string, unknown>;
|
|
45
|
+
/** The arguments to {@link verifyWebhook}. */
|
|
46
|
+
interface VerifyWebhookOptions {
|
|
47
|
+
/** The raw request body, exactly as received. Not a parsed object. */
|
|
48
|
+
payload: WebhookPayload;
|
|
49
|
+
/** The `X-Dregs-Signature` header. */
|
|
50
|
+
signature: string;
|
|
51
|
+
/** The channel's signing secret. */
|
|
52
|
+
secret: string;
|
|
53
|
+
/**
|
|
54
|
+
* How many seconds out of date the payload's own `timestamp` may be before it is treated as a
|
|
55
|
+
* replay. Defaults to 300. Pass `null` to skip the check, which you should only do if you are
|
|
56
|
+
* deduplicating on the event id yourself.
|
|
57
|
+
*
|
|
58
|
+
* The timestamp is inside the signed body, so an attacker cannot alter it without breaking
|
|
59
|
+
* the signature.
|
|
60
|
+
*/
|
|
61
|
+
tolerance?: number | null;
|
|
62
|
+
/** The current time. For tests. */
|
|
63
|
+
now?: Date;
|
|
64
|
+
}
|
|
65
|
+
/** Returns the hex-encoded HMAC-SHA256 of `payload` under `secret`. */
|
|
66
|
+
declare function computeWebhookSignature(payload: WebhookPayload, secret: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Returns whether `signature` matches `payload`.
|
|
69
|
+
*
|
|
70
|
+
* The comparison is constant-time. Prefer {@link verifyWebhook}, which also rejects replays and
|
|
71
|
+
* hands back the parsed event; reach for this one only when you need the boolean.
|
|
72
|
+
*/
|
|
73
|
+
declare function verifyWebhookSignature(payload: WebhookPayload, signature: string, secret: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Verifies a webhook and returns its parsed body.
|
|
76
|
+
*
|
|
77
|
+
* @returns The parsed webhook body: `event`, `timestamp`, and the payload for that event.
|
|
78
|
+
* @throws {WebhookVerificationError} The signature did not match, the body was not a JSON
|
|
79
|
+
* object, or the payload is older than the tolerance. Answer 400 and do not act on it.
|
|
80
|
+
*/
|
|
81
|
+
declare function verifyWebhook(options: VerifyWebhookOptions): WebhookEvent;
|
|
82
|
+
|
|
83
|
+
export { DEFAULT_TOLERANCE_SECONDS, EVENT_HEADER, SIGNATURE_HEADER, TIMESTAMP_HEADER, type VerifyWebhookOptions, type WebhookEvent, type WebhookPayload, computeWebhookSignature, verifyWebhook, verifyWebhookSignature };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verifying webhooks Dregs sends you.
|
|
3
|
+
*
|
|
4
|
+
* Dregs signs every webhook with the channel's signing secret: `X-Dregs-Signature` is the
|
|
5
|
+
* hex-encoded HMAC-SHA256 of the raw request body. Verify it before you act on the payload, and
|
|
6
|
+
* verify it against the bytes you received rather than a re-serialized object, because
|
|
7
|
+
* re-serializing changes key order and whitespace and will not match.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { verifyWebhook } from '@dregs/sdk/webhooks';
|
|
11
|
+
*
|
|
12
|
+
* app.post('/webhooks/dregs', express.raw({ type: 'application/json' }), (req, res) => {
|
|
13
|
+
* const event = verifyWebhook({
|
|
14
|
+
* payload: req.body, // the Buffer, not req.body parsed as JSON
|
|
15
|
+
* signature: req.header('X-Dregs-Signature') ?? '',
|
|
16
|
+
* secret: process.env.DREGS_WEBHOOK_SECRET!,
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* handle(event);
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* The signing secret is shown once, when you create the webhook channel. It is not your API
|
|
24
|
+
* secret key: one authenticates you to Dregs, the other proves a payload came from Dregs.
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
/** The header carrying the hex-encoded HMAC-SHA256 of the raw body. */
|
|
29
|
+
declare const SIGNATURE_HEADER = "X-Dregs-Signature";
|
|
30
|
+
/** The header carrying the delivery's timestamp. */
|
|
31
|
+
declare const TIMESTAMP_HEADER = "X-Dregs-Timestamp";
|
|
32
|
+
/** The header naming the event type. */
|
|
33
|
+
declare const EVENT_HEADER = "X-Dregs-Event";
|
|
34
|
+
/** How far out of date a webhook's timestamp may be before {@link verifyWebhook} rejects it. */
|
|
35
|
+
declare const DEFAULT_TOLERANCE_SECONDS = 300;
|
|
36
|
+
/**
|
|
37
|
+
* A raw webhook body.
|
|
38
|
+
*
|
|
39
|
+
* A `Buffer` or `Uint8Array` is what you want: the bytes exactly as received. A string is
|
|
40
|
+
* accepted for frameworks that hand you the raw text, and is hashed as UTF-8.
|
|
41
|
+
*/
|
|
42
|
+
type WebhookPayload = string | Uint8Array;
|
|
43
|
+
/** A verified webhook body: `event`, `timestamp`, and the payload for that event. */
|
|
44
|
+
type WebhookEvent = Record<string, unknown>;
|
|
45
|
+
/** The arguments to {@link verifyWebhook}. */
|
|
46
|
+
interface VerifyWebhookOptions {
|
|
47
|
+
/** The raw request body, exactly as received. Not a parsed object. */
|
|
48
|
+
payload: WebhookPayload;
|
|
49
|
+
/** The `X-Dregs-Signature` header. */
|
|
50
|
+
signature: string;
|
|
51
|
+
/** The channel's signing secret. */
|
|
52
|
+
secret: string;
|
|
53
|
+
/**
|
|
54
|
+
* How many seconds out of date the payload's own `timestamp` may be before it is treated as a
|
|
55
|
+
* replay. Defaults to 300. Pass `null` to skip the check, which you should only do if you are
|
|
56
|
+
* deduplicating on the event id yourself.
|
|
57
|
+
*
|
|
58
|
+
* The timestamp is inside the signed body, so an attacker cannot alter it without breaking
|
|
59
|
+
* the signature.
|
|
60
|
+
*/
|
|
61
|
+
tolerance?: number | null;
|
|
62
|
+
/** The current time. For tests. */
|
|
63
|
+
now?: Date;
|
|
64
|
+
}
|
|
65
|
+
/** Returns the hex-encoded HMAC-SHA256 of `payload` under `secret`. */
|
|
66
|
+
declare function computeWebhookSignature(payload: WebhookPayload, secret: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Returns whether `signature` matches `payload`.
|
|
69
|
+
*
|
|
70
|
+
* The comparison is constant-time. Prefer {@link verifyWebhook}, which also rejects replays and
|
|
71
|
+
* hands back the parsed event; reach for this one only when you need the boolean.
|
|
72
|
+
*/
|
|
73
|
+
declare function verifyWebhookSignature(payload: WebhookPayload, signature: string, secret: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Verifies a webhook and returns its parsed body.
|
|
76
|
+
*
|
|
77
|
+
* @returns The parsed webhook body: `event`, `timestamp`, and the payload for that event.
|
|
78
|
+
* @throws {WebhookVerificationError} The signature did not match, the body was not a JSON
|
|
79
|
+
* object, or the payload is older than the tolerance. Answer 400 and do not act on it.
|
|
80
|
+
*/
|
|
81
|
+
declare function verifyWebhook(options: VerifyWebhookOptions): WebhookEvent;
|
|
82
|
+
|
|
83
|
+
export { DEFAULT_TOLERANCE_SECONDS, EVENT_HEADER, SIGNATURE_HEADER, TIMESTAMP_HEADER, type VerifyWebhookOptions, type WebhookEvent, type WebhookPayload, computeWebhookSignature, verifyWebhook, verifyWebhookSignature };
|
package/dist/webhooks.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"webhooks.js"}
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dregs/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript SDK for Dregs, the fraud and abuse scoring service.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dregs",
|
|
7
|
+
"fraud",
|
|
8
|
+
"abuse",
|
|
9
|
+
"fraud-detection",
|
|
10
|
+
"bot-detection",
|
|
11
|
+
"risk-scoring"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://dregs.com",
|
|
14
|
+
"bugs": "https://github.com/dregs-sdk/dregs-sdk-typescript/issues",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/dregs-sdk/dregs-sdk-typescript.git"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "Dregs <support@dregs.com>",
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "./dist/index.cjs",
|
|
23
|
+
"module": "./dist/index.js",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"import": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"require": {
|
|
32
|
+
"types": "./dist/index.d.cts",
|
|
33
|
+
"default": "./dist/index.cjs"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"./webhooks": {
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./dist/webhooks.d.ts",
|
|
39
|
+
"default": "./dist/webhooks.js"
|
|
40
|
+
},
|
|
41
|
+
"require": {
|
|
42
|
+
"types": "./dist/webhooks.d.cts",
|
|
43
|
+
"default": "./dist/webhooks.cjs"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"./package.json": "./package.json"
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"dist",
|
|
50
|
+
"CHANGELOG.md"
|
|
51
|
+
],
|
|
52
|
+
"sideEffects": false,
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsup",
|
|
55
|
+
"clean": "rm -rf dist",
|
|
56
|
+
"format": "prettier --write .",
|
|
57
|
+
"format:check": "prettier --check .",
|
|
58
|
+
"lint": "eslint .",
|
|
59
|
+
"prepublishOnly": "npm run build",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"test:watch": "vitest",
|
|
62
|
+
"typecheck": "tsc --noEmit",
|
|
63
|
+
"verify:dist": "node scripts/smoke-dist.mjs",
|
|
64
|
+
"verify:package": "publint && attw --pack . --profile node16"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@arethetypeswrong/cli": "^0.18.2",
|
|
68
|
+
"@eslint/js": "^9.36.0",
|
|
69
|
+
"@types/node": "^22.20.4",
|
|
70
|
+
"eslint": "^9.36.0",
|
|
71
|
+
"eslint-config-prettier": "^10.1.8",
|
|
72
|
+
"prettier": "^3.6.2",
|
|
73
|
+
"publint": "^0.3.14",
|
|
74
|
+
"tsup": "^8.5.0",
|
|
75
|
+
"typescript": "^5.9.2",
|
|
76
|
+
"typescript-eslint": "^8.44.1",
|
|
77
|
+
"vitest": "^5.0.1"
|
|
78
|
+
},
|
|
79
|
+
"engines": {
|
|
80
|
+
"node": ">=20"
|
|
81
|
+
},
|
|
82
|
+
"publishConfig": {
|
|
83
|
+
"access": "public",
|
|
84
|
+
"provenance": true
|
|
85
|
+
}
|
|
86
|
+
}
|