atm-droid 1.0.2 → 1.0.3
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/package.json +1 -1
- package/src/api.js +63 -16
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -4,19 +4,35 @@ const { config, getDeviceId } = require('./config');
|
|
|
4
4
|
|
|
5
5
|
const getServerUrl = () => config.get('serverUrl');
|
|
6
6
|
|
|
7
|
-
//
|
|
8
|
-
function
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
// 解密静态字节(与 Rust 客户端一致)
|
|
8
|
+
function decryptStaticBytes(encrypted, keySeed) {
|
|
9
|
+
const result = [];
|
|
10
|
+
let key = keySeed;
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < encrypted.length; i++) {
|
|
13
|
+
const byte = encrypted[i];
|
|
14
|
+
let k1 = ((key * 0x1B) + i) & 0xff;
|
|
15
|
+
let k2 = ((k1 << 3) | (k1 >>> 5)) & 0xff; // rotate_left(3)
|
|
16
|
+
k2 = k2 ^ 0xA5;
|
|
17
|
+
const decrypted = byte ^ k2;
|
|
18
|
+
result.push(decrypted);
|
|
19
|
+
key = (((key + decrypted) & 0xff) * 0x3D) & 0xff;
|
|
18
20
|
}
|
|
19
|
-
|
|
21
|
+
|
|
22
|
+
return Buffer.from(result);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 加密的通信密钥(与 Rust 客户端一致)
|
|
26
|
+
const ENC_COMM_KEY = Buffer.from([
|
|
27
|
+
0x11, 0x18, 0xFC, 0x4A, 0xF9, 0xB8, 0x1A, 0x9C,
|
|
28
|
+
0x4F, 0xA4, 0xD1, 0x44, 0x47, 0xE5, 0x03, 0x57,
|
|
29
|
+
0xA3, 0x2B, 0x8E, 0x38, 0x3B, 0x99, 0x8F, 0x8C,
|
|
30
|
+
0x2B, 0x91, 0x60, 0xC1, 0x15, 0x07, 0x21, 0x53,
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
// 生成加密密钥(与客户端一致)
|
|
34
|
+
function getEncryptionKey() {
|
|
35
|
+
return decryptStaticBytes(ENC_COMM_KEY, 0x8D);
|
|
20
36
|
}
|
|
21
37
|
|
|
22
38
|
// 生成签名
|
|
@@ -28,7 +44,7 @@ function generateSignature(data, timestamp, deviceId) {
|
|
|
28
44
|
return hmac.digest('hex');
|
|
29
45
|
}
|
|
30
46
|
|
|
31
|
-
//
|
|
47
|
+
// 解密服务器返回的数据(返回字符串)
|
|
32
48
|
function decryptPayload(encryptedData, ivHex, tagHex) {
|
|
33
49
|
try {
|
|
34
50
|
const key = getEncryptionKey();
|
|
@@ -42,13 +58,26 @@ function decryptPayload(encryptedData, ivHex, tagHex) {
|
|
|
42
58
|
let decrypted = decipher.update(encrypted, null, 'utf8');
|
|
43
59
|
decrypted += decipher.final('utf8');
|
|
44
60
|
|
|
45
|
-
return
|
|
61
|
+
return decrypted;
|
|
46
62
|
} catch (e) {
|
|
47
63
|
console.error('解密失败:', e.message);
|
|
48
64
|
return null;
|
|
49
65
|
}
|
|
50
66
|
}
|
|
51
67
|
|
|
68
|
+
// 解密服务器返回的 JSON 数据
|
|
69
|
+
function decryptPayloadJson(encryptedData, ivHex, tagHex) {
|
|
70
|
+
const decrypted = decryptPayload(encryptedData, ivHex, tagHex);
|
|
71
|
+
if (decrypted) {
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(decrypted);
|
|
74
|
+
} catch (e) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
52
81
|
// 激活码登录
|
|
53
82
|
async function activate(code) {
|
|
54
83
|
const deviceId = getDeviceId();
|
|
@@ -88,7 +117,7 @@ async function getTokens() {
|
|
|
88
117
|
|
|
89
118
|
// 如果返回加密数据,需要解密
|
|
90
119
|
if (result.success && result.data && result.iv && result.tag) {
|
|
91
|
-
const decrypted =
|
|
120
|
+
const decrypted = decryptPayloadJson(result.data, result.iv, result.tag);
|
|
92
121
|
if (decrypted) {
|
|
93
122
|
return { success: true, data: decrypted };
|
|
94
123
|
}
|
|
@@ -117,7 +146,25 @@ async function activateToken(tokenId) {
|
|
|
117
146
|
body: JSON.stringify({ token_id: tokenId })
|
|
118
147
|
});
|
|
119
148
|
|
|
120
|
-
|
|
149
|
+
const result = await response.json();
|
|
150
|
+
|
|
151
|
+
// 解密 access_token 和 refresh_token
|
|
152
|
+
if (result.success && result.access_token && result.access_iv && result.access_tag) {
|
|
153
|
+
const accessToken = decryptPayload(result.access_token, result.access_iv, result.access_tag);
|
|
154
|
+
const refreshToken = decryptPayload(result.refresh_token, result.refresh_iv, result.refresh_tag);
|
|
155
|
+
|
|
156
|
+
if (accessToken && refreshToken) {
|
|
157
|
+
return {
|
|
158
|
+
success: true,
|
|
159
|
+
email: result.email,
|
|
160
|
+
access_token: accessToken,
|
|
161
|
+
refresh_token: refreshToken
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return { success: false, error: '解密失败' };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return result;
|
|
121
168
|
}
|
|
122
169
|
|
|
123
170
|
// 心跳
|