@cdteam/cdwa 0.0.0-stage → 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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +112 -2
  3. package/dist/auth/index.cjs +191 -0
  4. package/dist/auth/index.cjs.map +1 -0
  5. package/dist/auth/index.d.cts +25 -0
  6. package/dist/auth/index.d.ts +25 -0
  7. package/dist/auth/index.js +183 -0
  8. package/dist/auth/index.js.map +1 -0
  9. package/dist/binary/index.cjs +414 -0
  10. package/dist/binary/index.cjs.map +1 -0
  11. package/dist/binary/index.d.cts +92 -0
  12. package/dist/binary/index.d.ts +92 -0
  13. package/dist/binary/index.js +407 -0
  14. package/dist/binary/index.js.map +1 -0
  15. package/dist/crypto/index.cjs +207 -0
  16. package/dist/crypto/index.cjs.map +1 -0
  17. package/dist/crypto/index.d.cts +91 -0
  18. package/dist/crypto/index.d.ts +91 -0
  19. package/dist/crypto/index.js +201 -0
  20. package/dist/crypto/index.js.map +1 -0
  21. package/dist/index-CcMoHfPz.d.cts +70 -0
  22. package/dist/index-CcMoHfPz.d.ts +70 -0
  23. package/dist/index.cjs +1254 -0
  24. package/dist/index.cjs.map +1 -0
  25. package/dist/index.d.cts +97 -0
  26. package/dist/index.d.ts +97 -0
  27. package/dist/index.js +1224 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/messages/index.cjs +662 -0
  30. package/dist/messages/index.cjs.map +1 -0
  31. package/dist/messages/index.d.cts +122 -0
  32. package/dist/messages/index.d.ts +122 -0
  33. package/dist/messages/index.js +659 -0
  34. package/dist/messages/index.js.map +1 -0
  35. package/dist/signal/index.cjs +38 -0
  36. package/dist/signal/index.cjs.map +1 -0
  37. package/dist/signal/index.d.cts +30 -0
  38. package/dist/signal/index.d.ts +30 -0
  39. package/dist/signal/index.js +36 -0
  40. package/dist/signal/index.js.map +1 -0
  41. package/package.json +91 -4
@@ -0,0 +1,659 @@
1
+ import { randomBytes, createCipheriv, createHmac } from 'crypto';
2
+ import { sha256 } from '@noble/hashes/sha256';
3
+ import { x25519 } from '@noble/curves/ed25519';
4
+ import { hkdf } from '@noble/hashes/hkdf';
5
+ import { gcm } from '@noble/ciphers/aes';
6
+
7
+ // src/messages/media.ts
8
+
9
+ // src/crypto/index.ts
10
+ var CryptoEngine = class {
11
+ /**
12
+ * Gera um novo par de chaves Curve25519 (Diffie-Hellman)
13
+ */
14
+ static generateKeyPair() {
15
+ const priv = randomBytes(32);
16
+ const pub = x25519.getPublicKey(priv);
17
+ return {
18
+ private: new Uint8Array(priv),
19
+ public: new Uint8Array(pub)
20
+ };
21
+ }
22
+ /**
23
+ * Executa Diffie-Hellman compartilhado (Shared Secret) usando Curve25519
24
+ */
25
+ static sharedKey(privateKey, publicKey) {
26
+ return x25519.getSharedSecret(privateKey, publicKey);
27
+ }
28
+ /**
29
+ * HKDF baseado em SHA-256 para derivação segura de chaves (RFC 5869)
30
+ */
31
+ static deriveKey(secret, info, salt, length = 32) {
32
+ const infoBytes = typeof info === "string" ? new TextEncoder().encode(info) : info;
33
+ return hkdf(sha256, secret, salt, infoBytes, length);
34
+ }
35
+ /**
36
+ * Encriptação autenticada com AES-256-GCM
37
+ */
38
+ static aesGcmEncrypt(key, plaintext, iv, additionalData) {
39
+ const cipher = gcm(key, iv, additionalData);
40
+ return cipher.encrypt(plaintext);
41
+ }
42
+ /**
43
+ * Decriptação autenticada com AES-256-GCM
44
+ */
45
+ static aesGcmDecrypt(key, ciphertext, iv, additionalData) {
46
+ const cipher = gcm(key, iv, additionalData);
47
+ return cipher.decrypt(ciphertext);
48
+ }
49
+ /**
50
+ * Encripta um payload com uma senha mestra (para proteger credenciais at-rest)
51
+ */
52
+ static encryptAtRest(payload, masterPassphrase) {
53
+ const salt = randomBytes(16);
54
+ const iv = randomBytes(12);
55
+ const key = hkdf(sha256, new TextEncoder().encode(masterPassphrase), salt, new TextEncoder().encode("cdwa-at-rest"), 32);
56
+ const encrypted = this.aesGcmEncrypt(key, payload, iv);
57
+ return {
58
+ salt: Buffer.from(salt).toString("hex"),
59
+ iv: Buffer.from(iv).toString("hex"),
60
+ data: Buffer.from(encrypted).toString("base64")
61
+ };
62
+ }
63
+ /**
64
+ * Decripta um payload protegido com a senha mestra
65
+ */
66
+ static decryptAtRest(encryptedBundle, masterPassphrase) {
67
+ const salt = Buffer.from(encryptedBundle.salt, "hex");
68
+ const iv = Buffer.from(encryptedBundle.iv, "hex");
69
+ const data = Buffer.from(encryptedBundle.data, "base64");
70
+ const key = hkdf(sha256, new TextEncoder().encode(masterPassphrase), salt, new TextEncoder().encode("cdwa-at-rest"), 32);
71
+ return this.aesGcmDecrypt(key, data, iv);
72
+ }
73
+ };
74
+
75
+ // src/messages/media.ts
76
+ var MEDIA_HKDF_INFO = {
77
+ image: "WhatsApp Image Keys",
78
+ video: "WhatsApp Video Keys",
79
+ audio: "WhatsApp Audio Keys",
80
+ document: "WhatsApp Document Keys"
81
+ };
82
+ var MediaCrypto = class {
83
+ /**
84
+ * Criptografa o arquivo de mídia de acordo com o padrão RFC do WhatsApp
85
+ */
86
+ static encryptMedia(mediaBuffer, type) {
87
+ const mediaKey = randomBytes(32);
88
+ const info = MEDIA_HKDF_INFO[type];
89
+ const expandedKeys = CryptoEngine.deriveKey(new Uint8Array(mediaKey), info, void 0, 112);
90
+ const iv = expandedKeys.slice(0, 16);
91
+ const cipherKey = expandedKeys.slice(16, 48);
92
+ const macKey = expandedKeys.slice(48, 80);
93
+ const fileSha256 = sha256(mediaBuffer);
94
+ const cipher = createCipheriv("aes-256-cbc", Buffer.from(cipherKey), Buffer.from(iv));
95
+ const encryptedBody = Buffer.concat([cipher.update(Buffer.from(mediaBuffer)), cipher.final()]);
96
+ const hmac = createHmac("sha256", Buffer.from(macKey));
97
+ hmac.update(Buffer.from(iv));
98
+ hmac.update(encryptedBody);
99
+ const fullMac = hmac.digest();
100
+ const mac = fullMac.subarray(0, 10);
101
+ const finalCiphertext = new Uint8Array(encryptedBody.length + mac.length);
102
+ finalCiphertext.set(encryptedBody, 0);
103
+ finalCiphertext.set(mac, encryptedBody.length);
104
+ const fileEncSha256 = sha256(finalCiphertext);
105
+ return {
106
+ mediaKey: new Uint8Array(mediaKey),
107
+ ciphertext: finalCiphertext,
108
+ fileSha256: new Uint8Array(fileSha256),
109
+ fileEncSha256: new Uint8Array(fileEncSha256),
110
+ mac: new Uint8Array(mac)
111
+ };
112
+ }
113
+ };
114
+
115
+ // src/binary/constants.ts
116
+ var WABinaryConstants = {
117
+ LIST_EMPTY: 0,
118
+ LIST_8: 248,
119
+ LIST_16: 249,
120
+ BINARY_8: 252,
121
+ BINARY_32: 254};
122
+ var SINGLE_BYTE_TOKENS = [
123
+ "",
124
+ "",
125
+ "",
126
+ "200",
127
+ "400",
128
+ "404",
129
+ "500",
130
+ "501",
131
+ "502",
132
+ "action",
133
+ "add",
134
+ "after",
135
+ "archive",
136
+ "author",
137
+ "available",
138
+ "battery",
139
+ "before",
140
+ "body",
141
+ "broadcast",
142
+ "chat",
143
+ "clear",
144
+ "code",
145
+ "composing",
146
+ "config",
147
+ "contacts",
148
+ "count",
149
+ "create",
150
+ "debug",
151
+ "delete",
152
+ "demote",
153
+ "duplicate",
154
+ "encoding",
155
+ "error",
156
+ "false",
157
+ "filehash",
158
+ "from",
159
+ "g.us",
160
+ "group",
161
+ "groups_v2",
162
+ "height",
163
+ "ib",
164
+ "id",
165
+ "image",
166
+ "in",
167
+ "index",
168
+ "invis",
169
+ "item",
170
+ "jid",
171
+ "kind",
172
+ "last",
173
+ "leave",
174
+ "live",
175
+ "log",
176
+ "media",
177
+ "message",
178
+ "mimetype",
179
+ "missing",
180
+ "modify",
181
+ "name",
182
+ "notification",
183
+ "notify",
184
+ "out",
185
+ "owner",
186
+ "participant",
187
+ "paused",
188
+ "picture",
189
+ "played",
190
+ "presence",
191
+ "preview",
192
+ "promote",
193
+ "query",
194
+ "raw",
195
+ "read",
196
+ "receipt",
197
+ "received",
198
+ "recipient",
199
+ "recording",
200
+ "relay",
201
+ "remove",
202
+ "response",
203
+ "resume",
204
+ "retry",
205
+ "s.whatsapp.net",
206
+ "seconds",
207
+ "set",
208
+ "size",
209
+ "status",
210
+ "subject",
211
+ "subscribe",
212
+ "t",
213
+ "text",
214
+ "to",
215
+ "true",
216
+ "type",
217
+ "unarchive",
218
+ "unavailable",
219
+ "url",
220
+ "user",
221
+ "value",
222
+ "web",
223
+ "width",
224
+ "mute",
225
+ "read_only",
226
+ "admin",
227
+ "creator",
228
+ "short",
229
+ "update",
230
+ "powersave",
231
+ "rich",
232
+ "modify_tag",
233
+ "message_info",
234
+ "opaque",
235
+ "contact",
236
+ "unlink",
237
+ "iq",
238
+ "ping",
239
+ "version",
240
+ "client",
241
+ "pair-device",
242
+ "pair-success",
243
+ "success",
244
+ "failure"
245
+ ];
246
+ var TOKEN_MAP = /* @__PURE__ */ new Map();
247
+ SINGLE_BYTE_TOKENS.forEach((token, index) => {
248
+ if (token) {
249
+ TOKEN_MAP.set(token, index);
250
+ }
251
+ });
252
+
253
+ // src/binary/encoder.ts
254
+ var BinaryEncoder = class {
255
+ buffer = [];
256
+ encode(node) {
257
+ this.buffer = [];
258
+ this.writeNode(node);
259
+ return new Uint8Array(this.buffer);
260
+ }
261
+ writeByte(byte) {
262
+ this.buffer.push(byte & 255);
263
+ }
264
+ writeBytes(bytes) {
265
+ for (let i = 0; i < bytes.length; i++) {
266
+ this.writeByte(bytes[i]);
267
+ }
268
+ }
269
+ writeInt16(value) {
270
+ this.writeByte(value >> 8 & 255);
271
+ this.writeByte(value & 255);
272
+ }
273
+ writeInt32(value) {
274
+ this.writeByte(value >> 24 & 255);
275
+ this.writeByte(value >> 16 & 255);
276
+ this.writeByte(value >> 8 & 255);
277
+ this.writeByte(value & 255);
278
+ }
279
+ writeListStart(size) {
280
+ if (size === 0) {
281
+ this.writeByte(WABinaryConstants.LIST_EMPTY);
282
+ } else if (size < 256) {
283
+ this.writeByte(WABinaryConstants.LIST_8);
284
+ this.writeByte(size);
285
+ } else {
286
+ this.writeByte(WABinaryConstants.LIST_16);
287
+ this.writeInt16(size);
288
+ }
289
+ }
290
+ writeString(str) {
291
+ const tokenIndex = TOKEN_MAP.get(str);
292
+ if (tokenIndex !== void 0) {
293
+ this.writeByte(tokenIndex);
294
+ return;
295
+ }
296
+ const encoded = new TextEncoder().encode(str);
297
+ if (encoded.length < 256) {
298
+ this.writeByte(WABinaryConstants.BINARY_8);
299
+ this.writeByte(encoded.length);
300
+ } else {
301
+ this.writeByte(WABinaryConstants.BINARY_32);
302
+ this.writeInt32(encoded.length);
303
+ }
304
+ this.writeBytes(encoded);
305
+ }
306
+ writeNode(node) {
307
+ const numAttrs = Object.keys(node.attrs).length;
308
+ const hasContent = node.content !== void 0;
309
+ const listSize = 1 + numAttrs * 2 + (hasContent ? 1 : 0);
310
+ this.writeListStart(listSize);
311
+ this.writeString(node.tag);
312
+ for (const [key, value] of Object.entries(node.attrs)) {
313
+ if (value !== void 0) {
314
+ this.writeString(key);
315
+ this.writeString(String(value));
316
+ }
317
+ }
318
+ if (hasContent) {
319
+ if (Array.isArray(node.content)) {
320
+ this.writeListStart(node.content.length);
321
+ for (const child of node.content) {
322
+ this.writeNode(child);
323
+ }
324
+ } else if (typeof node.content === "string") {
325
+ this.writeString(node.content);
326
+ } else if (node.content instanceof Uint8Array) {
327
+ if (node.content.length < 256) {
328
+ this.writeByte(WABinaryConstants.BINARY_8);
329
+ this.writeByte(node.content.length);
330
+ } else {
331
+ this.writeByte(WABinaryConstants.BINARY_32);
332
+ this.writeInt32(node.content.length);
333
+ }
334
+ this.writeBytes(node.content);
335
+ }
336
+ }
337
+ }
338
+ };
339
+
340
+ // src/binary/decoder.ts
341
+ var BinaryDecoder = class {
342
+ buffer = new Uint8Array(0);
343
+ offset = 0;
344
+ decode(buffer) {
345
+ this.buffer = buffer;
346
+ this.offset = 0;
347
+ return this.readNode();
348
+ }
349
+ readByte() {
350
+ if (this.offset >= this.buffer.length) {
351
+ throw new Error(`Unexpected EOF in WABinary stream at offset ${this.offset}`);
352
+ }
353
+ const b = this.buffer[this.offset];
354
+ this.offset += 1;
355
+ return b;
356
+ }
357
+ readBytes(length) {
358
+ if (this.offset + length > this.buffer.length) {
359
+ throw new Error(`Buffer underrun: requested ${length} bytes, have ${this.buffer.length - this.offset}`);
360
+ }
361
+ const slice = this.buffer.slice(this.offset, this.offset + length);
362
+ this.offset += length;
363
+ return slice;
364
+ }
365
+ readInt16() {
366
+ const b0 = this.readByte();
367
+ const b1 = this.readByte();
368
+ return b0 << 8 | b1;
369
+ }
370
+ readInt32() {
371
+ const b0 = this.readByte();
372
+ const b1 = this.readByte();
373
+ const b2 = this.readByte();
374
+ const b3 = this.readByte();
375
+ return b0 << 24 | b1 << 16 | b2 << 8 | b3;
376
+ }
377
+ readListSize() {
378
+ const tag = this.readByte();
379
+ if (tag === WABinaryConstants.LIST_EMPTY) {
380
+ return 0;
381
+ }
382
+ if (tag === WABinaryConstants.LIST_8) {
383
+ return this.readByte();
384
+ }
385
+ if (tag === WABinaryConstants.LIST_16) {
386
+ return this.readInt16();
387
+ }
388
+ throw new Error(`Invalid list tag byte: ${tag}`);
389
+ }
390
+ readString() {
391
+ const tag = this.readByte();
392
+ if (tag < SINGLE_BYTE_TOKENS.length && SINGLE_BYTE_TOKENS[tag]) {
393
+ return SINGLE_BYTE_TOKENS[tag];
394
+ }
395
+ if (tag === WABinaryConstants.BINARY_8) {
396
+ const length = this.readByte();
397
+ const bytes = this.readBytes(length);
398
+ return new TextDecoder().decode(bytes);
399
+ }
400
+ if (tag === WABinaryConstants.BINARY_32) {
401
+ const length = this.readInt32();
402
+ const bytes = this.readBytes(length);
403
+ return new TextDecoder().decode(bytes);
404
+ }
405
+ throw new Error(`Unsupported string tag: ${tag} at offset ${this.offset - 1}`);
406
+ }
407
+ readNode() {
408
+ const listSize = this.readListSize();
409
+ if (listSize === 0) {
410
+ throw new Error("Invalid empty node");
411
+ }
412
+ const tag = this.readString();
413
+ const attrs = {};
414
+ let remaining = listSize - 1;
415
+ while (remaining > 1) {
416
+ const key = this.readString();
417
+ const val = this.readString();
418
+ attrs[key] = val;
419
+ remaining -= 2;
420
+ }
421
+ let content;
422
+ if (remaining === 1) {
423
+ const peekByte = this.buffer[this.offset];
424
+ if (peekByte === WABinaryConstants.LIST_EMPTY || peekByte === WABinaryConstants.LIST_8 || peekByte === WABinaryConstants.LIST_16) {
425
+ const childCount = this.readListSize();
426
+ const children = [];
427
+ for (let i = 0; i < childCount; i++) {
428
+ children.push(this.readNode());
429
+ }
430
+ content = children;
431
+ } else if (peekByte === WABinaryConstants.BINARY_8 || peekByte === WABinaryConstants.BINARY_32) {
432
+ const nextTag = this.readByte();
433
+ const length = nextTag === WABinaryConstants.BINARY_8 ? this.readByte() : this.readInt32();
434
+ content = this.readBytes(length);
435
+ } else {
436
+ content = this.readString();
437
+ }
438
+ }
439
+ return { tag, attrs, content };
440
+ }
441
+ };
442
+
443
+ // src/binary/index.ts
444
+ var BinaryProtocol = class {
445
+ static encoder = new BinaryEncoder();
446
+ static decoder = new BinaryDecoder();
447
+ /**
448
+ * Converte um BinaryNode para bytes WABinary
449
+ */
450
+ static encode(node) {
451
+ return this.encoder.encode(node);
452
+ }
453
+ /**
454
+ * Converte bytes WABinary de volta para um BinaryNode estruturado
455
+ */
456
+ static decode(buffer) {
457
+ return this.decoder.decode(buffer);
458
+ }
459
+ /**
460
+ * Constrói um nó binário com validação de formato
461
+ */
462
+ static createNode(tag, attrs = {}, content) {
463
+ return {
464
+ tag,
465
+ attrs,
466
+ content
467
+ };
468
+ }
469
+ /**
470
+ * Localiza o primeiro filho correspondente à tag fornecida
471
+ */
472
+ static getChildNode(node, childTag) {
473
+ if (Array.isArray(node.content)) {
474
+ return node.content.find((child) => child.tag === childTag);
475
+ }
476
+ return void 0;
477
+ }
478
+ /**
479
+ * Extrai todos os nós filhos que batem com uma determinada tag
480
+ */
481
+ static getChildrenNodes(node, childTag) {
482
+ if (Array.isArray(node.content)) {
483
+ return node.content.filter((child) => child.tag === childTag);
484
+ }
485
+ return [];
486
+ }
487
+ /**
488
+ * Converte o nó para representação em string legível para debug
489
+ */
490
+ static stringify(node, indent = 0) {
491
+ const spaces = " ".repeat(indent);
492
+ const attrsStr = Object.entries(node.attrs).map(([k, v]) => `${k}="${v}"`).join(" ");
493
+ const openTag = attrsStr ? `<${node.tag} ${attrsStr}>` : `<${node.tag}>`;
494
+ if (!node.content) {
495
+ return `${spaces}<${node.tag} ${attrsStr} />`;
496
+ }
497
+ if (Array.isArray(node.content)) {
498
+ const children = node.content.map((c) => this.stringify(c, indent + 1)).join("\n");
499
+ return `${spaces}${openTag}
500
+ ${children}
501
+ ${spaces}</${node.tag}>`;
502
+ }
503
+ const contentStr = node.content instanceof Uint8Array ? `[Buffer ${node.content.length}b]` : String(node.content);
504
+ return `${spaces}${openTag}${contentStr}</${node.tag}>`;
505
+ }
506
+ };
507
+
508
+ // src/messages/builder.ts
509
+ var MessageBuilder = class {
510
+ /**
511
+ * Converte qualquer conteúdo de mensagem em uma stanza <message> pronta para transmissão
512
+ */
513
+ static async buildMessageNode(jid, content, options = {}) {
514
+ const messageId = `3EB0${Date.now().toString(16).toUpperCase()}${Math.floor(Math.random() * 1e4)}`;
515
+ const timestamp = options.timestamp || Math.floor(Date.now() / 1e3);
516
+ const messageAttrs = {
517
+ id: messageId,
518
+ to: jid,
519
+ type: "text",
520
+ t: timestamp
521
+ };
522
+ let payloadContent = new Uint8Array(0);
523
+ if ("text" in content) {
524
+ payloadContent = new TextEncoder().encode(content.text);
525
+ } else if ("image" in content) {
526
+ messageAttrs.type = "media";
527
+ messageAttrs.mediatype = "image";
528
+ const buffer = await this.resolveMediaBuffer(content.image);
529
+ const encrypted = MediaCrypto.encryptMedia(buffer, "image");
530
+ payloadContent = [
531
+ BinaryProtocol.createNode("image", {
532
+ mimetype: content.mimetype || "image/jpeg",
533
+ caption: content.caption,
534
+ fileLength: buffer.length,
535
+ fileSha256: Buffer.from(encrypted.fileSha256).toString("base64"),
536
+ fileEncSha256: Buffer.from(encrypted.fileEncSha256).toString("base64"),
537
+ mediaKey: Buffer.from(encrypted.mediaKey).toString("base64")
538
+ })
539
+ ];
540
+ } else if ("video" in content) {
541
+ messageAttrs.type = "media";
542
+ messageAttrs.mediatype = "video";
543
+ const buffer = await this.resolveMediaBuffer(content.video);
544
+ const encrypted = MediaCrypto.encryptMedia(buffer, "video");
545
+ payloadContent = [
546
+ BinaryProtocol.createNode("video", {
547
+ mimetype: content.mimetype || "video/mp4",
548
+ caption: content.caption,
549
+ gifPlayback: content.gifPlayback ? "true" : void 0,
550
+ ptv: content.ptv ? "true" : void 0,
551
+ fileLength: buffer.length,
552
+ fileSha256: Buffer.from(encrypted.fileSha256).toString("base64"),
553
+ fileEncSha256: Buffer.from(encrypted.fileEncSha256).toString("base64"),
554
+ mediaKey: Buffer.from(encrypted.mediaKey).toString("base64")
555
+ })
556
+ ];
557
+ } else if ("audio" in content) {
558
+ messageAttrs.type = "media";
559
+ messageAttrs.mediatype = "audio";
560
+ const buffer = await this.resolveMediaBuffer(content.audio);
561
+ const encrypted = MediaCrypto.encryptMedia(buffer, "audio");
562
+ payloadContent = [
563
+ BinaryProtocol.createNode("audio", {
564
+ mimetype: content.mimetype || (content.ptt ? "audio/ogg; codecs=opus" : "audio/mp4"),
565
+ ptt: content.ptt ? "true" : "false",
566
+ fileLength: buffer.length,
567
+ fileSha256: Buffer.from(encrypted.fileSha256).toString("base64"),
568
+ fileEncSha256: Buffer.from(encrypted.fileEncSha256).toString("base64"),
569
+ mediaKey: Buffer.from(encrypted.mediaKey).toString("base64")
570
+ })
571
+ ];
572
+ } else if ("document" in content) {
573
+ messageAttrs.type = "media";
574
+ messageAttrs.mediatype = "document";
575
+ const buffer = await this.resolveMediaBuffer(content.document);
576
+ const encrypted = MediaCrypto.encryptMedia(buffer, "document");
577
+ payloadContent = [
578
+ BinaryProtocol.createNode("document", {
579
+ mimetype: content.mimetype,
580
+ fileName: content.fileName || "file",
581
+ caption: content.caption,
582
+ fileLength: buffer.length,
583
+ fileSha256: Buffer.from(encrypted.fileSha256).toString("base64"),
584
+ fileEncSha256: Buffer.from(encrypted.fileEncSha256).toString("base64"),
585
+ mediaKey: Buffer.from(encrypted.mediaKey).toString("base64")
586
+ })
587
+ ];
588
+ } else if ("location" in content) {
589
+ messageAttrs.type = "location";
590
+ payloadContent = [
591
+ BinaryProtocol.createNode("location", {
592
+ degreesLatitude: content.location.degreesLatitude,
593
+ degreesLongitude: content.location.degreesLongitude,
594
+ name: content.location.name,
595
+ address: content.location.address,
596
+ url: content.location.url
597
+ })
598
+ ];
599
+ } else if ("contact" in content) {
600
+ messageAttrs.type = "contact";
601
+ payloadContent = [
602
+ BinaryProtocol.createNode("contact", {
603
+ displayName: content.contact.displayName,
604
+ vcard: content.contact.vcard
605
+ })
606
+ ];
607
+ } else if ("contacts" in content) {
608
+ messageAttrs.type = "contacts";
609
+ const contactNodes = content.contacts.contacts.map(
610
+ (c) => BinaryProtocol.createNode("contact", {
611
+ displayName: c.displayName,
612
+ vcard: c.vcard
613
+ })
614
+ );
615
+ payloadContent = [
616
+ BinaryProtocol.createNode(
617
+ "contacts",
618
+ { displayName: content.contacts.displayName },
619
+ contactNodes
620
+ )
621
+ ];
622
+ } else if ("react" in content) {
623
+ messageAttrs.type = "reaction";
624
+ payloadContent = [
625
+ BinaryProtocol.createNode("reaction", {
626
+ text: content.react.text,
627
+ targetId: content.react.key.id,
628
+ targetJid: content.react.key.remoteJid
629
+ })
630
+ ];
631
+ }
632
+ const node = BinaryProtocol.createNode("message", messageAttrs, payloadContent);
633
+ return {
634
+ node,
635
+ messageId
636
+ };
637
+ }
638
+ /**
639
+ * Resolve diferentes fontes de mídia (Buffer, Uint8Array ou URL) para um Uint8Array em memória
640
+ */
641
+ static async resolveMediaBuffer(source) {
642
+ if (source instanceof Uint8Array) {
643
+ return source;
644
+ }
645
+ if (Buffer.isBuffer(source)) {
646
+ return new Uint8Array(source);
647
+ }
648
+ if (typeof source === "object" && source !== null && "url" in source) {
649
+ const res = await fetch(source.url);
650
+ const arrayBuf = await res.arrayBuffer();
651
+ return new Uint8Array(arrayBuf);
652
+ }
653
+ throw new Error("Unsupported media source format");
654
+ }
655
+ };
656
+
657
+ export { MediaCrypto, MessageBuilder };
658
+ //# sourceMappingURL=index.js.map
659
+ //# sourceMappingURL=index.js.map