webmaxsocket 1.1.3 → 1.1.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/README.md +87 -4
- package/api.package.md +193 -0
- package/index.js +3 -1
- package/lib/client.js +1128 -27
- package/lib/opcodes.js +3 -8
- package/lib/qrWebLogin.js +59 -0
- package/lib/socketTransport.js +3 -1
- package/package.json +3 -2
package/lib/opcodes.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Opcodes для протокола Max API
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
1
|
const Opcode = {
|
|
6
2
|
PING: 1,
|
|
7
3
|
DEBUG: 2,
|
|
@@ -27,8 +23,10 @@ const Opcode = {
|
|
|
27
23
|
CHAT_LEAVE: 58,
|
|
28
24
|
CHAT_MEMBERS: 59,
|
|
29
25
|
MSG_SEND: 64,
|
|
26
|
+
UPLOAD_ATTACH_PREP: 65,
|
|
30
27
|
MSG_DELETE: 66,
|
|
31
28
|
MSG_EDIT: 67,
|
|
29
|
+
CHAT_SUBSCRIBE: 75,
|
|
32
30
|
CHAT_MEMBERS_UPDATE: 77,
|
|
33
31
|
PHOTO_UPLOAD: 80,
|
|
34
32
|
VIDEO_UPLOAD: 82,
|
|
@@ -51,18 +49,15 @@ const Opcode = {
|
|
|
51
49
|
FOLDERS_DELETE: 276,
|
|
52
50
|
GET_QR: 288,
|
|
53
51
|
GET_QR_STATUS: 289,
|
|
52
|
+
AUTH_QR_APPROVE: 290,
|
|
54
53
|
LOGIN_BY_QR: 291,
|
|
55
54
|
};
|
|
56
55
|
|
|
57
|
-
// Обратная карта для расшифровки опкодов
|
|
58
56
|
const OpcodeNames = {};
|
|
59
57
|
for (const [name, code] of Object.entries(Opcode)) {
|
|
60
58
|
OpcodeNames[code] = name;
|
|
61
59
|
}
|
|
62
60
|
|
|
63
|
-
/**
|
|
64
|
-
* Получить название опкода
|
|
65
|
-
*/
|
|
66
61
|
function getOpcodeName(code) {
|
|
67
62
|
return OpcodeNames[code] || `UNKNOWN_${code}`;
|
|
68
63
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Извлекает идентификатор входа по QR: UUID trackId или opaque token (qr_…).
|
|
3
|
+
* Поддерживаются:
|
|
4
|
+
* - https://max.ru/qr/v1/auth?token=qr_…
|
|
5
|
+
* - https://max.ru/login/qr/<uuid> или :auth/<uuid>
|
|
6
|
+
* - web.max / trackId в query
|
|
7
|
+
* - «голый» UUID или строка qr_…
|
|
8
|
+
*
|
|
9
|
+
* @param {string} qrUrlOrTrackId
|
|
10
|
+
* @returns {string|null}
|
|
11
|
+
*/
|
|
12
|
+
function parseQrTrackId(qrUrlOrTrackId) {
|
|
13
|
+
const s = String(qrUrlOrTrackId == null ? '' : qrUrlOrTrackId).trim();
|
|
14
|
+
if (!s) return null;
|
|
15
|
+
|
|
16
|
+
let decoded = s;
|
|
17
|
+
try {
|
|
18
|
+
decoded = decodeURIComponent(s);
|
|
19
|
+
} catch (_) {
|
|
20
|
+
decoded = s;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const uuidRe = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
|
|
24
|
+
const qrTokenRe = /^qr_[a-zA-Z0-9_-]+$/i;
|
|
25
|
+
|
|
26
|
+
if (qrTokenRe.test(decoded)) {
|
|
27
|
+
return decoded;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
if (/^https?:\/\//i.test(decoded)) {
|
|
32
|
+
const u = new URL(decoded);
|
|
33
|
+
const tokenParam = u.searchParams.get('token');
|
|
34
|
+
if (tokenParam && qrTokenRe.test(tokenParam.trim())) {
|
|
35
|
+
return tokenParam.trim();
|
|
36
|
+
}
|
|
37
|
+
for (const key of ['trackId', 'track_id', 'track', 'tid']) {
|
|
38
|
+
const v = u.searchParams.get(key);
|
|
39
|
+
if (v) {
|
|
40
|
+
const m = String(v).match(uuidRe);
|
|
41
|
+
if (m) return m[0];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// https://max.ru/auth/<uuid> или max.ru/:auth/<uuid> (как в QR)
|
|
45
|
+
const pathSegs = u.pathname.split('/').filter(Boolean);
|
|
46
|
+
for (const seg of pathSegs) {
|
|
47
|
+
if (uuidRe.test(seg)) {
|
|
48
|
+
const m = seg.match(uuidRe);
|
|
49
|
+
if (m) return m[0];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
} catch (_) {}
|
|
54
|
+
|
|
55
|
+
const m = decoded.match(uuidRe);
|
|
56
|
+
return m ? m[0] : null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = { parseQrTrackId };
|
package/lib/socketTransport.js
CHANGED
|
@@ -65,6 +65,7 @@ function unpackPacket(data) {
|
|
|
65
65
|
|
|
66
66
|
/** JSON для логов: bigint → string, обрезка длинных строк */
|
|
67
67
|
function safeJsonForLog(obj, maxLen = 12000) {
|
|
68
|
+
if (obj === undefined) return '(no payload)';
|
|
68
69
|
try {
|
|
69
70
|
const s = JSON.stringify(
|
|
70
71
|
obj,
|
|
@@ -152,7 +153,8 @@ class MaxSocketTransport {
|
|
|
152
153
|
cmd,
|
|
153
154
|
seq: this.seq,
|
|
154
155
|
opcode,
|
|
155
|
-
|
|
156
|
+
// undefined — пустое тело пакета (как GET_QR без payload в web); null/{} — явный объект
|
|
157
|
+
payload: payload === undefined ? undefined : payload || {},
|
|
156
158
|
};
|
|
157
159
|
}
|
|
158
160
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webmaxsocket",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "Node.js client for Max Messenger with QR code and token authentication",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -58,7 +58,8 @@
|
|
|
58
58
|
"example-token.js",
|
|
59
59
|
"example-sms.js",
|
|
60
60
|
"example-ios.js",
|
|
61
|
-
"README.md"
|
|
61
|
+
"README.md",
|
|
62
|
+
"api.package.md"
|
|
62
63
|
]
|
|
63
64
|
}
|
|
64
65
|
|