@n4tzz/n4lyx 2.7.2 → 2.7.4

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.
@@ -1,229 +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");
36
12
 
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]];
41
- }
42
- return { webSubPlatform };
43
- };
13
+ const fileLocks = new Map();
44
14
 
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;
53
- };
54
-
55
- const generateLoginNode = (userJid, config) => {
56
- const { user, device } = (0, WABinary_1.jidDecode)(userJid);
57
- const payload = {
58
- ...getClientPayload(config),
59
- passive: true,
60
- pull: true,
61
- username: +user,
62
- device: device,
63
- lidDbMigrated: false
64
- };
65
- return WAProto_1.proto.ClientPayload.fromObject(payload);
15
+ const getFileLock = (path) => {
16
+ if (!fileLocks.has(path)) {
17
+ fileLocks.set(path, new Mutex());
18
+ }
19
+ return fileLocks.get(path);
66
20
  };
67
- exports.generateLoginNode = generateLoginNode;
68
21
 
69
- const getPlatformType = (platform) => {
70
- const platformType = platform.toUpperCase();
71
- return WAProto_1.proto.DeviceProps.PlatformType[platformType] || WAProto_1.proto.DeviceProps.PlatformType.CHROME;
22
+ const fixFileName = (file) => {
23
+ return file?.replace(/\//g, '__')?.replace(/:/g, '-');
72
24
  };
73
25
 
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
- supportGroupHistory: false,
97
- onDemandReady: undefined,
98
- supportGuestChat: undefined
99
- },
100
- version: {
101
- primary: 10,
102
- secondary: 15,
103
- tertiary: 7
104
- }
105
- };
26
+ const delay = (ms) => new Promise(res => setTimeout(res, ms));
106
27
 
107
- const companionProto = WAProto_1.proto.DeviceProps.encode(companion).finish();
108
-
109
- const registerPayload = {
110
- ...getClientPayload(config),
111
- passive: false,
112
- pull: false,
113
- devicePairingData: {
114
- buildHash: appVersionBuf,
115
- deviceProps: companionProto,
116
- eRegid: (0, generics_1.encodeBigEndian)(registrationId),
117
- eKeytype: Defaults_1.KEY_BUNDLE_TYPE,
118
- eIdent: signedIdentityKey.public,
119
- eSkeyId: (0, generics_1.encodeBigEndian)(signedPreKey.keyId, 3),
120
- eSkeyVal: signedPreKey.keyPair.public,
121
- eSkeySig: signedPreKey.signature,
122
- },
123
- };
124
- return WAProto_1.proto.ClientPayload.fromObject(registerPayload);
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(() => { });
125
33
  };
126
- exports.generateRegistrationNode = generateRegistrationNode;
127
-
128
- const configureSuccessfulPairing = (stanza, { advSecretKey, signedIdentityKey, signalIdentities }) => {
129
- const msgId = stanza.attrs.id;
130
- const pairSuccessNode = (0, WABinary_1.getBinaryNodeChild)(stanza, 'pair-success');
131
- const deviceIdentityNode = (0, WABinary_1.getBinaryNodeChild)(pairSuccessNode, 'device-identity');
132
- const platformNode = (0, WABinary_1.getBinaryNodeChild)(pairSuccessNode, 'platform');
133
- const deviceNode = (0, WABinary_1.getBinaryNodeChild)(pairSuccessNode, 'device');
134
- const businessNode = (0, WABinary_1.getBinaryNodeChild)(pairSuccessNode, 'biz');
135
-
136
- if (!deviceIdentityNode || !deviceNode) {
137
- throw new boom_1.Boom('Missing device-identity or device in pair success node', { data: stanza });
138
- }
139
34
 
140
- const bizName = businessNode?.attrs.name;
141
- const jid = deviceNode.attrs.jid;
142
- const lid = deviceNode.attrs.lid;
35
+ const useMultiFileAuthState = async (folder) => {
143
36
 
144
- const { details, hmac, accountType } = WAProto_1.proto.ADVSignedDeviceIdentityHMAC.decode(deviceIdentityNode.content);
37
+ const folderInfo = await stat(folder).catch(() => null);
145
38
 
146
- let hmacPrefix = Buffer.from([]);
147
- if (accountType !== undefined && accountType === WAProto_1.proto.ADVEncryptionType.HOSTED) {
148
- hmacPrefix = Buffer.from([0x06, 0x05]);
39
+ if (folderInfo && !folderInfo.isDirectory()) {
40
+ throw new Error(`Path ${folder} is not a directory`);
149
41
  }
150
42
 
151
- const advSign = (0, crypto_2.hmacSign)(Buffer.concat([hmacPrefix, details]), Buffer.from(advSecretKey, 'base64'));
152
- if (Buffer.compare(hmac, advSign) !== 0) {
153
- throw new boom_1.Boom('Invalid account signature');
43
+ if (!folderInfo) {
44
+ await mkdir(folder, { recursive: true });
154
45
  }
155
46
 
156
- const account = WAProto_1.proto.ADVSignedDeviceIdentity.decode(details);
157
- const { accountSignatureKey, accountSignature, details: deviceDetails } = account;
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
+ };
158
64
 
159
- const deviceIdentity = WAProto_1.proto.ADVDeviceIdentity.decode(deviceDetails);
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
+ };
160
80
 
161
- const accountSignaturePrefix = deviceIdentity.deviceType === WAProto_1.proto.ADVEncryptionType.HOSTED
162
- ? Buffer.from([0x06, 0x05])
163
- : Buffer.from([0x06, 0x00]);
164
- const accountMsg = Buffer.concat([accountSignaturePrefix, deviceDetails, signedIdentityKey.public]);
165
-
166
- if (!crypto_2.Curve.verify(accountSignatureKey, accountMsg, accountSignature)) {
167
- throw new boom_1.Boom('Failed to verify account signature');
168
- }
81
+ const removeData = async (file) => {
82
+ const filePath = join(folder, fixFileName(file));
83
+ const mutex = getFileLock(filePath);
169
84
 
170
- const deviceMsg = Buffer.concat([
171
- Buffer.from([0x06, 0x01]),
172
- deviceDetails,
173
- signedIdentityKey.public,
174
- accountSignatureKey
175
- ]);
176
- account.deviceSignature = crypto_2.Curve.sign(signedIdentityKey.private, deviceMsg);
177
-
178
- const identity = (0, signal_1.createSignalIdentity)(jid, accountSignatureKey);
179
- const accountEnc = (0, exports.encodeSignedDeviceIdentity)(account, false);
180
-
181
- const reply = {
182
- tag: 'iq',
183
- attrs: {
184
- to: WABinary_1.S_WHATSAPP_NET,
185
- type: 'result',
186
- id: msgId,
187
- },
188
- content: [
189
- {
190
- tag: 'pair-device-sign',
191
- attrs: {},
192
- content: [
193
- {
194
- tag: 'device-identity',
195
- attrs: { 'key-index': deviceIdentity.keyIndex.toString() },
196
- content: accountEnc
197
- }
198
- ]
85
+ return mutex.acquire().then(async (release) => {
86
+ try {
87
+ await unlink(filePath);
88
+ } catch (_) { }
89
+ finally {
90
+ release();
199
91
  }
200
- ]
92
+ });
201
93
  };
202
94
 
203
- const authUpdate = {
204
- account,
205
- me: { id: jid, name: bizName, lid },
206
- signalIdentities: [
207
- ...(signalIdentities || []),
208
- identity
209
- ],
210
- platform: platformNode?.attrs.name
211
- };
95
+ let creds = await readData('creds.json');
96
+
97
+ if (!creds) {
98
+ creds = initAuthCreds();
99
+ await writeData(creds, 'creds.json');
100
+ }
212
101
 
213
102
  return {
214
- creds: authUpdate,
215
- reply
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
+ }
136
+ }
137
+
138
+ await Promise.all(tasks);
139
+ }
140
+ }
141
+ },
142
+
143
+ saveCreds: async () => {
144
+ await writeData(creds, 'creds.json');
145
+ }
216
146
  };
217
147
  };
218
- exports.configureSuccessfulPairing = configureSuccessfulPairing;
219
148
 
220
- const encodeSignedDeviceIdentity = (account, includeSignatureKey) => {
221
- account = { ...account };
222
- if (!includeSignatureKey || !account.accountSignatureKey?.length) {
223
- account.accountSignatureKey = null;
224
- }
225
- return WAProto_1.proto.ADVSignedDeviceIdentity
226
- .encode(account)
227
- .finish();
228
- };
229
- 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.2",
3
+ "version": "2.7.4",
4
4
  "description": "N4lyx - WhatsApp Web API Library powered by N4tzzOfficial",
5
5
  "keywords": [
6
6
  "n4lyx",