@etsoo/appscript 1.2.58 → 1.2.61
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/README.md +36 -11
- package/lib/cjs/app/CoreApp.d.ts +5 -3
- package/lib/cjs/app/CoreApp.js +64 -34
- package/lib/cjs/bridges/IBridgeHost.d.ts +1 -1
- package/lib/cjs/i18n/en-US.json +1 -0
- package/lib/cjs/i18n/zh-CN.json +1 -0
- package/lib/cjs/i18n/zh-HK.json +1 -0
- package/lib/mjs/app/CoreApp.d.ts +5 -3
- package/lib/mjs/app/CoreApp.js +64 -34
- package/lib/mjs/bridges/IBridgeHost.d.ts +1 -1
- package/lib/mjs/i18n/en-US.json +1 -0
- package/lib/mjs/i18n/zh-CN.json +1 -0
- package/lib/mjs/i18n/zh-HK.json +1 -0
- package/package.json +18 -17
- package/src/app/CoreApp.ts +79 -41
- package/src/bridges/IBridgeHost.ts +1 -1
- package/src/i18n/en-US.json +1 -0
- package/src/i18n/zh-CN.json +1 -0
- package/src/i18n/zh-HK.json +1 -0
package/README.md
CHANGED
|
@@ -15,6 +15,12 @@ Using yarn:
|
|
|
15
15
|
$ yarn add @etsoo/appscript
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
## Client data security framework
|
|
19
|
+
- CoreApp, constructor, reads deviceId from session storage
|
|
20
|
+
- restore, when deviceId is empty, try to restore from persisted storage, get the passphrase (encryption / decription) or remove all data keys
|
|
21
|
+
- initCall (everytime the application running), if passphrase is there, just return, otherwise read from serverside
|
|
22
|
+
- device updated will cause validataion failure. Please call initCall(undefined, true);
|
|
23
|
+
|
|
18
24
|
## Structure
|
|
19
25
|
|
|
20
26
|
### address - Address (region) related
|
|
@@ -44,18 +50,19 @@ $ yarn add @etsoo/appscript
|
|
|
44
50
|
- IExternalSettings - External settings items
|
|
45
51
|
- IExternalSettingsHost - External settings host passed by external script
|
|
46
52
|
|
|
53
|
+
#### UserRole.ts ####
|
|
54
|
+
- Standard user roles
|
|
55
|
+
|
|
47
56
|
### bridges - Works with Electron
|
|
48
57
|
|
|
49
|
-
####
|
|
50
|
-
-
|
|
58
|
+
#### BridgeUtils.ts ####
|
|
59
|
+
- BridgeUtils - Bridge utils
|
|
51
60
|
|
|
52
|
-
####
|
|
53
|
-
-
|
|
61
|
+
#### FlutterHost.ts ####
|
|
62
|
+
- FlutterHost - Flutter JavaScript Host
|
|
54
63
|
|
|
55
|
-
####
|
|
56
|
-
-
|
|
57
|
-
- IBridgeListener - Bridge listener interface
|
|
58
|
-
- IBridge - Bridge interface
|
|
64
|
+
#### IBridgeHost.ts ####
|
|
65
|
+
- IBridgeHost - Bridge host interface
|
|
59
66
|
|
|
60
67
|
### business - Business logics
|
|
61
68
|
|
|
@@ -71,9 +78,20 @@ $ yarn add @etsoo/appscript
|
|
|
71
78
|
- getUnits - Get all product units
|
|
72
79
|
- getRepeatOptions - Get all repeat options
|
|
73
80
|
|
|
81
|
+
#### EntityStatus.ts ####
|
|
82
|
+
- EntityStatus - Standard entity status enum
|
|
83
|
+
|
|
74
84
|
#### ProductUnit.ts ####
|
|
75
85
|
- ProductUnit - Product units enum
|
|
76
86
|
|
|
87
|
+
#### RepeatOption.ts ####
|
|
88
|
+
- RepeatOption - Repeat options
|
|
89
|
+
|
|
90
|
+
### def - Type definition
|
|
91
|
+
|
|
92
|
+
#### ListItem.ts ####
|
|
93
|
+
- ListItem - List item definition
|
|
94
|
+
|
|
77
95
|
### dto - Data transfer object
|
|
78
96
|
|
|
79
97
|
#### IdDto.ts ####
|
|
@@ -82,8 +100,11 @@ $ yarn add @etsoo/appscript
|
|
|
82
100
|
#### IdLabelDto.ts ####
|
|
83
101
|
- IdLabelDto - Dto with id and label field
|
|
84
102
|
|
|
85
|
-
####
|
|
86
|
-
-
|
|
103
|
+
#### IdLabelPrimaryDto.ts ####
|
|
104
|
+
- IdLabelPrimaryDto - Dto with id, label and primary field
|
|
105
|
+
|
|
106
|
+
#### IdLabelPrimaryDto.ts ####
|
|
107
|
+
- InitCallDto - Init call dto
|
|
87
108
|
|
|
88
109
|
### i18n - Multiple cultures
|
|
89
110
|
|
|
@@ -93,7 +114,7 @@ $ yarn add @etsoo/appscript
|
|
|
93
114
|
- ActionResult - API call action result extends IActionResult
|
|
94
115
|
|
|
95
116
|
#### ActionResultError.ts ####
|
|
96
|
-
- ActionResultError - Action result to error type
|
|
117
|
+
- ActionResultError - Action result to error type
|
|
97
118
|
|
|
98
119
|
#### IActionResult.ts ####
|
|
99
120
|
- IResultData - Result data interface
|
|
@@ -102,6 +123,10 @@ $ yarn add @etsoo/appscript
|
|
|
102
123
|
- IActionResult - Action result interface
|
|
103
124
|
- ActionResultId - Action result with id data
|
|
104
125
|
|
|
126
|
+
#### InitCallResultData.ts ####
|
|
127
|
+
- InitCallResultData - Init call result data
|
|
128
|
+
- InitCallResult - Init call result
|
|
129
|
+
|
|
105
130
|
### state - State management
|
|
106
131
|
|
|
107
132
|
#### Culture.ts ####
|
package/lib/cjs/app/CoreApp.d.ts
CHANGED
|
@@ -299,9 +299,10 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
|
|
|
299
299
|
/**
|
|
300
300
|
* Init call
|
|
301
301
|
* @param callback Callback
|
|
302
|
+
* @param resetKeys Reset all keys first
|
|
302
303
|
* @returns Result
|
|
303
304
|
*/
|
|
304
|
-
initCall(callback?: (result: boolean) => void): Promise<void>;
|
|
305
|
+
initCall(callback?: (result: boolean) => void, resetKeys?: boolean): Promise<void>;
|
|
305
306
|
/**
|
|
306
307
|
* Callback where exit a page
|
|
307
308
|
*/
|
|
@@ -513,15 +514,16 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
|
|
|
513
514
|
/**
|
|
514
515
|
* Init call
|
|
515
516
|
* @param callback Callback
|
|
517
|
+
* @param resetKeys Reset all keys first
|
|
516
518
|
* @returns Result
|
|
517
519
|
*/
|
|
518
|
-
initCall(callback?: (result: boolean) => void): Promise<void>;
|
|
520
|
+
initCall(callback?: (result: boolean) => void, resetKeys?: boolean): Promise<void>;
|
|
519
521
|
/**
|
|
520
522
|
* Init call update
|
|
521
523
|
* @param data Result data
|
|
522
524
|
* @param timestamp Timestamp
|
|
523
525
|
*/
|
|
524
|
-
protected initCallUpdate(data: InitCallResultData, timestamp: number):
|
|
526
|
+
protected initCallUpdate(data: InitCallResultData, timestamp: number): boolean;
|
|
525
527
|
/**
|
|
526
528
|
* Init call encrypted fields update
|
|
527
529
|
* @returns Fields
|
package/lib/cjs/app/CoreApp.js
CHANGED
|
@@ -179,9 +179,9 @@ class CoreApp {
|
|
|
179
179
|
this.resetKeys();
|
|
180
180
|
return false;
|
|
181
181
|
}
|
|
182
|
-
// this.name to identifier different app's secret
|
|
183
182
|
const passphraseEncrypted = this.storage.getData(this.fields.devicePassphrase);
|
|
184
183
|
if (passphraseEncrypted) {
|
|
184
|
+
// this.name to identifier different app's secret
|
|
185
185
|
const passphraseDecrypted = this.decrypt(passphraseEncrypted, this.name);
|
|
186
186
|
if (passphraseDecrypted != null) {
|
|
187
187
|
// Add the device to the list
|
|
@@ -258,10 +258,14 @@ class CoreApp {
|
|
|
258
258
|
/**
|
|
259
259
|
* Init call
|
|
260
260
|
* @param callback Callback
|
|
261
|
+
* @param resetKeys Reset all keys first
|
|
261
262
|
* @returns Result
|
|
262
263
|
*/
|
|
263
|
-
async initCall(callback) {
|
|
264
|
+
async initCall(callback, resetKeys) {
|
|
264
265
|
var _a;
|
|
266
|
+
// Reset keys
|
|
267
|
+
if (resetKeys)
|
|
268
|
+
this.resetKeys();
|
|
265
269
|
// Passphrase exists?
|
|
266
270
|
if (this.passphrase) {
|
|
267
271
|
if (callback)
|
|
@@ -280,11 +284,13 @@ class CoreApp {
|
|
|
280
284
|
};
|
|
281
285
|
const result = await this.apiInitCall(data);
|
|
282
286
|
if (result == null) {
|
|
287
|
+
// API error will popup
|
|
283
288
|
if (callback)
|
|
284
289
|
callback(false);
|
|
285
290
|
return;
|
|
286
291
|
}
|
|
287
292
|
if (result.data == null) {
|
|
293
|
+
// Popup no data error
|
|
288
294
|
this.notifier.alert(this.get('noData'));
|
|
289
295
|
if (callback)
|
|
290
296
|
callback(false);
|
|
@@ -308,9 +314,12 @@ class CoreApp {
|
|
|
308
314
|
this.storage.setData(this.fields.deviceId, undefined);
|
|
309
315
|
return;
|
|
310
316
|
}
|
|
311
|
-
this.initCallUpdate(result.data, data.timestamp);
|
|
317
|
+
const updateResult = this.initCallUpdate(result.data, data.timestamp);
|
|
318
|
+
if (!updateResult) {
|
|
319
|
+
this.notifier.alert(this.get('noData') + '(Update)');
|
|
320
|
+
}
|
|
312
321
|
if (callback)
|
|
313
|
-
callback(
|
|
322
|
+
callback(updateResult);
|
|
314
323
|
}
|
|
315
324
|
/**
|
|
316
325
|
* Init call update
|
|
@@ -320,12 +329,12 @@ class CoreApp {
|
|
|
320
329
|
initCallUpdate(data, timestamp) {
|
|
321
330
|
// Data check
|
|
322
331
|
if (data.deviceId == null || data.passphrase == null)
|
|
323
|
-
return;
|
|
332
|
+
return false;
|
|
324
333
|
// Decrypt
|
|
325
334
|
// Should be done within 120 seconds after returning from the backend
|
|
326
335
|
const passphrase = this.decrypt(data.passphrase, timestamp.toString());
|
|
327
336
|
if (passphrase == null)
|
|
328
|
-
return;
|
|
337
|
+
return false;
|
|
329
338
|
// Update device id and cache it
|
|
330
339
|
this._deviceId = data.deviceId;
|
|
331
340
|
this.storage.setData(this.fields.deviceId, this._deviceId);
|
|
@@ -345,22 +354,31 @@ class CoreApp {
|
|
|
345
354
|
const currentValue = this.storage.getData(field);
|
|
346
355
|
if (currentValue == null || currentValue === '')
|
|
347
356
|
continue;
|
|
357
|
+
if (prev == null) {
|
|
358
|
+
// Reset the field
|
|
359
|
+
this.storage.setData(field, undefined);
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
348
362
|
const enhanced = currentValue.indexOf('!') >= 8;
|
|
349
|
-
let newValueSource
|
|
363
|
+
let newValueSource;
|
|
350
364
|
if (enhanced) {
|
|
351
365
|
newValueSource = this.decryptEnhanced(currentValue, prev, 12);
|
|
352
366
|
}
|
|
353
367
|
else {
|
|
354
368
|
newValueSource = this.decrypt(currentValue, prev);
|
|
355
369
|
}
|
|
356
|
-
if (newValueSource == null || newValueSource === '')
|
|
370
|
+
if (newValueSource == null || newValueSource === '') {
|
|
371
|
+
// Reset the field
|
|
372
|
+
this.storage.setData(field, undefined);
|
|
357
373
|
continue;
|
|
374
|
+
}
|
|
358
375
|
const newValue = enhanced
|
|
359
376
|
? this.encryptEnhanced(newValueSource)
|
|
360
377
|
: this.encrypt(newValueSource);
|
|
361
378
|
this.storage.setData(field, newValue);
|
|
362
379
|
}
|
|
363
380
|
}
|
|
381
|
+
return true;
|
|
364
382
|
}
|
|
365
383
|
/**
|
|
366
384
|
* Init call encrypted fields update
|
|
@@ -488,19 +506,25 @@ class CoreApp {
|
|
|
488
506
|
const iterations = parseInt(messageEncrypted.substring(0, 2), 10);
|
|
489
507
|
if (isNaN(iterations))
|
|
490
508
|
return undefined;
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
509
|
+
try {
|
|
510
|
+
const salt = crypto_js_1.enc.Hex.parse(messageEncrypted.substring(2, 34));
|
|
511
|
+
const iv = crypto_js_1.enc.Hex.parse(messageEncrypted.substring(34, 66));
|
|
512
|
+
const encrypted = messageEncrypted.substring(66);
|
|
513
|
+
const key = (0, crypto_js_1.PBKDF2)(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, salt, {
|
|
514
|
+
keySize: 8,
|
|
515
|
+
hasher: crypto_js_1.algo.SHA256,
|
|
516
|
+
iterations: 1000 * iterations
|
|
517
|
+
});
|
|
518
|
+
return crypto_js_1.AES.decrypt(encrypted, key, {
|
|
519
|
+
iv,
|
|
520
|
+
padding: crypto_js_1.pad.Pkcs7,
|
|
521
|
+
mode: crypto_js_1.mode.CBC
|
|
522
|
+
}).toString(crypto_js_1.enc.Utf8);
|
|
523
|
+
}
|
|
524
|
+
catch (e) {
|
|
525
|
+
console.log('decrypt', e);
|
|
526
|
+
return undefined;
|
|
527
|
+
}
|
|
504
528
|
}
|
|
505
529
|
/**
|
|
506
530
|
* Enhanced decrypt message
|
|
@@ -516,20 +540,26 @@ class CoreApp {
|
|
|
516
540
|
if (pos < 8 || messageEncrypted.length <= 66)
|
|
517
541
|
return undefined;
|
|
518
542
|
const timestamp = messageEncrypted.substring(0, pos);
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
543
|
+
try {
|
|
544
|
+
if (durationSeconds != null && durationSeconds > 0) {
|
|
545
|
+
const milseconds = shared_1.Utils.charsToNumber(timestamp);
|
|
546
|
+
if (isNaN(milseconds) || milseconds < 1)
|
|
547
|
+
return undefined;
|
|
548
|
+
const timespan = new Date().substract(new Date(milseconds));
|
|
549
|
+
if ((durationSeconds <= 12 &&
|
|
550
|
+
timespan.totalMonths > durationSeconds) ||
|
|
551
|
+
(durationSeconds > 12 &&
|
|
552
|
+
timespan.totalSeconds > durationSeconds))
|
|
553
|
+
return undefined;
|
|
554
|
+
}
|
|
555
|
+
const message = messageEncrypted.substring(pos + 1);
|
|
556
|
+
passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
|
|
557
|
+
return this.decrypt(message, passphrase);
|
|
558
|
+
}
|
|
559
|
+
catch (e) {
|
|
560
|
+
console.log('decryptEnhanced', e);
|
|
561
|
+
return undefined;
|
|
529
562
|
}
|
|
530
|
-
const message = messageEncrypted.substring(pos + 1);
|
|
531
|
-
passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
|
|
532
|
-
return this.decrypt(message, passphrase);
|
|
533
563
|
}
|
|
534
564
|
/**
|
|
535
565
|
* Detect IP data, call only one time
|
package/lib/cjs/i18n/en-US.json
CHANGED
package/lib/cjs/i18n/zh-CN.json
CHANGED
package/lib/cjs/i18n/zh-HK.json
CHANGED
package/lib/mjs/app/CoreApp.d.ts
CHANGED
|
@@ -299,9 +299,10 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
|
|
|
299
299
|
/**
|
|
300
300
|
* Init call
|
|
301
301
|
* @param callback Callback
|
|
302
|
+
* @param resetKeys Reset all keys first
|
|
302
303
|
* @returns Result
|
|
303
304
|
*/
|
|
304
|
-
initCall(callback?: (result: boolean) => void): Promise<void>;
|
|
305
|
+
initCall(callback?: (result: boolean) => void, resetKeys?: boolean): Promise<void>;
|
|
305
306
|
/**
|
|
306
307
|
* Callback where exit a page
|
|
307
308
|
*/
|
|
@@ -513,15 +514,16 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
|
|
|
513
514
|
/**
|
|
514
515
|
* Init call
|
|
515
516
|
* @param callback Callback
|
|
517
|
+
* @param resetKeys Reset all keys first
|
|
516
518
|
* @returns Result
|
|
517
519
|
*/
|
|
518
|
-
initCall(callback?: (result: boolean) => void): Promise<void>;
|
|
520
|
+
initCall(callback?: (result: boolean) => void, resetKeys?: boolean): Promise<void>;
|
|
519
521
|
/**
|
|
520
522
|
* Init call update
|
|
521
523
|
* @param data Result data
|
|
522
524
|
* @param timestamp Timestamp
|
|
523
525
|
*/
|
|
524
|
-
protected initCallUpdate(data: InitCallResultData, timestamp: number):
|
|
526
|
+
protected initCallUpdate(data: InitCallResultData, timestamp: number): boolean;
|
|
525
527
|
/**
|
|
526
528
|
* Init call encrypted fields update
|
|
527
529
|
* @returns Fields
|
package/lib/mjs/app/CoreApp.js
CHANGED
|
@@ -176,9 +176,9 @@ export class CoreApp {
|
|
|
176
176
|
this.resetKeys();
|
|
177
177
|
return false;
|
|
178
178
|
}
|
|
179
|
-
// this.name to identifier different app's secret
|
|
180
179
|
const passphraseEncrypted = this.storage.getData(this.fields.devicePassphrase);
|
|
181
180
|
if (passphraseEncrypted) {
|
|
181
|
+
// this.name to identifier different app's secret
|
|
182
182
|
const passphraseDecrypted = this.decrypt(passphraseEncrypted, this.name);
|
|
183
183
|
if (passphraseDecrypted != null) {
|
|
184
184
|
// Add the device to the list
|
|
@@ -255,10 +255,14 @@ export class CoreApp {
|
|
|
255
255
|
/**
|
|
256
256
|
* Init call
|
|
257
257
|
* @param callback Callback
|
|
258
|
+
* @param resetKeys Reset all keys first
|
|
258
259
|
* @returns Result
|
|
259
260
|
*/
|
|
260
|
-
async initCall(callback) {
|
|
261
|
+
async initCall(callback, resetKeys) {
|
|
261
262
|
var _a;
|
|
263
|
+
// Reset keys
|
|
264
|
+
if (resetKeys)
|
|
265
|
+
this.resetKeys();
|
|
262
266
|
// Passphrase exists?
|
|
263
267
|
if (this.passphrase) {
|
|
264
268
|
if (callback)
|
|
@@ -277,11 +281,13 @@ export class CoreApp {
|
|
|
277
281
|
};
|
|
278
282
|
const result = await this.apiInitCall(data);
|
|
279
283
|
if (result == null) {
|
|
284
|
+
// API error will popup
|
|
280
285
|
if (callback)
|
|
281
286
|
callback(false);
|
|
282
287
|
return;
|
|
283
288
|
}
|
|
284
289
|
if (result.data == null) {
|
|
290
|
+
// Popup no data error
|
|
285
291
|
this.notifier.alert(this.get('noData'));
|
|
286
292
|
if (callback)
|
|
287
293
|
callback(false);
|
|
@@ -305,9 +311,12 @@ export class CoreApp {
|
|
|
305
311
|
this.storage.setData(this.fields.deviceId, undefined);
|
|
306
312
|
return;
|
|
307
313
|
}
|
|
308
|
-
this.initCallUpdate(result.data, data.timestamp);
|
|
314
|
+
const updateResult = this.initCallUpdate(result.data, data.timestamp);
|
|
315
|
+
if (!updateResult) {
|
|
316
|
+
this.notifier.alert(this.get('noData') + '(Update)');
|
|
317
|
+
}
|
|
309
318
|
if (callback)
|
|
310
|
-
callback(
|
|
319
|
+
callback(updateResult);
|
|
311
320
|
}
|
|
312
321
|
/**
|
|
313
322
|
* Init call update
|
|
@@ -317,12 +326,12 @@ export class CoreApp {
|
|
|
317
326
|
initCallUpdate(data, timestamp) {
|
|
318
327
|
// Data check
|
|
319
328
|
if (data.deviceId == null || data.passphrase == null)
|
|
320
|
-
return;
|
|
329
|
+
return false;
|
|
321
330
|
// Decrypt
|
|
322
331
|
// Should be done within 120 seconds after returning from the backend
|
|
323
332
|
const passphrase = this.decrypt(data.passphrase, timestamp.toString());
|
|
324
333
|
if (passphrase == null)
|
|
325
|
-
return;
|
|
334
|
+
return false;
|
|
326
335
|
// Update device id and cache it
|
|
327
336
|
this._deviceId = data.deviceId;
|
|
328
337
|
this.storage.setData(this.fields.deviceId, this._deviceId);
|
|
@@ -342,22 +351,31 @@ export class CoreApp {
|
|
|
342
351
|
const currentValue = this.storage.getData(field);
|
|
343
352
|
if (currentValue == null || currentValue === '')
|
|
344
353
|
continue;
|
|
354
|
+
if (prev == null) {
|
|
355
|
+
// Reset the field
|
|
356
|
+
this.storage.setData(field, undefined);
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
345
359
|
const enhanced = currentValue.indexOf('!') >= 8;
|
|
346
|
-
let newValueSource
|
|
360
|
+
let newValueSource;
|
|
347
361
|
if (enhanced) {
|
|
348
362
|
newValueSource = this.decryptEnhanced(currentValue, prev, 12);
|
|
349
363
|
}
|
|
350
364
|
else {
|
|
351
365
|
newValueSource = this.decrypt(currentValue, prev);
|
|
352
366
|
}
|
|
353
|
-
if (newValueSource == null || newValueSource === '')
|
|
367
|
+
if (newValueSource == null || newValueSource === '') {
|
|
368
|
+
// Reset the field
|
|
369
|
+
this.storage.setData(field, undefined);
|
|
354
370
|
continue;
|
|
371
|
+
}
|
|
355
372
|
const newValue = enhanced
|
|
356
373
|
? this.encryptEnhanced(newValueSource)
|
|
357
374
|
: this.encrypt(newValueSource);
|
|
358
375
|
this.storage.setData(field, newValue);
|
|
359
376
|
}
|
|
360
377
|
}
|
|
378
|
+
return true;
|
|
361
379
|
}
|
|
362
380
|
/**
|
|
363
381
|
* Init call encrypted fields update
|
|
@@ -485,19 +503,25 @@ export class CoreApp {
|
|
|
485
503
|
const iterations = parseInt(messageEncrypted.substring(0, 2), 10);
|
|
486
504
|
if (isNaN(iterations))
|
|
487
505
|
return undefined;
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
506
|
+
try {
|
|
507
|
+
const salt = enc.Hex.parse(messageEncrypted.substring(2, 34));
|
|
508
|
+
const iv = enc.Hex.parse(messageEncrypted.substring(34, 66));
|
|
509
|
+
const encrypted = messageEncrypted.substring(66);
|
|
510
|
+
const key = PBKDF2(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, salt, {
|
|
511
|
+
keySize: 8,
|
|
512
|
+
hasher: algo.SHA256,
|
|
513
|
+
iterations: 1000 * iterations
|
|
514
|
+
});
|
|
515
|
+
return AES.decrypt(encrypted, key, {
|
|
516
|
+
iv,
|
|
517
|
+
padding: pad.Pkcs7,
|
|
518
|
+
mode: mode.CBC
|
|
519
|
+
}).toString(enc.Utf8);
|
|
520
|
+
}
|
|
521
|
+
catch (e) {
|
|
522
|
+
console.log('decrypt', e);
|
|
523
|
+
return undefined;
|
|
524
|
+
}
|
|
501
525
|
}
|
|
502
526
|
/**
|
|
503
527
|
* Enhanced decrypt message
|
|
@@ -513,20 +537,26 @@ export class CoreApp {
|
|
|
513
537
|
if (pos < 8 || messageEncrypted.length <= 66)
|
|
514
538
|
return undefined;
|
|
515
539
|
const timestamp = messageEncrypted.substring(0, pos);
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
540
|
+
try {
|
|
541
|
+
if (durationSeconds != null && durationSeconds > 0) {
|
|
542
|
+
const milseconds = Utils.charsToNumber(timestamp);
|
|
543
|
+
if (isNaN(milseconds) || milseconds < 1)
|
|
544
|
+
return undefined;
|
|
545
|
+
const timespan = new Date().substract(new Date(milseconds));
|
|
546
|
+
if ((durationSeconds <= 12 &&
|
|
547
|
+
timespan.totalMonths > durationSeconds) ||
|
|
548
|
+
(durationSeconds > 12 &&
|
|
549
|
+
timespan.totalSeconds > durationSeconds))
|
|
550
|
+
return undefined;
|
|
551
|
+
}
|
|
552
|
+
const message = messageEncrypted.substring(pos + 1);
|
|
553
|
+
passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
|
|
554
|
+
return this.decrypt(message, passphrase);
|
|
555
|
+
}
|
|
556
|
+
catch (e) {
|
|
557
|
+
console.log('decryptEnhanced', e);
|
|
558
|
+
return undefined;
|
|
526
559
|
}
|
|
527
|
-
const message = messageEncrypted.substring(pos + 1);
|
|
528
|
-
passphrase = this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp);
|
|
529
|
-
return this.decrypt(message, passphrase);
|
|
530
560
|
}
|
|
531
561
|
/**
|
|
532
562
|
* Detect IP data, call only one time
|
package/lib/mjs/i18n/en-US.json
CHANGED
package/lib/mjs/i18n/zh-CN.json
CHANGED
package/lib/mjs/i18n/zh-HK.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/appscript",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.61",
|
|
4
4
|
"description": "Applications shared TypeScript framework",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"module": "lib/mjs/index.js",
|
|
@@ -52,26 +52,27 @@
|
|
|
52
52
|
},
|
|
53
53
|
"homepage": "https://github.com/ETSOO/AppScript#readme",
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@etsoo/notificationbase": "^1.1.
|
|
56
|
-
"@etsoo/restclient": "^1.0.
|
|
57
|
-
"@etsoo/shared": "^1.1.
|
|
55
|
+
"@etsoo/notificationbase": "^1.1.4",
|
|
56
|
+
"@etsoo/restclient": "^1.0.69",
|
|
57
|
+
"@etsoo/shared": "^1.1.40",
|
|
58
58
|
"@types/crypto-js": "^4.1.1",
|
|
59
59
|
"crypto-js": "^4.1.1"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@babel/cli": "^7.17.
|
|
63
|
-
"@babel/core": "^7.
|
|
64
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
65
|
-
"@babel/preset-env": "^7.
|
|
66
|
-
"@babel/runtime-corejs3": "^7.
|
|
67
|
-
"@types/jest": "^27.
|
|
68
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
69
|
-
"@typescript-eslint/parser": "^5.
|
|
70
|
-
"eslint": "^8.
|
|
62
|
+
"@babel/cli": "^7.17.10",
|
|
63
|
+
"@babel/core": "^7.18.2",
|
|
64
|
+
"@babel/plugin-transform-runtime": "^7.18.2",
|
|
65
|
+
"@babel/preset-env": "^7.18.2",
|
|
66
|
+
"@babel/runtime-corejs3": "^7.18.3",
|
|
67
|
+
"@types/jest": "^27.5.1",
|
|
68
|
+
"@typescript-eslint/eslint-plugin": "^5.26.0",
|
|
69
|
+
"@typescript-eslint/parser": "^5.26.0",
|
|
70
|
+
"eslint": "^8.16.0",
|
|
71
71
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
72
|
-
"eslint-plugin-import": "^2.
|
|
73
|
-
"jest": "^
|
|
74
|
-
"
|
|
75
|
-
"
|
|
72
|
+
"eslint-plugin-import": "^2.26.0",
|
|
73
|
+
"jest": "^28.1.0",
|
|
74
|
+
"jest-environment-jsdom": "^28.1.0",
|
|
75
|
+
"ts-jest": "^28.0.3",
|
|
76
|
+
"typescript": "^4.7.2"
|
|
76
77
|
}
|
|
77
78
|
}
|
package/src/app/CoreApp.ts
CHANGED
|
@@ -412,9 +412,13 @@ export interface ICoreApp<
|
|
|
412
412
|
/**
|
|
413
413
|
* Init call
|
|
414
414
|
* @param callback Callback
|
|
415
|
+
* @param resetKeys Reset all keys first
|
|
415
416
|
* @returns Result
|
|
416
417
|
*/
|
|
417
|
-
initCall(
|
|
418
|
+
initCall(
|
|
419
|
+
callback?: (result: boolean) => void,
|
|
420
|
+
resetKeys?: boolean
|
|
421
|
+
): Promise<void>;
|
|
418
422
|
|
|
419
423
|
/**
|
|
420
424
|
* Callback where exit a page
|
|
@@ -765,11 +769,11 @@ export abstract class CoreApp<
|
|
|
765
769
|
return false;
|
|
766
770
|
}
|
|
767
771
|
|
|
768
|
-
// this.name to identifier different app's secret
|
|
769
772
|
const passphraseEncrypted = this.storage.getData<string>(
|
|
770
773
|
this.fields.devicePassphrase
|
|
771
774
|
);
|
|
772
775
|
if (passphraseEncrypted) {
|
|
776
|
+
// this.name to identifier different app's secret
|
|
773
777
|
const passphraseDecrypted = this.decrypt(
|
|
774
778
|
passphraseEncrypted,
|
|
775
779
|
this.name
|
|
@@ -861,9 +865,13 @@ export abstract class CoreApp<
|
|
|
861
865
|
/**
|
|
862
866
|
* Init call
|
|
863
867
|
* @param callback Callback
|
|
868
|
+
* @param resetKeys Reset all keys first
|
|
864
869
|
* @returns Result
|
|
865
870
|
*/
|
|
866
|
-
async initCall(callback?: (result: boolean) => void) {
|
|
871
|
+
async initCall(callback?: (result: boolean) => void, resetKeys?: boolean) {
|
|
872
|
+
// Reset keys
|
|
873
|
+
if (resetKeys) this.resetKeys();
|
|
874
|
+
|
|
867
875
|
// Passphrase exists?
|
|
868
876
|
if (this.passphrase) {
|
|
869
877
|
if (callback) callback(true);
|
|
@@ -887,11 +895,13 @@ export abstract class CoreApp<
|
|
|
887
895
|
|
|
888
896
|
const result = await this.apiInitCall(data);
|
|
889
897
|
if (result == null) {
|
|
898
|
+
// API error will popup
|
|
890
899
|
if (callback) callback(false);
|
|
891
900
|
return;
|
|
892
901
|
}
|
|
893
902
|
|
|
894
903
|
if (result.data == null) {
|
|
904
|
+
// Popup no data error
|
|
895
905
|
this.notifier.alert(this.get<string>('noData')!);
|
|
896
906
|
if (callback) callback(false);
|
|
897
907
|
return;
|
|
@@ -922,9 +932,12 @@ export abstract class CoreApp<
|
|
|
922
932
|
return;
|
|
923
933
|
}
|
|
924
934
|
|
|
925
|
-
this.initCallUpdate(result.data, data.timestamp);
|
|
935
|
+
const updateResult = this.initCallUpdate(result.data, data.timestamp);
|
|
936
|
+
if (!updateResult) {
|
|
937
|
+
this.notifier.alert(this.get<string>('noData')! + '(Update)');
|
|
938
|
+
}
|
|
926
939
|
|
|
927
|
-
if (callback) callback(
|
|
940
|
+
if (callback) callback(updateResult);
|
|
928
941
|
}
|
|
929
942
|
|
|
930
943
|
/**
|
|
@@ -932,14 +945,17 @@ export abstract class CoreApp<
|
|
|
932
945
|
* @param data Result data
|
|
933
946
|
* @param timestamp Timestamp
|
|
934
947
|
*/
|
|
935
|
-
protected initCallUpdate(
|
|
948
|
+
protected initCallUpdate(
|
|
949
|
+
data: InitCallResultData,
|
|
950
|
+
timestamp: number
|
|
951
|
+
): boolean {
|
|
936
952
|
// Data check
|
|
937
|
-
if (data.deviceId == null || data.passphrase == null) return;
|
|
953
|
+
if (data.deviceId == null || data.passphrase == null) return false;
|
|
938
954
|
|
|
939
955
|
// Decrypt
|
|
940
956
|
// Should be done within 120 seconds after returning from the backend
|
|
941
957
|
const passphrase = this.decrypt(data.passphrase, timestamp.toString());
|
|
942
|
-
if (passphrase == null) return;
|
|
958
|
+
if (passphrase == null) return false;
|
|
943
959
|
|
|
944
960
|
// Update device id and cache it
|
|
945
961
|
this._deviceId = data.deviceId;
|
|
@@ -973,8 +989,14 @@ export abstract class CoreApp<
|
|
|
973
989
|
const currentValue = this.storage.getData<string>(field);
|
|
974
990
|
if (currentValue == null || currentValue === '') continue;
|
|
975
991
|
|
|
992
|
+
if (prev == null) {
|
|
993
|
+
// Reset the field
|
|
994
|
+
this.storage.setData(field, undefined);
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
|
|
976
998
|
const enhanced = currentValue.indexOf('!') >= 8;
|
|
977
|
-
let newValueSource
|
|
999
|
+
let newValueSource: string | undefined;
|
|
978
1000
|
|
|
979
1001
|
if (enhanced) {
|
|
980
1002
|
newValueSource = this.decryptEnhanced(
|
|
@@ -986,7 +1008,11 @@ export abstract class CoreApp<
|
|
|
986
1008
|
newValueSource = this.decrypt(currentValue, prev);
|
|
987
1009
|
}
|
|
988
1010
|
|
|
989
|
-
if (newValueSource == null || newValueSource === '')
|
|
1011
|
+
if (newValueSource == null || newValueSource === '') {
|
|
1012
|
+
// Reset the field
|
|
1013
|
+
this.storage.setData(field, undefined);
|
|
1014
|
+
continue;
|
|
1015
|
+
}
|
|
990
1016
|
|
|
991
1017
|
const newValue = enhanced
|
|
992
1018
|
? this.encryptEnhanced(newValueSource)
|
|
@@ -995,6 +1021,8 @@ export abstract class CoreApp<
|
|
|
995
1021
|
this.storage.setData(field, newValue);
|
|
996
1022
|
}
|
|
997
1023
|
}
|
|
1024
|
+
|
|
1025
|
+
return true;
|
|
998
1026
|
}
|
|
999
1027
|
|
|
1000
1028
|
/**
|
|
@@ -1143,21 +1171,26 @@ export abstract class CoreApp<
|
|
|
1143
1171
|
const iterations = parseInt(messageEncrypted.substring(0, 2), 10);
|
|
1144
1172
|
if (isNaN(iterations)) return undefined;
|
|
1145
1173
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1174
|
+
try {
|
|
1175
|
+
const salt = enc.Hex.parse(messageEncrypted.substring(2, 34));
|
|
1176
|
+
const iv = enc.Hex.parse(messageEncrypted.substring(34, 66));
|
|
1177
|
+
const encrypted = messageEncrypted.substring(66);
|
|
1149
1178
|
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1179
|
+
const key = PBKDF2(passphrase ?? this.passphrase, salt, {
|
|
1180
|
+
keySize: 8, // 256 / 32
|
|
1181
|
+
hasher: algo.SHA256,
|
|
1182
|
+
iterations: 1000 * iterations
|
|
1183
|
+
});
|
|
1155
1184
|
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1185
|
+
return AES.decrypt(encrypted, key, {
|
|
1186
|
+
iv,
|
|
1187
|
+
padding: pad.Pkcs7,
|
|
1188
|
+
mode: mode.CBC
|
|
1189
|
+
}).toString(enc.Utf8);
|
|
1190
|
+
} catch (e) {
|
|
1191
|
+
console.log('decrypt', e);
|
|
1192
|
+
return undefined;
|
|
1193
|
+
}
|
|
1161
1194
|
}
|
|
1162
1195
|
|
|
1163
1196
|
/**
|
|
@@ -1180,26 +1213,31 @@ export abstract class CoreApp<
|
|
|
1180
1213
|
|
|
1181
1214
|
const timestamp = messageEncrypted.substring(0, pos);
|
|
1182
1215
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
(
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1216
|
+
try {
|
|
1217
|
+
if (durationSeconds != null && durationSeconds > 0) {
|
|
1218
|
+
const milseconds = Utils.charsToNumber(timestamp);
|
|
1219
|
+
if (isNaN(milseconds) || milseconds < 1) return undefined;
|
|
1220
|
+
const timespan = new Date().substract(new Date(milseconds));
|
|
1221
|
+
if (
|
|
1222
|
+
(durationSeconds <= 12 &&
|
|
1223
|
+
timespan.totalMonths > durationSeconds) ||
|
|
1224
|
+
(durationSeconds > 12 &&
|
|
1225
|
+
timespan.totalSeconds > durationSeconds)
|
|
1226
|
+
)
|
|
1227
|
+
return undefined;
|
|
1228
|
+
}
|
|
1195
1229
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1230
|
+
const message = messageEncrypted.substring(pos + 1);
|
|
1231
|
+
passphrase = this.encryptionEnhance(
|
|
1232
|
+
passphrase ?? this.passphrase,
|
|
1233
|
+
timestamp
|
|
1234
|
+
);
|
|
1201
1235
|
|
|
1202
|
-
|
|
1236
|
+
return this.decrypt(message, passphrase);
|
|
1237
|
+
} catch (e) {
|
|
1238
|
+
console.log('decryptEnhanced', e);
|
|
1239
|
+
return undefined;
|
|
1240
|
+
}
|
|
1203
1241
|
}
|
|
1204
1242
|
|
|
1205
1243
|
/**
|
package/src/i18n/en-US.json
CHANGED
package/src/i18n/zh-CN.json
CHANGED