@textbee/n8n-nodes-textbee 0.0.1 → 1.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/README.md +33 -10
- package/dist/credentials/TextbeeApi.credentials.js +2 -2
- package/dist/credentials/TextbeeApi.credentials.js.map +1 -1
- package/dist/nodes/Textbee/shared/signature.d.ts +3 -0
- package/dist/nodes/Textbee/shared/signature.js +40 -3
- package/dist/nodes/Textbee/shared/signature.js.map +1 -1
- package/dist/nodes/Textbee/shared/subscription.d.ts +3 -0
- package/dist/nodes/Textbee/shared/subscription.js +26 -0
- package/dist/nodes/Textbee/shared/subscription.js.map +1 -1
- package/dist/nodes/TextbeeTrigger/TextbeeTrigger.node.js +45 -18
- package/dist/nodes/TextbeeTrigger/TextbeeTrigger.node.js.map +1 -1
- package/package.json +74 -79
package/README.md
CHANGED
|
@@ -20,12 +20,14 @@ The textbee node can also be used as a tool by the n8n AI Agent.
|
|
|
20
20
|
3. Enter `@textbee/n8n-nodes-textbee`.
|
|
21
21
|
4. Agree to the risks and install.
|
|
22
22
|
|
|
23
|
-
Or
|
|
23
|
+
Or install it from the environment when n8n starts. The value is a JSON array:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
N8N_COMMUNITY_PACKAGES
|
|
26
|
+
N8N_COMMUNITY_PACKAGES='[{"name":"@textbee/n8n-nodes-textbee"}]'
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
Restart n8n after you set it. See [installing with environment variables](https://docs.n8n.io/integrations/community-nodes/installation-and-management/environment-variable-installation/) in the n8n docs.
|
|
30
|
+
|
|
29
31
|
### n8n Cloud
|
|
30
32
|
|
|
31
33
|
The nodes are in review for n8n verification. After approval you can add them from the nodes panel in n8n Cloud.
|
|
@@ -34,11 +36,11 @@ The nodes are in review for n8n verification. After approval you can add them fr
|
|
|
34
36
|
|
|
35
37
|
Create a **Textbee API** credential:
|
|
36
38
|
|
|
37
|
-
| Field | Required
|
|
38
|
-
| -------------------------- |
|
|
39
|
-
| **API Key** | Yes
|
|
40
|
-
| **Base URL** | No
|
|
41
|
-
| **Webhook Signing Secret** | Trigger
|
|
39
|
+
| Field | Required | Description |
|
|
40
|
+
| -------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
41
|
+
| **API Key** | Yes | From the [textbee dashboard](https://app.textbee.dev/dashboard). See [API keys](https://textbee.dev/docs/getting-started/api-keys). |
|
|
42
|
+
| **Base URL** | No | Defaults to `https://api.textbee.dev`. Change it for [self-hosted](https://textbee.dev/docs/self-hosting) instances. The `/api/v1` suffix is added automatically. |
|
|
43
|
+
| **Webhook Signing Secret** | No | Leave it empty: the textbee Trigger creates a separate secret for each workflow. Set it (at least 20 characters) only if you need the same secret across workflows. If set, it is always used. |
|
|
42
44
|
|
|
43
45
|
## Operations
|
|
44
46
|
|
|
@@ -55,9 +57,30 @@ Create a **Textbee API** credential:
|
|
|
55
57
|
|
|
56
58
|
Starts a workflow on these events: `MESSAGE_RECEIVED`, `MESSAGE_SENT`, `MESSAGE_DELIVERED`, `MESSAGE_FAILED`, `UNKNOWN_STATE`.
|
|
57
59
|
|
|
58
|
-
When you
|
|
60
|
+
No setup in the textbee dashboard is needed. When you publish the workflow, the trigger creates a webhook subscription in textbee that points at the n8n production webhook URL. When you unpublish it, the trigger deletes the subscription. If the URL, the events, or the signing secret change, the trigger updates the existing subscription instead of creating a new one. If events stop arriving, publish the workflow again.
|
|
61
|
+
|
|
62
|
+
The subscription is named `n8n: <workflow name> (<n8n host>)`, so you can see in the textbee dashboard which n8n instance owns it.
|
|
63
|
+
|
|
64
|
+
A textbee account can have 5 webhook subscriptions by default. The limit depends on your plan. Each published workflow with a textbee Trigger uses one.
|
|
65
|
+
|
|
66
|
+
#### Signing secret
|
|
67
|
+
|
|
68
|
+
When the credential **Webhook Signing Secret** is empty, the trigger creates a random secret for each workflow and keeps it in the workflow's static data in n8n. Each workflow then has its own secret, and the secret never appears in node output. When the credential secret is set, every trigger on that credential uses it, and the trigger also checks that each delivery belongs to its own subscription.
|
|
69
|
+
|
|
70
|
+
#### Signature checks and replay protection
|
|
71
|
+
|
|
72
|
+
textbee signs every delivery. Requests with a missing or wrong signature get HTTP 401.
|
|
73
|
+
|
|
74
|
+
- `X-Textbee-Signature: t=<unix seconds>,v1=<hex>`: `v1` is the HMAC-SHA256 of `<t>.<raw body>`. The trigger rejects a timestamp more than 5 minutes away from the current time, so a captured request cannot be replayed later. `X-Textbee-Timestamp` carries the same timestamp.
|
|
75
|
+
- `X-Signature`: the HMAC-SHA256 of the raw body, without a timestamp. textbee still sends it for older integrations.
|
|
76
|
+
|
|
77
|
+
When the textbee API reports timestamped signatures for the subscription, the trigger requires a valid `X-Textbee-Signature` and rejects requests that only carry `X-Signature`. Older and self-hosted textbee versions that do not send the timestamped header are still accepted with `X-Signature`.
|
|
78
|
+
|
|
79
|
+
Notes:
|
|
59
80
|
|
|
60
|
-
|
|
81
|
+
- After you upgrade this package, publish your textbee Trigger workflows again (or restart n8n). The trigger learns that the API supports timestamped signatures when the workflow is published.
|
|
82
|
+
- The n8n server clock must be correct (use NTP). A clock that is more than 5 minutes off makes every delivery fail.
|
|
83
|
+
- If you change the credential signing secret, publish the workflows again so textbee uses the new secret.
|
|
61
84
|
|
|
62
85
|
## Usage
|
|
63
86
|
|
|
@@ -75,7 +98,7 @@ A successful response means textbee accepted and queued the message. It is not a
|
|
|
75
98
|
1. In the textbee Android app, turn on **Receive SMS**.
|
|
76
99
|
2. Add a **textbee Trigger** and select **Message Received**.
|
|
77
100
|
3. Connect a **textbee** node with Operation **Send**. Set Recipients to `{{ $json.sender }}` and write the reply in Message.
|
|
78
|
-
4.
|
|
101
|
+
4. Publish the workflow. The production webhook URL must be public, because textbee does not deliver to localhost or private addresses. In development, use a tunnel.
|
|
79
102
|
|
|
80
103
|
textbee retries failed deliveries. Use the `idempotencyKey` field of the payload to skip duplicates.
|
|
81
104
|
|
|
@@ -32,8 +32,8 @@ class TextbeeApi {
|
|
|
32
32
|
type: 'string',
|
|
33
33
|
typeOptions: { password: true },
|
|
34
34
|
default: '',
|
|
35
|
-
description: '
|
|
36
|
-
hint: '
|
|
35
|
+
description: 'Optional. Leave empty and the textbee Trigger creates a separate secret for each workflow. Set it only if you need the same secret across workflows.',
|
|
36
|
+
hint: 'If set, use at least 20 characters',
|
|
37
37
|
},
|
|
38
38
|
];
|
|
39
39
|
this.authenticate = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextbeeApi.credentials.js","sourceRoot":"","sources":["../../credentials/TextbeeApi.credentials.ts"],"names":[],"mappings":";;;AAQA,6DAAoE;AAEpE,MAAa,UAAU;IAAvB;QACC,SAAI,GAAG,YAAY,CAAC;QAEpB,gBAAW,GAAG,aAAa,CAAC;QAE5B,SAAI,GAAS,EAAE,KAAK,EAAE,2BAA2B,EAAE,IAAI,EAAE,gCAAgC,EAAE,CAAC;QAE5F,qBAAgB,GAAG,mDAAmD,CAAC;QAEvE,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,oCAAoC;aACjD;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,yBAAyB;gBAClC,WAAW,EAAE,yBAAyB;gBACtC,WAAW,EACV,+IAA+I;aAChJ;YACD;gBACC,WAAW,EAAE,wBAAwB;gBACrC,IAAI,EAAE,sBAAsB;gBAC5B,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,
|
|
1
|
+
{"version":3,"file":"TextbeeApi.credentials.js","sourceRoot":"","sources":["../../credentials/TextbeeApi.credentials.ts"],"names":[],"mappings":";;;AAQA,6DAAoE;AAEpE,MAAa,UAAU;IAAvB;QACC,SAAI,GAAG,YAAY,CAAC;QAEpB,gBAAW,GAAG,aAAa,CAAC;QAE5B,SAAI,GAAS,EAAE,KAAK,EAAE,2BAA2B,EAAE,IAAI,EAAE,gCAAgC,EAAE,CAAC;QAE5F,qBAAgB,GAAG,mDAAmD,CAAC;QAEvE,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,oCAAoC;aACjD;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,yBAAyB;gBAClC,WAAW,EAAE,yBAAyB;gBACtC,WAAW,EACV,+IAA+I;aAChJ;YACD;gBACC,WAAW,EAAE,wBAAwB;gBACrC,IAAI,EAAE,sBAAsB;gBAC5B,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,sJAAsJ;gBACvJ,IAAI,EAAE,oCAAoC;aAC1C;SACD,CAAC;QAEF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACX,OAAO,EAAE;oBACR,WAAW,EAAE,0BAA0B;iBACvC;aACD;SACD,CAAC;QAEF,SAAI,GAA2B;YAC9B,OAAO,EAAE;gBACR,OAAO,EAAE,2BAAiB;gBAC1B,GAAG,EAAE,gBAAgB;gBACrB,MAAM,EAAE,KAAK;aACb;SACD,CAAC;IACH,CAAC;CAAA;AAxDD,gCAwDC"}
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export declare function computeSignature(body: Buffer | string, secret: string): string;
|
|
2
2
|
export declare function verifySignature(body: Buffer | string, header: string | undefined, secret: string | undefined): boolean;
|
|
3
|
+
export declare const SIGNATURE_TOLERANCE_SECONDS = 300;
|
|
4
|
+
export declare function verifyTimestampedSignature(body: Buffer | string, header: string | undefined, secret: string | undefined, nowSeconds: number, toleranceSeconds?: number): boolean;
|
|
5
|
+
export declare function generateSigningSecret(): string;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SIGNATURE_TOLERANCE_SECONDS = void 0;
|
|
3
4
|
exports.computeSignature = computeSignature;
|
|
4
5
|
exports.verifySignature = verifySignature;
|
|
6
|
+
exports.verifyTimestampedSignature = verifyTimestampedSignature;
|
|
7
|
+
exports.generateSigningSecret = generateSigningSecret;
|
|
5
8
|
const crypto_1 = require("crypto");
|
|
6
9
|
function computeSignature(body, secret) {
|
|
7
10
|
return (0, crypto_1.createHmac)('sha256', secret).update(body).digest('hex');
|
|
@@ -9,8 +12,42 @@ function computeSignature(body, secret) {
|
|
|
9
12
|
function verifySignature(body, header, secret) {
|
|
10
13
|
if (!secret || !header)
|
|
11
14
|
return false;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
return safeEqualHex(computeSignature(body, secret), header);
|
|
16
|
+
}
|
|
17
|
+
exports.SIGNATURE_TOLERANCE_SECONDS = 300;
|
|
18
|
+
function verifyTimestampedSignature(body, header, secret, nowSeconds, toleranceSeconds = exports.SIGNATURE_TOLERANCE_SECONDS) {
|
|
19
|
+
if (!secret || !header)
|
|
20
|
+
return false;
|
|
21
|
+
let timestamp;
|
|
22
|
+
const signatures = [];
|
|
23
|
+
for (const part of header.split(',')) {
|
|
24
|
+
const index = part.indexOf('=');
|
|
25
|
+
if (index < 0)
|
|
26
|
+
continue;
|
|
27
|
+
const key = part.slice(0, index).trim();
|
|
28
|
+
const value = part.slice(index + 1).trim();
|
|
29
|
+
if (key === 't') {
|
|
30
|
+
if (timestamp !== undefined)
|
|
31
|
+
return false;
|
|
32
|
+
timestamp = value;
|
|
33
|
+
}
|
|
34
|
+
else if (key === 'v1') {
|
|
35
|
+
signatures.push(value);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!timestamp || !/^\d{1,12}$/.test(timestamp) || signatures.length === 0)
|
|
39
|
+
return false;
|
|
40
|
+
if (Math.abs(nowSeconds - Number(timestamp)) > toleranceSeconds)
|
|
41
|
+
return false;
|
|
42
|
+
const expected = (0, crypto_1.createHmac)('sha256', secret).update(`${timestamp}.`).update(body).digest('hex');
|
|
43
|
+
return signatures.some((signature) => safeEqualHex(expected, signature));
|
|
44
|
+
}
|
|
45
|
+
function safeEqualHex(expected, provided) {
|
|
46
|
+
const a = Buffer.from(expected, 'utf8');
|
|
47
|
+
const b = Buffer.from(provided.trim().toLowerCase(), 'utf8');
|
|
48
|
+
return a.length === b.length && (0, crypto_1.timingSafeEqual)(a, b);
|
|
49
|
+
}
|
|
50
|
+
function generateSigningSecret() {
|
|
51
|
+
return (0, crypto_1.randomBytes)(32).toString('hex');
|
|
15
52
|
}
|
|
16
53
|
//# sourceMappingURL=signature.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signature.js","sourceRoot":"","sources":["../../../../nodes/Textbee/shared/signature.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"signature.js","sourceRoot":"","sources":["../../../../nodes/Textbee/shared/signature.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ export type WebhookSubscription = {
|
|
|
4
4
|
events?: string[];
|
|
5
5
|
isActive?: boolean;
|
|
6
6
|
signingSecret?: string;
|
|
7
|
+
signatureVersion?: number;
|
|
7
8
|
};
|
|
8
9
|
export type DesiredSubscription = {
|
|
9
10
|
deliveryUrl: string;
|
|
@@ -12,4 +13,6 @@ export type DesiredSubscription = {
|
|
|
12
13
|
};
|
|
13
14
|
export type SubscriptionPlan = 'keep' | 'update';
|
|
14
15
|
export declare function planSubscription(existing: WebhookSubscription, desired: DesiredSubscription): SubscriptionPlan;
|
|
16
|
+
export declare function subscriptionName(workflowName: string, deliveryUrl: string): string;
|
|
17
|
+
export declare function resolveSigningSecret(credentialSecret: unknown, storedSecret: unknown): string | undefined;
|
|
15
18
|
export declare function isNotFoundError(error: unknown): boolean;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.planSubscription = planSubscription;
|
|
4
|
+
exports.subscriptionName = subscriptionName;
|
|
5
|
+
exports.resolveSigningSecret = resolveSigningSecret;
|
|
4
6
|
exports.isNotFoundError = isNotFoundError;
|
|
5
7
|
function sameEvents(a, b) {
|
|
6
8
|
return [...a].sort().join(',') === [...b].sort().join(',');
|
|
@@ -13,6 +15,30 @@ function planSubscription(existing, desired) {
|
|
|
13
15
|
existing.signingSecret === desired.signingSecret;
|
|
14
16
|
return matches ? 'keep' : 'update';
|
|
15
17
|
}
|
|
18
|
+
const MAX_NAME_LENGTH = 64;
|
|
19
|
+
function subscriptionName(workflowName, deliveryUrl) {
|
|
20
|
+
const prefix = 'n8n: ';
|
|
21
|
+
let host = '';
|
|
22
|
+
try {
|
|
23
|
+
host = new URL(deliveryUrl).host;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
}
|
|
27
|
+
if (!host)
|
|
28
|
+
return `${prefix}${workflowName}`.slice(0, MAX_NAME_LENGTH).trimEnd();
|
|
29
|
+
const suffix = ` (${host})`;
|
|
30
|
+
const room = MAX_NAME_LENGTH - prefix.length - suffix.length;
|
|
31
|
+
if (room < 1)
|
|
32
|
+
return `${prefix}${workflowName}${suffix}`.slice(0, MAX_NAME_LENGTH);
|
|
33
|
+
return `${prefix}${workflowName.slice(0, room).trimEnd()}${suffix}`;
|
|
34
|
+
}
|
|
35
|
+
function resolveSigningSecret(credentialSecret, storedSecret) {
|
|
36
|
+
if (typeof credentialSecret === 'string' && credentialSecret !== '')
|
|
37
|
+
return credentialSecret;
|
|
38
|
+
if (typeof storedSecret === 'string' && storedSecret !== '')
|
|
39
|
+
return storedSecret;
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
16
42
|
function isNotFoundError(error) {
|
|
17
43
|
var _a, _b, _c, _d;
|
|
18
44
|
if (typeof error !== 'object' || error === null)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../../../nodes/Textbee/shared/subscription.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../../../nodes/Textbee/shared/subscription.ts"],"names":[],"mappings":";;AA2BA,4CAWC;AASD,4CAcC;AAMD,oDAOC;AAGD,0CAgBC;AA3ED,SAAS,UAAU,CAAC,CAAW,EAAE,CAAW;IAC3C,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5D,CAAC;AAOD,SAAgB,gBAAgB,CAC/B,QAA6B,EAC7B,OAA4B;;IAE5B,MAAM,OAAO,GACZ,QAAQ,CAAC,QAAQ,KAAK,IAAI;QAC1B,QAAQ,CAAC,WAAW,KAAK,OAAO,CAAC,WAAW;QAC5C,UAAU,CAAC,MAAA,QAAQ,CAAC,MAAM,mCAAI,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC;QACjD,QAAQ,CAAC,aAAa,KAAK,OAAO,CAAC,aAAa,CAAC;IAElD,OAAO,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpC,CAAC;AAGD,MAAM,eAAe,GAAG,EAAE,CAAC;AAM3B,SAAgB,gBAAgB,CAAC,YAAoB,EAAE,WAAmB;IACzE,MAAM,MAAM,GAAG,OAAO,CAAC;IACvB,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,CAAC;QACJ,IAAI,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;IAET,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,OAAO,GAAG,MAAM,GAAG,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,OAAO,EAAE,CAAC;IAEjF,MAAM,MAAM,GAAG,KAAK,IAAI,GAAG,CAAC;IAC5B,MAAM,IAAI,GAAG,eAAe,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7D,IAAI,IAAI,GAAG,CAAC;QAAE,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;IACnF,OAAO,GAAG,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC;AACrE,CAAC;AAMD,SAAgB,oBAAoB,CACnC,gBAAyB,EACzB,YAAqB;IAErB,IAAI,OAAO,gBAAgB,KAAK,QAAQ,IAAI,gBAAgB,KAAK,EAAE;QAAE,OAAO,gBAAgB,CAAC;IAC7F,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,KAAK,EAAE;QAAE,OAAO,YAAY,CAAC;IACjF,OAAO,SAAS,CAAC;AAClB,CAAC;AAGD,SAAgB,eAAe,CAAC,KAAc;;IAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAKT,CAAC;IACF,MAAM,KAAK,GAAG;QACb,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,UAAU;QACZ,MAAA,CAAC,CAAC,QAAQ,0CAAE,MAAM;QAClB,MAAA,MAAA,CAAC,CAAC,KAAK,0CAAE,QAAQ,0CAAE,MAAM;QACzB,MAAA,CAAC,CAAC,KAAK,0CAAE,MAAM;KACf,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -40,12 +40,20 @@ function webhookPath(webhookId) {
|
|
|
40
40
|
}
|
|
41
41
|
return `/webhooks/${webhookId}`;
|
|
42
42
|
}
|
|
43
|
-
async function desiredSubscription() {
|
|
43
|
+
async function desiredSubscription(generate) {
|
|
44
44
|
var _a;
|
|
45
45
|
const credentials = await this.getCredentials('textbeeApi');
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
48
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `
|
|
46
|
+
const sharedSecret = String((_a = credentials.webhookSigningSecret) !== null && _a !== void 0 ? _a : '');
|
|
47
|
+
if (sharedSecret !== '' && sharedSecret.length < MIN_SECRET_LENGTH) {
|
|
48
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The Webhook Signing Secret on the textbee API credential must be at least ${MIN_SECRET_LENGTH} characters. Leave it empty to let the trigger create one.`);
|
|
49
|
+
}
|
|
50
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
51
|
+
let signingSecret = (0, subscription_1.resolveSigningSecret)(sharedSecret, webhookData.signingSecret);
|
|
52
|
+
if (!signingSecret) {
|
|
53
|
+
if (!generate)
|
|
54
|
+
return undefined;
|
|
55
|
+
signingSecret = (0, signature_1.generateSigningSecret)();
|
|
56
|
+
webhookData.signingSecret = signingSecret;
|
|
49
57
|
}
|
|
50
58
|
return {
|
|
51
59
|
deliveryUrl: this.getNodeWebhookUrl('default'),
|
|
@@ -53,19 +61,27 @@ async function desiredSubscription() {
|
|
|
53
61
|
signingSecret,
|
|
54
62
|
};
|
|
55
63
|
}
|
|
56
|
-
function
|
|
64
|
+
function storeSignatureVersion(webhookData, subscription) {
|
|
65
|
+
var _a;
|
|
66
|
+
if (Number((_a = subscription === null || subscription === void 0 ? void 0 : subscription.signatureVersion) !== null && _a !== void 0 ? _a : 0) >= 2)
|
|
67
|
+
webhookData.signatureVersion = 2;
|
|
68
|
+
else
|
|
69
|
+
delete webhookData.signatureVersion;
|
|
70
|
+
}
|
|
71
|
+
function nameFor(desired) {
|
|
57
72
|
var _a;
|
|
58
|
-
return
|
|
73
|
+
return (0, subscription_1.subscriptionName)((_a = this.getWorkflow().name) !== null && _a !== void 0 ? _a : 'workflow', desired.deliveryUrl);
|
|
59
74
|
}
|
|
60
75
|
async function updateSubscription(webhookId, desired) {
|
|
61
76
|
try {
|
|
62
|
-
await transport_1.textbeeApiRequest.call(this, 'PATCH', webhookPath.call(this, webhookId), {
|
|
63
|
-
name:
|
|
77
|
+
const response = (await transport_1.textbeeApiRequest.call(this, 'PATCH', webhookPath.call(this, webhookId), {
|
|
78
|
+
name: nameFor.call(this, desired),
|
|
64
79
|
deliveryUrl: desired.deliveryUrl,
|
|
65
80
|
events: desired.events,
|
|
66
81
|
signingSecret: desired.signingSecret,
|
|
67
82
|
isActive: true,
|
|
68
|
-
});
|
|
83
|
+
}));
|
|
84
|
+
storeSignatureVersion(this.getWorkflowStaticData('node'), response === null || response === void 0 ? void 0 : response.data);
|
|
69
85
|
return true;
|
|
70
86
|
}
|
|
71
87
|
catch (error) {
|
|
@@ -114,7 +130,7 @@ class TextbeeTrigger {
|
|
|
114
130
|
description: 'The textbee events that start this workflow',
|
|
115
131
|
},
|
|
116
132
|
{
|
|
117
|
-
displayName: '
|
|
133
|
+
displayName: 'Publishing this workflow creates the webhook in textbee for you. You do not need to add a webhook in the textbee dashboard. textbee only delivers to public URLs, so a localhost n8n needs a tunnel. For Message Received, turn on Receive SMS in the textbee Android app. If events stop arriving, publish the workflow again.',
|
|
118
134
|
name: 'triggerNotice',
|
|
119
135
|
type: 'notice',
|
|
120
136
|
default: '',
|
|
@@ -141,13 +157,14 @@ class TextbeeTrigger {
|
|
|
141
157
|
delete webhookData.webhookId;
|
|
142
158
|
return false;
|
|
143
159
|
}
|
|
144
|
-
|
|
145
|
-
|
|
160
|
+
storeSignatureVersion(webhookData, subscription);
|
|
161
|
+
const desired = await desiredSubscription.call(this, false);
|
|
162
|
+
return desired !== undefined && (0, subscription_1.planSubscription)(subscription, desired) === 'keep';
|
|
146
163
|
},
|
|
147
164
|
async create() {
|
|
148
165
|
var _a;
|
|
149
166
|
const webhookData = this.getWorkflowStaticData('node');
|
|
150
|
-
const desired = await desiredSubscription.call(this);
|
|
167
|
+
const desired = (await desiredSubscription.call(this, true));
|
|
151
168
|
const storedId = webhookData.webhookId;
|
|
152
169
|
if (storedId && (await updateSubscription.call(this, storedId, desired))) {
|
|
153
170
|
return true;
|
|
@@ -160,12 +177,13 @@ class TextbeeTrigger {
|
|
|
160
177
|
return true;
|
|
161
178
|
}
|
|
162
179
|
const response = (await transport_1.textbeeApiRequest.call(this, 'POST', '/webhooks', {
|
|
163
|
-
name:
|
|
180
|
+
name: nameFor.call(this, desired),
|
|
164
181
|
deliveryUrl: desired.deliveryUrl,
|
|
165
182
|
signingSecret: desired.signingSecret,
|
|
166
183
|
events: desired.events,
|
|
167
184
|
}));
|
|
168
185
|
webhookData.webhookId = response.data._id;
|
|
186
|
+
storeSignatureVersion(webhookData, response.data);
|
|
169
187
|
return true;
|
|
170
188
|
},
|
|
171
189
|
async delete() {
|
|
@@ -181,26 +199,35 @@ class TextbeeTrigger {
|
|
|
181
199
|
throw (0, transport_1.toNodeApiError)(this.getNode(), error);
|
|
182
200
|
}
|
|
183
201
|
delete webhookData.webhookId;
|
|
202
|
+
delete webhookData.signingSecret;
|
|
203
|
+
delete webhookData.signatureVersion;
|
|
184
204
|
return true;
|
|
185
205
|
},
|
|
186
206
|
},
|
|
187
207
|
};
|
|
188
208
|
}
|
|
189
209
|
async webhook() {
|
|
210
|
+
var _a;
|
|
190
211
|
const credentials = await this.getCredentials('textbeeApi');
|
|
191
|
-
const
|
|
212
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
213
|
+
const signingSecret = (0, subscription_1.resolveSigningSecret)(credentials.webhookSigningSecret, webhookData.signingSecret);
|
|
192
214
|
const headerData = this.getHeaderData();
|
|
193
|
-
const
|
|
215
|
+
const legacyHeader = headerData['x-signature'];
|
|
216
|
+
const timestampedHeader = headerData['x-textbee-signature'];
|
|
194
217
|
const rawBody = this.getRequestObject().rawBody;
|
|
195
218
|
const bodyBuffer = Buffer.isBuffer(rawBody)
|
|
196
219
|
? rawBody
|
|
197
220
|
: Buffer.from(typeof rawBody === 'string' ? rawBody : JSON.stringify(this.getBodyData()));
|
|
198
|
-
|
|
221
|
+
const requireTimestamped = Number((_a = webhookData.signatureVersion) !== null && _a !== void 0 ? _a : 0) >= 2;
|
|
222
|
+
const valid = requireTimestamped || timestampedHeader !== undefined
|
|
223
|
+
? (0, signature_1.verifyTimestampedSignature)(bodyBuffer, timestampedHeader, signingSecret, Math.floor(Date.now() / 1000))
|
|
224
|
+
: (0, signature_1.verifySignature)(bodyBuffer, legacyHeader, signingSecret);
|
|
225
|
+
if (!valid) {
|
|
199
226
|
this.getResponseObject().status(401).json({ error: 'Invalid signature' });
|
|
200
227
|
return { noWebhookResponse: true };
|
|
201
228
|
}
|
|
202
229
|
const bodyData = this.getBodyData();
|
|
203
|
-
const ownId =
|
|
230
|
+
const ownId = webhookData.webhookId;
|
|
204
231
|
const deliveredFor = bodyData.webhookSubscriptionId;
|
|
205
232
|
if (ownId && deliveredFor && String(deliveredFor) !== String(ownId)) {
|
|
206
233
|
this.getResponseObject().status(401).json({ error: 'Unknown subscription' });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextbeeTrigger.node.js","sourceRoot":"","sources":["../../../nodes/TextbeeTrigger/TextbeeTrigger.node.ts"],"names":[],"mappings":";;;AAAA,+CASsB;AAEtB,
|
|
1
|
+
{"version":3,"file":"TextbeeTrigger.node.js","sourceRoot":"","sources":["../../../nodes/TextbeeTrigger/TextbeeTrigger.node.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,80 +1,75 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
},
|
|
77
|
-
"pnpm": {
|
|
78
|
-
"onlyBuiltDependencies": []
|
|
79
|
-
}
|
|
80
|
-
}
|
|
2
|
+
"name": "@textbee/n8n-nodes-textbee",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Official n8n nodes for textbee.dev: send and receive SMS through your own Android phone",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://textbee.dev/docs/agents/n8n",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"n8n-community-node-package",
|
|
9
|
+
"n8n",
|
|
10
|
+
"textbee",
|
|
11
|
+
"sms",
|
|
12
|
+
"sms-gateway",
|
|
13
|
+
"android"
|
|
14
|
+
],
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "textbee",
|
|
17
|
+
"email": "contact@textbee.dev",
|
|
18
|
+
"url": "https://textbee.dev"
|
|
19
|
+
},
|
|
20
|
+
"contributors": [
|
|
21
|
+
"Julius Haring (https://github.com/JuliusHaring)"
|
|
22
|
+
],
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/textbee/n8n-nodes-textbee.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/textbee/n8n-nodes-textbee/issues"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=20.15.0"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"!dist/package.json",
|
|
39
|
+
"!dist/tsconfig.tsbuildinfo",
|
|
40
|
+
"LICENSE.md",
|
|
41
|
+
"NOTICE.md"
|
|
42
|
+
],
|
|
43
|
+
"n8n": {
|
|
44
|
+
"n8nNodesApiVersion": 1,
|
|
45
|
+
"strict": true,
|
|
46
|
+
"credentials": [
|
|
47
|
+
"dist/credentials/TextbeeApi.credentials.js"
|
|
48
|
+
],
|
|
49
|
+
"nodes": [
|
|
50
|
+
"dist/nodes/Textbee/Textbee.node.js",
|
|
51
|
+
"dist/nodes/TextbeeTrigger/TextbeeTrigger.node.js"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@n8n/node-cli": "0.55.5",
|
|
56
|
+
"@types/node": "22.20.5",
|
|
57
|
+
"eslint": "9.29.0",
|
|
58
|
+
"n8n-workflow": "2.16.0",
|
|
59
|
+
"prettier": "3.9.10",
|
|
60
|
+
"typescript": "5.9.3",
|
|
61
|
+
"vitest": "5.1.0"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"n8n-workflow": "*"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "n8n-node build",
|
|
68
|
+
"dev": "n8n-node dev",
|
|
69
|
+
"lint": "n8n-node lint",
|
|
70
|
+
"lint:fix": "n8n-node lint --fix",
|
|
71
|
+
"typecheck": "tsc --noEmit",
|
|
72
|
+
"test": "vitest run --maxWorkers=2",
|
|
73
|
+
"check:hygiene": "node scripts/hygiene.mjs"
|
|
74
|
+
}
|
|
75
|
+
}
|