tsvesync 1.0.97 → 1.0.98

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.
@@ -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): Record<string, any>;
119
121
  /**
120
122
  * Builder for body of api requests
121
123
  */
@@ -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,50 @@ 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
- 'appVersion': exports.APP_VERSION,
168
- 'phoneBrand': exports.PHONE_BRAND,
169
- 'phoneOS': exports.PHONE_OS,
170
- 'traceId': Date.now().toString(),
171
- 'authProtocolType': 'pwd',
172
- 'clientType': 'android',
173
- 'sourceAppID': 'vesync_android',
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
- 'clientVersion': exports.CLIENT_VERSION
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) {
182
198
  const body = {
199
+ 'method': 'loginByAuthorizeCode4Vesync',
183
200
  'authorizeCode': authorizeCode,
184
- 'bizToken': bizToken,
185
- 'appID': appId,
201
+ 'acceptLanguage': 'en',
202
+ 'clientInfo': exports.CLIENT_INFO,
203
+ 'clientType': 'vesyncApp',
186
204
  'clientVersion': exports.CLIENT_VERSION,
187
- 'acceptLanguage': 'en'
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 (userCountryCode) {
190
- body.userCountryCode = userCountryCode;
213
+ // Only include bizToken if it's not null
214
+ if (bizToken) {
215
+ body.bizToken = bizToken;
191
216
  }
192
217
  return body;
193
218
  }
@@ -370,8 +395,10 @@ class Helpers {
370
395
  */
371
396
  static async authNewFlow(manager, appId, region = 'US') {
372
397
  try {
398
+ // Generate terminal ID to be used in both steps
399
+ const terminalId = generateTerminalId();
373
400
  // Step 1: Get authorization code
374
- const step1Body = this.reqBodyAuthStep1(manager, appId);
401
+ const step1Body = this.reqBodyAuthStep1(manager, appId, terminalId);
375
402
  const step1Headers = this.reqHeaderAuth();
376
403
  // Set the correct regional endpoint
377
404
  const originalUrl = getApiBaseUrl();
@@ -401,14 +428,14 @@ class Helpers {
401
428
  return [false, null, null, null];
402
429
  }
403
430
  const { authorizeCode, bizToken, userCountryCode } = authResponse.result || {};
404
- if (!authorizeCode || !bizToken) {
405
- logger_1.logger.error('Missing required fields in step 1 response:', authResponse.result);
431
+ if (!authorizeCode) {
432
+ logger_1.logger.error('Missing authorization code in step 1 response:', authResponse.result);
406
433
  setApiBaseUrl(originalUrl); // Restore original URL
407
434
  return [false, null, null, null];
408
435
  }
409
436
  logger_1.logger.debug('Step 1 successful, got authorization code');
410
437
  // Step 2: Login with authorization code
411
- const step2Body = this.reqBodyAuthStep2(authorizeCode, bizToken, appId, userCountryCode);
438
+ const step2Body = this.reqBodyAuthStep2(authorizeCode, bizToken, appId, terminalId, userCountryCode);
412
439
  logger_1.logger.debug('Step 2: Logging in with authorization code...');
413
440
  const [loginResponse, loginStatus] = await this.callApi('/user/api/accountManage/v1/loginByAuthorizeCode4Vesync', 'post', step2Body, step1Headers, manager);
414
441
  setApiBaseUrl(originalUrl); // Restore original URL
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsvesync",
3
- "version": "1.0.97",
3
+ "version": "1.0.98",
4
4
  "description": "A TypeScript library for interacting with VeSync smart home devices",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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,52 @@ 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
- 'appVersion': APP_VERSION,
237
- 'phoneBrand': PHONE_BRAND,
238
- 'phoneOS': PHONE_OS,
239
- 'traceId': Date.now().toString(),
240
- 'authProtocolType': 'pwd',
241
- 'clientType': 'android',
242
- 'sourceAppID': 'vesync_android',
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
- 'clientVersion': CLIENT_VERSION
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): Record<string, any> {
252
268
  const body: Record<string, any> = {
269
+ 'method': 'loginByAuthorizeCode4Vesync',
253
270
  'authorizeCode': authorizeCode,
254
- 'bizToken': bizToken,
255
- 'appID': appId,
271
+ 'acceptLanguage': 'en',
272
+ 'clientInfo': CLIENT_INFO,
273
+ 'clientType': 'vesyncApp',
256
274
  'clientVersion': CLIENT_VERSION,
257
- 'acceptLanguage': 'en'
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 (userCountryCode) {
261
- body.userCountryCode = userCountryCode;
284
+ // Only include bizToken if it's not null
285
+ if (bizToken) {
286
+ body.bizToken = bizToken;
262
287
  }
263
288
 
264
289
  return body;
@@ -470,8 +495,11 @@ export class Helpers {
470
495
  */
471
496
  static async authNewFlow(manager: VeSync, appId: string, region: string = 'US'): Promise<[boolean, string | null, string | null, string | null]> {
472
497
  try {
498
+ // Generate terminal ID to be used in both steps
499
+ const terminalId = generateTerminalId();
500
+
473
501
  // Step 1: Get authorization code
474
- const step1Body = this.reqBodyAuthStep1(manager, appId);
502
+ const step1Body = this.reqBodyAuthStep1(manager, appId, terminalId);
475
503
  const step1Headers = this.reqHeaderAuth();
476
504
 
477
505
  // Set the correct regional endpoint
@@ -516,8 +544,8 @@ export class Helpers {
516
544
 
517
545
  const { authorizeCode, bizToken, userCountryCode } = authResponse.result || {};
518
546
 
519
- if (!authorizeCode || !bizToken) {
520
- logger.error('Missing required fields in step 1 response:', authResponse.result);
547
+ if (!authorizeCode) {
548
+ logger.error('Missing authorization code in step 1 response:', authResponse.result);
521
549
  setApiBaseUrl(originalUrl); // Restore original URL
522
550
  return [false, null, null, null];
523
551
  }
@@ -525,7 +553,7 @@ export class Helpers {
525
553
  logger.debug('Step 1 successful, got authorization code');
526
554
 
527
555
  // Step 2: Login with authorization code
528
- const step2Body = this.reqBodyAuthStep2(authorizeCode, bizToken, appId, userCountryCode);
556
+ const step2Body = this.reqBodyAuthStep2(authorizeCode, bizToken, appId, terminalId, userCountryCode);
529
557
 
530
558
  logger.debug('Step 2: Logging in with authorization code...');
531
559