@gqb333/based 2.7.80 → 2.7.81
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/lib/Utils/decode-wa-message.js +192 -138
- package/lib/Utils/generics.js +149 -215
- package/package.json +1 -1
|
@@ -1,207 +1,261 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.decryptMessageNode = exports.NACK_REASONS = exports.MISSING_KEYS_ERROR_TEXT = exports.NO_MESSAGE_FOUND_ERROR_TEXT = void 0;
|
|
4
5
|
exports.decodeMessageNode = decodeMessageNode;
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
const boom_1 = require("@hapi/boom");
|
|
6
8
|
const WAProto_1 = require("../../WAProto");
|
|
7
9
|
const WABinary_1 = require("../WABinary");
|
|
8
10
|
const generics_1 = require("./generics");
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
9
14
|
exports.NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node';
|
|
10
|
-
exports.MISSING_KEYS_ERROR_TEXT
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
const senderLid = (_b = stanza === null || stanza === void 0 ? void 0 : stanza.attrs) === null || _b === void 0 ? void 0 : _b.sender_lid;
|
|
39
|
-
const participant = stanza.attrs.participant;
|
|
40
|
-
const participantLid = (_c = stanza === null || stanza === void 0 ? void 0 : stanza.attrs) === null || _c === void 0 ? void 0 : _c.participant_lid;
|
|
41
|
-
const recipient = stanza.attrs.recipient;
|
|
42
|
-
const isMe = (jid) => (0, WABinary_1.areJidsSameUser)(jid, meId);
|
|
15
|
+
exports.MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled';
|
|
16
|
+
|
|
17
|
+
exports.NACK_REASONS = Object.freeze({
|
|
18
|
+
ParsingError: 487,
|
|
19
|
+
UnrecognizedStanza: 488,
|
|
20
|
+
UnrecognizedStanzaClass: 489,
|
|
21
|
+
UnrecognizedStanzaType: 490,
|
|
22
|
+
InvalidProtobuf: 491,
|
|
23
|
+
InvalidHostedCompanionStanza:493,
|
|
24
|
+
MissingMessageSecret: 495,
|
|
25
|
+
SignalErrorOldCounter: 496,
|
|
26
|
+
MessageDeletedOnPeer: 499,
|
|
27
|
+
UnhandledError: 500,
|
|
28
|
+
UnsupportedAdminRevoke: 550,
|
|
29
|
+
UnsupportedLIDGroup: 551,
|
|
30
|
+
DBOperationFailed: 552
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
function attr(stanza, key) {
|
|
37
|
+
return stanza?.attrs?.[key];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
function makeIdentityCheckers(meId, meLid) {
|
|
42
|
+
const isMe = (jid) => (0, WABinary_1.areJidsSameUser)(jid, meId);
|
|
43
43
|
const isMeLid = (jid) => (0, WABinary_1.areJidsSameUser)(jid, meLid);
|
|
44
|
+
return { isMe, isMeLid };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
function decodeMessageNode(stanza, meId, meLid) {
|
|
50
|
+
const { isMe, isMeLid } = makeIdentityCheckers(meId, meLid);
|
|
51
|
+
|
|
52
|
+
const msgId = stanza.attrs.id;
|
|
53
|
+
const from = stanza.attrs.from;
|
|
54
|
+
const participant = stanza.attrs.participant;
|
|
55
|
+
const recipient = stanza.attrs.recipient;
|
|
56
|
+
const senderPn = attr(stanza, 'sender_pn');
|
|
57
|
+
const senderLid = attr(stanza, 'sender_lid');
|
|
58
|
+
const participantLid = attr(stanza, 'participant_lid');
|
|
59
|
+
|
|
60
|
+
let msgType, chatId, author;
|
|
61
|
+
|
|
62
|
+
|
|
44
63
|
if ((0, WABinary_1.isJidUser)(from) || (0, WABinary_1.isLidUser)(from)) {
|
|
45
64
|
if (recipient && !(0, WABinary_1.isJidMetaAi)(recipient)) {
|
|
46
65
|
if (!isMe(from) && !isMeLid(from)) {
|
|
47
|
-
throw new boom_1.Boom('
|
|
66
|
+
throw new boom_1.Boom('recipient present, but msg not from me', { data: stanza });
|
|
48
67
|
}
|
|
49
68
|
chatId = recipient;
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
69
|
+
} else {
|
|
52
70
|
chatId = from;
|
|
53
71
|
}
|
|
54
72
|
msgType = 'chat';
|
|
55
|
-
author
|
|
56
|
-
|
|
57
|
-
else if ((0, WABinary_1.isJidGroup)(from)) {
|
|
58
|
-
if (!participant)
|
|
59
|
-
throw new boom_1.Boom('No participant in group message');
|
|
60
|
-
}
|
|
73
|
+
author = from;
|
|
74
|
+
|
|
75
|
+
} else if ((0, WABinary_1.isJidGroup)(from)) {
|
|
76
|
+
if (!participant) throw new boom_1.Boom('No participant in group message');
|
|
61
77
|
msgType = 'group';
|
|
62
|
-
author
|
|
63
|
-
chatId
|
|
64
|
-
|
|
65
|
-
else if ((0, WABinary_1.isJidNewsletter)(from)) {
|
|
78
|
+
author = participant;
|
|
79
|
+
chatId = from;
|
|
80
|
+
|
|
81
|
+
} else if ((0, WABinary_1.isJidNewsletter)(from)) {
|
|
66
82
|
msgType = 'newsletter';
|
|
67
|
-
author
|
|
68
|
-
chatId
|
|
69
|
-
|
|
70
|
-
else if ((0, WABinary_1.isJidBroadcast)(from)) {
|
|
71
|
-
if (!participant)
|
|
72
|
-
throw new boom_1.Boom('No participant in group message');
|
|
73
|
-
}
|
|
83
|
+
author = from;
|
|
84
|
+
chatId = from;
|
|
85
|
+
|
|
86
|
+
} else if ((0, WABinary_1.isJidBroadcast)(from)) {
|
|
87
|
+
if (!participant) throw new boom_1.Boom('No participant in broadcast message');
|
|
74
88
|
const isParticipantMe = isMe(participant);
|
|
75
89
|
if ((0, WABinary_1.isJidStatusBroadcast)(from)) {
|
|
76
90
|
msgType = isParticipantMe ? 'direct_peer_status' : 'other_status';
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
91
|
+
} else {
|
|
79
92
|
msgType = isParticipantMe ? 'peer_broadcast' : 'other_broadcast';
|
|
80
93
|
}
|
|
81
94
|
chatId = from;
|
|
82
95
|
author = participant;
|
|
83
|
-
|
|
84
|
-
else {
|
|
96
|
+
|
|
97
|
+
} else {
|
|
85
98
|
throw new boom_1.Boom('Unknown message type', { data: stanza });
|
|
86
99
|
}
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
const fromMe = (0, WABinary_1.isJidNewsletter)(from)
|
|
103
|
+
? !!(stanza.attrs?.is_sender) || false
|
|
104
|
+
: ((0, WABinary_1.isLidUser)(from) ? isMeLid : isMe)(participant || from);
|
|
105
|
+
|
|
106
|
+
|
|
89
107
|
const key = {
|
|
90
|
-
remoteJid:
|
|
108
|
+
remoteJid: chatId,
|
|
91
109
|
fromMe,
|
|
92
|
-
id:
|
|
110
|
+
id: msgId,
|
|
93
111
|
senderPn,
|
|
94
112
|
senderLid,
|
|
95
113
|
participant,
|
|
96
114
|
participantLid,
|
|
97
|
-
|
|
115
|
+
server_id: attr(stanza, 'server_id')
|
|
98
116
|
};
|
|
117
|
+
|
|
99
118
|
const fullMessage = {
|
|
100
119
|
key,
|
|
101
120
|
messageTimestamp: +stanza.attrs.t,
|
|
102
|
-
pushName:
|
|
103
|
-
broadcast:
|
|
121
|
+
pushName: attr(stanza, 'notify'),
|
|
122
|
+
broadcast: (0, WABinary_1.isJidBroadcast)(from)
|
|
104
123
|
};
|
|
124
|
+
|
|
105
125
|
if (msgType === 'newsletter') {
|
|
106
|
-
fullMessage.newsletterServerId = +((
|
|
126
|
+
fullMessage.newsletterServerId = +(attr(stanza, 'server_id'));
|
|
107
127
|
}
|
|
128
|
+
|
|
108
129
|
if (key.fromMe) {
|
|
109
130
|
fullMessage.status = WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK;
|
|
110
131
|
}
|
|
132
|
+
|
|
111
133
|
return {
|
|
112
134
|
fullMessage,
|
|
113
135
|
author,
|
|
114
136
|
sender: msgType === 'chat' ? author : chatId
|
|
115
137
|
};
|
|
116
138
|
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
117
142
|
const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
118
143
|
const { fullMessage, author, sender } = decodeMessageNode(stanza, meId, meLid);
|
|
144
|
+
|
|
119
145
|
return {
|
|
120
146
|
fullMessage,
|
|
121
147
|
category: stanza.attrs.category,
|
|
122
148
|
author,
|
|
149
|
+
|
|
123
150
|
async decrypt() {
|
|
124
|
-
var _a;
|
|
125
151
|
let decryptables = 0;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (msg.senderKeyDistributionMessage) {
|
|
175
|
-
try {
|
|
176
|
-
await repository.processSenderKeyDistributionMessage({
|
|
177
|
-
authorJid: author,
|
|
178
|
-
item: msg.senderKeyDistributionMessage
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
catch (err) {
|
|
182
|
-
logger.error({ key: fullMessage.key, err }, 'failed to decrypt message');
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
if (fullMessage.message) {
|
|
186
|
-
Object.assign(fullMessage.message, msg);
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
fullMessage.message = msg;
|
|
152
|
+
|
|
153
|
+
if (!Array.isArray(stanza.content)) {
|
|
154
|
+
fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT;
|
|
155
|
+
fullMessage.messageStubParameters = [exports.NO_MESSAGE_FOUND_ERROR_TEXT];
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
for (const { tag, attrs, content } of stanza.content) {
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
if (tag === 'verified_name' && content instanceof Uint8Array) {
|
|
164
|
+
const cert = WAProto_1.proto.VerifiedNameCertificate.decode(content);
|
|
165
|
+
const details = WAProto_1.proto.VerifiedNameCertificate.Details.decode(cert.details);
|
|
166
|
+
fullMessage.verifiedBizName = details.verifiedName;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (tag === 'unavailable' && attrs.type === 'view_once') {
|
|
171
|
+
fullMessage.key.isViewOnce = true;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if ((tag !== 'enc' && tag !== 'plaintext') || !(content instanceof Uint8Array)) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
decryptables++;
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const msgBuffer = await decryptContent(tag, attrs, content, sender, author, repository);
|
|
183
|
+
|
|
184
|
+
let msg = WAProto_1.proto.Message.decode(
|
|
185
|
+
tag !== 'plaintext' ? (0, generics_1.unpadRandomMax16)(msgBuffer) : msgBuffer
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// Unwrap device-sent message
|
|
189
|
+
msg = msg?.deviceSentMessage?.message || msg;
|
|
190
|
+
|
|
191
|
+
// Processa sender key distribution
|
|
192
|
+
if (msg.senderKeyDistributionMessage) {
|
|
193
|
+
try {
|
|
194
|
+
await repository.processSenderKeyDistributionMessage({
|
|
195
|
+
authorJid: author,
|
|
196
|
+
item: msg.senderKeyDistributionMessage
|
|
197
|
+
});
|
|
198
|
+
} catch (err) {
|
|
199
|
+
logger.error({ key: fullMessage.key, err }, 'failed to process senderKeyDistribution');
|
|
190
200
|
}
|
|
191
201
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
fullMessage.
|
|
202
|
+
|
|
203
|
+
// Merge nel messaggio completo
|
|
204
|
+
if (fullMessage.message) {
|
|
205
|
+
Object.assign(fullMessage.message, msg);
|
|
206
|
+
} else {
|
|
207
|
+
fullMessage.message = msg;
|
|
196
208
|
}
|
|
209
|
+
|
|
210
|
+
} catch (err) {
|
|
211
|
+
logger.error({ key: fullMessage.key, err }, 'failed to decrypt message');
|
|
212
|
+
fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT;
|
|
213
|
+
fullMessage.messageStubParameters = [err.message];
|
|
197
214
|
}
|
|
198
215
|
}
|
|
199
|
-
|
|
216
|
+
|
|
217
|
+
// Nessun contenuto decifrable trovato
|
|
200
218
|
if (!decryptables) {
|
|
201
|
-
fullMessage.messageStubType
|
|
219
|
+
fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT;
|
|
202
220
|
fullMessage.messageStubParameters = [exports.NO_MESSAGE_FOUND_ERROR_TEXT];
|
|
203
221
|
}
|
|
204
222
|
}
|
|
205
223
|
};
|
|
206
224
|
};
|
|
207
|
-
exports.decryptMessageNode = decryptMessageNode;
|
|
225
|
+
exports.decryptMessageNode = decryptMessageNode;
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Decifra il contenuto di un nodo enc/plaintext.
|
|
231
|
+
* Estratto per leggibilità e testabilità.
|
|
232
|
+
*/
|
|
233
|
+
async function decryptContent(tag, attrs, content, sender, author, repository) {
|
|
234
|
+
const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type;
|
|
235
|
+
|
|
236
|
+
switch (e2eType) {
|
|
237
|
+
case 'skmsg':
|
|
238
|
+
return repository.decryptGroupMessage({
|
|
239
|
+
group: sender,
|
|
240
|
+
authorJid: author,
|
|
241
|
+
msg: content
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
case 'pkmsg':
|
|
245
|
+
case 'msg': {
|
|
246
|
+
const user = (0, WABinary_1.isJidUser)(sender) ? sender : author;
|
|
247
|
+
return repository.decryptMessage({
|
|
248
|
+
jid: user,
|
|
249
|
+
type: e2eType,
|
|
250
|
+
ciphertext: content
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
case 'plaintext':
|
|
255
|
+
case undefined:
|
|
256
|
+
return content;
|
|
257
|
+
|
|
258
|
+
default:
|
|
259
|
+
throw new Error(`Tipo e2e non riconosciuto: ${e2eType}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
package/lib/Utils/generics.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
|
|
2
3
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
4
|
if (k2 === undefined) k2 = k;
|
|
4
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
6
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
8
|
}
|
|
8
9
|
Object.defineProperty(o, k2, desc);
|
|
9
10
|
}) : (function(o, m, k, k2) {
|
|
@@ -35,94 +36,108 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
36
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
37
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
38
|
};
|
|
39
|
+
|
|
38
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
41
|
exports.isWABusinessPlatform = exports.getCodeFromWSError = exports.getCallStatusFromNode = exports.getErrorCodeFromStreamError = exports.getStatusFromReceiptType = exports.generateMdTagPrefix = exports.fetchLatestWaWebVersion = exports.fetchLatestBaileysVersion = exports.printQRIfNecessaryListener = exports.bindWaitForConnectionUpdate = exports.generateMessageID = exports.generateMessageIDV2 = exports.delayCancellable = exports.delay = exports.debouncedTimeout = exports.unixTimestampSeconds = exports.toNumber = exports.encodeBigEndian = exports.generateRegistrationId = exports.encodeNewsletterMessage = exports.encodeWAMessage = exports.unpadRandomMax16 = exports.writeRandomPadMax16 = exports.getKeyAuthor = exports.BufferJSON = exports.getPlatformId = exports.Browsers = void 0;
|
|
40
42
|
exports.promiseTimeout = promiseTimeout;
|
|
41
43
|
exports.bindWaitForEvent = bindWaitForEvent;
|
|
42
44
|
exports.trimUndefined = trimUndefined;
|
|
43
45
|
exports.bytesToCrockford = bytesToCrockford;
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
46
|
+
|
|
47
|
+
const boom_1 = require("@hapi/boom");
|
|
48
|
+
const axios_1 = __importDefault(require("axios"));
|
|
49
|
+
const crypto_1 = require("crypto");
|
|
50
|
+
const os_1 = require("os");
|
|
48
51
|
const WAProto_1 = require("../../WAProto");
|
|
49
52
|
const baileys_version_json_1 = require("../Defaults/baileys-version.json");
|
|
50
|
-
const Types_1
|
|
53
|
+
const Types_1 = require("../Types");
|
|
51
54
|
const WABinary_1 = require("../WABinary");
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
'
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
|
|
56
|
+
const COMPANION_PLATFORM_MAP = Object.freeze({
|
|
57
|
+
Chrome: '49',
|
|
58
|
+
Edge: '50',
|
|
59
|
+
Firefox: '51',
|
|
60
|
+
Opera: '53',
|
|
61
|
+
Safari: '54'
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const PLATFORM_MAP = Object.freeze({
|
|
65
|
+
aix: 'AIX',
|
|
66
|
+
darwin: 'Mac OS',
|
|
67
|
+
win32: 'Windows',
|
|
68
|
+
android: 'Android',
|
|
69
|
+
freebsd: 'FreeBSD',
|
|
70
|
+
openbsd: 'OpenBSD',
|
|
71
|
+
sunos: 'Solaris'
|
|
72
|
+
});
|
|
73
|
+
|
|
68
74
|
exports.Browsers = {
|
|
69
|
-
ubuntu:
|
|
70
|
-
macOS:
|
|
71
|
-
baileys:
|
|
72
|
-
windows:
|
|
75
|
+
ubuntu: (browser) => ['Ubuntu', browser, '24.04.1'],
|
|
76
|
+
macOS: (browser) => ['Mac OS', browser, '15.2.0'],
|
|
77
|
+
baileys: (browser) => ['Baileys', browser, '6.7.9'],
|
|
78
|
+
windows: (browser) => ['Windows', browser, '10.0.26100'],
|
|
73
79
|
appropriate: (browser) => [PLATFORM_MAP[(0, os_1.platform)()] || 'Ubuntu', browser, (0, os_1.release)()]
|
|
74
80
|
};
|
|
81
|
+
|
|
75
82
|
const getPlatformId = (browser) => {
|
|
76
83
|
const platformType = WAProto_1.proto.DeviceProps.PlatformType[browser.toUpperCase()];
|
|
77
|
-
return platformType ? platformType.toString() : '49';
|
|
84
|
+
return platformType ? platformType.toString() : '49';
|
|
78
85
|
};
|
|
79
86
|
exports.getPlatformId = getPlatformId;
|
|
87
|
+
|
|
80
88
|
exports.BufferJSON = {
|
|
81
89
|
replacer: (k, value) => {
|
|
82
|
-
if (Buffer.isBuffer(value) || value instanceof Uint8Array ||
|
|
83
|
-
return { type: 'Buffer', data: Buffer.from(
|
|
90
|
+
if (Buffer.isBuffer(value) || value instanceof Uint8Array || value?.type === 'Buffer') {
|
|
91
|
+
return { type: 'Buffer', data: Buffer.from(value?.data || value).toString('base64') };
|
|
84
92
|
}
|
|
85
93
|
return value;
|
|
86
94
|
},
|
|
87
95
|
reviver: (_, value) => {
|
|
88
|
-
if (typeof value === 'object' &&
|
|
96
|
+
if (typeof value === 'object' && value && (value.buffer === true || value.type === 'Buffer')) {
|
|
89
97
|
const val = value.data || value.value;
|
|
90
98
|
return typeof val === 'string' ? Buffer.from(val, 'base64') : Buffer.from(val || []);
|
|
91
99
|
}
|
|
92
100
|
return value;
|
|
93
101
|
}
|
|
94
102
|
};
|
|
95
|
-
|
|
103
|
+
|
|
104
|
+
const getKeyAuthor = (key, meId = 'me') => (
|
|
105
|
+
(key?.fromMe ? meId : key?.participant || key?.remoteJid) || ''
|
|
106
|
+
);
|
|
96
107
|
exports.getKeyAuthor = getKeyAuthor;
|
|
108
|
+
|
|
97
109
|
const writeRandomPadMax16 = (msg) => {
|
|
98
110
|
const pad = (0, crypto_1.randomBytes)(1);
|
|
99
111
|
pad[0] &= 0xf;
|
|
100
|
-
if (!pad[0])
|
|
101
|
-
pad[0] = 0xf;
|
|
102
|
-
}
|
|
112
|
+
if (!pad[0]) pad[0] = 0xf;
|
|
103
113
|
return Buffer.concat([msg, Buffer.alloc(pad[0], pad[0])]);
|
|
104
114
|
};
|
|
105
115
|
exports.writeRandomPadMax16 = writeRandomPadMax16;
|
|
116
|
+
|
|
106
117
|
const unpadRandomMax16 = (e) => {
|
|
107
118
|
const t = new Uint8Array(e);
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
var r = t[t.length - 1];
|
|
112
|
-
if (r > t.length) {
|
|
113
|
-
throw new Error(`unpad given ${t.length} bytes, but pad is ${r}`);
|
|
114
|
-
}
|
|
119
|
+
if (t.length === 0) throw new Error('unpadPkcs7 given empty bytes');
|
|
120
|
+
const r = t[t.length - 1];
|
|
121
|
+
if (r > t.length) throw new Error(`unpad given ${t.length} bytes, but pad is ${r}`);
|
|
115
122
|
return new Uint8Array(t.buffer, t.byteOffset, t.length - r);
|
|
116
123
|
};
|
|
117
124
|
exports.unpadRandomMax16 = unpadRandomMax16;
|
|
118
|
-
|
|
125
|
+
|
|
126
|
+
const encodeWAMessage = (message) => (
|
|
127
|
+
(0, exports.writeRandomPadMax16)(WAProto_1.proto.Message.encode(message).finish())
|
|
128
|
+
);
|
|
119
129
|
exports.encodeWAMessage = encodeWAMessage;
|
|
120
|
-
|
|
130
|
+
|
|
131
|
+
const encodeNewsletterMessage = (message) => (
|
|
132
|
+
WAProto_1.proto.Message.encode(message).finish()
|
|
133
|
+
);
|
|
121
134
|
exports.encodeNewsletterMessage = encodeNewsletterMessage;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
135
|
+
|
|
136
|
+
const generateRegistrationId = () => (
|
|
137
|
+
Uint16Array.from((0, crypto_1.randomBytes)(2))[0] & 16383
|
|
138
|
+
);
|
|
125
139
|
exports.generateRegistrationId = generateRegistrationId;
|
|
140
|
+
|
|
126
141
|
const encodeBigEndian = (e, t = 4) => {
|
|
127
142
|
let r = e;
|
|
128
143
|
const a = new Uint8Array(t);
|
|
@@ -133,78 +148,70 @@ const encodeBigEndian = (e, t = 4) => {
|
|
|
133
148
|
return a;
|
|
134
149
|
};
|
|
135
150
|
exports.encodeBigEndian = encodeBigEndian;
|
|
136
|
-
|
|
151
|
+
|
|
152
|
+
const toNumber = (t) => (
|
|
153
|
+
(typeof t === 'object' && t) ? ('toNumber' in t ? t.toNumber() : t.low) : t || 0
|
|
154
|
+
);
|
|
137
155
|
exports.toNumber = toNumber;
|
|
138
|
-
|
|
156
|
+
|
|
139
157
|
const unixTimestampSeconds = (date = new Date()) => Math.floor(date.getTime() / 1000);
|
|
140
158
|
exports.unixTimestampSeconds = unixTimestampSeconds;
|
|
159
|
+
|
|
141
160
|
const debouncedTimeout = (intervalMs = 1000, task) => {
|
|
142
161
|
let timeout;
|
|
143
162
|
return {
|
|
144
163
|
start: (newIntervalMs, newTask) => {
|
|
145
164
|
task = newTask || task;
|
|
146
165
|
intervalMs = newIntervalMs || intervalMs;
|
|
147
|
-
timeout
|
|
148
|
-
timeout = setTimeout(() => task
|
|
166
|
+
if (timeout) clearTimeout(timeout);
|
|
167
|
+
timeout = setTimeout(() => task?.(), intervalMs);
|
|
149
168
|
},
|
|
150
169
|
cancel: () => {
|
|
151
|
-
timeout
|
|
170
|
+
if (timeout) clearTimeout(timeout);
|
|
152
171
|
timeout = undefined;
|
|
153
172
|
},
|
|
154
|
-
setTask:
|
|
173
|
+
setTask: (newTask) => task = newTask,
|
|
155
174
|
setInterval: (newInterval) => intervalMs = newInterval
|
|
156
175
|
};
|
|
157
176
|
};
|
|
158
177
|
exports.debouncedTimeout = debouncedTimeout;
|
|
178
|
+
|
|
159
179
|
const delay = (ms) => (0, exports.delayCancellable)(ms).delay;
|
|
160
180
|
exports.delay = delay;
|
|
181
|
+
|
|
161
182
|
const delayCancellable = (ms) => {
|
|
162
183
|
const stack = new Error().stack;
|
|
163
|
-
let timeout;
|
|
164
|
-
let reject;
|
|
184
|
+
let timeout, reject;
|
|
165
185
|
const delay = new Promise((resolve, _reject) => {
|
|
166
186
|
timeout = setTimeout(resolve, ms);
|
|
167
|
-
reject
|
|
187
|
+
reject = _reject;
|
|
168
188
|
});
|
|
169
189
|
const cancel = () => {
|
|
170
190
|
clearTimeout(timeout);
|
|
171
|
-
reject(new boom_1.Boom('Cancelled', {
|
|
172
|
-
statusCode: 500,
|
|
173
|
-
data: {
|
|
174
|
-
stack
|
|
175
|
-
}
|
|
176
|
-
}));
|
|
191
|
+
reject(new boom_1.Boom('Cancelled', { statusCode: 500, data: { stack } }));
|
|
177
192
|
};
|
|
178
193
|
return { delay, cancel };
|
|
179
194
|
};
|
|
180
195
|
exports.delayCancellable = delayCancellable;
|
|
196
|
+
|
|
181
197
|
async function promiseTimeout(ms, promise) {
|
|
182
|
-
if (!ms)
|
|
183
|
-
return new Promise(promise);
|
|
184
|
-
}
|
|
198
|
+
if (!ms) return new Promise(promise);
|
|
185
199
|
const stack = new Error().stack;
|
|
186
|
-
// Create a promise that rejects in <ms> milliseconds
|
|
187
200
|
const { delay, cancel } = (0, exports.delayCancellable)(ms);
|
|
188
|
-
|
|
201
|
+
return new Promise((resolve, reject) => {
|
|
189
202
|
delay
|
|
190
|
-
.then(() => reject(new boom_1.Boom('Timed Out', {
|
|
191
|
-
statusCode: Types_1.DisconnectReason.timedOut,
|
|
192
|
-
data: {
|
|
193
|
-
stack
|
|
194
|
-
}
|
|
195
|
-
})))
|
|
203
|
+
.then(() => reject(new boom_1.Boom('Timed Out', { statusCode: Types_1.DisconnectReason.timedOut, data: { stack } })))
|
|
196
204
|
.catch(err => reject(err));
|
|
197
205
|
promise(resolve, reject);
|
|
198
|
-
})
|
|
199
|
-
.finally(cancel);
|
|
200
|
-
return p;
|
|
206
|
+
}).finally(cancel);
|
|
201
207
|
}
|
|
208
|
+
|
|
202
209
|
const generateMessageIDV2 = (userId) => {
|
|
203
210
|
const data = Buffer.alloc(8 + 20 + 16);
|
|
204
211
|
data.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)));
|
|
205
212
|
if (userId) {
|
|
206
213
|
const id = (0, WABinary_1.jidDecode)(userId);
|
|
207
|
-
if (id
|
|
214
|
+
if (id?.user) {
|
|
208
215
|
data.write(id.user, 8);
|
|
209
216
|
data.write('@c.us', 8 + id.user.length);
|
|
210
217
|
}
|
|
@@ -215,215 +222,144 @@ const generateMessageIDV2 = (userId) => {
|
|
|
215
222
|
return '3EB0' + hash.toString('hex').toUpperCase().substring(0, 18);
|
|
216
223
|
};
|
|
217
224
|
exports.generateMessageIDV2 = generateMessageIDV2;
|
|
218
|
-
|
|
225
|
+
|
|
219
226
|
const generateMessageID = () => '3EB0' + (0, crypto_1.randomBytes)(18).toString('hex').toUpperCase();
|
|
220
227
|
exports.generateMessageID = generateMessageID;
|
|
228
|
+
|
|
221
229
|
function bindWaitForEvent(ev, event) {
|
|
222
230
|
return async (check, timeoutMs) => {
|
|
223
|
-
let listener;
|
|
224
|
-
|
|
225
|
-
await (promiseTimeout(timeoutMs, (resolve, reject) => {
|
|
231
|
+
let listener, closeListener;
|
|
232
|
+
await promiseTimeout(timeoutMs, (resolve, reject) => {
|
|
226
233
|
closeListener = ({ connection, lastDisconnect }) => {
|
|
227
234
|
if (connection === 'close') {
|
|
228
|
-
reject(
|
|
229
|
-
|| new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed }));
|
|
235
|
+
reject(lastDisconnect?.error || new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed }));
|
|
230
236
|
}
|
|
231
237
|
};
|
|
232
238
|
ev.on('connection.update', closeListener);
|
|
233
239
|
listener = async (update) => {
|
|
234
|
-
if (await check(update))
|
|
235
|
-
resolve();
|
|
236
|
-
}
|
|
240
|
+
if (await check(update)) resolve();
|
|
237
241
|
};
|
|
238
242
|
ev.on(event, listener);
|
|
239
|
-
})
|
|
240
|
-
.finally(() => {
|
|
243
|
+
}).finally(() => {
|
|
241
244
|
ev.off(event, listener);
|
|
242
245
|
ev.off('connection.update', closeListener);
|
|
243
|
-
})
|
|
246
|
+
});
|
|
244
247
|
};
|
|
245
248
|
}
|
|
249
|
+
|
|
246
250
|
const bindWaitForConnectionUpdate = (ev) => bindWaitForEvent(ev, 'connection.update');
|
|
247
251
|
exports.bindWaitForConnectionUpdate = bindWaitForConnectionUpdate;
|
|
252
|
+
|
|
248
253
|
const printQRIfNecessaryListener = (ev, logger) => {
|
|
249
254
|
ev.on('connection.update', async ({ qr }) => {
|
|
250
255
|
if (qr) {
|
|
251
|
-
const QR = await Promise.resolve()
|
|
252
|
-
.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
QR
|
|
256
|
+
const QR = await Promise.resolve()
|
|
257
|
+
.then(() => __importStar(require('qrcode-terminal')))
|
|
258
|
+
.then(m => m.default || m)
|
|
259
|
+
.catch(() => { logger.error('QR code terminal not added as dependency'); });
|
|
260
|
+
QR?.generate(qr, { small: true });
|
|
256
261
|
}
|
|
257
262
|
});
|
|
258
263
|
};
|
|
259
264
|
exports.printQRIfNecessaryListener = printQRIfNecessaryListener;
|
|
265
|
+
|
|
260
266
|
const fetchLatestBaileysVersion = async (options = {}) => {
|
|
261
267
|
const URL = 'https://github.com/GabWT333/based/lib/Defaults/baileys-version.json';
|
|
262
268
|
try {
|
|
263
|
-
const result = await axios_1.default.get(URL, {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
return {
|
|
268
|
-
version: result.data.version,
|
|
269
|
-
isLatest: true
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
catch (error) {
|
|
273
|
-
return {
|
|
274
|
-
version: baileys_version_json_1.version,
|
|
275
|
-
isLatest: false,
|
|
276
|
-
error
|
|
277
|
-
};
|
|
269
|
+
const result = await axios_1.default.get(URL, { ...options, responseType: 'json' });
|
|
270
|
+
return { version: result.data.version, isLatest: true };
|
|
271
|
+
} catch (error) {
|
|
272
|
+
return { version: baileys_version_json_1.version, isLatest: false, error };
|
|
278
273
|
}
|
|
279
274
|
};
|
|
280
275
|
exports.fetchLatestBaileysVersion = fetchLatestBaileysVersion;
|
|
281
|
-
|
|
282
|
-
* A utility that fetches the latest web version of whatsapp.
|
|
283
|
-
* Use to ensure your WA connection is always on the latest version
|
|
284
|
-
*/
|
|
276
|
+
|
|
285
277
|
const fetchLatestWaWebVersion = async (options) => {
|
|
286
278
|
try {
|
|
287
|
-
const { data } = await axios_1.default.get('https://web.whatsapp.com/sw.js', {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const regex = /\\?"client_revision\\?":\s*(\d+)/;
|
|
292
|
-
const match = data.match(regex);
|
|
293
|
-
if (!(match === null || match === void 0 ? void 0 : match[1])) {
|
|
294
|
-
return {
|
|
295
|
-
version: baileys_version_json_1.version,
|
|
296
|
-
isLatest: false,
|
|
297
|
-
error: {
|
|
298
|
-
message: 'Could not find client revision in the fetched content'
|
|
299
|
-
}
|
|
300
|
-
};
|
|
279
|
+
const { data } = await axios_1.default.get('https://web.whatsapp.com/sw.js', { ...options, responseType: 'json' });
|
|
280
|
+
const match = data.match(/\\?"client_revision\\?":\s*(\d+)/);
|
|
281
|
+
if (!match?.[1]) {
|
|
282
|
+
return { version: baileys_version_json_1.version, isLatest: false, error: { message: 'Could not find client revision in the fetched content' } };
|
|
301
283
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
isLatest: true
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
catch (error) {
|
|
309
|
-
return {
|
|
310
|
-
version: baileys_version_json_1.version,
|
|
311
|
-
isLatest: false,
|
|
312
|
-
error
|
|
313
|
-
};
|
|
284
|
+
return { version: [2, 3000, +match[1]], isLatest: true };
|
|
285
|
+
} catch (error) {
|
|
286
|
+
return { version: baileys_version_json_1.version, isLatest: false, error };
|
|
314
287
|
}
|
|
315
288
|
};
|
|
316
289
|
exports.fetchLatestWaWebVersion = fetchLatestWaWebVersion;
|
|
317
|
-
|
|
290
|
+
|
|
318
291
|
const generateMdTagPrefix = () => {
|
|
319
292
|
const bytes = (0, crypto_1.randomBytes)(4);
|
|
320
293
|
return `${bytes.readUInt16BE()}.${bytes.readUInt16BE(2)}-`;
|
|
321
294
|
};
|
|
322
295
|
exports.generateMdTagPrefix = generateMdTagPrefix;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
296
|
+
|
|
297
|
+
const STATUS_MAP = Object.freeze({
|
|
298
|
+
sender: WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK,
|
|
299
|
+
played: WAProto_1.proto.WebMessageInfo.Status.PLAYED,
|
|
300
|
+
read: WAProto_1.proto.WebMessageInfo.Status.READ,
|
|
327
301
|
'read-self': WAProto_1.proto.WebMessageInfo.Status.READ
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
* Given a type of receipt, returns what the new status of the message should be
|
|
331
|
-
* @param type type from receipt
|
|
332
|
-
*/
|
|
302
|
+
});
|
|
303
|
+
|
|
333
304
|
const getStatusFromReceiptType = (type) => {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
return WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK;
|
|
337
|
-
}
|
|
338
|
-
return status;
|
|
305
|
+
if (typeof type === 'undefined') return WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK;
|
|
306
|
+
return STATUS_MAP[type];
|
|
339
307
|
};
|
|
340
308
|
exports.getStatusFromReceiptType = getStatusFromReceiptType;
|
|
341
|
-
|
|
309
|
+
|
|
310
|
+
const CODE_MAP = Object.freeze({
|
|
342
311
|
conflict: Types_1.DisconnectReason.connectionReplaced
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
* Stream errors generally provide a reason, map that to a baileys DisconnectReason
|
|
346
|
-
* @param reason the string reason given, eg. "conflict"
|
|
347
|
-
*/
|
|
312
|
+
});
|
|
313
|
+
|
|
348
314
|
const getErrorCodeFromStreamError = (node) => {
|
|
349
315
|
const [reasonNode] = (0, WABinary_1.getAllBinaryNodeChildren)(node);
|
|
350
|
-
let reason =
|
|
316
|
+
let reason = reasonNode?.tag || 'unknown';
|
|
351
317
|
const statusCode = +(node.attrs.code || CODE_MAP[reason] || Types_1.DisconnectReason.badSession);
|
|
352
|
-
if (statusCode === Types_1.DisconnectReason.restartRequired)
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
return {
|
|
356
|
-
reason,
|
|
357
|
-
statusCode
|
|
358
|
-
};
|
|
318
|
+
if (statusCode === Types_1.DisconnectReason.restartRequired) reason = 'restart required';
|
|
319
|
+
return { reason, statusCode };
|
|
359
320
|
};
|
|
360
321
|
exports.getErrorCodeFromStreamError = getErrorCodeFromStreamError;
|
|
322
|
+
|
|
361
323
|
const getCallStatusFromNode = ({ tag, attrs }) => {
|
|
362
|
-
let status;
|
|
363
324
|
switch (tag) {
|
|
364
325
|
case 'offer':
|
|
365
|
-
case 'offer_notice':
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
case '
|
|
369
|
-
|
|
370
|
-
status = 'timeout';
|
|
371
|
-
}
|
|
372
|
-
else {
|
|
373
|
-
// fired when accepted/rejected/timeout/caller hangs up
|
|
374
|
-
status = 'terminate';
|
|
375
|
-
}
|
|
376
|
-
break;
|
|
377
|
-
case 'reject':
|
|
378
|
-
status = 'reject';
|
|
379
|
-
break;
|
|
380
|
-
case 'accept':
|
|
381
|
-
status = 'accept';
|
|
382
|
-
break;
|
|
383
|
-
default:
|
|
384
|
-
status = 'ringing';
|
|
385
|
-
break;
|
|
326
|
+
case 'offer_notice': return 'offer';
|
|
327
|
+
case 'terminate': return attrs.reason === 'timeout' ? 'timeout' : 'terminate';
|
|
328
|
+
case 'reject': return 'reject';
|
|
329
|
+
case 'accept': return 'accept';
|
|
330
|
+
default: return 'ringing';
|
|
386
331
|
}
|
|
387
|
-
return status;
|
|
388
332
|
};
|
|
389
333
|
exports.getCallStatusFromNode = getCallStatusFromNode;
|
|
334
|
+
|
|
390
335
|
const UNEXPECTED_SERVER_CODE_TEXT = 'Unexpected server response: ';
|
|
336
|
+
|
|
391
337
|
const getCodeFromWSError = (error) => {
|
|
392
|
-
var _a, _b, _c;
|
|
393
338
|
let statusCode = 500;
|
|
394
|
-
if (
|
|
395
|
-
const code = +(error
|
|
396
|
-
if (!Number.isNaN(code) && code >= 400)
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
else if (((_b = error === null || error === void 0 ? void 0 : error.code) === null || _b === void 0 ? void 0 : _b.startsWith('E'))
|
|
401
|
-
|| ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.includes('timed out'))) { // handle ETIMEOUT, ENOTFOUND etc
|
|
339
|
+
if (error?.message?.includes(UNEXPECTED_SERVER_CODE_TEXT)) {
|
|
340
|
+
const code = +(error.message.slice(UNEXPECTED_SERVER_CODE_TEXT.length));
|
|
341
|
+
if (!Number.isNaN(code) && code >= 400) statusCode = code;
|
|
342
|
+
} else if (error?.code?.startsWith('E') || error?.message?.includes('timed out')) {
|
|
402
343
|
statusCode = 408;
|
|
403
344
|
}
|
|
404
345
|
return statusCode;
|
|
405
346
|
};
|
|
406
347
|
exports.getCodeFromWSError = getCodeFromWSError;
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
* @param platform AuthenticationCreds.platform
|
|
410
|
-
*/
|
|
411
|
-
const isWABusinessPlatform = (platform) => {
|
|
412
|
-
return platform === 'smbi' || platform === 'smba';
|
|
413
|
-
};
|
|
348
|
+
|
|
349
|
+
const isWABusinessPlatform = (platform) => platform === 'smbi' || platform === 'smba';
|
|
414
350
|
exports.isWABusinessPlatform = isWABusinessPlatform;
|
|
351
|
+
|
|
415
352
|
function trimUndefined(obj) {
|
|
416
353
|
for (const key in obj) {
|
|
417
|
-
if (typeof obj[key] === 'undefined')
|
|
418
|
-
delete obj[key];
|
|
419
|
-
}
|
|
354
|
+
if (typeof obj[key] === 'undefined') delete obj[key];
|
|
420
355
|
}
|
|
421
356
|
return obj;
|
|
422
357
|
}
|
|
358
|
+
|
|
423
359
|
const CROCKFORD_CHARACTERS = '123456789ABCDEFGHJKLMNPQRSTVWXYZ';
|
|
360
|
+
|
|
424
361
|
function bytesToCrockford(buffer) {
|
|
425
|
-
let value = 0;
|
|
426
|
-
let bitCount = 0;
|
|
362
|
+
let value = 0, bitCount = 0;
|
|
427
363
|
const crockford = [];
|
|
428
364
|
for (let i = 0; i < buffer.length; i++) {
|
|
429
365
|
value = (value << 8) | (buffer[i] & 0xff);
|
|
@@ -433,8 +369,6 @@ function bytesToCrockford(buffer) {
|
|
|
433
369
|
bitCount -= 5;
|
|
434
370
|
}
|
|
435
371
|
}
|
|
436
|
-
if (bitCount > 0)
|
|
437
|
-
crockford.push(CROCKFORD_CHARACTERS.charAt((value << (5 - bitCount)) & 31));
|
|
438
|
-
}
|
|
372
|
+
if (bitCount > 0) crockford.push(CROCKFORD_CHARACTERS.charAt((value << (5 - bitCount)) & 31));
|
|
439
373
|
return crockford.join('');
|
|
440
|
-
}
|
|
374
|
+
}
|