tsvesync 1.0.97 → 1.0.99
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/dist/lib/helpers.d.ts +4 -2
- package/dist/lib/helpers.js +76 -21
- package/package.json +1 -1
- package/src/lib/helpers.ts +90 -20
package/dist/lib/helpers.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare const API_TIMEOUT = 15000;
|
|
|
12
12
|
export declare const APP_VERSION = "5.6.60";
|
|
13
13
|
export declare const PHONE_BRAND = "SM N9005";
|
|
14
14
|
export declare const PHONE_OS = "Android";
|
|
15
|
+
export declare const CLIENT_INFO = "SM N9005";
|
|
15
16
|
export declare const USER_TYPE = "1";
|
|
16
17
|
export declare const DEFAULT_TZ = "America/New_York";
|
|
17
18
|
export declare const DEFAULT_REGION = "US";
|
|
@@ -28,6 +29,7 @@ export declare const REGION_ENDPOINTS: {
|
|
|
28
29
|
export declare const CROSS_REGION_ERROR_CODE = -11260022;
|
|
29
30
|
export declare const APP_VERSION_TOO_LOW_ERROR_CODE = -11012022;
|
|
30
31
|
export declare function generateAppId(): string;
|
|
32
|
+
export declare function generateTerminalId(): string;
|
|
31
33
|
export interface RequestBody {
|
|
32
34
|
acceptLanguage?: string;
|
|
33
35
|
accountID?: string;
|
|
@@ -111,11 +113,11 @@ export declare class Helpers {
|
|
|
111
113
|
/**
|
|
112
114
|
* Build request body for initial authentication step
|
|
113
115
|
*/
|
|
114
|
-
static reqBodyAuthStep1(manager: VeSync, appId: string): Record<string, any>;
|
|
116
|
+
static reqBodyAuthStep1(manager: VeSync, appId: string, terminalId: string): Record<string, any>;
|
|
115
117
|
/**
|
|
116
118
|
* Build request body for second authentication step (login with authorize code)
|
|
117
119
|
*/
|
|
118
|
-
static reqBodyAuthStep2(authorizeCode: string, bizToken: string, appId: string, userCountryCode?: string): Record<string, any>;
|
|
120
|
+
static reqBodyAuthStep2(authorizeCode: string, bizToken: string | null, appId: string, terminalId: string, userCountryCode?: string, regionChange?: string): Record<string, any>;
|
|
119
121
|
/**
|
|
120
122
|
* Builder for body of api requests
|
|
121
123
|
*/
|
package/dist/lib/helpers.js
CHANGED
|
@@ -6,13 +6,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
7
|
};
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.Helpers = exports.APP_VERSION_TOO_LOW_ERROR_CODE = exports.CROSS_REGION_ERROR_CODE = exports.REGION_ENDPOINTS = exports.CLIENT_VERSION = exports.BYPASS_HEADER_UA = exports.MOBILE_ID = exports.DEFAULT_REGION = exports.DEFAULT_TZ = exports.USER_TYPE = exports.PHONE_OS = exports.PHONE_BRAND = exports.APP_VERSION = exports.API_TIMEOUT = exports.API_RATE_LIMIT = void 0;
|
|
9
|
+
exports.Helpers = exports.APP_VERSION_TOO_LOW_ERROR_CODE = exports.CROSS_REGION_ERROR_CODE = exports.REGION_ENDPOINTS = exports.CLIENT_VERSION = exports.BYPASS_HEADER_UA = exports.MOBILE_ID = exports.DEFAULT_REGION = exports.DEFAULT_TZ = exports.USER_TYPE = exports.CLIENT_INFO = exports.PHONE_OS = exports.PHONE_BRAND = exports.APP_VERSION = exports.API_TIMEOUT = exports.API_RATE_LIMIT = void 0;
|
|
10
10
|
exports.getApiBaseUrl = getApiBaseUrl;
|
|
11
11
|
exports.setApiBaseUrl = setApiBaseUrl;
|
|
12
12
|
exports.getCurrentRegion = getCurrentRegion;
|
|
13
13
|
exports.setCurrentRegion = setCurrentRegion;
|
|
14
14
|
exports.getRegionFromCountryCode = getRegionFromCountryCode;
|
|
15
15
|
exports.generateAppId = generateAppId;
|
|
16
|
+
exports.generateTerminalId = generateTerminalId;
|
|
16
17
|
const axios_1 = __importDefault(require("axios"));
|
|
17
18
|
const crypto_1 = __importDefault(require("crypto"));
|
|
18
19
|
const logger_1 = require("./logger");
|
|
@@ -53,6 +54,7 @@ exports.API_TIMEOUT = 15000;
|
|
|
53
54
|
exports.APP_VERSION = '5.6.60';
|
|
54
55
|
exports.PHONE_BRAND = 'SM N9005';
|
|
55
56
|
exports.PHONE_OS = 'Android';
|
|
57
|
+
exports.CLIENT_INFO = 'SM N9005';
|
|
56
58
|
exports.USER_TYPE = '1';
|
|
57
59
|
exports.DEFAULT_TZ = 'America/New_York';
|
|
58
60
|
exports.DEFAULT_REGION = 'US';
|
|
@@ -79,6 +81,15 @@ function generateAppId() {
|
|
|
79
81
|
}
|
|
80
82
|
return result;
|
|
81
83
|
}
|
|
84
|
+
// Generate unique terminal ID for authentication
|
|
85
|
+
function generateTerminalId() {
|
|
86
|
+
const chars = 'abcdef0123456789';
|
|
87
|
+
let result = '';
|
|
88
|
+
for (let i = 0; i < 16; i++) {
|
|
89
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
82
93
|
class Helpers {
|
|
83
94
|
/**
|
|
84
95
|
* Calculate MD5 hash
|
|
@@ -158,36 +169,54 @@ class Helpers {
|
|
|
158
169
|
/**
|
|
159
170
|
* Build request body for initial authentication step
|
|
160
171
|
*/
|
|
161
|
-
static reqBodyAuthStep1(manager, appId) {
|
|
172
|
+
static reqBodyAuthStep1(manager, appId, terminalId) {
|
|
162
173
|
return {
|
|
163
174
|
'email': manager.username,
|
|
175
|
+
'method': 'authByPWDOrOTM',
|
|
164
176
|
'password': this.hashPassword(manager.password),
|
|
165
|
-
'timeZone': manager.timeZone,
|
|
166
177
|
'acceptLanguage': 'en',
|
|
167
|
-
'
|
|
168
|
-
'
|
|
169
|
-
'
|
|
170
|
-
'
|
|
171
|
-
'
|
|
172
|
-
'
|
|
173
|
-
'
|
|
178
|
+
'accountID': '',
|
|
179
|
+
'authProtocolType': 'generic',
|
|
180
|
+
'clientInfo': exports.CLIENT_INFO,
|
|
181
|
+
'clientType': 'vesyncApp',
|
|
182
|
+
'clientVersion': exports.CLIENT_VERSION,
|
|
183
|
+
'debugMode': false,
|
|
184
|
+
'osInfo': exports.PHONE_OS,
|
|
185
|
+
'terminalId': terminalId,
|
|
186
|
+
'timeZone': manager.timeZone || exports.DEFAULT_TZ,
|
|
187
|
+
'token': '',
|
|
188
|
+
'userCountryCode': 'US',
|
|
174
189
|
'appID': appId,
|
|
175
|
-
'
|
|
190
|
+
'sourceAppID': appId,
|
|
191
|
+
'traceId': `APP${appId}${Math.floor(Date.now() / 1000)}`
|
|
176
192
|
};
|
|
177
193
|
}
|
|
178
194
|
/**
|
|
179
195
|
* Build request body for second authentication step (login with authorize code)
|
|
180
196
|
*/
|
|
181
|
-
static reqBodyAuthStep2(authorizeCode, bizToken, appId, userCountryCode) {
|
|
197
|
+
static reqBodyAuthStep2(authorizeCode, bizToken, appId, terminalId, userCountryCode, regionChange) {
|
|
182
198
|
const body = {
|
|
199
|
+
'method': 'loginByAuthorizeCode4Vesync',
|
|
183
200
|
'authorizeCode': authorizeCode,
|
|
184
|
-
'
|
|
185
|
-
'
|
|
201
|
+
'acceptLanguage': 'en',
|
|
202
|
+
'clientInfo': exports.CLIENT_INFO,
|
|
203
|
+
'clientType': 'vesyncApp',
|
|
186
204
|
'clientVersion': exports.CLIENT_VERSION,
|
|
187
|
-
'
|
|
205
|
+
'debugMode': false,
|
|
206
|
+
'emailSubscriptions': false,
|
|
207
|
+
'osInfo': exports.PHONE_OS,
|
|
208
|
+
'terminalId': terminalId,
|
|
209
|
+
'timeZone': exports.DEFAULT_TZ,
|
|
210
|
+
'userCountryCode': userCountryCode || 'US',
|
|
211
|
+
'traceId': `APP${appId}${Math.floor(Date.now() / 1000)}`
|
|
188
212
|
};
|
|
189
|
-
if
|
|
190
|
-
|
|
213
|
+
// Only include bizToken if it's not null
|
|
214
|
+
if (bizToken) {
|
|
215
|
+
body.bizToken = bizToken;
|
|
216
|
+
}
|
|
217
|
+
// Only include regionChange if provided
|
|
218
|
+
if (regionChange) {
|
|
219
|
+
body.regionChange = regionChange;
|
|
191
220
|
}
|
|
192
221
|
return body;
|
|
193
222
|
}
|
|
@@ -370,8 +399,10 @@ class Helpers {
|
|
|
370
399
|
*/
|
|
371
400
|
static async authNewFlow(manager, appId, region = 'US') {
|
|
372
401
|
try {
|
|
402
|
+
// Generate terminal ID to be used in both steps
|
|
403
|
+
const terminalId = generateTerminalId();
|
|
373
404
|
// Step 1: Get authorization code
|
|
374
|
-
const step1Body = this.reqBodyAuthStep1(manager, appId);
|
|
405
|
+
const step1Body = this.reqBodyAuthStep1(manager, appId, terminalId);
|
|
375
406
|
const step1Headers = this.reqHeaderAuth();
|
|
376
407
|
// Set the correct regional endpoint
|
|
377
408
|
const originalUrl = getApiBaseUrl();
|
|
@@ -401,14 +432,14 @@ class Helpers {
|
|
|
401
432
|
return [false, null, null, null];
|
|
402
433
|
}
|
|
403
434
|
const { authorizeCode, bizToken, userCountryCode } = authResponse.result || {};
|
|
404
|
-
if (!authorizeCode
|
|
405
|
-
logger_1.logger.error('Missing
|
|
435
|
+
if (!authorizeCode) {
|
|
436
|
+
logger_1.logger.error('Missing authorization code in step 1 response:', authResponse.result);
|
|
406
437
|
setApiBaseUrl(originalUrl); // Restore original URL
|
|
407
438
|
return [false, null, null, null];
|
|
408
439
|
}
|
|
409
440
|
logger_1.logger.debug('Step 1 successful, got authorization code');
|
|
410
441
|
// Step 2: Login with authorization code
|
|
411
|
-
const step2Body = this.reqBodyAuthStep2(authorizeCode, bizToken, appId, userCountryCode);
|
|
442
|
+
const step2Body = this.reqBodyAuthStep2(authorizeCode, bizToken, appId, terminalId, userCountryCode);
|
|
412
443
|
logger_1.logger.debug('Step 2: Logging in with authorization code...');
|
|
413
444
|
const [loginResponse, loginStatus] = await this.callApi('/user/api/accountManage/v1/loginByAuthorizeCode4Vesync', 'post', step2Body, step1Headers, manager);
|
|
414
445
|
setApiBaseUrl(originalUrl); // Restore original URL
|
|
@@ -417,6 +448,30 @@ class Helpers {
|
|
|
417
448
|
return [false, null, null, null];
|
|
418
449
|
}
|
|
419
450
|
if (loginResponse.code !== 0) {
|
|
451
|
+
// Handle cross-region error with retry (like pyvesync PR #340)
|
|
452
|
+
if (loginResponse.code === exports.CROSS_REGION_ERROR_CODE) {
|
|
453
|
+
logger_1.logger.debug('Cross-region error detected in Step 2, retrying with region change token...');
|
|
454
|
+
const { bizToken: regionChangeToken, countryCode: newCountryCode } = loginResponse.result || {};
|
|
455
|
+
if (regionChangeToken) {
|
|
456
|
+
// Retry Step 2 with region change token
|
|
457
|
+
const retryBody = {
|
|
458
|
+
...step2Body,
|
|
459
|
+
bizToken: regionChangeToken,
|
|
460
|
+
regionChange: 'last_region',
|
|
461
|
+
userCountryCode: newCountryCode || userCountryCode
|
|
462
|
+
};
|
|
463
|
+
logger_1.logger.debug('Retrying Step 2 with region change token...');
|
|
464
|
+
const [retryResponse, retryStatus] = await this.callApi('/user/api/accountManage/v1/loginByAuthorizeCode4Vesync', 'post', retryBody, step1Headers, manager);
|
|
465
|
+
if (retryResponse && retryResponse.code === 0) {
|
|
466
|
+
const { token, accountID, countryCode } = retryResponse.result || {};
|
|
467
|
+
if (token && accountID) {
|
|
468
|
+
logger_1.logger.debug('Step 2 retry successful with region change');
|
|
469
|
+
return [true, token, accountID, countryCode || newCountryCode];
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
logger_1.logger.error('Step 2 retry failed:', retryResponse);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
420
475
|
logger_1.logger.error('Step 2 error code:', loginResponse.code, 'message:', loginResponse.msg);
|
|
421
476
|
return [false, null, null, null];
|
|
422
477
|
}
|
package/package.json
CHANGED
package/src/lib/helpers.ts
CHANGED
|
@@ -54,6 +54,7 @@ export const API_TIMEOUT = 15000;
|
|
|
54
54
|
export const APP_VERSION = '5.6.60';
|
|
55
55
|
export const PHONE_BRAND = 'SM N9005';
|
|
56
56
|
export const PHONE_OS = 'Android';
|
|
57
|
+
export const CLIENT_INFO = 'SM N9005';
|
|
57
58
|
export const USER_TYPE = '1';
|
|
58
59
|
export const DEFAULT_TZ = 'America/New_York';
|
|
59
60
|
export const DEFAULT_REGION = 'US';
|
|
@@ -84,6 +85,16 @@ export function generateAppId(): string {
|
|
|
84
85
|
return result;
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
// Generate unique terminal ID for authentication
|
|
89
|
+
export function generateTerminalId(): string {
|
|
90
|
+
const chars = 'abcdef0123456789';
|
|
91
|
+
let result = '';
|
|
92
|
+
for (let i = 0; i < 16; i++) {
|
|
93
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
|
|
87
98
|
export interface RequestBody {
|
|
88
99
|
acceptLanguage?: string;
|
|
89
100
|
accountID?: string;
|
|
@@ -227,38 +238,57 @@ export class Helpers {
|
|
|
227
238
|
/**
|
|
228
239
|
* Build request body for initial authentication step
|
|
229
240
|
*/
|
|
230
|
-
static reqBodyAuthStep1(manager: VeSync, appId: string): Record<string, any> {
|
|
241
|
+
static reqBodyAuthStep1(manager: VeSync, appId: string, terminalId: string): Record<string, any> {
|
|
231
242
|
return {
|
|
232
243
|
'email': manager.username,
|
|
244
|
+
'method': 'authByPWDOrOTM',
|
|
233
245
|
'password': this.hashPassword(manager.password),
|
|
234
|
-
'timeZone': manager.timeZone,
|
|
235
246
|
'acceptLanguage': 'en',
|
|
236
|
-
'
|
|
237
|
-
'
|
|
238
|
-
'
|
|
239
|
-
'
|
|
240
|
-
'
|
|
241
|
-
'
|
|
242
|
-
'
|
|
247
|
+
'accountID': '',
|
|
248
|
+
'authProtocolType': 'generic',
|
|
249
|
+
'clientInfo': CLIENT_INFO,
|
|
250
|
+
'clientType': 'vesyncApp',
|
|
251
|
+
'clientVersion': CLIENT_VERSION,
|
|
252
|
+
'debugMode': false,
|
|
253
|
+
'osInfo': PHONE_OS,
|
|
254
|
+
'terminalId': terminalId,
|
|
255
|
+
'timeZone': manager.timeZone || DEFAULT_TZ,
|
|
256
|
+
'token': '',
|
|
257
|
+
'userCountryCode': 'US',
|
|
243
258
|
'appID': appId,
|
|
244
|
-
'
|
|
259
|
+
'sourceAppID': appId,
|
|
260
|
+
'traceId': `APP${appId}${Math.floor(Date.now() / 1000)}`
|
|
245
261
|
};
|
|
246
262
|
}
|
|
247
263
|
|
|
248
264
|
/**
|
|
249
265
|
* Build request body for second authentication step (login with authorize code)
|
|
250
266
|
*/
|
|
251
|
-
static reqBodyAuthStep2(authorizeCode: string, bizToken: string, appId: string, userCountryCode?: string): Record<string, any> {
|
|
267
|
+
static reqBodyAuthStep2(authorizeCode: string, bizToken: string | null, appId: string, terminalId: string, userCountryCode?: string, regionChange?: string): Record<string, any> {
|
|
252
268
|
const body: Record<string, any> = {
|
|
269
|
+
'method': 'loginByAuthorizeCode4Vesync',
|
|
253
270
|
'authorizeCode': authorizeCode,
|
|
254
|
-
'
|
|
255
|
-
'
|
|
271
|
+
'acceptLanguage': 'en',
|
|
272
|
+
'clientInfo': CLIENT_INFO,
|
|
273
|
+
'clientType': 'vesyncApp',
|
|
256
274
|
'clientVersion': CLIENT_VERSION,
|
|
257
|
-
'
|
|
275
|
+
'debugMode': false,
|
|
276
|
+
'emailSubscriptions': false,
|
|
277
|
+
'osInfo': PHONE_OS,
|
|
278
|
+
'terminalId': terminalId,
|
|
279
|
+
'timeZone': DEFAULT_TZ,
|
|
280
|
+
'userCountryCode': userCountryCode || 'US',
|
|
281
|
+
'traceId': `APP${appId}${Math.floor(Date.now() / 1000)}`
|
|
258
282
|
};
|
|
259
283
|
|
|
260
|
-
if
|
|
261
|
-
|
|
284
|
+
// Only include bizToken if it's not null
|
|
285
|
+
if (bizToken) {
|
|
286
|
+
body.bizToken = bizToken;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Only include regionChange if provided
|
|
290
|
+
if (regionChange) {
|
|
291
|
+
body.regionChange = regionChange;
|
|
262
292
|
}
|
|
263
293
|
|
|
264
294
|
return body;
|
|
@@ -470,8 +500,11 @@ export class Helpers {
|
|
|
470
500
|
*/
|
|
471
501
|
static async authNewFlow(manager: VeSync, appId: string, region: string = 'US'): Promise<[boolean, string | null, string | null, string | null]> {
|
|
472
502
|
try {
|
|
503
|
+
// Generate terminal ID to be used in both steps
|
|
504
|
+
const terminalId = generateTerminalId();
|
|
505
|
+
|
|
473
506
|
// Step 1: Get authorization code
|
|
474
|
-
const step1Body = this.reqBodyAuthStep1(manager, appId);
|
|
507
|
+
const step1Body = this.reqBodyAuthStep1(manager, appId, terminalId);
|
|
475
508
|
const step1Headers = this.reqHeaderAuth();
|
|
476
509
|
|
|
477
510
|
// Set the correct regional endpoint
|
|
@@ -516,8 +549,8 @@ export class Helpers {
|
|
|
516
549
|
|
|
517
550
|
const { authorizeCode, bizToken, userCountryCode } = authResponse.result || {};
|
|
518
551
|
|
|
519
|
-
if (!authorizeCode
|
|
520
|
-
logger.error('Missing
|
|
552
|
+
if (!authorizeCode) {
|
|
553
|
+
logger.error('Missing authorization code in step 1 response:', authResponse.result);
|
|
521
554
|
setApiBaseUrl(originalUrl); // Restore original URL
|
|
522
555
|
return [false, null, null, null];
|
|
523
556
|
}
|
|
@@ -525,7 +558,7 @@ export class Helpers {
|
|
|
525
558
|
logger.debug('Step 1 successful, got authorization code');
|
|
526
559
|
|
|
527
560
|
// Step 2: Login with authorization code
|
|
528
|
-
const step2Body = this.reqBodyAuthStep2(authorizeCode, bizToken, appId, userCountryCode);
|
|
561
|
+
const step2Body = this.reqBodyAuthStep2(authorizeCode, bizToken, appId, terminalId, userCountryCode);
|
|
529
562
|
|
|
530
563
|
logger.debug('Step 2: Logging in with authorization code...');
|
|
531
564
|
|
|
@@ -545,6 +578,43 @@ export class Helpers {
|
|
|
545
578
|
}
|
|
546
579
|
|
|
547
580
|
if (loginResponse.code !== 0) {
|
|
581
|
+
// Handle cross-region error with retry (like pyvesync PR #340)
|
|
582
|
+
if (loginResponse.code === CROSS_REGION_ERROR_CODE) {
|
|
583
|
+
logger.debug('Cross-region error detected in Step 2, retrying with region change token...');
|
|
584
|
+
|
|
585
|
+
const { bizToken: regionChangeToken, countryCode: newCountryCode } = loginResponse.result || {};
|
|
586
|
+
|
|
587
|
+
if (regionChangeToken) {
|
|
588
|
+
// Retry Step 2 with region change token
|
|
589
|
+
const retryBody = {
|
|
590
|
+
...step2Body,
|
|
591
|
+
bizToken: regionChangeToken,
|
|
592
|
+
regionChange: 'last_region',
|
|
593
|
+
userCountryCode: newCountryCode || userCountryCode
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
logger.debug('Retrying Step 2 with region change token...');
|
|
597
|
+
|
|
598
|
+
const [retryResponse, retryStatus] = await this.callApi(
|
|
599
|
+
'/user/api/accountManage/v1/loginByAuthorizeCode4Vesync',
|
|
600
|
+
'post',
|
|
601
|
+
retryBody,
|
|
602
|
+
step1Headers,
|
|
603
|
+
manager
|
|
604
|
+
);
|
|
605
|
+
|
|
606
|
+
if (retryResponse && retryResponse.code === 0) {
|
|
607
|
+
const { token, accountID, countryCode } = retryResponse.result || {};
|
|
608
|
+
if (token && accountID) {
|
|
609
|
+
logger.debug('Step 2 retry successful with region change');
|
|
610
|
+
return [true, token, accountID, countryCode || newCountryCode];
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
logger.error('Step 2 retry failed:', retryResponse);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
548
618
|
logger.error('Step 2 error code:', loginResponse.code, 'message:', loginResponse.msg);
|
|
549
619
|
return [false, null, null, null];
|
|
550
620
|
}
|