@etsoo/appscript 1.1.70 → 1.1.74

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 @@ import { AddressUtils } from '../../src/address/AddressUtils';
12
12
  import { IAppSettings } from '../../src/app/AppSettings';
13
13
  import { CoreApp } from '../../src/app/CoreApp';
14
14
  import { zhCN } from '../../src/i18n/zhCN';
15
+ import { InitCallResultData } from '../../src/result/InitCallResult';
15
16
 
16
17
  // Detected country or region
17
18
  const { detectedCountry } = DomUtils;
@@ -108,6 +109,11 @@ class CoreAppTest extends CoreApp<IAppSettings, {}, NotificationCallProps> {
108
109
  freshCountdownUI(callback?: () => PromiseLike<unknown>): void {
109
110
  throw new Error('Method not implemented.');
110
111
  }
112
+
113
+ initCallUpdateLocal(data: InitCallResultData, timestamp: number) {
114
+ this.initCallUpdate(data, timestamp);
115
+ return this.passphrase;
116
+ }
111
117
  }
112
118
 
113
119
  const app = new CoreAppTest();
@@ -122,3 +128,17 @@ test('Tests for encrypt / decrypt', () => {
122
128
  const plain = app.decrypt(encrypted, passphrase);
123
129
  expect(plain).toEqual(input);
124
130
  });
131
+
132
+ test('Tests for initCallUpdateLocal', () => {
133
+ // Act
134
+ const passphrase = app.initCallUpdateLocal(
135
+ {
136
+ deviceId:
137
+ 'ZmNjZlov+10067A1520126643352C2022735B85DC8F380088468402C98A5631A8CFBE14E134zXfxmw77lFopTTlbqOfsK2KUqPSsTAQb35Ejrm1BAvUaQH3SuZcwGYu3+PQ/Rd56',
138
+ passphrase:
139
+ '01397BF28A93FC031BC8B9B808F880F12C398AB792DF2ADE7A8768CADD2259EB50HJuKhqGuLQO+SmvCVzuEGUN4TdkUuPMWR0E6lliszbNiXboCziXx5SdfX3lMpoBX'
140
+ },
141
+ 1639282438620
142
+ );
143
+ expect(passphrase).not.toBeNull();
144
+ });
@@ -68,6 +68,10 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
68
68
  * Currency, like USD for US dollar
69
69
  */
70
70
  readonly currency: string;
71
+ /**
72
+ * Device id
73
+ */
74
+ readonly deviceId: string;
71
75
  /**
72
76
  * Country or region, like CN
73
77
  */
@@ -118,10 +122,17 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
118
122
  * Decrypt message
119
123
  * @param messageEncrypted Encrypted message
120
124
  * @param passphrase Secret passphrase
125
+ * @returns Pure text
126
+ */
127
+ decrypt(messageEncrypted: string, passphrase?: string): string | undefined;
128
+ /**
129
+ * Enhanced decrypt message
130
+ * @param messageEncrypted Encrypted message
131
+ * @param passphrase Secret passphrase
121
132
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
122
133
  * @returns Pure text
123
134
  */
124
- decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
135
+ decryptEnhanced(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
125
136
  /**
126
137
  * Detect IP data, call only one time
127
138
  * @param callback Callback will be called when the IP is ready
@@ -135,6 +146,14 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
135
146
  * @returns Result
136
147
  */
137
148
  encrypt(message: string, passphrase?: string, iterations?: number): string;
149
+ /**
150
+ * Enhanced encrypt message
151
+ * @param message Message
152
+ * @param passphrase Secret passphrase
153
+ * @param iterations Iterations, 1000 times, 1 - 99
154
+ * @returns Result
155
+ */
156
+ encryptEnhanced(message: string, passphrase?: string, iterations?: number): string;
138
157
  /**
139
158
  * Format date to string
140
159
  * @param input Input date
@@ -334,6 +353,12 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
334
353
  * Country or region, like CN
335
354
  */
336
355
  get region(): string;
356
+ private _deviceId;
357
+ /**
358
+ * Country or region, like CN
359
+ */
360
+ get deviceId(): string;
361
+ protected set deviceId(value: string);
337
362
  /**
338
363
  * Label delegate
339
364
  */
@@ -374,10 +399,6 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
374
399
  * Device id field name
375
400
  */
376
401
  protected deviceIdField: string;
377
- /**
378
- * Device id
379
- */
380
- protected deviceId: string;
381
402
  /**
382
403
  * Passphrase for encryption
383
404
  */
@@ -434,10 +455,17 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
434
455
  * Decrypt message
435
456
  * @param messageEncrypted Encrypted message
436
457
  * @param passphrase Secret passphrase
458
+ * @returns Pure text
459
+ */
460
+ decrypt(messageEncrypted: string, passphrase?: string): string | undefined;
461
+ /**
462
+ * Enhanced decrypt message
463
+ * @param messageEncrypted Encrypted message
464
+ * @param passphrase Secret passphrase
437
465
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
438
466
  * @returns Pure text
439
467
  */
440
- decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
468
+ decryptEnhanced(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
441
469
  /**
442
470
  * Detect IP data, call only one time
443
471
  * @param callback Callback will be called when the IP is ready
@@ -452,6 +480,14 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
452
480
  * @returns Result
453
481
  */
454
482
  encrypt(message: string, passphrase?: string, iterations?: number): string;
483
+ /**
484
+ * Enhanced encrypt message
485
+ * @param message Message
486
+ * @param passphrase Secret passphrase
487
+ * @param iterations Iterations, 1000 times, 1 - 99
488
+ * @returns Result
489
+ */
490
+ encryptEnhanced(message: string, passphrase?: string, iterations?: number): string;
455
491
  /**
456
492
  * Enchance secret passphrase
457
493
  * @param passphrase Secret passphrase
@@ -20,6 +20,7 @@ class CoreApp {
20
20
  * @param name Application name
21
21
  */
22
22
  constructor(settings, api, notifier, name) {
23
+ this._deviceId = '***';
23
24
  /**
24
25
  * Response token header field name
25
26
  */
@@ -72,6 +73,15 @@ class CoreApp {
72
73
  get region() {
73
74
  return this._region;
74
75
  }
76
+ /**
77
+ * Country or region, like CN
78
+ */
79
+ get deviceId() {
80
+ return this._deviceId;
81
+ }
82
+ set deviceId(value) {
83
+ this._deviceId = value;
84
+ }
75
85
  /**
76
86
  * Label delegate
77
87
  */
@@ -154,6 +164,8 @@ class CoreApp {
154
164
  }
155
165
  if (callback)
156
166
  callback(false);
167
+ // Clear device id
168
+ shared_1.StorageUtils.setLocalData(this.deviceIdField, null);
157
169
  return;
158
170
  }
159
171
  this.initCallUpdate(result.data, data.timestamp);
@@ -170,7 +182,7 @@ class CoreApp {
170
182
  return;
171
183
  // Decrypt
172
184
  // Should be done within 120 seconds after returning from the backend
173
- const passphrase = this.decrypt(data.passphrase, timestamp.toString(), 120);
185
+ const passphrase = this.decrypt(data.passphrase, timestamp.toString());
174
186
  if (passphrase == null)
175
187
  return;
176
188
  // Update device id and cache it
@@ -180,17 +192,17 @@ class CoreApp {
180
192
  this.passphrase = passphrase;
181
193
  // Previous passphrase
182
194
  if (data.previousPassphrase) {
183
- const prev = this.decrypt(data.previousPassphrase, timestamp.toString(), 120);
195
+ const prev = this.decrypt(data.previousPassphrase, timestamp.toString());
184
196
  // Update
185
197
  const fields = this.initCallUpdateFields();
186
198
  for (const field of fields) {
187
199
  const currentValue = shared_1.StorageUtils.getLocalData(field, '');
188
200
  if (currentValue === '' || currentValue.indexOf('+') === -1)
189
201
  continue;
190
- const newValueSource = this.decrypt(currentValue, prev, 12);
202
+ const newValueSource = this.decryptEnhanced(currentValue, prev, 12);
191
203
  if (newValueSource == null)
192
204
  continue;
193
- const newValue = this.encrypt(newValueSource);
205
+ const newValue = this.encryptEnhanced(newValueSource);
194
206
  shared_1.StorageUtils.setLocalData(field, newValue);
195
207
  }
196
208
  }
@@ -294,16 +306,41 @@ class CoreApp {
294
306
  * Decrypt message
295
307
  * @param messageEncrypted Encrypted message
296
308
  * @param passphrase Secret passphrase
309
+ * @returns Pure text
310
+ */
311
+ decrypt(messageEncrypted, passphrase) {
312
+ // Iterations
313
+ const iterations = parseInt(messageEncrypted.substring(0, 2), 10);
314
+ if (isNaN(iterations))
315
+ return undefined;
316
+ const salt = crypto_js_1.enc.Hex.parse(messageEncrypted.substring(2, 34));
317
+ const iv = crypto_js_1.enc.Hex.parse(messageEncrypted.substring(34, 66));
318
+ const encrypted = messageEncrypted.substring(66);
319
+ const key = (0, crypto_js_1.PBKDF2)(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, salt, {
320
+ keySize: 8,
321
+ hasher: crypto_js_1.algo.SHA256,
322
+ iterations: 1000 * iterations
323
+ });
324
+ return crypto_js_1.AES.decrypt(encrypted, key, {
325
+ iv,
326
+ padding: crypto_js_1.pad.Pkcs7,
327
+ mode: crypto_js_1.mode.CBC
328
+ }).toString(crypto_js_1.enc.Utf8);
329
+ }
330
+ /**
331
+ * Enhanced decrypt message
332
+ * @param messageEncrypted Encrypted message
333
+ * @param passphrase Secret passphrase
297
334
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
298
335
  * @returns Pure text
299
336
  */
300
- decrypt(messageEncrypted, passphrase, durationSeconds) {
337
+ decryptEnhanced(messageEncrypted, passphrase, durationSeconds) {
301
338
  // Timestamp splitter
302
- const pos = messageEncrypted.indexOf('+');
303
- if (pos === -1 || messageEncrypted.length <= 66)
339
+ const pos = messageEncrypted.indexOf('!');
340
+ // Miliseconds chars are longer than 8
341
+ if (pos < 8 || messageEncrypted.length <= 66)
304
342
  return undefined;
305
343
  const timestamp = messageEncrypted.substring(0, pos);
306
- const message = messageEncrypted.substring(pos + 1);
307
344
  if (durationSeconds != null && durationSeconds > 0) {
308
345
  const milseconds = shared_1.Utils.charsToNumber(timestamp);
309
346
  if (isNaN(milseconds) || milseconds < 1)
@@ -315,23 +352,9 @@ class CoreApp {
315
352
  timespan.totalSeconds > durationSeconds))
316
353
  return undefined;
317
354
  }
318
- // Iterations
319
- const iterations = parseInt(message.substring(0, 2), 10);
320
- if (isNaN(iterations))
321
- return undefined;
322
- const salt = crypto_js_1.enc.Hex.parse(message.substring(2, 34));
323
- const iv = crypto_js_1.enc.Hex.parse(message.substring(34, 66));
324
- const encrypted = message.substring(66);
325
- const key = (0, crypto_js_1.PBKDF2)(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
326
- keySize: 8,
327
- hasher: crypto_js_1.algo.SHA256,
328
- iterations: 1000 * iterations
329
- });
330
- return crypto_js_1.AES.decrypt(encrypted, key, {
331
- iv,
332
- padding: crypto_js_1.pad.Pkcs7,
333
- mode: crypto_js_1.mode.CBC
334
- }).toString(crypto_js_1.enc.Utf8);
355
+ const message = messageEncrypted.substring(pos + 1);
356
+ passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
357
+ return this.decrypt(message, passphrase);
335
358
  }
336
359
  /**
337
360
  * Detect IP data, call only one time
@@ -376,19 +399,15 @@ class CoreApp {
376
399
  encrypt(message, passphrase, iterations) {
377
400
  // Default 1 * 1000
378
401
  iterations !== null && iterations !== void 0 ? iterations : (iterations = 1);
379
- // Timestamp
380
- const timestamp = shared_1.Utils.numberToChars(new Date().getTime());
381
402
  const bits = 16; // 128 / 8
382
403
  const salt = crypto_js_1.lib.WordArray.random(bits);
383
- const key = (0, crypto_js_1.PBKDF2)(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
404
+ const key = (0, crypto_js_1.PBKDF2)(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, salt, {
384
405
  keySize: 8,
385
406
  hasher: crypto_js_1.algo.SHA256,
386
407
  iterations: 1000 * iterations
387
408
  });
388
409
  const iv = crypto_js_1.lib.WordArray.random(bits);
389
- return (timestamp +
390
- '+' +
391
- iterations.toString().padStart(2, '0') +
410
+ return (iterations.toString().padStart(2, '0') +
392
411
  salt.toString(crypto_js_1.enc.Hex) +
393
412
  iv.toString(crypto_js_1.enc.Hex) +
394
413
  crypto_js_1.AES.encrypt(message, key, {
@@ -398,6 +417,19 @@ class CoreApp {
398
417
  }).toString() // enc.Base64
399
418
  );
400
419
  }
420
+ /**
421
+ * Enhanced encrypt message
422
+ * @param message Message
423
+ * @param passphrase Secret passphrase
424
+ * @param iterations Iterations, 1000 times, 1 - 99
425
+ * @returns Result
426
+ */
427
+ encryptEnhanced(message, passphrase, iterations) {
428
+ // Timestamp
429
+ const timestamp = shared_1.Utils.numberToChars(new Date().getTime());
430
+ passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
431
+ return timestamp + '!' + this.encrypt(message, passphrase, iterations);
432
+ }
401
433
  /**
402
434
  * Enchance secret passphrase
403
435
  * @param passphrase Secret passphrase
@@ -68,6 +68,10 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
68
68
  * Currency, like USD for US dollar
69
69
  */
70
70
  readonly currency: string;
71
+ /**
72
+ * Device id
73
+ */
74
+ readonly deviceId: string;
71
75
  /**
72
76
  * Country or region, like CN
73
77
  */
@@ -118,10 +122,17 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
118
122
  * Decrypt message
119
123
  * @param messageEncrypted Encrypted message
120
124
  * @param passphrase Secret passphrase
125
+ * @returns Pure text
126
+ */
127
+ decrypt(messageEncrypted: string, passphrase?: string): string | undefined;
128
+ /**
129
+ * Enhanced decrypt message
130
+ * @param messageEncrypted Encrypted message
131
+ * @param passphrase Secret passphrase
121
132
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
122
133
  * @returns Pure text
123
134
  */
124
- decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
135
+ decryptEnhanced(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
125
136
  /**
126
137
  * Detect IP data, call only one time
127
138
  * @param callback Callback will be called when the IP is ready
@@ -135,6 +146,14 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
135
146
  * @returns Result
136
147
  */
137
148
  encrypt(message: string, passphrase?: string, iterations?: number): string;
149
+ /**
150
+ * Enhanced encrypt message
151
+ * @param message Message
152
+ * @param passphrase Secret passphrase
153
+ * @param iterations Iterations, 1000 times, 1 - 99
154
+ * @returns Result
155
+ */
156
+ encryptEnhanced(message: string, passphrase?: string, iterations?: number): string;
138
157
  /**
139
158
  * Format date to string
140
159
  * @param input Input date
@@ -334,6 +353,12 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
334
353
  * Country or region, like CN
335
354
  */
336
355
  get region(): string;
356
+ private _deviceId;
357
+ /**
358
+ * Country or region, like CN
359
+ */
360
+ get deviceId(): string;
361
+ protected set deviceId(value: string);
337
362
  /**
338
363
  * Label delegate
339
364
  */
@@ -374,10 +399,6 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
374
399
  * Device id field name
375
400
  */
376
401
  protected deviceIdField: string;
377
- /**
378
- * Device id
379
- */
380
- protected deviceId: string;
381
402
  /**
382
403
  * Passphrase for encryption
383
404
  */
@@ -434,10 +455,17 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
434
455
  * Decrypt message
435
456
  * @param messageEncrypted Encrypted message
436
457
  * @param passphrase Secret passphrase
458
+ * @returns Pure text
459
+ */
460
+ decrypt(messageEncrypted: string, passphrase?: string): string | undefined;
461
+ /**
462
+ * Enhanced decrypt message
463
+ * @param messageEncrypted Encrypted message
464
+ * @param passphrase Secret passphrase
437
465
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
438
466
  * @returns Pure text
439
467
  */
440
- decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
468
+ decryptEnhanced(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
441
469
  /**
442
470
  * Detect IP data, call only one time
443
471
  * @param callback Callback will be called when the IP is ready
@@ -452,6 +480,14 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
452
480
  * @returns Result
453
481
  */
454
482
  encrypt(message: string, passphrase?: string, iterations?: number): string;
483
+ /**
484
+ * Enhanced encrypt message
485
+ * @param message Message
486
+ * @param passphrase Secret passphrase
487
+ * @param iterations Iterations, 1000 times, 1 - 99
488
+ * @returns Result
489
+ */
490
+ encryptEnhanced(message: string, passphrase?: string, iterations?: number): string;
455
491
  /**
456
492
  * Enchance secret passphrase
457
493
  * @param passphrase Secret passphrase
@@ -17,6 +17,7 @@ export class CoreApp {
17
17
  * @param name Application name
18
18
  */
19
19
  constructor(settings, api, notifier, name) {
20
+ this._deviceId = '***';
20
21
  /**
21
22
  * Response token header field name
22
23
  */
@@ -69,6 +70,15 @@ export class CoreApp {
69
70
  get region() {
70
71
  return this._region;
71
72
  }
73
+ /**
74
+ * Country or region, like CN
75
+ */
76
+ get deviceId() {
77
+ return this._deviceId;
78
+ }
79
+ set deviceId(value) {
80
+ this._deviceId = value;
81
+ }
72
82
  /**
73
83
  * Label delegate
74
84
  */
@@ -151,6 +161,8 @@ export class CoreApp {
151
161
  }
152
162
  if (callback)
153
163
  callback(false);
164
+ // Clear device id
165
+ StorageUtils.setLocalData(this.deviceIdField, null);
154
166
  return;
155
167
  }
156
168
  this.initCallUpdate(result.data, data.timestamp);
@@ -167,7 +179,7 @@ export class CoreApp {
167
179
  return;
168
180
  // Decrypt
169
181
  // Should be done within 120 seconds after returning from the backend
170
- const passphrase = this.decrypt(data.passphrase, timestamp.toString(), 120);
182
+ const passphrase = this.decrypt(data.passphrase, timestamp.toString());
171
183
  if (passphrase == null)
172
184
  return;
173
185
  // Update device id and cache it
@@ -177,17 +189,17 @@ export class CoreApp {
177
189
  this.passphrase = passphrase;
178
190
  // Previous passphrase
179
191
  if (data.previousPassphrase) {
180
- const prev = this.decrypt(data.previousPassphrase, timestamp.toString(), 120);
192
+ const prev = this.decrypt(data.previousPassphrase, timestamp.toString());
181
193
  // Update
182
194
  const fields = this.initCallUpdateFields();
183
195
  for (const field of fields) {
184
196
  const currentValue = StorageUtils.getLocalData(field, '');
185
197
  if (currentValue === '' || currentValue.indexOf('+') === -1)
186
198
  continue;
187
- const newValueSource = this.decrypt(currentValue, prev, 12);
199
+ const newValueSource = this.decryptEnhanced(currentValue, prev, 12);
188
200
  if (newValueSource == null)
189
201
  continue;
190
- const newValue = this.encrypt(newValueSource);
202
+ const newValue = this.encryptEnhanced(newValueSource);
191
203
  StorageUtils.setLocalData(field, newValue);
192
204
  }
193
205
  }
@@ -291,16 +303,41 @@ export class CoreApp {
291
303
  * Decrypt message
292
304
  * @param messageEncrypted Encrypted message
293
305
  * @param passphrase Secret passphrase
306
+ * @returns Pure text
307
+ */
308
+ decrypt(messageEncrypted, passphrase) {
309
+ // Iterations
310
+ const iterations = parseInt(messageEncrypted.substring(0, 2), 10);
311
+ if (isNaN(iterations))
312
+ return undefined;
313
+ const salt = enc.Hex.parse(messageEncrypted.substring(2, 34));
314
+ const iv = enc.Hex.parse(messageEncrypted.substring(34, 66));
315
+ const encrypted = messageEncrypted.substring(66);
316
+ const key = PBKDF2(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, salt, {
317
+ keySize: 8,
318
+ hasher: algo.SHA256,
319
+ iterations: 1000 * iterations
320
+ });
321
+ return AES.decrypt(encrypted, key, {
322
+ iv,
323
+ padding: pad.Pkcs7,
324
+ mode: mode.CBC
325
+ }).toString(enc.Utf8);
326
+ }
327
+ /**
328
+ * Enhanced decrypt message
329
+ * @param messageEncrypted Encrypted message
330
+ * @param passphrase Secret passphrase
294
331
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
295
332
  * @returns Pure text
296
333
  */
297
- decrypt(messageEncrypted, passphrase, durationSeconds) {
334
+ decryptEnhanced(messageEncrypted, passphrase, durationSeconds) {
298
335
  // Timestamp splitter
299
- const pos = messageEncrypted.indexOf('+');
300
- if (pos === -1 || messageEncrypted.length <= 66)
336
+ const pos = messageEncrypted.indexOf('!');
337
+ // Miliseconds chars are longer than 8
338
+ if (pos < 8 || messageEncrypted.length <= 66)
301
339
  return undefined;
302
340
  const timestamp = messageEncrypted.substring(0, pos);
303
- const message = messageEncrypted.substring(pos + 1);
304
341
  if (durationSeconds != null && durationSeconds > 0) {
305
342
  const milseconds = Utils.charsToNumber(timestamp);
306
343
  if (isNaN(milseconds) || milseconds < 1)
@@ -312,23 +349,9 @@ export class CoreApp {
312
349
  timespan.totalSeconds > durationSeconds))
313
350
  return undefined;
314
351
  }
315
- // Iterations
316
- const iterations = parseInt(message.substring(0, 2), 10);
317
- if (isNaN(iterations))
318
- return undefined;
319
- const salt = enc.Hex.parse(message.substring(2, 34));
320
- const iv = enc.Hex.parse(message.substring(34, 66));
321
- const encrypted = message.substring(66);
322
- const key = PBKDF2(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
323
- keySize: 8,
324
- hasher: algo.SHA256,
325
- iterations: 1000 * iterations
326
- });
327
- return AES.decrypt(encrypted, key, {
328
- iv,
329
- padding: pad.Pkcs7,
330
- mode: mode.CBC
331
- }).toString(enc.Utf8);
352
+ const message = messageEncrypted.substring(pos + 1);
353
+ passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
354
+ return this.decrypt(message, passphrase);
332
355
  }
333
356
  /**
334
357
  * Detect IP data, call only one time
@@ -373,19 +396,15 @@ export class CoreApp {
373
396
  encrypt(message, passphrase, iterations) {
374
397
  // Default 1 * 1000
375
398
  iterations !== null && iterations !== void 0 ? iterations : (iterations = 1);
376
- // Timestamp
377
- const timestamp = Utils.numberToChars(new Date().getTime());
378
399
  const bits = 16; // 128 / 8
379
400
  const salt = lib.WordArray.random(bits);
380
- const key = PBKDF2(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
401
+ const key = PBKDF2(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, salt, {
381
402
  keySize: 8,
382
403
  hasher: algo.SHA256,
383
404
  iterations: 1000 * iterations
384
405
  });
385
406
  const iv = lib.WordArray.random(bits);
386
- return (timestamp +
387
- '+' +
388
- iterations.toString().padStart(2, '0') +
407
+ return (iterations.toString().padStart(2, '0') +
389
408
  salt.toString(enc.Hex) +
390
409
  iv.toString(enc.Hex) +
391
410
  AES.encrypt(message, key, {
@@ -395,6 +414,19 @@ export class CoreApp {
395
414
  }).toString() // enc.Base64
396
415
  );
397
416
  }
417
+ /**
418
+ * Enhanced encrypt message
419
+ * @param message Message
420
+ * @param passphrase Secret passphrase
421
+ * @param iterations Iterations, 1000 times, 1 - 99
422
+ * @returns Result
423
+ */
424
+ encryptEnhanced(message, passphrase, iterations) {
425
+ // Timestamp
426
+ const timestamp = Utils.numberToChars(new Date().getTime());
427
+ passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
428
+ return timestamp + '!' + this.encrypt(message, passphrase, iterations);
429
+ }
398
430
  /**
399
431
  * Enchance secret passphrase
400
432
  * @param passphrase Secret passphrase
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/appscript",
3
- "version": "1.1.70",
3
+ "version": "1.1.74",
4
4
  "description": "Applications shared TypeScript framework",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -117,6 +117,11 @@ export interface ICoreApp<
117
117
  */
118
118
  readonly currency: string;
119
119
 
120
+ /**
121
+ * Device id
122
+ */
123
+ readonly deviceId: string;
124
+
120
125
  /**
121
126
  * Country or region, like CN
122
127
  */
@@ -177,10 +182,18 @@ export interface ICoreApp<
177
182
  * Decrypt message
178
183
  * @param messageEncrypted Encrypted message
179
184
  * @param passphrase Secret passphrase
185
+ * @returns Pure text
186
+ */
187
+ decrypt(messageEncrypted: string, passphrase?: string): string | undefined;
188
+
189
+ /**
190
+ * Enhanced decrypt message
191
+ * @param messageEncrypted Encrypted message
192
+ * @param passphrase Secret passphrase
180
193
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
181
194
  * @returns Pure text
182
195
  */
183
- decrypt(
196
+ decryptEnhanced(
184
197
  messageEncrypted: string,
185
198
  passphrase?: string,
186
199
  durationSeconds?: number
@@ -201,6 +214,19 @@ export interface ICoreApp<
201
214
  */
202
215
  encrypt(message: string, passphrase?: string, iterations?: number): string;
203
216
 
217
+ /**
218
+ * Enhanced encrypt message
219
+ * @param message Message
220
+ * @param passphrase Secret passphrase
221
+ * @param iterations Iterations, 1000 times, 1 - 99
222
+ * @returns Result
223
+ */
224
+ encryptEnhanced(
225
+ message: string,
226
+ passphrase?: string,
227
+ iterations?: number
228
+ ): string;
229
+
204
230
  /**
205
231
  * Format date to string
206
232
  * @param input Input date
@@ -457,6 +483,17 @@ export abstract class CoreApp<
457
483
  return this._region;
458
484
  }
459
485
 
486
+ private _deviceId: string = '***';
487
+ /**
488
+ * Country or region, like CN
489
+ */
490
+ get deviceId() {
491
+ return this._deviceId;
492
+ }
493
+ protected set deviceId(value: string) {
494
+ this._deviceId = value;
495
+ }
496
+
460
497
  /**
461
498
  * Label delegate
462
499
  */
@@ -516,11 +553,6 @@ export abstract class CoreApp<
516
553
  */
517
554
  protected deviceIdField: string = 'SmartERPDeviceId';
518
555
 
519
- /**
520
- * Device id
521
- */
522
- protected deviceId: string;
523
-
524
556
  /**
525
557
  * Passphrase for encryption
526
558
  */
@@ -637,6 +669,9 @@ export abstract class CoreApp<
637
669
 
638
670
  if (callback) callback(false);
639
671
 
672
+ // Clear device id
673
+ StorageUtils.setLocalData(this.deviceIdField, null);
674
+
640
675
  return;
641
676
  }
642
677
 
@@ -655,11 +690,7 @@ export abstract class CoreApp<
655
690
 
656
691
  // Decrypt
657
692
  // Should be done within 120 seconds after returning from the backend
658
- const passphrase = this.decrypt(
659
- data.passphrase,
660
- timestamp.toString(),
661
- 120
662
- );
693
+ const passphrase = this.decrypt(data.passphrase, timestamp.toString());
663
694
  if (passphrase == null) return;
664
695
 
665
696
  // Update device id and cache it
@@ -673,8 +704,7 @@ export abstract class CoreApp<
673
704
  if (data.previousPassphrase) {
674
705
  const prev = this.decrypt(
675
706
  data.previousPassphrase,
676
- timestamp.toString(),
677
- 120
707
+ timestamp.toString()
678
708
  );
679
709
 
680
710
  // Update
@@ -687,10 +717,14 @@ export abstract class CoreApp<
687
717
  if (currentValue === '' || currentValue.indexOf('+') === -1)
688
718
  continue;
689
719
 
690
- const newValueSource = this.decrypt(currentValue, prev, 12);
720
+ const newValueSource = this.decryptEnhanced(
721
+ currentValue,
722
+ prev,
723
+ 12
724
+ );
691
725
  if (newValueSource == null) continue;
692
726
 
693
- const newValue = this.encrypt(newValueSource);
727
+ const newValue = this.encryptEnhanced(newValueSource);
694
728
  StorageUtils.setLocalData(field, newValue);
695
729
  }
696
730
  }
@@ -819,20 +853,49 @@ export abstract class CoreApp<
819
853
  * Decrypt message
820
854
  * @param messageEncrypted Encrypted message
821
855
  * @param passphrase Secret passphrase
856
+ * @returns Pure text
857
+ */
858
+ decrypt(messageEncrypted: string, passphrase?: string) {
859
+ // Iterations
860
+ const iterations = parseInt(messageEncrypted.substring(0, 2), 10);
861
+ if (isNaN(iterations)) return undefined;
862
+
863
+ const salt = enc.Hex.parse(messageEncrypted.substring(2, 34));
864
+ const iv = enc.Hex.parse(messageEncrypted.substring(34, 66));
865
+ const encrypted = messageEncrypted.substring(66);
866
+
867
+ const key = PBKDF2(passphrase ?? this.passphrase, salt, {
868
+ keySize: 8, // 256 / 32
869
+ hasher: algo.SHA256,
870
+ iterations: 1000 * iterations
871
+ });
872
+
873
+ return AES.decrypt(encrypted, key, {
874
+ iv,
875
+ padding: pad.Pkcs7,
876
+ mode: mode.CBC
877
+ }).toString(enc.Utf8);
878
+ }
879
+
880
+ /**
881
+ * Enhanced decrypt message
882
+ * @param messageEncrypted Encrypted message
883
+ * @param passphrase Secret passphrase
822
884
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
823
885
  * @returns Pure text
824
886
  */
825
- decrypt(
887
+ decryptEnhanced(
826
888
  messageEncrypted: string,
827
889
  passphrase?: string,
828
890
  durationSeconds?: number
829
891
  ) {
830
892
  // Timestamp splitter
831
- const pos = messageEncrypted.indexOf('+');
832
- if (pos === -1 || messageEncrypted.length <= 66) return undefined;
893
+ const pos = messageEncrypted.indexOf('!');
894
+
895
+ // Miliseconds chars are longer than 8
896
+ if (pos < 8 || messageEncrypted.length <= 66) return undefined;
833
897
 
834
898
  const timestamp = messageEncrypted.substring(0, pos);
835
- const message = messageEncrypted.substring(pos + 1);
836
899
 
837
900
  if (durationSeconds != null && durationSeconds > 0) {
838
901
  const milseconds = Utils.charsToNumber(timestamp);
@@ -847,29 +910,13 @@ export abstract class CoreApp<
847
910
  return undefined;
848
911
  }
849
912
 
850
- // Iterations
851
- const iterations = parseInt(message.substring(0, 2), 10);
852
- if (isNaN(iterations)) return undefined;
853
-
854
- const salt = enc.Hex.parse(message.substring(2, 34));
855
- const iv = enc.Hex.parse(message.substring(34, 66));
856
- const encrypted = message.substring(66);
857
-
858
- const key = PBKDF2(
859
- this.encryptionEnhance(passphrase ?? this.passphrase, timestamp),
860
- salt,
861
- {
862
- keySize: 8, // 256 / 32
863
- hasher: algo.SHA256,
864
- iterations: 1000 * iterations
865
- }
913
+ const message = messageEncrypted.substring(pos + 1);
914
+ passphrase = this.encryptionEnhance(
915
+ passphrase ?? this.passphrase,
916
+ timestamp
866
917
  );
867
918
 
868
- return AES.decrypt(encrypted, key, {
869
- iv,
870
- padding: pad.Pkcs7,
871
- mode: mode.CBC
872
- }).toString(enc.Utf8);
919
+ return this.decrypt(message, passphrase);
873
920
  }
874
921
 
875
922
  /**
@@ -923,25 +970,16 @@ export abstract class CoreApp<
923
970
  // Default 1 * 1000
924
971
  iterations ??= 1;
925
972
 
926
- // Timestamp
927
- const timestamp = Utils.numberToChars(new Date().getTime());
928
-
929
973
  const bits = 16; // 128 / 8
930
974
  const salt = lib.WordArray.random(bits);
931
- const key = PBKDF2(
932
- this.encryptionEnhance(passphrase ?? this.passphrase, timestamp),
933
- salt,
934
- {
935
- keySize: 8, // 256 / 32
936
- hasher: algo.SHA256,
937
- iterations: 1000 * iterations
938
- }
939
- );
975
+ const key = PBKDF2(passphrase ?? this.passphrase, salt, {
976
+ keySize: 8, // 256 / 32
977
+ hasher: algo.SHA256,
978
+ iterations: 1000 * iterations
979
+ });
940
980
  const iv = lib.WordArray.random(bits);
941
981
 
942
982
  return (
943
- timestamp +
944
- '+' +
945
983
  iterations.toString().padStart(2, '0') +
946
984
  salt.toString(enc.Hex) +
947
985
  iv.toString(enc.Hex) +
@@ -953,6 +991,25 @@ export abstract class CoreApp<
953
991
  );
954
992
  }
955
993
 
994
+ /**
995
+ * Enhanced encrypt message
996
+ * @param message Message
997
+ * @param passphrase Secret passphrase
998
+ * @param iterations Iterations, 1000 times, 1 - 99
999
+ * @returns Result
1000
+ */
1001
+ encryptEnhanced(message: string, passphrase?: string, iterations?: number) {
1002
+ // Timestamp
1003
+ const timestamp = Utils.numberToChars(new Date().getTime());
1004
+
1005
+ passphrase = this.encryptionEnhance(
1006
+ passphrase ?? this.passphrase,
1007
+ timestamp
1008
+ );
1009
+
1010
+ return timestamp + '!' + this.encrypt(message, passphrase, iterations);
1011
+ }
1012
+
956
1013
  /**
957
1014
  * Enchance secret passphrase
958
1015
  * @param passphrase Secret passphrase