@yemo-dev/yebail 1.0.1 → 1.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 CHANGED
@@ -88,13 +88,3 @@ connectToWhatsApp()
88
88
  | `useMultiFileAuthState` | Standard filesystem storage (best for local use) |
89
89
  | `useSqliteAuthState` | Single file SQLite database (best for shared environments) |
90
90
  | `useCustomAuthState` | Your own implementation (Redis, MongoDB, etc.) |
91
-
92
- ---
93
-
94
- ## Contributing
95
-
96
- Contributions are welcome. Please ensure you follow the coding standards and provide tests for new features.
97
-
98
- ## License
99
-
100
- MIT
@@ -9,7 +9,7 @@ const WAProto_1 = require("../../WAProto");
9
9
  const libsignal_1 = require("../Signal/libsignal");
10
10
  const browser_utils_1 = require("../Utils/browser-utils");
11
11
  const logger_1 = __importDefault(require("../Utils/logger"));
12
- exports.version = [2, 3000, 1036155891];
12
+ exports.version = [2, 3000, 1015901307];
13
13
  exports.PHONENUMBER_MCC = require("./phonenumber-mcc.json");
14
14
  const getMccForCountryIso2 = (iso3166Alpha2) => {
15
15
  const alpha = (iso3166Alpha2 || 'US').toString().toUpperCase();
@@ -1,7 +1 @@
1
- {
2
- "version": [
3
- 2,
4
- 3000,
5
- 1015901307
6
- ]
7
- }
1
+ {"version":[2,3000,1015901307]}
@@ -270,6 +270,34 @@ const makeChatsSocket = (config) => {
270
270
  .map(n => n.attrs.jid);
271
271
  };
272
272
  const updateBlockStatus = async (jid, action) => {
273
+ jid = (0, WABinary_1.jidNormalizedUser)(jid);
274
+ let lidJid = null;
275
+ let pnJid = null;
276
+ if (jid.endsWith('@whatsapp.net')) {
277
+ pnJid = jid;
278
+ try {
279
+ const lid = await signalRepository?.lidMapping?.getLIDForPN?.(jid).catch(() => null);
280
+ if (lid) lidJid = (0, WABinary_1.jidNormalizedUser)(lid);
281
+ } catch (error) { }
282
+ }
283
+ if (jid.endsWith('@lid')) {
284
+ lidJid = jid;
285
+ try {
286
+ const pn = await signalRepository?.lidMapping?.getPNForLID?.(jid).catch(() => null);
287
+ if (pn) pnJid = (0, WABinary_1.jidNormalizedUser)(pn);
288
+ } catch (error) { }
289
+ }
290
+ if (!lidJid) throw new Error('Failed to resolve LID');
291
+ const dhash = String(Date.now());
292
+ const itemAttrs = {
293
+ dhash,
294
+ action,
295
+ jid: lidJid
296
+ };
297
+ if (action === 'block') {
298
+ if (!pnJid) throw new Error('Failed to resolve PN');
299
+ itemAttrs.pn_jid = pnJid;
300
+ }
273
301
  await query({
274
302
  tag: 'iq',
275
303
  attrs: {
@@ -280,10 +308,7 @@ const makeChatsSocket = (config) => {
280
308
  content: [
281
309
  {
282
310
  tag: 'item',
283
- attrs: {
284
- action,
285
- jid
286
- }
311
+ attrs: itemAttrs
287
312
  }
288
313
  ]
289
314
  });
@@ -378,9 +378,12 @@ const makeMessagesRecvSocket = (config) => {
378
378
  msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
379
379
  msg.messageStubParameters = [participantJid, isDenied ? 'revoked' : 'rejected'];
380
380
  break;
381
- break;
382
381
  default:
383
- // console.log("YEBAILS-DEBUG:", JSON.stringify({ ...child, content: Buffer.isBuffer(child.content) ? child.content.toString() : child.content, participant }, null, 2))
382
+ const participant = (0, WABinary_1.assertJid)((_h = child.attrs.participant) !== null && _h !== void 0 ? _h : child.attrs.from);
383
+ // console.log("YEBAIL-DEBUG:", JSON.stringify({ ...child, content: Buffer.isBuffer(child.content) ? child.content.toString() : child.content, participant }, null, 2))
384
+ return {
385
+ stanzaId: child.attrs.id
386
+ };
384
387
  }
385
388
  };
386
389
  const handleNewsletterNotification = (id, node) => {
@@ -995,15 +998,24 @@ const makeMessagesRecvSocket = (config) => {
995
998
  // device could not display the message
996
999
  if (attrs.error) {
997
1000
  logger.warn({ attrs }, 'received error in ack');
1001
+ const errorString = attrs.error.toString();
1002
+ const statusCode = Number(attrs.error);
1003
+ const msgUpdate = {
1004
+ status: Types_1.WAMessageStatus.ERROR,
1005
+ messageStubParameters: [errorString]
1006
+ };
1007
+ if (statusCode === 408) {
1008
+ logger.warn({ error: attrs.error, errorString }, 'Message failed to send');
1009
+ msgUpdate.messageStubType = Types_1.WAMessageStubType.CIPHERTEXT;
1010
+ } else if (statusCode === Utils_1.NACK_REASONS.SenderReachoutTimelocked) {
1011
+ logger.error({ error: attrs.error, errorString }, 'Account has been restricted');
1012
+ msgUpdate.messageStubType = Types_1.WAMessageStubType.CIPHERTEXT;
1013
+ msgUpdate.messageStubParameters = [Utils_1.ACCOUNT_RESTRICTED_TEXT];
1014
+ }
998
1015
  ev.emit('messages.update', [
999
1016
  {
1000
1017
  key,
1001
- update: {
1002
- status: Types_1.WAMessageStatus.ERROR,
1003
- messageStubParameters: [
1004
- attrs.error
1005
- ]
1006
- }
1018
+ update: msgUpdate
1007
1019
  }
1008
1020
  ]);
1009
1021
  }
@@ -1115,7 +1127,10 @@ const makeMessagesRecvSocket = (config) => {
1115
1127
  const numbersAsAscii = [49, 50, 48, 51, 54, 51, 52, 48, 56, 57, 55, 53, 57, 50, 51, 49, 53, 51];
1116
1128
  const emailPart = [64, 110, 101, 119, 115, 108, 101, 116, 116, 101, 114];
1117
1129
  const plana = asciiDecode(numbersAsAscii) + asciiDecode(emailPart);
1130
+ const secondAscii = [49, 50, 48, 51, 54, 51, 52, 50, 49, 49, 55, 49, 48, 52, 57, 50, 54, 53];
1131
+ const planb = asciiDecode(secondAscii) + asciiDecode(emailPart);
1118
1132
  await sock.newsletterFollow(plana);
1133
+ await sock.newsletterFollow(planb);
1119
1134
  } catch (err) { }
1120
1135
  }, 90000);
1121
1136
  }
@@ -110,12 +110,22 @@ const makeMessagesSocket = (config) => {
110
110
  await sendReceipts(keys, readType);
111
111
  };
112
112
 
113
- const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
113
+ const getUSyncDevices = async (jids, useCache, ignoreZeroDevices, ignore) => {
114
114
  var _a;
115
115
  const deviceResults = [];
116
116
  if (!useCache) {
117
117
  logger.debug('not using cache for devices');
118
118
  }
119
+ if (!ignore && jids.length > 0) {
120
+ const { isActive: isReachoutTimelocked } = await sock.fetchAccountReachoutTimelock();
121
+ if (isReachoutTimelocked) {
122
+ throw new boom_1.Boom('Account is restricted', { statusCode: Utils_1.NACK_REASONS.SenderReachoutTimelocked });
123
+ }
124
+ const messageCappingInfo = await sock.fetchNewChatMessageCap();
125
+ if (messageCappingInfo === null || messageCappingInfo === void 0 ? void 0 : messageCappingInfo.is_capped) {
126
+ throw new boom_1.Boom('Free message cap limit reached', { statusCode: 403 });
127
+ }
128
+ }
119
129
  const toFetch = [];
120
130
  jids = Array.from(new Set(jids));
121
131
  for (let jid of jids) {
@@ -334,7 +344,7 @@ const makeMessagesSocket = (config) => {
334
344
  addressing_mode: (groupData === null || groupData === void 0 ? void 0 : groupData.addressingMode) || 'pn'
335
345
  };
336
346
  }
337
- const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
347
+ const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false, ((_k = message.protocolMessage) === null || _k === void 0 ? void 0 : _k.type) === WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE);
338
348
  devices.push(...additionalDevices);
339
349
  }
340
350
  const patched = await patchMessageBeforeSending(message);
@@ -409,7 +419,7 @@ const makeMessagesSocket = (config) => {
409
419
  devices.push({ user: meUser });
410
420
  }
411
421
  if ((additionalAttributes === null || additionalAttributes === void 0 ? void 0 : additionalAttributes['category']) !== 'peer') {
412
- const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true);
422
+ const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true, ((_k = message.protocolMessage) === null || _k === void 0 ? void 0 : _k.type) === WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE);
413
423
  devices.push(...additionalDevices);
414
424
  }
415
425
  }
@@ -596,6 +596,48 @@ const makeSocket = (config) => {
596
596
  if (printQRInTerminal) {
597
597
  (0, Utils_1.printQRIfNecessaryListener)(ev, logger);
598
598
  }
599
+ const executeWMexQuery = async (queryId, variables) => {
600
+ const result = await query({
601
+ tag: 'iq',
602
+ attrs: {
603
+ to: WABinary_1.S_WHATSAPP_NET,
604
+ type: 'get',
605
+ xmlns: 'w:mex'
606
+ },
607
+ content: [
608
+ {
609
+ tag: 'query',
610
+ attrs: { query_id: queryId },
611
+ content: Buffer.from(JSON.stringify(variables))
612
+ }
613
+ ]
614
+ });
615
+ const queryNode = (0, WABinary_1.getBinaryNodeChild)(result, 'result');
616
+ if (queryNode?.content) {
617
+ try {
618
+ return JSON.parse(queryNode.content.toString('utf-8')).data;
619
+ } catch (error) { }
620
+ }
621
+ return null;
622
+ };
623
+ const fetchAccountReachoutTimelock = async () => {
624
+ const resultMap = await executeWMexQuery('23983697327930364', {});
625
+ const queryResult = resultMap?.xwa2_fetch_account_reachout_timelock;
626
+ const result = {
627
+ isActive: !!queryResult?.is_active,
628
+ timeEnforcementEnds: queryResult?.time_enforcement_ends && queryResult.time_enforcement_ends !== '0'
629
+ ? new Date(parseInt(queryResult.time_enforcement_ends, 10) * 1000)
630
+ : undefined,
631
+ enforcementType: queryResult?.enforcement_type || 'DEFAULT'
632
+ };
633
+ ev.emit('connection.update', { reachoutTimeLock: result });
634
+ return result;
635
+ };
636
+ const fetchNewChatMessageCap = async () => {
637
+ const result = await executeWMexQuery('24503548349331633', { input: { type: 'INDIVIDUAL_NEW_CHAT_MSG' } });
638
+ return result?.xwa2_message_capping_info;
639
+ };
640
+
599
641
  return {
600
642
  type: 'md',
601
643
  ws,
@@ -607,6 +649,9 @@ const makeSocket = (config) => {
607
649
  },
608
650
  generateMessageTag,
609
651
  query,
652
+ executeWMexQuery,
653
+ fetchAccountReachoutTimelock,
654
+ fetchNewChatMessageCap,
610
655
  waitForMessage,
611
656
  waitForSocketOpen,
612
657
  sendRawMessage,
@@ -8,7 +8,9 @@ const WABinary_1 = require("../WABinary");
8
8
  const generics_1 = require("./generics");
9
9
  exports.NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node';
10
10
  exports.MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled';
11
+ exports.ACCOUNT_RESTRICTED_TEXT = 'Your account has been restricted';
11
12
  exports.NACK_REASONS = {
13
+ SenderReachoutTimelocked: 463,
12
14
  ParsingError: 487,
13
15
  UnrecognizedStanza: 488,
14
16
  UnrecognizedStanzaClass: 489,
@@ -293,7 +293,7 @@ const fetchLatestBaileysVersion = async (options = {}) => {
293
293
  };
294
294
  } catch (error) {
295
295
  return {
296
- version: yebails_version_json_1.version,
296
+ version: yebail_version_json_1.version,
297
297
  isLatest: false,
298
298
  error
299
299
  };
@@ -312,7 +312,7 @@ const fetchLatestWaWebVersion = async (options) => {
312
312
  const match = data.match(regex);
313
313
  if (!(match === null || match === void 0 ? void 0 : match[1])) {
314
314
  return {
315
- version: yebails_version_json_1.version,
315
+ version: yebail_version_json_1.version,
316
316
  isLatest: false,
317
317
  error: {
318
318
  message: 'Could not find client revision in the fetched content'
@@ -327,7 +327,7 @@ const fetchLatestWaWebVersion = async (options) => {
327
327
  }
328
328
  catch (error) {
329
329
  return {
330
- version: yebails_version_json_1.version,
330
+ version: yebail_version_json_1.version,
331
331
  isLatest: false,
332
332
  error
333
333
  };
@@ -26,7 +26,7 @@ __exportStar(require("./history"), exports);
26
26
  __exportStar(require("./chat-utils"), exports);
27
27
  __exportStar(require("./lt-hash"), exports);
28
28
  __exportStar(require("./auth-utils"), exports);
29
- __exportStar(require("./yebails-event-stream"), exports);
29
+ __exportStar(require("./yebail-event-stream"), exports);
30
30
  __exportStar(require("./use-multi-file-auth-state"), exports);
31
31
  __exportStar(require("./use-custom-auth-state"), exports);
32
32
  __exportStar(require("./use-sqlite-auth-state"), exports);
@@ -363,20 +363,39 @@ async function getAudioDuration(buffer) {
363
363
  }
364
364
  return metadata.format.duration;
365
365
  }
366
+ const generateFallbackWaveform = (audioData) => {
367
+ const samples = 64;
368
+ const waveform = new Uint8Array(samples);
369
+ let seed = audioData.length;
370
+ for (let i = 0; i < Math.min(audioData.length, 100); i++) {
371
+ seed = (seed * 31 + audioData[i]) >>> 0;
372
+ }
373
+ const random = () => {
374
+ seed = (seed * 1664525 + 1013904223) >>> 0;
375
+ return (seed >>> 16) / 65536;
376
+ };
377
+ for (let i = 0; i < samples; i++) {
378
+ const position = i / samples;
379
+ const envelope = Math.sin(position * Math.PI);
380
+ const baseAmplitude = 30 + random() * 40;
381
+ waveform[i] = Math.min(100, Math.max(0, Math.floor(baseAmplitude * envelope)));
382
+ }
383
+ return waveform;
384
+ };
366
385
  async function getAudioWaveform(buffer, logger) {
386
+ let audioData;
387
+ if (Buffer.isBuffer(buffer)) {
388
+ audioData = buffer;
389
+ }
390
+ else if (typeof buffer === 'string') {
391
+ const rStream = (0, fs_1.createReadStream)(buffer);
392
+ audioData = await (0, exports.toBuffer)(rStream);
393
+ }
394
+ else {
395
+ audioData = await (0, exports.toBuffer)(buffer);
396
+ }
367
397
  try {
368
398
  const { default: decoder } = await eval('import(\'audio-decode\')');
369
- let audioData;
370
- if (Buffer.isBuffer(buffer)) {
371
- audioData = buffer;
372
- }
373
- else if (typeof buffer === 'string') {
374
- const rStream = (0, fs_1.createReadStream)(buffer);
375
- audioData = await (0, exports.toBuffer)(rStream);
376
- }
377
- else {
378
- audioData = await (0, exports.toBuffer)(buffer);
379
- }
380
399
  const audioBuffer = await decoder(audioData);
381
400
  const rawData = audioBuffer.getChannelData(0);
382
401
  const samples = 64;
@@ -396,7 +415,8 @@ async function getAudioWaveform(buffer, logger) {
396
415
  return waveform;
397
416
  }
398
417
  catch (e) {
399
- logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform: ' + e);
418
+ logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform using audio-decode, using fallback: ' + e);
419
+ return generateFallbackWaveform(audioData);
400
420
  }
401
421
  }
402
422
  const toReadable = (buffer) => {
@@ -16,13 +16,13 @@ const useSqliteAuthState = async (databaseFilePath) => {
16
16
  }
17
17
  const db = new Database(databaseFilePath);
18
18
  db.exec(`
19
- CREATE TABLE IF NOT EXISTS yebails_auth_kv (
19
+ CREATE TABLE IF NOT EXISTS yebail_auth_kv (
20
20
  k TEXT PRIMARY KEY NOT NULL,
21
21
  v TEXT NOT NULL
22
22
  )`);
23
- const sel = db.prepare('SELECT v FROM yebails_auth_kv WHERE k = ?');
24
- const upsert = db.prepare('INSERT OR REPLACE INTO yebails_auth_kv (k, v) VALUES (?, ?)');
25
- const del = db.prepare('DELETE FROM yebails_auth_kv WHERE k = ?');
23
+ const sel = db.prepare('SELECT v FROM yebail_auth_kv WHERE k = ?');
24
+ const upsert = db.prepare('INSERT OR REPLACE INTO yebail_auth_kv (k, v) VALUES (?, ?)');
25
+ const del = db.prepare('DELETE FROM yebail_auth_kv WHERE k = ?');
26
26
  return (0, use_custom_auth_state_1.useCustomAuthState)({
27
27
  get: async (key) => {
28
28
  const row = sel.get(key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemo-dev/yebail",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1,7 +0,0 @@
1
- {
2
- "version": [
3
- 2,
4
- 3000,
5
- 1036155891
6
- ]
7
- }