@wppconnect/wa-proto 0.0.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.
- package/CHANGELOG.md +35 -0
- package/LICENSE +190 -0
- package/README.md +34 -0
- package/WAProto.proto +3808 -0
- package/dist/index.d.ts +44342 -0
- package/dist/index.js +137957 -0
- package/index-2x.js +488 -0
- package/index.js +526 -0
- package/package.json +56 -0
package/index.js
ADDED
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2024 WPPConnect Team
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Based on https://github.com/WhiskeySockets/Baileys/tree/master/WAProto
|
|
19
|
+
*/
|
|
20
|
+
const request = require('request-promise-native');
|
|
21
|
+
const acorn = require('acorn');
|
|
22
|
+
const walk = require('acorn-walk');
|
|
23
|
+
const fs = require('fs/promises');
|
|
24
|
+
|
|
25
|
+
let whatsAppVersion = 'latest';
|
|
26
|
+
|
|
27
|
+
const addPrefix = (lines, prefix) => lines.map((line) => prefix + line);
|
|
28
|
+
|
|
29
|
+
const extractAllExpressions = (node) => {
|
|
30
|
+
const expressions = [node];
|
|
31
|
+
const exp = node.expression;
|
|
32
|
+
if (exp) {
|
|
33
|
+
expressions.push(exp);
|
|
34
|
+
}
|
|
35
|
+
if(node?.expression?.arguments?.length) {
|
|
36
|
+
for (const arg of node?.expression?.arguments) {
|
|
37
|
+
if(arg?.body?.body?.length){
|
|
38
|
+
for(const exp of arg?.body.body) {
|
|
39
|
+
expressions.push(...extractAllExpressions(exp));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if(node?.body?.body?.length) {
|
|
45
|
+
for (const exp of node?.body?.body) {
|
|
46
|
+
if(exp.expression){
|
|
47
|
+
expressions.push(...extractAllExpressions(exp.expression));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (node.expression?.expressions?.length) {
|
|
53
|
+
for (const exp of node.expression?.expressions) {
|
|
54
|
+
expressions.push(...extractAllExpressions(exp));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return expressions;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
async function findAppModules() {
|
|
63
|
+
const ua = {
|
|
64
|
+
headers: {
|
|
65
|
+
'User-Agent':
|
|
66
|
+
'Mozilla/5.0 (X11; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0',
|
|
67
|
+
'Sec-Fetch-Dest': 'script',
|
|
68
|
+
'Sec-Fetch-Mode': 'no-cors',
|
|
69
|
+
'Sec-Fetch-Site': 'same-origin',
|
|
70
|
+
Referer: 'https://web.whatsapp.com/',
|
|
71
|
+
Accept: '*/*',
|
|
72
|
+
'Accept-Language': 'Accept-Language: en-US,en;q=0.5',
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
const baseURL = 'https://web.whatsapp.com';
|
|
76
|
+
const serviceworker = await request.get(`${baseURL}/sw.js`, ua);
|
|
77
|
+
|
|
78
|
+
const versions = [
|
|
79
|
+
...serviceworker.matchAll(/client_revision\\":([\d\.]+),/g),
|
|
80
|
+
].map((r) => r[1]);
|
|
81
|
+
const version = versions[0];
|
|
82
|
+
console.log(`Current version: 2.3000.${version}`);
|
|
83
|
+
|
|
84
|
+
const waVersion = `2.3000.${version}`;
|
|
85
|
+
whatsAppVersion = waVersion;
|
|
86
|
+
|
|
87
|
+
let bootstrapQRURL = '';
|
|
88
|
+
const clearString = serviceworker.replaceAll('/*BTDS*/', '');
|
|
89
|
+
const URLScript = clearString.match(/(?<=importScripts\(["'])(.*?)(?=["']\);)/g);
|
|
90
|
+
bootstrapQRURL = new URL(URLScript[0].replaceAll("\\",'')).href;
|
|
91
|
+
|
|
92
|
+
console.info('Found source JS URL:', bootstrapQRURL);
|
|
93
|
+
|
|
94
|
+
const qrData = await request.get(bootstrapQRURL, ua);
|
|
95
|
+
|
|
96
|
+
// This one list of types is so long that it's split into two JavaScript declarations.
|
|
97
|
+
// The module finder below can't handle it, so just patch it manually here.
|
|
98
|
+
const patchedQrData = qrData.replace(
|
|
99
|
+
't.ActionLinkSpec=void 0,t.TemplateButtonSpec',
|
|
100
|
+
't.ActionLinkSpec=t.TemplateButtonSpec'
|
|
101
|
+
);
|
|
102
|
+
//const patchedQrData = qrData.replace("Spec=void 0,t.", "Spec=t.")
|
|
103
|
+
|
|
104
|
+
const qrModules = acorn.parse(patchedQrData).body;
|
|
105
|
+
|
|
106
|
+
const result = qrModules.filter((m) => {
|
|
107
|
+
const expressions = extractAllExpressions(m);
|
|
108
|
+
return expressions?.find(
|
|
109
|
+
(e) => {
|
|
110
|
+
return e?.left?.property?.name === 'internalSpec'
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
(async () => {
|
|
118
|
+
const unspecName = (name) =>
|
|
119
|
+
name.endsWith('Spec') ? name.slice(0, -4) : name;
|
|
120
|
+
const unnestName = (name) => name.split('$').slice(-1)[0];
|
|
121
|
+
const getNesting = (name) => name.split('$').slice(0, -1).join('$');
|
|
122
|
+
const makeRenameFunc = () => (name) => {
|
|
123
|
+
name = unspecName(name);
|
|
124
|
+
return name; // .replaceAll('$', '__')
|
|
125
|
+
// return renames[name] ?? unnestName(name)
|
|
126
|
+
};
|
|
127
|
+
// The constructor IDs that can be used for enum types
|
|
128
|
+
|
|
129
|
+
const modules = await findAppModules();
|
|
130
|
+
|
|
131
|
+
// find aliases of cross references between the wanted modules
|
|
132
|
+
const modulesInfo = {};
|
|
133
|
+
const moduleIndentationMap = {};
|
|
134
|
+
modules.forEach((module) => {
|
|
135
|
+
const moduleName = module.expression.arguments[0].value;
|
|
136
|
+
modulesInfo[moduleName] = { crossRefs: [] };
|
|
137
|
+
walk.simple(module, {
|
|
138
|
+
AssignmentExpression(node) {
|
|
139
|
+
if (
|
|
140
|
+
node &&
|
|
141
|
+
node?.right?.type == 'CallExpression' &&
|
|
142
|
+
node?.right?.arguments?.length == 1 &&
|
|
143
|
+
node?.right?.arguments[0].type !== 'ObjectExpression'
|
|
144
|
+
) {
|
|
145
|
+
/*if(node.right.arguments[0].value == '$InternalEnum') {
|
|
146
|
+
console.log(node);
|
|
147
|
+
console.log(node.right.arguments[0]);
|
|
148
|
+
exit;
|
|
149
|
+
}*/
|
|
150
|
+
modulesInfo[moduleName].crossRefs.push({
|
|
151
|
+
alias: node.left.name,
|
|
152
|
+
module: node.right.arguments[0].value,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// find all identifiers and, for enums, their array of values
|
|
160
|
+
for (const mod of modules) {
|
|
161
|
+
const modInfo = modulesInfo[mod.expression.arguments[0].value];
|
|
162
|
+
const rename = makeRenameFunc(mod.expression.arguments[0].value);
|
|
163
|
+
|
|
164
|
+
const assignments = []
|
|
165
|
+
walk.simple(mod, {
|
|
166
|
+
AssignmentExpression(node) {
|
|
167
|
+
const left = node.left;
|
|
168
|
+
if(
|
|
169
|
+
left.property?.name &&
|
|
170
|
+
left.property?.name !== 'internalSpec' &&
|
|
171
|
+
left.property?.name !== 'internalDefaults'
|
|
172
|
+
) {
|
|
173
|
+
assignments.push(left);
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
const makeBlankIdent = (a) => {
|
|
180
|
+
const key = rename(a?.property?.name);
|
|
181
|
+
const indentation = getNesting(key);
|
|
182
|
+
const value = { name: key };
|
|
183
|
+
|
|
184
|
+
moduleIndentationMap[key] = moduleIndentationMap[key] || {};
|
|
185
|
+
moduleIndentationMap[key].indentation = indentation;
|
|
186
|
+
|
|
187
|
+
if (indentation.length) {
|
|
188
|
+
moduleIndentationMap[indentation] =
|
|
189
|
+
moduleIndentationMap[indentation] || {};
|
|
190
|
+
moduleIndentationMap[indentation].members =
|
|
191
|
+
moduleIndentationMap[indentation].members || new Set();
|
|
192
|
+
moduleIndentationMap[indentation].members.add(key);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return [key, value];
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
modInfo.identifiers = Object.fromEntries(
|
|
199
|
+
assignments.map(makeBlankIdent).reverse()
|
|
200
|
+
);
|
|
201
|
+
const enumAliases = {};
|
|
202
|
+
// enums are defined directly, and both enums and messages get a one-letter alias
|
|
203
|
+
walk.ancestor(mod, {
|
|
204
|
+
Property(node, anc) {
|
|
205
|
+
const fatherNode = anc[anc.length - 3];
|
|
206
|
+
const fatherFather = anc[anc.length - 4];
|
|
207
|
+
if(
|
|
208
|
+
fatherNode?.type === 'AssignmentExpression' &&
|
|
209
|
+
fatherNode?.left?.property?.name == 'internalSpec'
|
|
210
|
+
&& fatherNode?.right?.properties.length
|
|
211
|
+
) {
|
|
212
|
+
const values = fatherNode?.right?.properties.map((p) => ({
|
|
213
|
+
name: p.key.name,
|
|
214
|
+
id: p.value.value,
|
|
215
|
+
}));
|
|
216
|
+
const nameAlias = fatherNode?.left?.name;
|
|
217
|
+
enumAliases[nameAlias] = values;
|
|
218
|
+
}
|
|
219
|
+
else if (node?.key && node?.key?.name && fatherNode.arguments?.length > 0) {
|
|
220
|
+
const values = fatherNode.arguments?.[0]?.properties.map((p) => ({
|
|
221
|
+
name: p.key.name,
|
|
222
|
+
id: p.value.value,
|
|
223
|
+
}));
|
|
224
|
+
const nameAlias = fatherFather?.left?.name || fatherFather.id.name;
|
|
225
|
+
enumAliases[nameAlias] = values;
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
walk.simple(mod, {
|
|
230
|
+
AssignmentExpression(node) {
|
|
231
|
+
if (
|
|
232
|
+
node.left.type === 'MemberExpression' &&
|
|
233
|
+
modInfo.identifiers?.[rename(node.left.property.name)]
|
|
234
|
+
) {
|
|
235
|
+
const ident = modInfo.identifiers[rename(node.left.property.name)];
|
|
236
|
+
ident.alias = node.right.name;
|
|
237
|
+
ident.enumValues = enumAliases[ident.alias];
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// find the contents for all protobuf messages
|
|
244
|
+
for (const mod of modules) {
|
|
245
|
+
const modInfo = modulesInfo[mod.expression.arguments[0].value];
|
|
246
|
+
const rename = makeRenameFunc(mod.expression.arguments[0].value);
|
|
247
|
+
const findByAliasInIdentifier = (obj, alias) => {
|
|
248
|
+
return Object.values(obj).find(item => item.alias === alias);
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// message specifications are stored in a "internalSpec" attribute of the respective identifier alias
|
|
252
|
+
walk.simple(mod, {
|
|
253
|
+
AssignmentExpression(node) {
|
|
254
|
+
if (
|
|
255
|
+
node.left.type === 'MemberExpression' &&
|
|
256
|
+
node.left.property.name === 'internalSpec' &&
|
|
257
|
+
node.right.type === 'ObjectExpression'
|
|
258
|
+
) {
|
|
259
|
+
const targetIdent = Object.values(modInfo.identifiers).find(
|
|
260
|
+
(v) => v.alias === node.left.object.name
|
|
261
|
+
);
|
|
262
|
+
if (!targetIdent) {
|
|
263
|
+
console.warn(
|
|
264
|
+
`found message specification for unknown identifier alias: ${node.left.object.name}`
|
|
265
|
+
);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// partition spec properties by normal members and constraints (like "__oneofs__") which will be processed afterwards
|
|
270
|
+
const constraints = [];
|
|
271
|
+
let members = [];
|
|
272
|
+
for (const p of node.right.properties) {
|
|
273
|
+
p.key.name = p.key.type === 'Identifier' ? p.key.name : p.key.value;
|
|
274
|
+
const arr =
|
|
275
|
+
p.key.name.substr(0, 2) === '__' ? constraints : members;
|
|
276
|
+
arr.push(p);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
members = members.map(({ key: { name }, value: { elements } }) => {
|
|
280
|
+
let type;
|
|
281
|
+
const flags = [];
|
|
282
|
+
const unwrapBinaryOr = (n) =>
|
|
283
|
+
n.type === 'BinaryExpression' && n.operator === '|'
|
|
284
|
+
? [].concat(unwrapBinaryOr(n.left), unwrapBinaryOr(n.right))
|
|
285
|
+
: [n];
|
|
286
|
+
|
|
287
|
+
// find type and flags
|
|
288
|
+
unwrapBinaryOr(elements[1]).forEach((m) => {
|
|
289
|
+
if (
|
|
290
|
+
m.type === 'MemberExpression' &&
|
|
291
|
+
m.object.type === 'MemberExpression'
|
|
292
|
+
) {
|
|
293
|
+
if (m.object.property.name === 'TYPES') {
|
|
294
|
+
type = m.property.name.toLowerCase();
|
|
295
|
+
if(type == 'map'){
|
|
296
|
+
|
|
297
|
+
let typeStr = 'map<';
|
|
298
|
+
if (elements[2]?.type === 'ArrayExpression') {
|
|
299
|
+
const subElements = elements[2].elements;
|
|
300
|
+
subElements.forEach((element, index) => {
|
|
301
|
+
if(element?.property?.name) {
|
|
302
|
+
typeStr += element?.property?.name?.toLowerCase();
|
|
303
|
+
} else {
|
|
304
|
+
const ref = findByAliasInIdentifier(modInfo.identifiers, element.name);
|
|
305
|
+
typeStr += ref.name;
|
|
306
|
+
}
|
|
307
|
+
if (index < subElements.length - 1) {
|
|
308
|
+
typeStr += ', ';
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
typeStr += '>';
|
|
312
|
+
type = typeStr;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
} else if (m.object.property.name === 'FLAGS') {
|
|
316
|
+
flags.push(m.property.name.toLowerCase());
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// determine cross reference name from alias if this member has type "message" or "enum"
|
|
322
|
+
|
|
323
|
+
if (type === 'message' || type === 'enum') {
|
|
324
|
+
const currLoc = ` from member '${name}' of message ${targetIdent.name}'`;
|
|
325
|
+
if (elements[2].type === 'Identifier') {
|
|
326
|
+
type = Object.values(modInfo.identifiers).find(
|
|
327
|
+
(v) => v.alias === elements[2].name
|
|
328
|
+
)?.name;
|
|
329
|
+
if (!type) {
|
|
330
|
+
console.warn(
|
|
331
|
+
`unable to find reference of alias '${elements[2].name}'` +
|
|
332
|
+
currLoc
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
} else if (elements[2].type === 'MemberExpression') {
|
|
336
|
+
let crossRef = modInfo.crossRefs.find(
|
|
337
|
+
(r) => r.alias === elements[2]?.object?.name || elements[2]?.object?.left?.name || elements[2]?.object?.callee?.name
|
|
338
|
+
);
|
|
339
|
+
if(elements[1]?.property?.name === 'ENUM' && elements[2]?.property?.name?.includes('Type')) {
|
|
340
|
+
type = rename(elements[2]?.property?.name);
|
|
341
|
+
}
|
|
342
|
+
else if(elements[2]?.property?.name.includes('Spec')) {
|
|
343
|
+
type = rename(elements[2].property.name);
|
|
344
|
+
} else if (
|
|
345
|
+
crossRef &&
|
|
346
|
+
crossRef.module !== '$InternalEnum' &&
|
|
347
|
+
modulesInfo[crossRef.module].identifiers[
|
|
348
|
+
rename(elements[2].property.name)
|
|
349
|
+
]
|
|
350
|
+
) {
|
|
351
|
+
type = rename(elements[2].property.name);
|
|
352
|
+
} else {
|
|
353
|
+
console.warn(
|
|
354
|
+
`unable to find reference of alias to other module '${elements[2].object.name}' or to message ${elements[2].property.name} of this module` +
|
|
355
|
+
currLoc
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return { name, id: elements[0].value, type, flags };
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// resolve constraints for members
|
|
365
|
+
constraints.forEach((c) => {
|
|
366
|
+
if (
|
|
367
|
+
c.key.name === '__oneofs__' &&
|
|
368
|
+
c.value.type === 'ObjectExpression'
|
|
369
|
+
) {
|
|
370
|
+
const newOneOfs = c.value.properties.map((p) => ({
|
|
371
|
+
name: p.key.name,
|
|
372
|
+
type: '__oneof__',
|
|
373
|
+
members: p.value.elements.map((e) => {
|
|
374
|
+
const idx = members.findIndex((m) => m.name === e.value);
|
|
375
|
+
const member = members[idx];
|
|
376
|
+
members.splice(idx, 1);
|
|
377
|
+
return member;
|
|
378
|
+
}),
|
|
379
|
+
}));
|
|
380
|
+
members.push(...newOneOfs);
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
targetIdent.members = members;
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const decodedProtoMap = {};
|
|
391
|
+
const spaceIndent = ' '.repeat(4);
|
|
392
|
+
for (const mod of modules) {
|
|
393
|
+
const modInfo = modulesInfo[mod.expression.arguments[0].value];
|
|
394
|
+
const identifiers = Object.values(modInfo?.identifiers);
|
|
395
|
+
|
|
396
|
+
// enum stringifying function
|
|
397
|
+
const stringifyEnum = (ident, overrideName = null) =>
|
|
398
|
+
[].concat(
|
|
399
|
+
[`enum ${overrideName || ident.displayName || ident.name} {`],
|
|
400
|
+
addPrefix(
|
|
401
|
+
ident.enumValues.map((v) => `${v.name} = ${v.id};`),
|
|
402
|
+
spaceIndent
|
|
403
|
+
),
|
|
404
|
+
['}']
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
// message specification member stringifying function
|
|
408
|
+
const stringifyMessageSpecMember = (
|
|
409
|
+
info,
|
|
410
|
+
completeFlags,
|
|
411
|
+
parentName = undefined
|
|
412
|
+
) => {
|
|
413
|
+
if (info.type === '__oneof__') {
|
|
414
|
+
return [].concat(
|
|
415
|
+
[`oneof ${info.name} {`],
|
|
416
|
+
addPrefix(
|
|
417
|
+
[].concat(
|
|
418
|
+
...info.members.map((m) => stringifyMessageSpecMember(m, false))
|
|
419
|
+
),
|
|
420
|
+
spaceIndent
|
|
421
|
+
),
|
|
422
|
+
['}']
|
|
423
|
+
);
|
|
424
|
+
} else {
|
|
425
|
+
if (info.flags.includes('packed')) {
|
|
426
|
+
info.flags.splice(info.flags.indexOf('packed'));
|
|
427
|
+
info.packed = ' [packed=true]';
|
|
428
|
+
}
|
|
429
|
+
if (completeFlags && info.flags.length === 0 && !info.type.includes('map')) {
|
|
430
|
+
info.flags.push('optional');
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const ret = [];
|
|
434
|
+
const indentation = moduleIndentationMap[info.type]?.indentation;
|
|
435
|
+
let typeName = unnestName(info.type);
|
|
436
|
+
if (indentation !== parentName && indentation) {
|
|
437
|
+
typeName = `${indentation.replaceAll('$', '.')}.${typeName}`;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// if(info.enumValues) {
|
|
441
|
+
// // typeName = unnestName(info.type)
|
|
442
|
+
// ret = stringifyEnum(info, typeName)
|
|
443
|
+
// }
|
|
444
|
+
|
|
445
|
+
ret.push(
|
|
446
|
+
`${
|
|
447
|
+
info.flags.join(' ') + (info.flags.length === 0 ? '' : ' ')
|
|
448
|
+
}${typeName} ${info.name} = ${info.id}${info.packed || ''};`
|
|
449
|
+
);
|
|
450
|
+
return ret;
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
// message specification stringifying function
|
|
455
|
+
const stringifyMessageSpec = (ident) => {
|
|
456
|
+
const members = moduleIndentationMap[ident.name]?.members;
|
|
457
|
+
const result = [];
|
|
458
|
+
result.push(
|
|
459
|
+
`message ${ident.displayName || ident.name} {`,
|
|
460
|
+
...addPrefix(
|
|
461
|
+
[].concat(
|
|
462
|
+
...ident.members.map((m) =>
|
|
463
|
+
stringifyMessageSpecMember(m, true, ident.name)
|
|
464
|
+
)
|
|
465
|
+
),
|
|
466
|
+
spaceIndent
|
|
467
|
+
)
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
if (members?.size) {
|
|
471
|
+
const sortedMembers = Array.from(members).sort();
|
|
472
|
+
for (const memberName of sortedMembers) {
|
|
473
|
+
let entity = modInfo.identifiers[memberName];
|
|
474
|
+
if (entity) {
|
|
475
|
+
const displayName = entity.name.slice(ident.name.length + 1);
|
|
476
|
+
entity = { ...entity, displayName };
|
|
477
|
+
result.push(...addPrefix(getEntity(entity), spaceIndent));
|
|
478
|
+
} else {
|
|
479
|
+
console.log('missing nested entity ', memberName);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
result.push('}');
|
|
485
|
+
result.push('');
|
|
486
|
+
|
|
487
|
+
return result;
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
const getEntity = (v) => {
|
|
491
|
+
let result;
|
|
492
|
+
if (v.members) {
|
|
493
|
+
result = stringifyMessageSpec(v);
|
|
494
|
+
} else if (v.enumValues?.length) {
|
|
495
|
+
result = stringifyEnum(v);
|
|
496
|
+
} else {
|
|
497
|
+
result = ['// Unknown entity ' + v.name];
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return result;
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
const stringifyEntity = (v) => {
|
|
504
|
+
return {
|
|
505
|
+
content: getEntity(v).join('\n'),
|
|
506
|
+
name: v.name,
|
|
507
|
+
};
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
for (const value of identifiers) {
|
|
511
|
+
const { name, content } = stringifyEntity(value);
|
|
512
|
+
if (!moduleIndentationMap[name]?.indentation?.length) {
|
|
513
|
+
decodedProtoMap[name] = content;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const decodedProto = Object.keys(decodedProtoMap).sort();
|
|
519
|
+
const sortedStr = decodedProto.map((d) => decodedProtoMap[d]).join('\n');
|
|
520
|
+
|
|
521
|
+
const decodedProtoStr = `syntax = "proto3";\npackage waproto;\n\n/// WhatsApp Version: ${whatsAppVersion}\n\n${sortedStr}`;
|
|
522
|
+
const destinationPath = 'WAProto.proto';
|
|
523
|
+
await fs.writeFile(destinationPath, decodedProtoStr);
|
|
524
|
+
|
|
525
|
+
console.log(`Extracted protobuf schema to "${destinationPath}"`);
|
|
526
|
+
})();
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wppconnect/wa-proto",
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"description": "Protobuf files from WhatsApp WEB",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Cleiton Costa",
|
|
8
|
+
"url": "https://github.com/icleitoncosta"
|
|
9
|
+
},
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "npm run fetch && npm run compile",
|
|
14
|
+
"compile": "npm run compile:js && npm run compile:ts",
|
|
15
|
+
"compile:js": "pbjs -t static-module --sparse -w commonjs -o ./dist/index.js ./WAProto.proto",
|
|
16
|
+
"compile:ts": "pbts -o ./dist/index.d.ts ./dist/index.js",
|
|
17
|
+
"fetch": "node index.js",
|
|
18
|
+
"changelog:last": "conventional-changelog -p angular -r 2",
|
|
19
|
+
"changelog:preview": "conventional-changelog -p angular -u",
|
|
20
|
+
"changelog:update": "conventional-changelog -p angular -i CHANGELOG.md -s",
|
|
21
|
+
"release": "release-it"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"long": "^5.2.3",
|
|
25
|
+
"protobufjs": "^7.4.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"acorn": "^8.11.3",
|
|
29
|
+
"acorn-walk": "^8.3.2",
|
|
30
|
+
"conventional-changelog-cli": "^4.1.0",
|
|
31
|
+
"protobufjs-cli": "^1.1.3",
|
|
32
|
+
"release-it": "^17.1.1",
|
|
33
|
+
"request": "^2.88.2",
|
|
34
|
+
"request-promise-core": "^1.1.4",
|
|
35
|
+
"request-promise-native": "^1.0.9"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/wppconnect-team/wa-proto.git"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"wa-proto",
|
|
43
|
+
"whatsapp",
|
|
44
|
+
"proto",
|
|
45
|
+
"whatsapp",
|
|
46
|
+
"protobuf",
|
|
47
|
+
"files",
|
|
48
|
+
"whatsapp",
|
|
49
|
+
"2.3000",
|
|
50
|
+
"3000x"
|
|
51
|
+
],
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/wppconnect-team/wa-proto/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/wppconnect-team/wa-proto#readme"
|
|
56
|
+
}
|