@n4tzz/n4lyx 2.7.3 → 2.7.5

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.
@@ -8,7 +8,7 @@ const WAProto_1 = require("../../WAProto");
8
8
  const libsignal_1 = require("../Signal/libsignal");
9
9
  const browser_utils_1 = require("../Utils/browser-utils");
10
10
  const logger_1 = __importDefault(require("../Utils/logger"));
11
- exports.version = [2, 3000, 1033105955];
11
+ exports.version = [2, 2413, 51];
12
12
  exports.UNAUTHORIZED_CODES = [401, 403, 419];
13
13
  exports.DEFAULT_ORIGIN = 'https://web.whatsapp.com';
14
14
  exports.CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/';
@@ -1,219 +1,149 @@
1
1
  "use strict";
2
+
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.encodeSignedDeviceIdentity = exports.configureSuccessfulPairing = exports.generateRegistrationNode = exports.generateLoginNode = void 0;
4
- const boom_1 = require("@hapi/boom");
5
- const crypto_1 = require("crypto");
6
- const WAProto_1 = require("../../WAProto");
7
- const Defaults_1 = require("../Defaults");
8
- const WABinary_1 = require("../WABinary");
9
- const crypto_2 = require("./crypto");
10
- const generics_1 = require("./generics");
11
- const signal_1 = require("./signal");
12
-
13
- const getUserAgent = (config) => {
14
- return {
15
- appVersion: {
16
- primary: config.version[0],
17
- secondary: config.version[1],
18
- tertiary: config.version[2],
19
- },
20
- platform: WAProto_1.proto.ClientPayload.UserAgent.Platform.WEB,
21
- releaseChannel: WAProto_1.proto.ClientPayload.UserAgent.ReleaseChannel.RELEASE,
22
- osVersion: '0.1',
23
- device: 'Desktop',
24
- osBuildNumber: '0.1',
25
- localeLanguageIso6391: 'en',
26
- mnc: '000',
27
- mcc: '000',
28
- localeCountryIso31661Alpha2: config.countryCode || 'US'
29
- };
30
- };
4
+ exports.useMultiFileAuthState = void 0;
31
5
 
32
- const PLATFORM_MAP = {
33
- 'Mac OS': WAProto_1.proto.ClientPayload.WebInfo.WebSubPlatform.DARWIN,
34
- 'Windows': WAProto_1.proto.ClientPayload.WebInfo.WebSubPlatform.WIN32
35
- };
6
+ const { Mutex } = require("async-mutex");
7
+ const { writeFile, readFile, unlink, stat, mkdir } = require("fs/promises");
8
+ const { join } = require("path");
9
+ const { proto } = require("../../WAProto");
10
+ const { initAuthCreds } = require("./auth-utils");
11
+ const { BufferJSON } = require("./generics");
12
+
13
+ const fileLocks = new Map();
36
14
 
37
- const getWebInfo = (config) => {
38
- let webSubPlatform = WAProto_1.proto.ClientPayload.WebInfo.WebSubPlatform.WEB_BROWSER;
39
- if (config.syncFullHistory && PLATFORM_MAP[config.browser[0]] && config.browser[1] === 'Desktop') {
40
- webSubPlatform = PLATFORM_MAP[config.browser[0]];
15
+ const getFileLock = (path) => {
16
+ if (!fileLocks.has(path)) {
17
+ fileLocks.set(path, new Mutex());
41
18
  }
42
- return { webSubPlatform };
19
+ return fileLocks.get(path);
43
20
  };
44
21
 
45
- const getClientPayload = (config) => {
46
- const payload = {
47
- connectType: WAProto_1.proto.ClientPayload.ConnectType.WIFI_UNKNOWN,
48
- connectReason: WAProto_1.proto.ClientPayload.ConnectReason.USER_ACTIVATED,
49
- userAgent: getUserAgent(config),
50
- };
51
- payload.webInfo = getWebInfo(config);
52
- return payload;
22
+ const fixFileName = (file) => {
23
+ return file?.replace(/\//g, '__')?.replace(/:/g, '-');
53
24
  };
54
25
 
55
- // FIX: Hapus lidDbMigrated yang bikin WA reject
56
- const generateLoginNode = (userJid, config) => {
57
- const { user, device } = (0, WABinary_1.jidDecode)(userJid);
58
- const payload = {
59
- ...getClientPayload(config),
60
- passive: true,
61
- pull: true,
62
- username: +user,
63
- device: device,
64
- };
65
- return WAProto_1.proto.ClientPayload.fromObject(payload);
66
- };
67
- exports.generateLoginNode = generateLoginNode;
26
+ const delay = (ms) => new Promise(res => setTimeout(res, ms));
68
27
 
69
- const getPlatformType = (platform) => {
70
- const platformType = platform.toUpperCase();
71
- return WAProto_1.proto.DeviceProps.PlatformType[platformType] || WAProto_1.proto.DeviceProps.PlatformType.CHROME;
28
+ const safeWrite = async (filePath, data) => {
29
+ const tmp = filePath + ".tmp";
30
+ await writeFile(tmp, JSON.stringify(data, BufferJSON.replacer));
31
+ await writeFile(filePath, await readFile(tmp));
32
+ await unlink(tmp).catch(() => { });
72
33
  };
73
34
 
74
- const generateRegistrationNode = ({ registrationId, signedPreKey, signedIdentityKey }, config) => {
75
- const appVersionBuf = (0, crypto_1.createHash)('md5')
76
- .update(config.version.join('.'))
77
- .digest();
78
-
79
- const companion = {
80
- os: config.browser[0],
81
- platformType: getPlatformType(config.browser[1]),
82
- requireFullSync: config.syncFullHistory,
83
- historySyncConfig: {
84
- storageQuotaMb: 10240,
85
- inlineInitialPayloadInE2EeMsg: true,
86
- recentSyncDaysLimit: undefined,
87
- supportCallLogHistory: false,
88
- supportBotUserAgentChatHistory: true,
89
- supportCagReactionsAndPolls: true,
90
- supportBizHostedMsg: true,
91
- supportRecentSyncChunkMessageCountTuning: true,
92
- supportHostedGroupMsg: true,
93
- supportFbidBotChatHistory: true,
94
- supportAddOnHistorySyncMigration: undefined,
95
- supportMessageAssociation: true,
96
- },
97
- };
35
+ const useMultiFileAuthState = async (folder) => {
98
36
 
99
- const companionProto = WAProto_1.proto.DeviceProps.encode(companion).finish();
100
-
101
- const registerPayload = {
102
- ...getClientPayload(config),
103
- passive: false,
104
- pull: false,
105
- devicePairingData: {
106
- buildHash: appVersionBuf,
107
- deviceProps: companionProto,
108
- eRegid: (0, generics_1.encodeBigEndian)(registrationId),
109
- eKeytype: Defaults_1.KEY_BUNDLE_TYPE,
110
- eIdent: signedIdentityKey.public,
111
- eSkeyId: (0, generics_1.encodeBigEndian)(signedPreKey.keyId, 3),
112
- eSkeyVal: signedPreKey.keyPair.public,
113
- eSkeySig: signedPreKey.signature,
114
- },
115
- };
116
- return WAProto_1.proto.ClientPayload.fromObject(registerPayload);
117
- };
118
- exports.generateRegistrationNode = generateRegistrationNode;
119
-
120
- const configureSuccessfulPairing = (stanza, { advSecretKey, signedIdentityKey, signalIdentities }) => {
121
- const msgId = stanza.attrs.id;
122
- const pairSuccessNode = (0, WABinary_1.getBinaryNodeChild)(stanza, 'pair-success');
123
- const deviceIdentityNode = (0, WABinary_1.getBinaryNodeChild)(pairSuccessNode, 'device-identity');
124
- const platformNode = (0, WABinary_1.getBinaryNodeChild)(pairSuccessNode, 'platform');
125
- const deviceNode = (0, WABinary_1.getBinaryNodeChild)(pairSuccessNode, 'device');
126
- const businessNode = (0, WABinary_1.getBinaryNodeChild)(pairSuccessNode, 'biz');
127
-
128
- if (!deviceIdentityNode || !deviceNode) {
129
- throw new boom_1.Boom('Missing device-identity or device in pair success node', { data: stanza });
130
- }
37
+ const folderInfo = await stat(folder).catch(() => null);
131
38
 
132
- const bizName = businessNode?.attrs.name;
133
- const jid = deviceNode.attrs.jid;
134
- const lid = deviceNode.attrs.lid;
39
+ if (folderInfo && !folderInfo.isDirectory()) {
40
+ throw new Error(`Path ${folder} is not a directory`);
41
+ }
135
42
 
136
- const { details, hmac, accountType } = WAProto_1.proto.ADVSignedDeviceIdentityHMAC.decode(deviceIdentityNode.content);
43
+ if (!folderInfo) {
44
+ await mkdir(folder, { recursive: true });
45
+ }
137
46
 
138
- const isHostedAccount = accountType !== undefined && accountType === WAProto_1.proto.ADVEncryptionType.HOSTED;
139
- const hmacPrefix = isHostedAccount ? Buffer.from([0x06, 0x05]) : Buffer.alloc(0);
47
+ const writeData = async (data, file) => {
48
+ const filePath = join(folder, fixFileName(file));
49
+ const mutex = getFileLock(filePath);
50
+
51
+ return mutex.acquire().then(async (release) => {
52
+ try {
53
+ await safeWrite(filePath, data);
54
+ } catch (e) {
55
+ await delay(100);
56
+ try {
57
+ await safeWrite(filePath, data);
58
+ } catch (_) { }
59
+ } finally {
60
+ release();
61
+ }
62
+ });
63
+ };
140
64
 
141
- const advSign = (0, crypto_2.hmacSign)(Buffer.concat([hmacPrefix, details]), Buffer.from(advSecretKey, 'base64'));
142
- if (Buffer.compare(hmac, advSign) !== 0) {
143
- throw new boom_1.Boom('Invalid account signature');
144
- }
65
+ const readData = async (file) => {
66
+ const filePath = join(folder, fixFileName(file));
67
+ const mutex = getFileLock(filePath);
68
+
69
+ return mutex.acquire().then(async (release) => {
70
+ try {
71
+ const data = await readFile(filePath, { encoding: 'utf-8' });
72
+ return JSON.parse(data, BufferJSON.reviver);
73
+ } catch (_) {
74
+ return null;
75
+ } finally {
76
+ release();
77
+ }
78
+ });
79
+ };
145
80
 
146
- const account = WAProto_1.proto.ADVSignedDeviceIdentity.decode(details);
147
- const { accountSignatureKey, accountSignature, details: deviceDetails } = account;
81
+ const removeData = async (file) => {
82
+ const filePath = join(folder, fixFileName(file));
83
+ const mutex = getFileLock(filePath);
148
84
 
149
- const deviceIdentity = WAProto_1.proto.ADVDeviceIdentity.decode(deviceDetails);
85
+ return mutex.acquire().then(async (release) => {
86
+ try {
87
+ await unlink(filePath);
88
+ } catch (_) { }
89
+ finally {
90
+ release();
91
+ }
92
+ });
93
+ };
150
94
 
151
- const accountSignaturePrefix = deviceIdentity.deviceType === WAProto_1.proto.ADVEncryptionType.HOSTED
152
- ? Buffer.from([0x06, 0x05])
153
- : Buffer.from([0x06, 0x00]);
154
- const accountMsg = Buffer.concat([accountSignaturePrefix, deviceDetails, signedIdentityKey.public]);
95
+ let creds = await readData('creds.json');
155
96
 
156
- if (!crypto_2.Curve.verify(accountSignatureKey, accountMsg, accountSignature)) {
157
- throw new boom_1.Boom('Failed to verify account signature');
97
+ if (!creds) {
98
+ creds = initAuthCreds();
99
+ await writeData(creds, 'creds.json');
158
100
  }
159
101
 
160
- const deviceMsg = Buffer.concat([
161
- Buffer.from([0x06, 0x01]),
162
- deviceDetails,
163
- signedIdentityKey.public,
164
- accountSignatureKey
165
- ]);
166
- account.deviceSignature = crypto_2.Curve.sign(signedIdentityKey.private, deviceMsg);
167
-
168
- const identity = (0, signal_1.createSignalIdentity)(jid, accountSignatureKey);
169
- const accountEnc = (0, exports.encodeSignedDeviceIdentity)(account, false);
170
-
171
- const reply = {
172
- tag: 'iq',
173
- attrs: {
174
- to: WABinary_1.S_WHATSAPP_NET,
175
- type: 'result',
176
- id: msgId,
177
- },
178
- content: [
179
- {
180
- tag: 'pair-device-sign',
181
- attrs: {},
182
- content: [
183
- {
184
- tag: 'device-identity',
185
- attrs: { 'key-index': deviceIdentity.keyIndex.toString() },
186
- content: accountEnc
102
+ return {
103
+ state: {
104
+ creds,
105
+ keys: {
106
+ get: async (type, ids) => {
107
+ const data = {};
108
+
109
+ await Promise.all(ids.map(async (id) => {
110
+ let value = await readData(`${type}-${id}.json`);
111
+
112
+ if (type === 'app-state-sync-key' && value) {
113
+ value = proto.Message.AppStateSyncKeyData.fromObject(value);
114
+ }
115
+
116
+ data[id] = value;
117
+ }));
118
+
119
+ return data;
120
+ },
121
+
122
+ set: async (data) => {
123
+ const tasks = [];
124
+
125
+ for (const category in data) {
126
+ for (const id in data[category]) {
127
+ const value = data[category][id];
128
+ const file = `${category}-${id}.json`;
129
+
130
+ if (value) {
131
+ tasks.push(writeData(value, file));
132
+ } else {
133
+ tasks.push(removeData(file));
134
+ }
135
+ }
187
136
  }
188
- ]
189
- }
190
- ]
191
- };
192
137
 
193
- const authUpdate = {
194
- account,
195
- me: { id: jid, name: bizName, lid },
196
- signalIdentities: [
197
- ...(signalIdentities || []),
198
- identity
199
- ],
200
- platform: platformNode?.attrs.name
201
- };
138
+ await Promise.all(tasks);
139
+ }
140
+ }
141
+ },
202
142
 
203
- return {
204
- creds: authUpdate,
205
- reply
143
+ saveCreds: async () => {
144
+ await writeData(creds, 'creds.json');
145
+ }
206
146
  };
207
147
  };
208
- exports.configureSuccessfulPairing = configureSuccessfulPairing;
209
148
 
210
- const encodeSignedDeviceIdentity = (account, includeSignatureKey) => {
211
- account = { ...account };
212
- if (!includeSignatureKey || !account.accountSignatureKey?.length) {
213
- account.accountSignatureKey = null;
214
- }
215
- return WAProto_1.proto.ADVSignedDeviceIdentity
216
- .encode(account)
217
- .finish();
218
- };
219
- exports.encodeSignedDeviceIdentity = encodeSignedDeviceIdentity;
149
+ exports.useMultiFileAuthState = useMultiFileAuthState;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@n4tzz/n4lyx",
3
- "version": "2.7.3",
3
+ "version": "2.7.5",
4
4
  "description": "N4lyx - WhatsApp Web API Library powered by N4tzzOfficial",
5
5
  "keywords": [
6
6
  "n4lyx",