@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.
- package/__tests__/app/CoreApp.ts +20 -0
- package/lib/cjs/app/CoreApp.d.ts +42 -6
- package/lib/cjs/app/CoreApp.js +63 -31
- package/lib/mjs/app/CoreApp.d.ts +42 -6
- package/lib/mjs/app/CoreApp.js +63 -31
- package/package.json +1 -1
- package/src/app/CoreApp.ts +111 -54
package/__tests__/app/CoreApp.ts
CHANGED
|
@@ -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
|
+
});
|
package/lib/cjs/app/CoreApp.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
package/lib/cjs/app/CoreApp.js
CHANGED
|
@@ -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()
|
|
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()
|
|
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.
|
|
202
|
+
const newValueSource = this.decryptEnhanced(currentValue, prev, 12);
|
|
191
203
|
if (newValueSource == null)
|
|
192
204
|
continue;
|
|
193
|
-
const newValue = this.
|
|
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
|
-
|
|
337
|
+
decryptEnhanced(messageEncrypted, passphrase, durationSeconds) {
|
|
301
338
|
// Timestamp splitter
|
|
302
|
-
const pos = messageEncrypted.indexOf('
|
|
303
|
-
|
|
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
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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)(
|
|
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 (
|
|
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
|
package/lib/mjs/app/CoreApp.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
package/lib/mjs/app/CoreApp.js
CHANGED
|
@@ -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()
|
|
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()
|
|
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.
|
|
199
|
+
const newValueSource = this.decryptEnhanced(currentValue, prev, 12);
|
|
188
200
|
if (newValueSource == null)
|
|
189
201
|
continue;
|
|
190
|
-
const newValue = this.
|
|
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
|
-
|
|
334
|
+
decryptEnhanced(messageEncrypted, passphrase, durationSeconds) {
|
|
298
335
|
// Timestamp splitter
|
|
299
|
-
const pos = messageEncrypted.indexOf('
|
|
300
|
-
|
|
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
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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(
|
|
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 (
|
|
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
package/src/app/CoreApp.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
720
|
+
const newValueSource = this.decryptEnhanced(
|
|
721
|
+
currentValue,
|
|
722
|
+
prev,
|
|
723
|
+
12
|
|
724
|
+
);
|
|
691
725
|
if (newValueSource == null) continue;
|
|
692
726
|
|
|
693
|
-
const newValue = this.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
851
|
-
|
|
852
|
-
|
|
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
|
|
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
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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
|