n8n-nodes-zap-api 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/README.md +37 -0
- package/dist/credentials/ZapApiApi.credentials.d.ts +9 -0
- package/dist/credentials/ZapApiApi.credentials.js +43 -0
- package/dist/credentials/ZapApiApi.credentials.js.map +1 -0
- package/dist/nodes/ZapApi/ZapApi.node.d.ts +10 -0
- package/dist/nodes/ZapApi/ZapApi.node.js +119 -0
- package/dist/nodes/ZapApi/ZapApi.node.js.map +1 -0
- package/dist/nodes/ZapApi/zapapi.svg +1 -0
- package/dist/nodes/ZapApiTrigger/ZapApiTrigger.node.d.ts +18 -0
- package/dist/nodes/ZapApiTrigger/ZapApiTrigger.node.js +172 -0
- package/dist/nodes/ZapApiTrigger/ZapApiTrigger.node.js.map +1 -0
- package/dist/nodes/ZapApiTrigger/zapapi.svg +1 -0
- package/dist/nodes/shared/loadOptions.d.ts +10 -0
- package/dist/nodes/shared/loadOptions.js +31 -0
- package/dist/nodes/shared/loadOptions.js.map +1 -0
- package/dist/nodes/shared/verifySignature.d.ts +5 -0
- package/dist/nodes/shared/verifySignature.js +23 -0
- package/dist/nodes/shared/verifySignature.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# n8n-nodes-zap-api
|
|
2
|
+
|
|
3
|
+
Community node da [ZAP-API](https://zap-api.tech) (WhatsApp) para o [n8n](https://n8n.io).
|
|
4
|
+
|
|
5
|
+
## Instalação
|
|
6
|
+
|
|
7
|
+
n8n → **Settings → Community Nodes → Install** → `n8n-nodes-zap-api`.
|
|
8
|
+
|
|
9
|
+
## Credential
|
|
10
|
+
|
|
11
|
+
Crie uma credential **ZAP-API API**: `Base URL` (default `https://api.zap-api.tech/v1`)
|
|
12
|
+
e seu **API Token** (`tk_...`, do painel → Instâncias). Ao salvar, a credential é
|
|
13
|
+
validada com um `GET /instances`.
|
|
14
|
+
|
|
15
|
+
## Nodes
|
|
16
|
+
|
|
17
|
+
- **ZAP-API** (ação): operação *Send* — envia texto / imagem / áudio / vídeo / documento
|
|
18
|
+
(`type` + `mediaUrl`).
|
|
19
|
+
- **ZAP-API Trigger**: inicia o workflow em eventos (ex: `message.received`,
|
|
20
|
+
`message.status`, `instance.connected`, ...). Ao **ativar**, registra o webhook da
|
|
21
|
+
instância na URL do n8n e guarda o secret HMAC; ao **desativar**, limpa o webhook.
|
|
22
|
+
Cada evento recebido é verificado via `X-ZapAPI-Signature-256` (HMAC) — pode desligar
|
|
23
|
+
em *Verify Signature*, mas não é recomendado em produção.
|
|
24
|
+
|
|
25
|
+
### Requisitos do Trigger
|
|
26
|
+
|
|
27
|
+
- A instância precisa de uma **URL pública HTTPS** (n8n Cloud ou self-hosted com ingress
|
|
28
|
+
público) — webhooks **não** são entregues a IP privado/localhost (proteção anti-SSRF).
|
|
29
|
+
- **Atenção:** ativar o trigger **sobrescreve** um webhook já configurado na instância
|
|
30
|
+
(uma URL por instância).
|
|
31
|
+
|
|
32
|
+
## Publicação (mantenedor)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
cd n8n-node && npm run build && npm publish --access public
|
|
36
|
+
```
|
|
37
|
+
Requer `npm login` com permissão no pacote.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from "n8n-workflow";
|
|
2
|
+
export declare class ZapApiApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
authenticate: IAuthenticateGeneric;
|
|
8
|
+
test: ICredentialTestRequest;
|
|
9
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZapApiApi = void 0;
|
|
4
|
+
class ZapApiApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = "zapApiApi";
|
|
7
|
+
this.displayName = "ZAP-API API";
|
|
8
|
+
this.documentationUrl = "https://zap-api.tech/dashboard/docs";
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: "Base URL",
|
|
12
|
+
name: "baseUrl",
|
|
13
|
+
type: "string",
|
|
14
|
+
default: "https://api.zap-api.tech/v1",
|
|
15
|
+
description: "URL base da API (inclui /v1)",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
displayName: "API Token",
|
|
19
|
+
name: "apiToken",
|
|
20
|
+
type: "string",
|
|
21
|
+
typeOptions: { password: true },
|
|
22
|
+
default: "",
|
|
23
|
+
required: true,
|
|
24
|
+
description: "Token da instância (tk_...). Painel ZAP-API → Instâncias.",
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
this.authenticate = {
|
|
28
|
+
type: "generic",
|
|
29
|
+
properties: {
|
|
30
|
+
headers: { Authorization: "=Bearer {{$credentials.apiToken}}" },
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
// Valida a chave ao salvar: GET /instances deve responder 2xx.
|
|
34
|
+
this.test = {
|
|
35
|
+
request: {
|
|
36
|
+
baseURL: "={{$credentials.baseUrl}}",
|
|
37
|
+
url: "/instances",
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.ZapApiApi = ZapApiApi;
|
|
43
|
+
//# sourceMappingURL=ZapApiApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ZapApiApi.credentials.js","sourceRoot":"","sources":["../../credentials/ZapApiApi.credentials.ts"],"names":[],"mappings":";;;AAOA,MAAa,SAAS;IAAtB;QACE,SAAI,GAAG,WAAW,CAAC;QAEnB,gBAAW,GAAG,aAAa,CAAC;QAE5B,qBAAgB,GAAG,qCAAqC,CAAC;QAEzD,eAAU,GAAsB;YAC9B;gBACE,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,6BAA6B;gBACtC,WAAW,EAAE,8BAA8B;aAC5C;YACD;gBACE,WAAW,EAAE,WAAW;gBACxB,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,2DAA2D;aACzE;SACF,CAAC;QAEF,iBAAY,GAAyB;YACnC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACV,OAAO,EAAE,EAAE,aAAa,EAAE,mCAAmC,EAAE;aAChE;SACF,CAAC;QAEF,+DAA+D;QAC/D,SAAI,GAA2B;YAC7B,OAAO,EAAE;gBACP,OAAO,EAAE,2BAA2B;gBACpC,GAAG,EAAE,YAAY;aAClB;SACF,CAAC;IACJ,CAAC;CAAA;AAxCD,8BAwCC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { INodeType, INodeTypeDescription } from "n8n-workflow";
|
|
2
|
+
import { getInstances } from "../shared/loadOptions";
|
|
3
|
+
export declare class ZapApi implements INodeType {
|
|
4
|
+
description: INodeTypeDescription;
|
|
5
|
+
methods: {
|
|
6
|
+
loadOptions: {
|
|
7
|
+
getInstances: typeof getInstances;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZapApi = void 0;
|
|
4
|
+
const loadOptions_1 = require("../shared/loadOptions");
|
|
5
|
+
class ZapApi {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.description = {
|
|
8
|
+
displayName: "ZAP-API",
|
|
9
|
+
name: "zapApi",
|
|
10
|
+
icon: "file:zapapi.svg",
|
|
11
|
+
group: ["output"],
|
|
12
|
+
version: 1,
|
|
13
|
+
subtitle: '={{"Enviar para " + $parameter["phone"]}}',
|
|
14
|
+
description: "Enviar mensagens WhatsApp via ZAP-API",
|
|
15
|
+
defaults: { name: "ZAP-API" },
|
|
16
|
+
inputs: ["main"],
|
|
17
|
+
outputs: ["main"],
|
|
18
|
+
credentials: [{ name: "zapApiApi", required: true }],
|
|
19
|
+
requestDefaults: {
|
|
20
|
+
baseURL: "={{$credentials.baseUrl}}",
|
|
21
|
+
headers: { "Content-Type": "application/json" }
|
|
22
|
+
},
|
|
23
|
+
properties: [
|
|
24
|
+
{ displayName: "Resource", name: "resource", type: "hidden", default: "message" },
|
|
25
|
+
{
|
|
26
|
+
displayName: "Operation",
|
|
27
|
+
name: "operation",
|
|
28
|
+
type: "options",
|
|
29
|
+
noDataExpression: true,
|
|
30
|
+
options: [
|
|
31
|
+
{
|
|
32
|
+
name: "Send",
|
|
33
|
+
value: "send",
|
|
34
|
+
action: "Send a message",
|
|
35
|
+
routing: {
|
|
36
|
+
request: {
|
|
37
|
+
method: "POST",
|
|
38
|
+
url: "=/instances/{{$parameter.instanceId}}/send"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
default: "send"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
displayName: "Instance Name or ID",
|
|
47
|
+
name: "instanceId",
|
|
48
|
+
type: "options",
|
|
49
|
+
typeOptions: { loadOptionsMethod: "getInstances" },
|
|
50
|
+
default: "",
|
|
51
|
+
required: true,
|
|
52
|
+
description: "Escolha a instância. Choose from the list, or specify an ID using an expression."
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
displayName: "Phone",
|
|
56
|
+
name: "phone",
|
|
57
|
+
type: "string",
|
|
58
|
+
default: "",
|
|
59
|
+
required: true,
|
|
60
|
+
placeholder: "5511999999999",
|
|
61
|
+
routing: { send: { type: "body", property: "phone" } }
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
displayName: "Type",
|
|
65
|
+
name: "type",
|
|
66
|
+
type: "options",
|
|
67
|
+
options: [
|
|
68
|
+
{ name: "Text", value: "text" },
|
|
69
|
+
{ name: "Image", value: "image" },
|
|
70
|
+
{ name: "Audio", value: "audio" },
|
|
71
|
+
{ name: "Video", value: "video" },
|
|
72
|
+
{ name: "Document", value: "document" }
|
|
73
|
+
],
|
|
74
|
+
default: "text",
|
|
75
|
+
routing: { send: { type: "body", property: "type" } }
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
displayName: "Text",
|
|
79
|
+
name: "text",
|
|
80
|
+
type: "string",
|
|
81
|
+
typeOptions: { rows: 3 },
|
|
82
|
+
default: "",
|
|
83
|
+
displayOptions: { show: { type: ["text"] } },
|
|
84
|
+
routing: { send: { type: "body", property: "text" } }
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
displayName: "Media URL",
|
|
88
|
+
name: "mediaUrl",
|
|
89
|
+
type: "string",
|
|
90
|
+
default: "",
|
|
91
|
+
placeholder: "https://exemplo.com/arquivo.pdf",
|
|
92
|
+
displayOptions: { show: { type: ["image", "audio", "video", "document"] } },
|
|
93
|
+
routing: { send: { type: "body", property: "mediaUrl" } }
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
displayName: "Caption",
|
|
97
|
+
name: "caption",
|
|
98
|
+
type: "string",
|
|
99
|
+
default: "",
|
|
100
|
+
displayOptions: { show: { type: ["image", "video", "document"] } },
|
|
101
|
+
routing: { send: { type: "body", property: "caption" } }
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
displayName: "File Name",
|
|
105
|
+
name: "fileName",
|
|
106
|
+
type: "string",
|
|
107
|
+
default: "",
|
|
108
|
+
displayOptions: { show: { type: ["document"] } },
|
|
109
|
+
routing: { send: { type: "body", property: "fileName" } }
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
};
|
|
113
|
+
this.methods = {
|
|
114
|
+
loadOptions: { getInstances: loadOptions_1.getInstances }
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.ZapApi = ZapApi;
|
|
119
|
+
//# sourceMappingURL=ZapApi.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ZapApi.node.js","sourceRoot":"","sources":["../../../nodes/ZapApi/ZapApi.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><rect width="24" height="24" rx="5" fill="#22c55e"/><path d="M12 5a7 7 0 0 0-6 10.6L5 19l3.5-1A7 7 0 1 0 12 5z" fill="#fff"/></svg>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IHookFunctions, INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from "n8n-workflow";
|
|
2
|
+
import { getInstances } from "../shared/loadOptions";
|
|
3
|
+
export declare class ZapApiTrigger implements INodeType {
|
|
4
|
+
description: INodeTypeDescription;
|
|
5
|
+
methods: {
|
|
6
|
+
loadOptions: {
|
|
7
|
+
getInstances: typeof getInstances;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
webhookMethods: {
|
|
11
|
+
default: {
|
|
12
|
+
checkExists(this: IHookFunctions): Promise<boolean>;
|
|
13
|
+
create(this: IHookFunctions): Promise<boolean>;
|
|
14
|
+
delete(this: IHookFunctions): Promise<boolean>;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZapApiTrigger = void 0;
|
|
4
|
+
const loadOptions_1 = require("../shared/loadOptions");
|
|
5
|
+
const verifySignature_1 = require("../shared/verifySignature");
|
|
6
|
+
const EVENT_OPTIONS = [
|
|
7
|
+
"call.received",
|
|
8
|
+
"call.rejected",
|
|
9
|
+
"contact.update",
|
|
10
|
+
"group.join",
|
|
11
|
+
"group.leave",
|
|
12
|
+
"group.update",
|
|
13
|
+
"instance.connected",
|
|
14
|
+
"instance.disconnected",
|
|
15
|
+
"instance.qrcode",
|
|
16
|
+
"instance.test",
|
|
17
|
+
"label.update",
|
|
18
|
+
"message.deleted",
|
|
19
|
+
"message.edited",
|
|
20
|
+
"message.read",
|
|
21
|
+
"message.reaction",
|
|
22
|
+
"message.received",
|
|
23
|
+
"message.sent",
|
|
24
|
+
"message.status",
|
|
25
|
+
"newsletter.update",
|
|
26
|
+
"presence.update",
|
|
27
|
+
"status.viewed",
|
|
28
|
+
].map((e) => ({ name: e, value: e }));
|
|
29
|
+
class ZapApiTrigger {
|
|
30
|
+
constructor() {
|
|
31
|
+
this.description = {
|
|
32
|
+
displayName: "ZAP-API Trigger",
|
|
33
|
+
name: "zapApiTrigger",
|
|
34
|
+
icon: "file:zapapi.svg",
|
|
35
|
+
group: ["trigger"],
|
|
36
|
+
version: 1,
|
|
37
|
+
description: "Inicia o workflow em eventos do WhatsApp (ZAP-API)",
|
|
38
|
+
defaults: { name: "ZAP-API Trigger" },
|
|
39
|
+
inputs: [],
|
|
40
|
+
outputs: ["main"],
|
|
41
|
+
credentials: [{ name: "zapApiApi", required: true }],
|
|
42
|
+
webhooks: [
|
|
43
|
+
{
|
|
44
|
+
name: "default",
|
|
45
|
+
httpMethod: "POST",
|
|
46
|
+
responseMode: "onReceived",
|
|
47
|
+
path: "webhook",
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
properties: [
|
|
51
|
+
{
|
|
52
|
+
displayName: "Ativar este trigger SOBRESCREVE o webhook configurado na instância (uma URL por instância). Ao desativar, o webhook é limpo.",
|
|
53
|
+
name: "overwriteNotice",
|
|
54
|
+
type: "notice",
|
|
55
|
+
default: "",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
displayName: "Instance Name or ID",
|
|
59
|
+
name: "instanceId",
|
|
60
|
+
type: "options",
|
|
61
|
+
typeOptions: { loadOptionsMethod: "getInstances" },
|
|
62
|
+
default: "",
|
|
63
|
+
required: true,
|
|
64
|
+
description: "Escolha a instância. Choose from the list, or specify an ID using an expression.",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
displayName: "Events",
|
|
68
|
+
name: "events",
|
|
69
|
+
type: "multiOptions",
|
|
70
|
+
options: EVENT_OPTIONS,
|
|
71
|
+
default: ["message.received"],
|
|
72
|
+
required: true,
|
|
73
|
+
description: "Quais eventos disparam o workflow",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
displayName: "Verify Signature",
|
|
77
|
+
name: "verifySignature",
|
|
78
|
+
type: "boolean",
|
|
79
|
+
default: true,
|
|
80
|
+
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
|
|
81
|
+
description: "Whether to verify the X-ZapAPI-Signature-256 HMAC of each incoming webhook",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
displayName: "Com a verificação desligada, qualquer um que souber a URL do webhook pode disparar este fluxo. Mantenha ligada em produção.",
|
|
85
|
+
name: "noVerifyNotice",
|
|
86
|
+
type: "notice",
|
|
87
|
+
default: "",
|
|
88
|
+
displayOptions: { show: { verifySignature: [false] } },
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
this.methods = {
|
|
93
|
+
loadOptions: { getInstances: loadOptions_1.getInstances },
|
|
94
|
+
};
|
|
95
|
+
this.webhookMethods = {
|
|
96
|
+
default: {
|
|
97
|
+
async checkExists() {
|
|
98
|
+
// Always (re)create on activation — PUT is idempotent (overwrites the URL).
|
|
99
|
+
return false;
|
|
100
|
+
},
|
|
101
|
+
async create() {
|
|
102
|
+
const webhookUrl = this.getNodeWebhookUrl("default");
|
|
103
|
+
const instanceId = this.getNodeParameter("instanceId");
|
|
104
|
+
const events = this.getNodeParameter("events");
|
|
105
|
+
const creds = await this.getCredentials("zapApiApi");
|
|
106
|
+
let response;
|
|
107
|
+
try {
|
|
108
|
+
response = (await this.helpers.httpRequestWithAuthentication.call(this, "zapApiApi", {
|
|
109
|
+
method: "PUT",
|
|
110
|
+
baseURL: creds.baseUrl,
|
|
111
|
+
url: `/instances/${instanceId}/webhook`,
|
|
112
|
+
// secret: true → a ZAP-API gera um secret novo e o RETORNA na resposta.
|
|
113
|
+
body: { url: webhookUrl, events, secret: true },
|
|
114
|
+
json: true,
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
throw new Error(`Falha ao registrar o webhook na instância ${instanceId} (verifique o token, o ID da instância e se a URL do n8n é pública HTTPS): ${error.message}`);
|
|
119
|
+
}
|
|
120
|
+
if (!response?.webhookSecret) {
|
|
121
|
+
throw new Error("A ZAP-API não retornou o webhookSecret ao registrar — não é possível verificar a assinatura. Verifique a versão da API.");
|
|
122
|
+
}
|
|
123
|
+
this.getWorkflowStaticData("node").secret = response.webhookSecret;
|
|
124
|
+
return true;
|
|
125
|
+
},
|
|
126
|
+
async delete() {
|
|
127
|
+
const instanceId = this.getNodeParameter("instanceId");
|
|
128
|
+
const creds = await this.getCredentials("zapApiApi");
|
|
129
|
+
try {
|
|
130
|
+
await this.helpers.httpRequestWithAuthentication.call(this, "zapApiApi", {
|
|
131
|
+
method: "DELETE",
|
|
132
|
+
baseURL: creds.baseUrl,
|
|
133
|
+
url: `/instances/${instanceId}/webhook`,
|
|
134
|
+
json: true,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// best-effort: if the instance is gone, ignore the error.
|
|
139
|
+
}
|
|
140
|
+
const staticData = this.getWorkflowStaticData("node");
|
|
141
|
+
delete staticData.secret;
|
|
142
|
+
return true;
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async webhook() {
|
|
148
|
+
const shouldVerify = this.getNodeParameter("verifySignature");
|
|
149
|
+
const body = this.getBodyData();
|
|
150
|
+
if (shouldVerify) {
|
|
151
|
+
const staticData = this.getWorkflowStaticData("node");
|
|
152
|
+
const secret = staticData.secret;
|
|
153
|
+
const headers = this.getHeaderData();
|
|
154
|
+
// headers são lowercased pelo Node.js; "X-ZapAPI-Signature-256" chega assim:
|
|
155
|
+
const sig = headers["x-zapapi-signature-256"];
|
|
156
|
+
// Prefer raw body (n8n populates req.rawBody); fallback to deterministic
|
|
157
|
+
// re-serialisation (our payload is a plain object, JSON.stringify is stable).
|
|
158
|
+
const req = this.getRequestObject();
|
|
159
|
+
const raw = req.rawBody ? req.rawBody.toString("utf8") : JSON.stringify(body);
|
|
160
|
+
if (!secret || !(0, verifySignature_1.verifySignature)(raw, secret, sig)) {
|
|
161
|
+
const res = this.getResponseObject();
|
|
162
|
+
res.status(401).send("invalid signature");
|
|
163
|
+
return { noWebhookResponse: true };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
workflowData: [this.helpers.returnJsonArray([body])],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.ZapApiTrigger = ZapApiTrigger;
|
|
172
|
+
//# sourceMappingURL=ZapApiTrigger.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ZapApiTrigger.node.js","sourceRoot":"","sources":["../../../nodes/ZapApiTrigger/ZapApiTrigger.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><rect width="24" height="24" rx="5" fill="#22c55e"/><path d="M12 5a7 7 0 0 0-6 10.6L5 19l3.5-1A7 7 0 1 0 12 5z" fill="#fff"/></svg>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ILoadOptionsFunctions, INodePropertyOptions } from "n8n-workflow";
|
|
2
|
+
/**
|
|
3
|
+
* Popula o dropdown de instâncias chamando GET {baseUrl}/instances com a
|
|
4
|
+
* credential. Compartilhado pelos nodes ZapApi e ZapApiTrigger.
|
|
5
|
+
*
|
|
6
|
+
* A API responde { instances: [{ id, instanceId, displayName, ... }] }. O
|
|
7
|
+
* `value` é o `instanceId` público (inst_...) — é o `:id` que as rotas
|
|
8
|
+
* /instances/:id/* esperam.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getInstances(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getInstances = getInstances;
|
|
4
|
+
/**
|
|
5
|
+
* Popula o dropdown de instâncias chamando GET {baseUrl}/instances com a
|
|
6
|
+
* credential. Compartilhado pelos nodes ZapApi e ZapApiTrigger.
|
|
7
|
+
*
|
|
8
|
+
* A API responde { instances: [{ id, instanceId, displayName, ... }] }. O
|
|
9
|
+
* `value` é o `instanceId` público (inst_...) — é o `:id` que as rotas
|
|
10
|
+
* /instances/:id/* esperam.
|
|
11
|
+
*/
|
|
12
|
+
async function getInstances() {
|
|
13
|
+
const creds = await this.getCredentials("zapApiApi");
|
|
14
|
+
const res = (await this.helpers.httpRequestWithAuthentication.call(this, "zapApiApi", {
|
|
15
|
+
method: "GET",
|
|
16
|
+
baseURL: creds.baseUrl,
|
|
17
|
+
url: "/instances",
|
|
18
|
+
json: true,
|
|
19
|
+
}));
|
|
20
|
+
// Cobre array direto, { instances: [...] } e { data: [...] }.
|
|
21
|
+
const list = (Array.isArray(res)
|
|
22
|
+
? res
|
|
23
|
+
: (res?.instances ??
|
|
24
|
+
res?.data ??
|
|
25
|
+
[]));
|
|
26
|
+
return list.map((i) => ({
|
|
27
|
+
name: (i.displayName || i.instanceId || i.id),
|
|
28
|
+
value: (i.instanceId || i.id),
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=loadOptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadOptions.js","sourceRoot":"","sources":["../../../nodes/shared/loadOptions.ts"],"names":[],"mappings":";;AAUA,oCAwBC;AAhCD;;;;;;;GAOG;AACI,KAAK,UAAU,YAAY;IAGhC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,6BAA6B,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE;QACpF,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,KAAK,CAAC,OAAiB;QAChC,GAAG,EAAE,YAAY;QACjB,IAAI,EAAE,IAAI;KACX,CAAC,CAAY,CAAC;IAEf,8DAA8D;IAC9D,MAAM,IAAI,GAAG,CACX,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAChB,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,CAAE,GAAmD,EAAE,SAAS;YAC/D,GAA4B,EAAE,IAAI;YACnC,EAAE,CAAC,CAC6D,CAAC;IAEvE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtB,IAAI,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,EAAE,CAAW;QACvD,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,EAAE,CAAW;KACxC,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verifica o header X-ZapAPI-Signature-256 (formato `sha256=<hexhmac>`),
|
|
3
|
+
* HMAC-SHA256 do corpo cru com o secret registrado. Comparação timing-safe.
|
|
4
|
+
*/
|
|
5
|
+
export declare function verifySignature(rawBody: string, secret: string, signatureHeader: string | undefined): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
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.verifySignature = verifySignature;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
/**
|
|
9
|
+
* Verifica o header X-ZapAPI-Signature-256 (formato `sha256=<hexhmac>`),
|
|
10
|
+
* HMAC-SHA256 do corpo cru com o secret registrado. Comparação timing-safe.
|
|
11
|
+
*/
|
|
12
|
+
function verifySignature(rawBody, secret, signatureHeader) {
|
|
13
|
+
if (!signatureHeader || !signatureHeader.startsWith("sha256="))
|
|
14
|
+
return false;
|
|
15
|
+
const provided = signatureHeader.slice("sha256=".length);
|
|
16
|
+
const expected = crypto_1.default.createHmac("sha256", secret).update(rawBody).digest("hex");
|
|
17
|
+
const a = Buffer.from(provided, "utf8");
|
|
18
|
+
const b = Buffer.from(expected, "utf8");
|
|
19
|
+
if (a.length !== b.length)
|
|
20
|
+
return false;
|
|
21
|
+
return crypto_1.default.timingSafeEqual(a, b);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=verifySignature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifySignature.js","sourceRoot":"","sources":["../../../nodes/shared/verifySignature.ts"],"names":[],"mappings":";;;;;AAMA,0CAYC;AAlBD,oDAA4B;AAE5B;;;GAGG;AACH,SAAgB,eAAe,CAC7B,OAAe,EACf,MAAc,EACd,eAAmC;IAEnC,IAAI,CAAC,eAAe,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7E,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,gBAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnF,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,gBAAM,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACtC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-zap-api",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "n8n community node para a ZAP-API (WhatsApp): enviar mensagens e reagir a eventos.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"whatsapp",
|
|
8
|
+
"zap-api"
|
|
9
|
+
],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"homepage": "https://zap-api.tech",
|
|
12
|
+
"author": {
|
|
13
|
+
"name": "ZAP-API"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc && gulp build:icons",
|
|
17
|
+
"dev": "tsc --watch",
|
|
18
|
+
"lint": "eslint nodes credentials --ext .ts",
|
|
19
|
+
"test": "vitest run"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"n8n": {
|
|
25
|
+
"n8nNodesApiVersion": 1,
|
|
26
|
+
"credentials": [
|
|
27
|
+
"dist/credentials/ZapApiApi.credentials.js"
|
|
28
|
+
],
|
|
29
|
+
"nodes": [
|
|
30
|
+
"dist/nodes/ZapApi/ZapApi.node.js",
|
|
31
|
+
"dist/nodes/ZapApiTrigger/ZapApiTrigger.node.js"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^25.9.1",
|
|
36
|
+
"@typescript-eslint/parser": "^7.0.0",
|
|
37
|
+
"eslint-plugin-n8n-nodes-base": "^1.16.0",
|
|
38
|
+
"gulp": "^4.0.2",
|
|
39
|
+
"n8n-workflow": "^1.40.0",
|
|
40
|
+
"typescript": "^5.4.0",
|
|
41
|
+
"vitest": "^1.6.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"n8n-workflow": "*"
|
|
45
|
+
}
|
|
46
|
+
}
|