@robinpath/webhook 0.1.0 → 0.1.1
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/README.md +91 -91
- package/package.json +36 -7
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -12
- package/dist/index.js.map +0 -1
- package/dist/webhook.d.ts +0 -113
- package/dist/webhook.d.ts.map +0 -1
- package/dist/webhook.js +0 -228
- package/dist/webhook.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
# @robinpath/webhook
|
|
2
|
-
|
|
3
|
-
> Send webhooks with HMAC signatures, verify incoming webhook payloads, and prevent replay attacks
|
|
4
|
-
|
|
5
|
-
   
|
|
6
|
-
|
|
7
|
-
## Why use this module?
|
|
8
|
-
|
|
9
|
-
The `webhook` module lets you:
|
|
10
|
-
|
|
11
|
-
- Send a webhook POST request with optional HMAC signature
|
|
12
|
-
- Create an HMAC signature for a webhook payload
|
|
13
|
-
- Verify a webhook HMAC signature using timing-safe comparison
|
|
14
|
-
- Verify a webhook timestamp is within acceptable tolerance to prevent replay attacks
|
|
15
|
-
- Parse a raw webhook body based on content type
|
|
16
|
-
|
|
17
|
-
All functions are callable directly from RobinPath scripts with a simple, consistent API.
|
|
18
|
-
|
|
19
|
-
## Installation
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install @robinpath/webhook
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Quick Start
|
|
26
|
-
|
|
27
|
-
No credentials needed — start using it right away:
|
|
28
|
-
|
|
29
|
-
```robinpath
|
|
30
|
-
webhook.sign $payload "whsec_abc"
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Available Functions
|
|
34
|
-
|
|
35
|
-
| Function | Description |
|
|
36
|
-
|----------|-------------|
|
|
37
|
-
| `webhook.send` | Send a webhook POST request with optional HMAC signature |
|
|
38
|
-
| `webhook.sign` | Create an HMAC signature for a webhook payload |
|
|
39
|
-
| `webhook.verify` | Verify a webhook HMAC signature using timing-safe comparison |
|
|
40
|
-
| `webhook.verifyTimestamp` | Verify a webhook timestamp is within acceptable tolerance to prevent replay attacks |
|
|
41
|
-
| `webhook.parsePayload` | Parse a raw webhook body based on content type |
|
|
42
|
-
| `webhook.buildPayload` | Build a standardized webhook payload with event name, data, timestamp, and ID |
|
|
43
|
-
| `webhook.headers` | Build webhook headers including signature and timestamp |
|
|
44
|
-
| `webhook.isValidUrl` | Check if a string is a valid HTTP/HTTPS webhook URL |
|
|
45
|
-
|
|
46
|
-
## Examples
|
|
47
|
-
|
|
48
|
-
### Create an HMAC signature for a webhook payload
|
|
49
|
-
|
|
50
|
-
```robinpath
|
|
51
|
-
webhook.sign $payload "whsec_abc"
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Verify a webhook HMAC signature using timing-safe comparison
|
|
55
|
-
|
|
56
|
-
```robinpath
|
|
57
|
-
webhook.verify $body "whsec_abc" $signatureHeader
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Verify a webhook timestamp is within acceptable tolerance to prevent replay attacks
|
|
61
|
-
|
|
62
|
-
```robinpath
|
|
63
|
-
webhook.verifyTimestamp $timestamp 60000
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Integration with RobinPath
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
69
|
-
import { RobinPath } from "@wiredwp/robinpath";
|
|
70
|
-
import Module from "@robinpath/webhook";
|
|
71
|
-
|
|
72
|
-
const rp = new RobinPath();
|
|
73
|
-
rp.registerModule(Module.name, Module.functions);
|
|
74
|
-
rp.registerModuleMeta(Module.name, Module.functionMetadata);
|
|
75
|
-
|
|
76
|
-
const result = await rp.executeScript(`
|
|
77
|
-
webhook.sign $payload "whsec_abc"
|
|
78
|
-
`);
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## Full API Reference
|
|
82
|
-
|
|
83
|
-
See [MODULE.md](./MODULE.md) for complete documentation including all parameters, return types, error handling, and advanced examples.
|
|
84
|
-
|
|
85
|
-
## Related Modules
|
|
86
|
-
|
|
87
|
-
- [`@robinpath/json`](../json) — JSON module for complementary functionality
|
|
88
|
-
|
|
89
|
-
## License
|
|
90
|
-
|
|
91
|
-
MIT
|
|
1
|
+
# @robinpath/webhook
|
|
2
|
+
|
|
3
|
+
> Send webhooks with HMAC signatures, verify incoming webhook payloads, and prevent replay attacks
|
|
4
|
+
|
|
5
|
+
   
|
|
6
|
+
|
|
7
|
+
## Why use this module?
|
|
8
|
+
|
|
9
|
+
The `webhook` module lets you:
|
|
10
|
+
|
|
11
|
+
- Send a webhook POST request with optional HMAC signature
|
|
12
|
+
- Create an HMAC signature for a webhook payload
|
|
13
|
+
- Verify a webhook HMAC signature using timing-safe comparison
|
|
14
|
+
- Verify a webhook timestamp is within acceptable tolerance to prevent replay attacks
|
|
15
|
+
- Parse a raw webhook body based on content type
|
|
16
|
+
|
|
17
|
+
All functions are callable directly from RobinPath scripts with a simple, consistent API.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @robinpath/webhook
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
No credentials needed — start using it right away:
|
|
28
|
+
|
|
29
|
+
```robinpath
|
|
30
|
+
webhook.sign $payload "whsec_abc"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Available Functions
|
|
34
|
+
|
|
35
|
+
| Function | Description |
|
|
36
|
+
|----------|-------------|
|
|
37
|
+
| `webhook.send` | Send a webhook POST request with optional HMAC signature |
|
|
38
|
+
| `webhook.sign` | Create an HMAC signature for a webhook payload |
|
|
39
|
+
| `webhook.verify` | Verify a webhook HMAC signature using timing-safe comparison |
|
|
40
|
+
| `webhook.verifyTimestamp` | Verify a webhook timestamp is within acceptable tolerance to prevent replay attacks |
|
|
41
|
+
| `webhook.parsePayload` | Parse a raw webhook body based on content type |
|
|
42
|
+
| `webhook.buildPayload` | Build a standardized webhook payload with event name, data, timestamp, and ID |
|
|
43
|
+
| `webhook.headers` | Build webhook headers including signature and timestamp |
|
|
44
|
+
| `webhook.isValidUrl` | Check if a string is a valid HTTP/HTTPS webhook URL |
|
|
45
|
+
|
|
46
|
+
## Examples
|
|
47
|
+
|
|
48
|
+
### Create an HMAC signature for a webhook payload
|
|
49
|
+
|
|
50
|
+
```robinpath
|
|
51
|
+
webhook.sign $payload "whsec_abc"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Verify a webhook HMAC signature using timing-safe comparison
|
|
55
|
+
|
|
56
|
+
```robinpath
|
|
57
|
+
webhook.verify $body "whsec_abc" $signatureHeader
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Verify a webhook timestamp is within acceptable tolerance to prevent replay attacks
|
|
61
|
+
|
|
62
|
+
```robinpath
|
|
63
|
+
webhook.verifyTimestamp $timestamp 60000
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Integration with RobinPath
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { RobinPath } from "@wiredwp/robinpath";
|
|
70
|
+
import Module from "@robinpath/webhook";
|
|
71
|
+
|
|
72
|
+
const rp = new RobinPath();
|
|
73
|
+
rp.registerModule(Module.name, Module.functions);
|
|
74
|
+
rp.registerModuleMeta(Module.name, Module.functionMetadata);
|
|
75
|
+
|
|
76
|
+
const result = await rp.executeScript(`
|
|
77
|
+
webhook.sign $payload "whsec_abc"
|
|
78
|
+
`);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Full API Reference
|
|
82
|
+
|
|
83
|
+
See [MODULE.md](./MODULE.md) for complete documentation including all parameters, return types, error handling, and advanced examples.
|
|
84
|
+
|
|
85
|
+
## Related Modules
|
|
86
|
+
|
|
87
|
+
- [`@robinpath/json`](../json) — JSON module for complementary functionality
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,14 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robinpath/webhook",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Send and verify webhooks with HMAC signatures for RobinPath",
|
|
5
|
-
"publishConfig": {
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
6
8
|
"type": "module",
|
|
7
9
|
"main": "dist/index.js",
|
|
8
10
|
"types": "dist/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"test": "node --import tsx --test tests/*.test.ts"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@robinpath/core": ">=0.20.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@robinpath/core": "^0.30.1",
|
|
29
|
+
"tsx": "^4.19.0",
|
|
30
|
+
"typescript": "^5.6.0"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"webhook",
|
|
34
|
+
"web"
|
|
35
|
+
],
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"robinpath": {
|
|
38
|
+
"category": "web",
|
|
39
|
+
"type": "utility",
|
|
40
|
+
"auth": "none",
|
|
41
|
+
"functionCount": 8
|
|
42
|
+
}
|
|
14
43
|
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { ModuleAdapter } from "@wiredwp/robinpath";
|
|
2
|
-
declare const WebhookModule: ModuleAdapter;
|
|
3
|
-
export default WebhookModule;
|
|
4
|
-
export { WebhookModule };
|
|
5
|
-
export { WebhookFunctions, WebhookFunctionMetadata, WebhookModuleMetadata } from "./webhook.js";
|
|
6
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,QAAA,MAAM,aAAa,EAAE,aAMpB,CAAC;AAEF,eAAe,aAAa,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { WebhookFunctions, WebhookFunctionMetadata, WebhookModuleMetadata } from "./webhook.js";
|
|
2
|
-
const WebhookModule = {
|
|
3
|
-
name: "webhook",
|
|
4
|
-
functions: WebhookFunctions,
|
|
5
|
-
functionMetadata: WebhookFunctionMetadata,
|
|
6
|
-
moduleMetadata: WebhookModuleMetadata,
|
|
7
|
-
global: false,
|
|
8
|
-
}; // as ModuleAdapter
|
|
9
|
-
export default WebhookModule;
|
|
10
|
-
export { WebhookModule };
|
|
11
|
-
export { WebhookFunctions, WebhookFunctionMetadata, WebhookModuleMetadata } from "./webhook.js";
|
|
12
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAEhG,MAAM,aAAa,GAAkB;IACnC,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,gBAAgB;IAC3B,gBAAgB,EAAE,uBAA8B;IAChD,cAAc,EAAE,qBAA4B;IAC5C,MAAM,EAAE,KAAK;CACd,CAAC,CAAC,mBAAmB;AAEtB,eAAe,aAAa,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/webhook.d.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import type { BuiltinHandler } from "@wiredwp/robinpath";
|
|
2
|
-
export declare const WebhookFunctions: Record<string, BuiltinHandler>;
|
|
3
|
-
export declare const WebhookFunctionMetadata: {
|
|
4
|
-
send: {
|
|
5
|
-
description: string;
|
|
6
|
-
parameters: {
|
|
7
|
-
name: string;
|
|
8
|
-
dataType: string;
|
|
9
|
-
description: string;
|
|
10
|
-
formInputType: string;
|
|
11
|
-
required: boolean;
|
|
12
|
-
}[];
|
|
13
|
-
returnType: string;
|
|
14
|
-
returnDescription: string;
|
|
15
|
-
example: string;
|
|
16
|
-
};
|
|
17
|
-
sign: {
|
|
18
|
-
description: string;
|
|
19
|
-
parameters: {
|
|
20
|
-
name: string;
|
|
21
|
-
dataType: string;
|
|
22
|
-
description: string;
|
|
23
|
-
formInputType: string;
|
|
24
|
-
required: boolean;
|
|
25
|
-
}[];
|
|
26
|
-
returnType: string;
|
|
27
|
-
returnDescription: string;
|
|
28
|
-
example: string;
|
|
29
|
-
};
|
|
30
|
-
verify: {
|
|
31
|
-
description: string;
|
|
32
|
-
parameters: {
|
|
33
|
-
name: string;
|
|
34
|
-
dataType: string;
|
|
35
|
-
description: string;
|
|
36
|
-
formInputType: string;
|
|
37
|
-
required: boolean;
|
|
38
|
-
}[];
|
|
39
|
-
returnType: string;
|
|
40
|
-
returnDescription: string;
|
|
41
|
-
example: string;
|
|
42
|
-
};
|
|
43
|
-
verifyTimestamp: {
|
|
44
|
-
description: string;
|
|
45
|
-
parameters: {
|
|
46
|
-
name: string;
|
|
47
|
-
dataType: string;
|
|
48
|
-
description: string;
|
|
49
|
-
formInputType: string;
|
|
50
|
-
required: boolean;
|
|
51
|
-
}[];
|
|
52
|
-
returnType: string;
|
|
53
|
-
returnDescription: string;
|
|
54
|
-
example: string;
|
|
55
|
-
};
|
|
56
|
-
parsePayload: {
|
|
57
|
-
description: string;
|
|
58
|
-
parameters: {
|
|
59
|
-
name: string;
|
|
60
|
-
dataType: string;
|
|
61
|
-
description: string;
|
|
62
|
-
formInputType: string;
|
|
63
|
-
required: boolean;
|
|
64
|
-
}[];
|
|
65
|
-
returnType: string;
|
|
66
|
-
returnDescription: string;
|
|
67
|
-
example: string;
|
|
68
|
-
};
|
|
69
|
-
buildPayload: {
|
|
70
|
-
description: string;
|
|
71
|
-
parameters: {
|
|
72
|
-
name: string;
|
|
73
|
-
dataType: string;
|
|
74
|
-
description: string;
|
|
75
|
-
formInputType: string;
|
|
76
|
-
required: boolean;
|
|
77
|
-
}[];
|
|
78
|
-
returnType: string;
|
|
79
|
-
returnDescription: string;
|
|
80
|
-
example: string;
|
|
81
|
-
};
|
|
82
|
-
headers: {
|
|
83
|
-
description: string;
|
|
84
|
-
parameters: {
|
|
85
|
-
name: string;
|
|
86
|
-
dataType: string;
|
|
87
|
-
description: string;
|
|
88
|
-
formInputType: string;
|
|
89
|
-
required: boolean;
|
|
90
|
-
}[];
|
|
91
|
-
returnType: string;
|
|
92
|
-
returnDescription: string;
|
|
93
|
-
example: string;
|
|
94
|
-
};
|
|
95
|
-
isValidUrl: {
|
|
96
|
-
description: string;
|
|
97
|
-
parameters: {
|
|
98
|
-
name: string;
|
|
99
|
-
dataType: string;
|
|
100
|
-
description: string;
|
|
101
|
-
formInputType: string;
|
|
102
|
-
required: boolean;
|
|
103
|
-
}[];
|
|
104
|
-
returnType: string;
|
|
105
|
-
returnDescription: string;
|
|
106
|
-
example: string;
|
|
107
|
-
};
|
|
108
|
-
};
|
|
109
|
-
export declare const WebhookModuleMetadata: {
|
|
110
|
-
description: string;
|
|
111
|
-
methods: string[];
|
|
112
|
-
};
|
|
113
|
-
//# sourceMappingURL=webhook.d.ts.map
|
package/dist/webhook.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA2C,MAAM,oBAAoB,CAAC;AAiLlG,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAE3D,CAAC;AAEF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEnC,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;CAGjC,CAAC"}
|
package/dist/webhook.js
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
-
// ── Function Handlers ───────────────────────────────────────────────
|
|
3
|
-
const send = async (args) => {
|
|
4
|
-
const url = String(args[0] ?? "");
|
|
5
|
-
const payload = args[1];
|
|
6
|
-
const opts = (typeof args[2] === "object" && args[2] !== null ? args[2] : {});
|
|
7
|
-
if (!url)
|
|
8
|
-
throw new Error("URL is required");
|
|
9
|
-
const secret = opts.secret != null ? String(opts.secret) : undefined;
|
|
10
|
-
const method = String(opts.method ?? "POST").toUpperCase();
|
|
11
|
-
const contentType = String(opts.contentType ?? "application/json");
|
|
12
|
-
const headers = {
|
|
13
|
-
"Content-Type": contentType,
|
|
14
|
-
"User-Agent": "RobinPath-Webhook/1.0",
|
|
15
|
-
};
|
|
16
|
-
// Merge custom headers
|
|
17
|
-
if (typeof opts.headers === "object" && opts.headers !== null) {
|
|
18
|
-
for (const [k, v] of Object.entries(opts.headers)) {
|
|
19
|
-
headers[k] = String(v);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
const body = contentType.includes("json") ? JSON.stringify(payload) : String(payload);
|
|
23
|
-
// Sign the payload if secret is provided
|
|
24
|
-
if (secret) {
|
|
25
|
-
const algorithm = String(opts.algorithm ?? "sha256");
|
|
26
|
-
const signature = createHmac(algorithm, secret).update(body).digest("hex");
|
|
27
|
-
const headerName = String(opts.signatureHeader ?? "X-Webhook-Signature");
|
|
28
|
-
headers[headerName] = `${algorithm}=${signature}`;
|
|
29
|
-
}
|
|
30
|
-
// Add timestamp
|
|
31
|
-
const timestamp = Date.now().toString();
|
|
32
|
-
headers["X-Webhook-Timestamp"] = timestamp;
|
|
33
|
-
// Add custom event type
|
|
34
|
-
if (opts.event) {
|
|
35
|
-
headers["X-Webhook-Event"] = String(opts.event);
|
|
36
|
-
}
|
|
37
|
-
const response = await fetch(url, { method, headers, body });
|
|
38
|
-
return {
|
|
39
|
-
status: response.status,
|
|
40
|
-
statusText: response.statusText,
|
|
41
|
-
ok: response.ok,
|
|
42
|
-
headers: Object.fromEntries(response.headers.entries()),
|
|
43
|
-
body: response.headers.get("content-type")?.includes("json")
|
|
44
|
-
? await response.json()
|
|
45
|
-
: await response.text(),
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
|
-
const sign = (args) => {
|
|
49
|
-
const payload = typeof args[0] === "string" ? args[0] : JSON.stringify(args[0]);
|
|
50
|
-
const secret = String(args[1] ?? "");
|
|
51
|
-
const algorithm = String(args[2] ?? "sha256");
|
|
52
|
-
const signature = createHmac(algorithm, secret).update(payload).digest("hex");
|
|
53
|
-
return `${algorithm}=${signature}`;
|
|
54
|
-
};
|
|
55
|
-
const verify = (args) => {
|
|
56
|
-
const payload = typeof args[0] === "string" ? args[0] : JSON.stringify(args[0]);
|
|
57
|
-
const secret = String(args[1] ?? "");
|
|
58
|
-
const signature = String(args[2] ?? "");
|
|
59
|
-
const algorithm = String(args[3] ?? "sha256");
|
|
60
|
-
// Parse the signature format "algorithm=hex"
|
|
61
|
-
let expectedAlgo = algorithm;
|
|
62
|
-
let sigHex = signature;
|
|
63
|
-
if (signature.includes("=")) {
|
|
64
|
-
const parts = signature.split("=");
|
|
65
|
-
expectedAlgo = parts[0];
|
|
66
|
-
sigHex = parts.slice(1).join("=");
|
|
67
|
-
}
|
|
68
|
-
const expected = createHmac(expectedAlgo, secret).update(payload).digest("hex");
|
|
69
|
-
if (expected.length !== sigHex.length)
|
|
70
|
-
return false;
|
|
71
|
-
try {
|
|
72
|
-
return timingSafeEqual(Buffer.from(expected), Buffer.from(sigHex));
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
const verifyTimestamp = (args) => {
|
|
79
|
-
const timestamp = parseInt(String(args[0] ?? "0"), 10);
|
|
80
|
-
const toleranceMs = parseInt(String(args[1] ?? "300000"), 10); // default 5 minutes
|
|
81
|
-
const now = Date.now();
|
|
82
|
-
const diff = Math.abs(now - timestamp);
|
|
83
|
-
return {
|
|
84
|
-
valid: diff <= toleranceMs,
|
|
85
|
-
ageMs: diff,
|
|
86
|
-
toleranceMs,
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
const parsePayload = (args) => {
|
|
90
|
-
const body = args[0];
|
|
91
|
-
const contentType = String(args[1] ?? "application/json");
|
|
92
|
-
if (contentType.includes("json")) {
|
|
93
|
-
if (typeof body === "string")
|
|
94
|
-
return JSON.parse(body);
|
|
95
|
-
return body;
|
|
96
|
-
}
|
|
97
|
-
if (contentType.includes("x-www-form-urlencoded")) {
|
|
98
|
-
const params = new URLSearchParams(String(body));
|
|
99
|
-
const result = {};
|
|
100
|
-
for (const [key, value] of params.entries()) {
|
|
101
|
-
result[key] = value;
|
|
102
|
-
}
|
|
103
|
-
return result;
|
|
104
|
-
}
|
|
105
|
-
return String(body);
|
|
106
|
-
};
|
|
107
|
-
const buildPayload = (args) => {
|
|
108
|
-
const event = String(args[0] ?? "");
|
|
109
|
-
const data = args[1];
|
|
110
|
-
const opts = (typeof args[2] === "object" && args[2] !== null ? args[2] : {});
|
|
111
|
-
return {
|
|
112
|
-
event,
|
|
113
|
-
data,
|
|
114
|
-
timestamp: new Date().toISOString(),
|
|
115
|
-
id: opts.id ?? `wh_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`,
|
|
116
|
-
...(opts.metadata ? { metadata: opts.metadata } : {}),
|
|
117
|
-
};
|
|
118
|
-
};
|
|
119
|
-
const headers = (args) => {
|
|
120
|
-
const secret = String(args[0] ?? "");
|
|
121
|
-
const payload = typeof args[1] === "string" ? args[1] : JSON.stringify(args[1]);
|
|
122
|
-
const event = args[2] != null ? String(args[2]) : undefined;
|
|
123
|
-
const algorithm = String(args[3] ?? "sha256");
|
|
124
|
-
const timestamp = Date.now().toString();
|
|
125
|
-
const result = {
|
|
126
|
-
"Content-Type": "application/json",
|
|
127
|
-
"User-Agent": "RobinPath-Webhook/1.0",
|
|
128
|
-
"X-Webhook-Timestamp": timestamp,
|
|
129
|
-
};
|
|
130
|
-
if (secret) {
|
|
131
|
-
const signature = createHmac(algorithm, secret).update(payload).digest("hex");
|
|
132
|
-
result["X-Webhook-Signature"] = `${algorithm}=${signature}`;
|
|
133
|
-
}
|
|
134
|
-
if (event) {
|
|
135
|
-
result["X-Webhook-Event"] = event;
|
|
136
|
-
}
|
|
137
|
-
return result;
|
|
138
|
-
};
|
|
139
|
-
const isValidUrl = (args) => {
|
|
140
|
-
const url = String(args[0] ?? "");
|
|
141
|
-
try {
|
|
142
|
-
const parsed = new URL(url);
|
|
143
|
-
return parsed.protocol === "https:" || parsed.protocol === "http:";
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
// ── Exports ─────────────────────────────────────────────────────────
|
|
150
|
-
export const WebhookFunctions = {
|
|
151
|
-
send, sign, verify, verifyTimestamp, parsePayload, buildPayload, headers, isValidUrl,
|
|
152
|
-
};
|
|
153
|
-
export const WebhookFunctionMetadata = {
|
|
154
|
-
send: {
|
|
155
|
-
description: "Send a webhook POST request with optional HMAC signature",
|
|
156
|
-
parameters: [
|
|
157
|
-
{ name: "url", dataType: "string", description: "Target webhook URL", formInputType: "text", required: true },
|
|
158
|
-
{ name: "payload", dataType: "any", description: "Data to send", formInputType: "text", required: true },
|
|
159
|
-
{ name: "options", dataType: "object", description: "{secret, method, contentType, headers, algorithm, signatureHeader, event}", formInputType: "text", required: false },
|
|
160
|
-
],
|
|
161
|
-
returnType: "object", returnDescription: "{status, statusText, ok, headers, body}", example: 'webhook.send "https://example.com/hook" $data {"secret": "whsec_abc"}',
|
|
162
|
-
},
|
|
163
|
-
sign: {
|
|
164
|
-
description: "Create an HMAC signature for a webhook payload",
|
|
165
|
-
parameters: [
|
|
166
|
-
{ name: "payload", dataType: "any", description: "The payload to sign (string or object)", formInputType: "text", required: true },
|
|
167
|
-
{ name: "secret", dataType: "string", description: "The webhook secret", formInputType: "text", required: true },
|
|
168
|
-
{ name: "algorithm", dataType: "string", description: "Hash algorithm (default: sha256)", formInputType: "text", required: false },
|
|
169
|
-
],
|
|
170
|
-
returnType: "string", returnDescription: "Signature in format 'algorithm=hex'", example: 'webhook.sign $payload "whsec_abc"',
|
|
171
|
-
},
|
|
172
|
-
verify: {
|
|
173
|
-
description: "Verify a webhook HMAC signature using timing-safe comparison",
|
|
174
|
-
parameters: [
|
|
175
|
-
{ name: "payload", dataType: "any", description: "The received payload", formInputType: "text", required: true },
|
|
176
|
-
{ name: "secret", dataType: "string", description: "The webhook secret", formInputType: "text", required: true },
|
|
177
|
-
{ name: "signature", dataType: "string", description: "The received signature", formInputType: "text", required: true },
|
|
178
|
-
{ name: "algorithm", dataType: "string", description: "Hash algorithm (default: sha256)", formInputType: "text", required: false },
|
|
179
|
-
],
|
|
180
|
-
returnType: "boolean", returnDescription: "True if signature is valid", example: 'webhook.verify $body "whsec_abc" $signatureHeader',
|
|
181
|
-
},
|
|
182
|
-
verifyTimestamp: {
|
|
183
|
-
description: "Verify a webhook timestamp is within acceptable tolerance to prevent replay attacks",
|
|
184
|
-
parameters: [
|
|
185
|
-
{ name: "timestamp", dataType: "number", description: "Timestamp in milliseconds", formInputType: "text", required: true },
|
|
186
|
-
{ name: "toleranceMs", dataType: "number", description: "Tolerance in ms (default 300000 = 5min)", formInputType: "text", required: false },
|
|
187
|
-
],
|
|
188
|
-
returnType: "object", returnDescription: "{valid, ageMs, toleranceMs}", example: 'webhook.verifyTimestamp $timestamp 60000',
|
|
189
|
-
},
|
|
190
|
-
parsePayload: {
|
|
191
|
-
description: "Parse a raw webhook body based on content type",
|
|
192
|
-
parameters: [
|
|
193
|
-
{ name: "body", dataType: "any", description: "Raw request body", formInputType: "text", required: true },
|
|
194
|
-
{ name: "contentType", dataType: "string", description: "Content-Type header (default: application/json)", formInputType: "text", required: false },
|
|
195
|
-
],
|
|
196
|
-
returnType: "any", returnDescription: "Parsed payload", example: 'webhook.parsePayload $rawBody "application/json"',
|
|
197
|
-
},
|
|
198
|
-
buildPayload: {
|
|
199
|
-
description: "Build a standardized webhook payload with event name, data, timestamp, and ID",
|
|
200
|
-
parameters: [
|
|
201
|
-
{ name: "event", dataType: "string", description: "Event type name", formInputType: "text", required: true },
|
|
202
|
-
{ name: "data", dataType: "any", description: "Event data", formInputType: "text", required: true },
|
|
203
|
-
{ name: "options", dataType: "object", description: "{id, metadata}", formInputType: "text", required: false },
|
|
204
|
-
],
|
|
205
|
-
returnType: "object", returnDescription: "{event, data, timestamp, id}", example: 'webhook.buildPayload "order.created" $orderData',
|
|
206
|
-
},
|
|
207
|
-
headers: {
|
|
208
|
-
description: "Build webhook headers including signature and timestamp",
|
|
209
|
-
parameters: [
|
|
210
|
-
{ name: "secret", dataType: "string", description: "Webhook secret for signing", formInputType: "text", required: true },
|
|
211
|
-
{ name: "payload", dataType: "any", description: "The payload being sent", formInputType: "text", required: true },
|
|
212
|
-
{ name: "event", dataType: "string", description: "Event type header (optional)", formInputType: "text", required: false },
|
|
213
|
-
],
|
|
214
|
-
returnType: "object", returnDescription: "Headers object ready for HTTP request", example: 'webhook.headers "whsec_abc" $payload "order.created"',
|
|
215
|
-
},
|
|
216
|
-
isValidUrl: {
|
|
217
|
-
description: "Check if a string is a valid HTTP/HTTPS webhook URL",
|
|
218
|
-
parameters: [
|
|
219
|
-
{ name: "url", dataType: "string", description: "URL to validate", formInputType: "text", required: true },
|
|
220
|
-
],
|
|
221
|
-
returnType: "boolean", returnDescription: "True if valid HTTP(S) URL", example: 'webhook.isValidUrl "https://example.com/hook"',
|
|
222
|
-
},
|
|
223
|
-
};
|
|
224
|
-
export const WebhookModuleMetadata = {
|
|
225
|
-
description: "Send webhooks with HMAC signatures, verify incoming webhook payloads, and prevent replay attacks",
|
|
226
|
-
methods: ["send", "sign", "verify", "verifyTimestamp", "parsePayload", "buildPayload", "headers", "isValidUrl"],
|
|
227
|
-
};
|
|
228
|
-
//# sourceMappingURL=webhook.js.map
|
package/dist/webhook.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"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"}
|