@etsoo/appscript 1.1.69 → 1.1.73

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
+ });
@@ -118,10 +118,17 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
118
118
  * Decrypt message
119
119
  * @param messageEncrypted Encrypted message
120
120
  * @param passphrase Secret passphrase
121
+ * @returns Pure text
122
+ */
123
+ decrypt(messageEncrypted: string, passphrase?: string): string | undefined;
124
+ /**
125
+ * Enhanced decrypt message
126
+ * @param messageEncrypted Encrypted message
127
+ * @param passphrase Secret passphrase
121
128
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
122
129
  * @returns Pure text
123
130
  */
124
- decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
131
+ decryptEnhanced(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
125
132
  /**
126
133
  * Detect IP data, call only one time
127
134
  * @param callback Callback will be called when the IP is ready
@@ -135,6 +142,14 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
135
142
  * @returns Result
136
143
  */
137
144
  encrypt(message: string, passphrase?: string, iterations?: number): string;
145
+ /**
146
+ * Enhanced encrypt message
147
+ * @param message Message
148
+ * @param passphrase Secret passphrase
149
+ * @param iterations Iterations, 1000 times, 1 - 99
150
+ * @returns Result
151
+ */
152
+ encryptEnhanced(message: string, passphrase?: string, iterations?: number): string;
138
153
  /**
139
154
  * Format date to string
140
155
  * @param input Input date
@@ -434,10 +449,17 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
434
449
  * Decrypt message
435
450
  * @param messageEncrypted Encrypted message
436
451
  * @param passphrase Secret passphrase
452
+ * @returns Pure text
453
+ */
454
+ decrypt(messageEncrypted: string, passphrase?: string): string | undefined;
455
+ /**
456
+ * Enhanced decrypt message
457
+ * @param messageEncrypted Encrypted message
458
+ * @param passphrase Secret passphrase
437
459
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
438
460
  * @returns Pure text
439
461
  */
440
- decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
462
+ decryptEnhanced(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
441
463
  /**
442
464
  * Detect IP data, call only one time
443
465
  * @param callback Callback will be called when the IP is ready
@@ -452,6 +474,14 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
452
474
  * @returns Result
453
475
  */
454
476
  encrypt(message: string, passphrase?: string, iterations?: number): string;
477
+ /**
478
+ * Enhanced encrypt message
479
+ * @param message Message
480
+ * @param passphrase Secret passphrase
481
+ * @param iterations Iterations, 1000 times, 1 - 99
482
+ * @returns Result
483
+ */
484
+ encryptEnhanced(message: string, passphrase?: string, iterations?: number): string;
455
485
  /**
456
486
  * Enchance secret passphrase
457
487
  * @param passphrase Secret passphrase
@@ -154,6 +154,8 @@ class CoreApp {
154
154
  }
155
155
  if (callback)
156
156
  callback(false);
157
+ // Clear device id
158
+ shared_1.StorageUtils.setLocalData(this.deviceIdField, null);
157
159
  return;
158
160
  }
159
161
  this.initCallUpdate(result.data, data.timestamp);
@@ -170,7 +172,7 @@ class CoreApp {
170
172
  return;
171
173
  // Decrypt
172
174
  // Should be done within 120 seconds after returning from the backend
173
- const passphrase = this.decrypt(data.passphrase, timestamp.toString(), 120);
175
+ const passphrase = this.decrypt(data.passphrase, timestamp.toString());
174
176
  if (passphrase == null)
175
177
  return;
176
178
  // Update device id and cache it
@@ -180,17 +182,17 @@ class CoreApp {
180
182
  this.passphrase = passphrase;
181
183
  // Previous passphrase
182
184
  if (data.previousPassphrase) {
183
- const prev = this.decrypt(data.previousPassphrase, timestamp.toString(), 120);
185
+ const prev = this.decrypt(data.previousPassphrase, timestamp.toString());
184
186
  // Update
185
187
  const fields = this.initCallUpdateFields();
186
188
  for (const field of fields) {
187
189
  const currentValue = shared_1.StorageUtils.getLocalData(field, '');
188
190
  if (currentValue === '' || currentValue.indexOf('+') === -1)
189
191
  continue;
190
- const newValueSource = this.decrypt(currentValue, prev, 12);
192
+ const newValueSource = this.decryptEnhanced(currentValue, prev, 12);
191
193
  if (newValueSource == null)
192
194
  continue;
193
- const newValue = this.encrypt(newValueSource);
195
+ const newValue = this.encryptEnhanced(newValueSource);
194
196
  shared_1.StorageUtils.setLocalData(field, newValue);
195
197
  }
196
198
  }
@@ -294,16 +296,41 @@ class CoreApp {
294
296
  * Decrypt message
295
297
  * @param messageEncrypted Encrypted message
296
298
  * @param passphrase Secret passphrase
299
+ * @returns Pure text
300
+ */
301
+ decrypt(messageEncrypted, passphrase) {
302
+ // Iterations
303
+ const iterations = parseInt(messageEncrypted.substring(0, 2), 10);
304
+ if (isNaN(iterations))
305
+ return undefined;
306
+ const salt = crypto_js_1.enc.Hex.parse(messageEncrypted.substring(2, 34));
307
+ const iv = crypto_js_1.enc.Hex.parse(messageEncrypted.substring(34, 66));
308
+ const encrypted = messageEncrypted.substring(66);
309
+ const key = (0, crypto_js_1.PBKDF2)(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, salt, {
310
+ keySize: 8,
311
+ hasher: crypto_js_1.algo.SHA256,
312
+ iterations: 1000 * iterations
313
+ });
314
+ return crypto_js_1.AES.decrypt(encrypted, key, {
315
+ iv,
316
+ padding: crypto_js_1.pad.Pkcs7,
317
+ mode: crypto_js_1.mode.CBC
318
+ }).toString(crypto_js_1.enc.Utf8);
319
+ }
320
+ /**
321
+ * Enhanced decrypt message
322
+ * @param messageEncrypted Encrypted message
323
+ * @param passphrase Secret passphrase
297
324
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
298
325
  * @returns Pure text
299
326
  */
300
- decrypt(messageEncrypted, passphrase, durationSeconds) {
327
+ decryptEnhanced(messageEncrypted, passphrase, durationSeconds) {
301
328
  // Timestamp splitter
302
- const pos = messageEncrypted.indexOf('+');
303
- if (pos === -1 || messageEncrypted.length <= 66)
329
+ const pos = messageEncrypted.indexOf('!');
330
+ // Miliseconds chars are longer than 8
331
+ if (pos < 8 || messageEncrypted.length <= 66)
304
332
  return undefined;
305
333
  const timestamp = messageEncrypted.substring(0, pos);
306
- const message = messageEncrypted.substring(pos + 1);
307
334
  if (durationSeconds != null && durationSeconds > 0) {
308
335
  const milseconds = shared_1.Utils.charsToNumber(timestamp);
309
336
  if (isNaN(milseconds) || milseconds < 1)
@@ -315,23 +342,9 @@ class CoreApp {
315
342
  timespan.totalSeconds > durationSeconds))
316
343
  return undefined;
317
344
  }
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);
345
+ const message = messageEncrypted.substring(pos + 1);
346
+ passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
347
+ return this.decrypt(message, passphrase);
335
348
  }
336
349
  /**
337
350
  * Detect IP data, call only one time
@@ -376,19 +389,15 @@ class CoreApp {
376
389
  encrypt(message, passphrase, iterations) {
377
390
  // Default 1 * 1000
378
391
  iterations !== null && iterations !== void 0 ? iterations : (iterations = 1);
379
- // Timestamp
380
- const timestamp = shared_1.Utils.numberToChars(new Date().getTime());
381
392
  const bits = 16; // 128 / 8
382
393
  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, {
394
+ const key = (0, crypto_js_1.PBKDF2)(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, salt, {
384
395
  keySize: 8,
385
396
  hasher: crypto_js_1.algo.SHA256,
386
397
  iterations: 1000 * iterations
387
398
  });
388
399
  const iv = crypto_js_1.lib.WordArray.random(bits);
389
- return (timestamp +
390
- '+' +
391
- iterations.toString().padStart(2, '0') +
400
+ return (iterations.toString().padStart(2, '0') +
392
401
  salt.toString(crypto_js_1.enc.Hex) +
393
402
  iv.toString(crypto_js_1.enc.Hex) +
394
403
  crypto_js_1.AES.encrypt(message, key, {
@@ -398,6 +407,19 @@ class CoreApp {
398
407
  }).toString() // enc.Base64
399
408
  );
400
409
  }
410
+ /**
411
+ * Enhanced encrypt message
412
+ * @param message Message
413
+ * @param passphrase Secret passphrase
414
+ * @param iterations Iterations, 1000 times, 1 - 99
415
+ * @returns Result
416
+ */
417
+ encryptEnhanced(message, passphrase, iterations) {
418
+ // Timestamp
419
+ const timestamp = shared_1.Utils.numberToChars(new Date().getTime());
420
+ passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
421
+ return timestamp + '!' + this.encrypt(message, passphrase, iterations);
422
+ }
401
423
  /**
402
424
  * Enchance secret passphrase
403
425
  * @param passphrase Secret passphrase
@@ -118,10 +118,17 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
118
118
  * Decrypt message
119
119
  * @param messageEncrypted Encrypted message
120
120
  * @param passphrase Secret passphrase
121
+ * @returns Pure text
122
+ */
123
+ decrypt(messageEncrypted: string, passphrase?: string): string | undefined;
124
+ /**
125
+ * Enhanced decrypt message
126
+ * @param messageEncrypted Encrypted message
127
+ * @param passphrase Secret passphrase
121
128
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
122
129
  * @returns Pure text
123
130
  */
124
- decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
131
+ decryptEnhanced(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
125
132
  /**
126
133
  * Detect IP data, call only one time
127
134
  * @param callback Callback will be called when the IP is ready
@@ -135,6 +142,14 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
135
142
  * @returns Result
136
143
  */
137
144
  encrypt(message: string, passphrase?: string, iterations?: number): string;
145
+ /**
146
+ * Enhanced encrypt message
147
+ * @param message Message
148
+ * @param passphrase Secret passphrase
149
+ * @param iterations Iterations, 1000 times, 1 - 99
150
+ * @returns Result
151
+ */
152
+ encryptEnhanced(message: string, passphrase?: string, iterations?: number): string;
138
153
  /**
139
154
  * Format date to string
140
155
  * @param input Input date
@@ -434,10 +449,17 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
434
449
  * Decrypt message
435
450
  * @param messageEncrypted Encrypted message
436
451
  * @param passphrase Secret passphrase
452
+ * @returns Pure text
453
+ */
454
+ decrypt(messageEncrypted: string, passphrase?: string): string | undefined;
455
+ /**
456
+ * Enhanced decrypt message
457
+ * @param messageEncrypted Encrypted message
458
+ * @param passphrase Secret passphrase
437
459
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
438
460
  * @returns Pure text
439
461
  */
440
- decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
462
+ decryptEnhanced(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
441
463
  /**
442
464
  * Detect IP data, call only one time
443
465
  * @param callback Callback will be called when the IP is ready
@@ -452,6 +474,14 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
452
474
  * @returns Result
453
475
  */
454
476
  encrypt(message: string, passphrase?: string, iterations?: number): string;
477
+ /**
478
+ * Enhanced encrypt message
479
+ * @param message Message
480
+ * @param passphrase Secret passphrase
481
+ * @param iterations Iterations, 1000 times, 1 - 99
482
+ * @returns Result
483
+ */
484
+ encryptEnhanced(message: string, passphrase?: string, iterations?: number): string;
455
485
  /**
456
486
  * Enchance secret passphrase
457
487
  * @param passphrase Secret passphrase
@@ -151,6 +151,8 @@ export class CoreApp {
151
151
  }
152
152
  if (callback)
153
153
  callback(false);
154
+ // Clear device id
155
+ StorageUtils.setLocalData(this.deviceIdField, null);
154
156
  return;
155
157
  }
156
158
  this.initCallUpdate(result.data, data.timestamp);
@@ -167,7 +169,7 @@ export class CoreApp {
167
169
  return;
168
170
  // Decrypt
169
171
  // Should be done within 120 seconds after returning from the backend
170
- const passphrase = this.decrypt(data.passphrase, timestamp.toString(), 120);
172
+ const passphrase = this.decrypt(data.passphrase, timestamp.toString());
171
173
  if (passphrase == null)
172
174
  return;
173
175
  // Update device id and cache it
@@ -177,17 +179,17 @@ export class CoreApp {
177
179
  this.passphrase = passphrase;
178
180
  // Previous passphrase
179
181
  if (data.previousPassphrase) {
180
- const prev = this.decrypt(data.previousPassphrase, timestamp.toString(), 120);
182
+ const prev = this.decrypt(data.previousPassphrase, timestamp.toString());
181
183
  // Update
182
184
  const fields = this.initCallUpdateFields();
183
185
  for (const field of fields) {
184
186
  const currentValue = StorageUtils.getLocalData(field, '');
185
187
  if (currentValue === '' || currentValue.indexOf('+') === -1)
186
188
  continue;
187
- const newValueSource = this.decrypt(currentValue, prev, 12);
189
+ const newValueSource = this.decryptEnhanced(currentValue, prev, 12);
188
190
  if (newValueSource == null)
189
191
  continue;
190
- const newValue = this.encrypt(newValueSource);
192
+ const newValue = this.encryptEnhanced(newValueSource);
191
193
  StorageUtils.setLocalData(field, newValue);
192
194
  }
193
195
  }
@@ -291,16 +293,41 @@ export class CoreApp {
291
293
  * Decrypt message
292
294
  * @param messageEncrypted Encrypted message
293
295
  * @param passphrase Secret passphrase
296
+ * @returns Pure text
297
+ */
298
+ decrypt(messageEncrypted, passphrase) {
299
+ // Iterations
300
+ const iterations = parseInt(messageEncrypted.substring(0, 2), 10);
301
+ if (isNaN(iterations))
302
+ return undefined;
303
+ const salt = enc.Hex.parse(messageEncrypted.substring(2, 34));
304
+ const iv = enc.Hex.parse(messageEncrypted.substring(34, 66));
305
+ const encrypted = messageEncrypted.substring(66);
306
+ const key = PBKDF2(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, salt, {
307
+ keySize: 8,
308
+ hasher: algo.SHA256,
309
+ iterations: 1000 * iterations
310
+ });
311
+ return AES.decrypt(encrypted, key, {
312
+ iv,
313
+ padding: pad.Pkcs7,
314
+ mode: mode.CBC
315
+ }).toString(enc.Utf8);
316
+ }
317
+ /**
318
+ * Enhanced decrypt message
319
+ * @param messageEncrypted Encrypted message
320
+ * @param passphrase Secret passphrase
294
321
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
295
322
  * @returns Pure text
296
323
  */
297
- decrypt(messageEncrypted, passphrase, durationSeconds) {
324
+ decryptEnhanced(messageEncrypted, passphrase, durationSeconds) {
298
325
  // Timestamp splitter
299
- const pos = messageEncrypted.indexOf('+');
300
- if (pos === -1 || messageEncrypted.length <= 66)
326
+ const pos = messageEncrypted.indexOf('!');
327
+ // Miliseconds chars are longer than 8
328
+ if (pos < 8 || messageEncrypted.length <= 66)
301
329
  return undefined;
302
330
  const timestamp = messageEncrypted.substring(0, pos);
303
- const message = messageEncrypted.substring(pos + 1);
304
331
  if (durationSeconds != null && durationSeconds > 0) {
305
332
  const milseconds = Utils.charsToNumber(timestamp);
306
333
  if (isNaN(milseconds) || milseconds < 1)
@@ -312,23 +339,9 @@ export class CoreApp {
312
339
  timespan.totalSeconds > durationSeconds))
313
340
  return undefined;
314
341
  }
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);
342
+ const message = messageEncrypted.substring(pos + 1);
343
+ passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
344
+ return this.decrypt(message, passphrase);
332
345
  }
333
346
  /**
334
347
  * Detect IP data, call only one time
@@ -373,19 +386,15 @@ export class CoreApp {
373
386
  encrypt(message, passphrase, iterations) {
374
387
  // Default 1 * 1000
375
388
  iterations !== null && iterations !== void 0 ? iterations : (iterations = 1);
376
- // Timestamp
377
- const timestamp = Utils.numberToChars(new Date().getTime());
378
389
  const bits = 16; // 128 / 8
379
390
  const salt = lib.WordArray.random(bits);
380
- const key = PBKDF2(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
391
+ const key = PBKDF2(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, salt, {
381
392
  keySize: 8,
382
393
  hasher: algo.SHA256,
383
394
  iterations: 1000 * iterations
384
395
  });
385
396
  const iv = lib.WordArray.random(bits);
386
- return (timestamp +
387
- '+' +
388
- iterations.toString().padStart(2, '0') +
397
+ return (iterations.toString().padStart(2, '0') +
389
398
  salt.toString(enc.Hex) +
390
399
  iv.toString(enc.Hex) +
391
400
  AES.encrypt(message, key, {
@@ -395,6 +404,19 @@ export class CoreApp {
395
404
  }).toString() // enc.Base64
396
405
  );
397
406
  }
407
+ /**
408
+ * Enhanced encrypt message
409
+ * @param message Message
410
+ * @param passphrase Secret passphrase
411
+ * @param iterations Iterations, 1000 times, 1 - 99
412
+ * @returns Result
413
+ */
414
+ encryptEnhanced(message, passphrase, iterations) {
415
+ // Timestamp
416
+ const timestamp = Utils.numberToChars(new Date().getTime());
417
+ passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
418
+ return timestamp + '!' + this.encrypt(message, passphrase, iterations);
419
+ }
398
420
  /**
399
421
  * Enchance secret passphrase
400
422
  * @param passphrase Secret passphrase
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/appscript",
3
- "version": "1.1.69",
3
+ "version": "1.1.73",
4
4
  "description": "Applications shared TypeScript framework",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -70,8 +70,8 @@
70
70
  "eslint": "^8.4.1",
71
71
  "eslint-config-airbnb-base": "^15.0.0",
72
72
  "eslint-plugin-import": "^2.25.3",
73
- "jest": "^27.4.3",
74
- "ts-jest": "^27.1.0",
75
- "typescript": "^4.5.2"
73
+ "jest": "^27.4.4",
74
+ "ts-jest": "^27.1.1",
75
+ "typescript": "^4.5.3"
76
76
  }
77
77
  }
@@ -177,10 +177,18 @@ export interface ICoreApp<
177
177
  * Decrypt message
178
178
  * @param messageEncrypted Encrypted message
179
179
  * @param passphrase Secret passphrase
180
+ * @returns Pure text
181
+ */
182
+ decrypt(messageEncrypted: string, passphrase?: string): string | undefined;
183
+
184
+ /**
185
+ * Enhanced decrypt message
186
+ * @param messageEncrypted Encrypted message
187
+ * @param passphrase Secret passphrase
180
188
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
181
189
  * @returns Pure text
182
190
  */
183
- decrypt(
191
+ decryptEnhanced(
184
192
  messageEncrypted: string,
185
193
  passphrase?: string,
186
194
  durationSeconds?: number
@@ -201,6 +209,19 @@ export interface ICoreApp<
201
209
  */
202
210
  encrypt(message: string, passphrase?: string, iterations?: number): string;
203
211
 
212
+ /**
213
+ * Enhanced encrypt message
214
+ * @param message Message
215
+ * @param passphrase Secret passphrase
216
+ * @param iterations Iterations, 1000 times, 1 - 99
217
+ * @returns Result
218
+ */
219
+ encryptEnhanced(
220
+ message: string,
221
+ passphrase?: string,
222
+ iterations?: number
223
+ ): string;
224
+
204
225
  /**
205
226
  * Format date to string
206
227
  * @param input Input date
@@ -637,6 +658,9 @@ export abstract class CoreApp<
637
658
 
638
659
  if (callback) callback(false);
639
660
 
661
+ // Clear device id
662
+ StorageUtils.setLocalData(this.deviceIdField, null);
663
+
640
664
  return;
641
665
  }
642
666
 
@@ -655,11 +679,7 @@ export abstract class CoreApp<
655
679
 
656
680
  // Decrypt
657
681
  // 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
- );
682
+ const passphrase = this.decrypt(data.passphrase, timestamp.toString());
663
683
  if (passphrase == null) return;
664
684
 
665
685
  // Update device id and cache it
@@ -673,8 +693,7 @@ export abstract class CoreApp<
673
693
  if (data.previousPassphrase) {
674
694
  const prev = this.decrypt(
675
695
  data.previousPassphrase,
676
- timestamp.toString(),
677
- 120
696
+ timestamp.toString()
678
697
  );
679
698
 
680
699
  // Update
@@ -687,10 +706,14 @@ export abstract class CoreApp<
687
706
  if (currentValue === '' || currentValue.indexOf('+') === -1)
688
707
  continue;
689
708
 
690
- const newValueSource = this.decrypt(currentValue, prev, 12);
709
+ const newValueSource = this.decryptEnhanced(
710
+ currentValue,
711
+ prev,
712
+ 12
713
+ );
691
714
  if (newValueSource == null) continue;
692
715
 
693
- const newValue = this.encrypt(newValueSource);
716
+ const newValue = this.encryptEnhanced(newValueSource);
694
717
  StorageUtils.setLocalData(field, newValue);
695
718
  }
696
719
  }
@@ -819,20 +842,49 @@ export abstract class CoreApp<
819
842
  * Decrypt message
820
843
  * @param messageEncrypted Encrypted message
821
844
  * @param passphrase Secret passphrase
845
+ * @returns Pure text
846
+ */
847
+ decrypt(messageEncrypted: string, passphrase?: string) {
848
+ // Iterations
849
+ const iterations = parseInt(messageEncrypted.substring(0, 2), 10);
850
+ if (isNaN(iterations)) return undefined;
851
+
852
+ const salt = enc.Hex.parse(messageEncrypted.substring(2, 34));
853
+ const iv = enc.Hex.parse(messageEncrypted.substring(34, 66));
854
+ const encrypted = messageEncrypted.substring(66);
855
+
856
+ const key = PBKDF2(passphrase ?? this.passphrase, salt, {
857
+ keySize: 8, // 256 / 32
858
+ hasher: algo.SHA256,
859
+ iterations: 1000 * iterations
860
+ });
861
+
862
+ return AES.decrypt(encrypted, key, {
863
+ iv,
864
+ padding: pad.Pkcs7,
865
+ mode: mode.CBC
866
+ }).toString(enc.Utf8);
867
+ }
868
+
869
+ /**
870
+ * Enhanced decrypt message
871
+ * @param messageEncrypted Encrypted message
872
+ * @param passphrase Secret passphrase
822
873
  * @param durationSeconds Duration seconds, <= 12 will be considered as month
823
874
  * @returns Pure text
824
875
  */
825
- decrypt(
876
+ decryptEnhanced(
826
877
  messageEncrypted: string,
827
878
  passphrase?: string,
828
879
  durationSeconds?: number
829
880
  ) {
830
881
  // Timestamp splitter
831
- const pos = messageEncrypted.indexOf('+');
832
- if (pos === -1 || messageEncrypted.length <= 66) return undefined;
882
+ const pos = messageEncrypted.indexOf('!');
883
+
884
+ // Miliseconds chars are longer than 8
885
+ if (pos < 8 || messageEncrypted.length <= 66) return undefined;
833
886
 
834
887
  const timestamp = messageEncrypted.substring(0, pos);
835
- const message = messageEncrypted.substring(pos + 1);
836
888
 
837
889
  if (durationSeconds != null && durationSeconds > 0) {
838
890
  const milseconds = Utils.charsToNumber(timestamp);
@@ -847,29 +899,13 @@ export abstract class CoreApp<
847
899
  return undefined;
848
900
  }
849
901
 
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
- }
902
+ const message = messageEncrypted.substring(pos + 1);
903
+ passphrase = this.encryptionEnhance(
904
+ passphrase ?? this.passphrase,
905
+ timestamp
866
906
  );
867
907
 
868
- return AES.decrypt(encrypted, key, {
869
- iv,
870
- padding: pad.Pkcs7,
871
- mode: mode.CBC
872
- }).toString(enc.Utf8);
908
+ return this.decrypt(message, passphrase);
873
909
  }
874
910
 
875
911
  /**
@@ -923,25 +959,16 @@ export abstract class CoreApp<
923
959
  // Default 1 * 1000
924
960
  iterations ??= 1;
925
961
 
926
- // Timestamp
927
- const timestamp = Utils.numberToChars(new Date().getTime());
928
-
929
962
  const bits = 16; // 128 / 8
930
963
  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
- );
964
+ const key = PBKDF2(passphrase ?? this.passphrase, salt, {
965
+ keySize: 8, // 256 / 32
966
+ hasher: algo.SHA256,
967
+ iterations: 1000 * iterations
968
+ });
940
969
  const iv = lib.WordArray.random(bits);
941
970
 
942
971
  return (
943
- timestamp +
944
- '+' +
945
972
  iterations.toString().padStart(2, '0') +
946
973
  salt.toString(enc.Hex) +
947
974
  iv.toString(enc.Hex) +
@@ -953,6 +980,25 @@ export abstract class CoreApp<
953
980
  );
954
981
  }
955
982
 
983
+ /**
984
+ * Enhanced encrypt message
985
+ * @param message Message
986
+ * @param passphrase Secret passphrase
987
+ * @param iterations Iterations, 1000 times, 1 - 99
988
+ * @returns Result
989
+ */
990
+ encryptEnhanced(message: string, passphrase?: string, iterations?: number) {
991
+ // Timestamp
992
+ const timestamp = Utils.numberToChars(new Date().getTime());
993
+
994
+ passphrase = this.encryptionEnhance(
995
+ passphrase ?? this.passphrase,
996
+ timestamp
997
+ );
998
+
999
+ return timestamp + '!' + this.encrypt(message, passphrase, iterations);
1000
+ }
1001
+
956
1002
  /**
957
1003
  * Enchance secret passphrase
958
1004
  * @param passphrase Secret passphrase