@etsoo/appscript 1.1.64 → 1.1.68
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 +124 -0
- package/lib/cjs/app/CoreApp.d.ts +67 -14
- package/lib/cjs/app/CoreApp.js +183 -13
- package/lib/cjs/dto/InitCallDto.d.ts +13 -0
- package/lib/cjs/dto/InitCallDto.js +2 -0
- 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/cjs/index.d.ts +2 -0
- package/lib/cjs/index.js +2 -0
- package/lib/cjs/result/IActionResult.d.ts +2 -2
- package/lib/cjs/result/InitCallResult.d.ts +30 -0
- package/lib/cjs/result/InitCallResult.js +2 -0
- package/lib/mjs/app/CoreApp.d.ts +67 -14
- package/lib/mjs/app/CoreApp.js +184 -14
- package/lib/mjs/dto/InitCallDto.d.ts +13 -0
- package/lib/mjs/dto/InitCallDto.js +1 -0
- 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/lib/mjs/index.d.ts +2 -0
- package/lib/mjs/index.js +2 -0
- package/lib/mjs/result/IActionResult.d.ts +2 -2
- package/lib/mjs/result/InitCallResult.d.ts +30 -0
- package/lib/mjs/result/InitCallResult.js +1 -0
- package/package.json +5 -5
- package/src/app/CoreApp.ts +280 -32
- package/src/dto/InitCallDto.ts +14 -0
- 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/src/index.ts +2 -0
- package/src/result/IActionResult.ts +2 -2
- package/src/result/InitCallResult.ts +36 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
INotificaseBase,
|
|
3
|
+
INotification,
|
|
4
|
+
Notification,
|
|
5
|
+
NotificationCallProps,
|
|
6
|
+
NotificationContainer,
|
|
7
|
+
NotificationRenderProps
|
|
8
|
+
} from '@etsoo/notificationbase';
|
|
9
|
+
import { ApiAuthorizationScheme, createClient } from '@etsoo/restclient';
|
|
10
|
+
import { DataTypes, DomUtils, Utils } from '@etsoo/shared';
|
|
11
|
+
import { AddressUtils } from '../../src/address/AddressUtils';
|
|
12
|
+
import { IAppSettings } from '../../src/app/AppSettings';
|
|
13
|
+
import { CoreApp } from '../../src/app/CoreApp';
|
|
14
|
+
import { zhCN } from '../../src/i18n/zhCN';
|
|
15
|
+
|
|
16
|
+
// Detected country or region
|
|
17
|
+
const { detectedCountry } = DomUtils;
|
|
18
|
+
|
|
19
|
+
// Detected culture
|
|
20
|
+
const { detectedCulture } = DomUtils;
|
|
21
|
+
|
|
22
|
+
// Supported cultures
|
|
23
|
+
const supportedCultures: DataTypes.CultureDefinition[] = [zhCN({})];
|
|
24
|
+
|
|
25
|
+
// Supported regions
|
|
26
|
+
const supportedRegions = ['CN'];
|
|
27
|
+
|
|
28
|
+
// Class implementation for tests
|
|
29
|
+
class NotificationTest extends Notification<any, NotificationCallProps> {
|
|
30
|
+
render(props: NotificationRenderProps, className?: string, options?: any) {
|
|
31
|
+
throw new Error('Method not implemented.');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class NotificationContainerTest extends NotificationContainer<
|
|
36
|
+
any,
|
|
37
|
+
NotificationCallProps
|
|
38
|
+
> {
|
|
39
|
+
protected addRaw(
|
|
40
|
+
data: INotificaseBase<any, NotificationCallProps>
|
|
41
|
+
): INotification<any, NotificationCallProps> {
|
|
42
|
+
throw new Error('Method not implemented.');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Container
|
|
47
|
+
var container = new NotificationContainerTest((update) => {});
|
|
48
|
+
|
|
49
|
+
// Arrange
|
|
50
|
+
class CoreAppTest extends CoreApp<IAppSettings, {}, NotificationCallProps> {
|
|
51
|
+
/**
|
|
52
|
+
* Constructor
|
|
53
|
+
* @param settings Settings
|
|
54
|
+
* @param name Application name
|
|
55
|
+
*/
|
|
56
|
+
constructor() {
|
|
57
|
+
super(
|
|
58
|
+
{
|
|
59
|
+
/**
|
|
60
|
+
* Endpoint of the API service
|
|
61
|
+
*/
|
|
62
|
+
endpoint: 'http://{hostname}/com.etsoo.SmartERPApi/api/',
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* App root url
|
|
66
|
+
*/
|
|
67
|
+
homepage: '',
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Web url of the cloud
|
|
71
|
+
*/
|
|
72
|
+
webUrl: 'http://localhost',
|
|
73
|
+
|
|
74
|
+
// Authorization scheme
|
|
75
|
+
authScheme: ApiAuthorizationScheme.Bearer,
|
|
76
|
+
|
|
77
|
+
// Detected culture
|
|
78
|
+
detectedCulture,
|
|
79
|
+
|
|
80
|
+
// Supported cultures
|
|
81
|
+
cultures: supportedCultures,
|
|
82
|
+
|
|
83
|
+
// Supported regions
|
|
84
|
+
regions: supportedRegions,
|
|
85
|
+
|
|
86
|
+
// Browser's time zone
|
|
87
|
+
timeZone: Utils.getTimeZone(),
|
|
88
|
+
|
|
89
|
+
// Current country or region
|
|
90
|
+
currentRegion: AddressUtils.getRegion(
|
|
91
|
+
supportedRegions,
|
|
92
|
+
detectedCountry,
|
|
93
|
+
detectedCulture
|
|
94
|
+
),
|
|
95
|
+
|
|
96
|
+
// Current culture
|
|
97
|
+
currentCulture: DomUtils.getCulture(
|
|
98
|
+
supportedCultures,
|
|
99
|
+
detectedCulture
|
|
100
|
+
)!
|
|
101
|
+
},
|
|
102
|
+
createClient(),
|
|
103
|
+
container,
|
|
104
|
+
'SmartERP'
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
freshCountdownUI(callback?: () => PromiseLike<unknown>): void {
|
|
109
|
+
throw new Error('Method not implemented.');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const app = new CoreAppTest();
|
|
114
|
+
|
|
115
|
+
test('Tests for encrypt / decrypt', () => {
|
|
116
|
+
// Arrange
|
|
117
|
+
const input = 'Hello, world!';
|
|
118
|
+
const passphrase = 'My password';
|
|
119
|
+
|
|
120
|
+
// Act
|
|
121
|
+
const encrypted = app.encrypt(input, passphrase);
|
|
122
|
+
const plain = app.decrypt(encrypted, passphrase);
|
|
123
|
+
expect(plain).toEqual(input);
|
|
124
|
+
});
|
package/lib/cjs/app/CoreApp.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { ApiDataError, IApi, IPData } from '@etsoo/restclient';
|
|
|
3
3
|
import { DataTypes, DateUtils } from '@etsoo/shared';
|
|
4
4
|
import { AddressRegion } from '../address/AddressRegion';
|
|
5
5
|
import { IActionResult } from '../result/IActionResult';
|
|
6
|
+
import { InitCallResultData } from '../result/InitCallResult';
|
|
6
7
|
import { IUserData } from '../state/User';
|
|
7
8
|
import { IAppSettings } from './AppSettings';
|
|
8
9
|
import { UserRole } from './UserRole';
|
|
@@ -87,10 +88,6 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
|
|
|
87
88
|
* User data
|
|
88
89
|
*/
|
|
89
90
|
userData?: IUserData;
|
|
90
|
-
/**
|
|
91
|
-
* Passphrase for encryption
|
|
92
|
-
*/
|
|
93
|
-
passphrase?: string;
|
|
94
91
|
/**
|
|
95
92
|
* Search input element
|
|
96
93
|
*/
|
|
@@ -121,9 +118,10 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
|
|
|
121
118
|
* Decrypt message
|
|
122
119
|
* @param messageEncrypted Encrypted message
|
|
123
120
|
* @param passphrase Secret passphrase
|
|
121
|
+
* @param durationSeconds Duration seconds, <= 12 will be considered as month
|
|
124
122
|
* @returns Pure text
|
|
125
123
|
*/
|
|
126
|
-
decrypt(messageEncrypted: string, passphrase
|
|
124
|
+
decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
|
|
127
125
|
/**
|
|
128
126
|
* Detect IP data, call only one time
|
|
129
127
|
* @param callback Callback will be called when the IP is ready
|
|
@@ -133,9 +131,10 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
|
|
|
133
131
|
* Encrypt message
|
|
134
132
|
* @param message Message
|
|
135
133
|
* @param passphrase Secret passphrase
|
|
134
|
+
* @param iterations Iterations, 1000 times, 1 - 99
|
|
136
135
|
* @returns Result
|
|
137
136
|
*/
|
|
138
|
-
encrypt(message: string, passphrase
|
|
137
|
+
encrypt(message: string, passphrase?: string, iterations?: number): string;
|
|
139
138
|
/**
|
|
140
139
|
* Format date to string
|
|
141
140
|
* @param input Input date
|
|
@@ -216,6 +215,20 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
|
|
|
216
215
|
* @returns Time zone
|
|
217
216
|
*/
|
|
218
217
|
getTimeZone(): string | undefined;
|
|
218
|
+
/**
|
|
219
|
+
* Hash message, SHA3 or HmacSHA512, 512 as Base64
|
|
220
|
+
* https://cryptojs.gitbook.io/docs/
|
|
221
|
+
* @param message Message
|
|
222
|
+
* @param passphrase Secret passphrase
|
|
223
|
+
*/
|
|
224
|
+
hash(message: string, passphrase?: string): string;
|
|
225
|
+
/**
|
|
226
|
+
* Hash message Hex, SHA3 or HmacSHA512, 512 as Base64
|
|
227
|
+
* https://cryptojs.gitbook.io/docs/
|
|
228
|
+
* @param message Message
|
|
229
|
+
* @param passphrase Secret passphrase
|
|
230
|
+
*/
|
|
231
|
+
hashHex(message: string, passphrase?: string): string;
|
|
219
232
|
/**
|
|
220
233
|
* Check use has the specific role permission or not
|
|
221
234
|
* @param roles Roles to check
|
|
@@ -327,10 +340,6 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
|
|
|
327
340
|
* User data
|
|
328
341
|
*/
|
|
329
342
|
userData?: IUserData;
|
|
330
|
-
/**
|
|
331
|
-
* Passphrase for encryption
|
|
332
|
-
*/
|
|
333
|
-
passphrase?: string;
|
|
334
343
|
/**
|
|
335
344
|
* Response token header field name
|
|
336
345
|
*/
|
|
@@ -355,6 +364,18 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
|
|
|
355
364
|
* Token refresh count down seed
|
|
356
365
|
*/
|
|
357
366
|
protected refreshCountdownSeed: number;
|
|
367
|
+
/**
|
|
368
|
+
* Device id field name
|
|
369
|
+
*/
|
|
370
|
+
protected deviceIdField: string;
|
|
371
|
+
/**
|
|
372
|
+
* Device id
|
|
373
|
+
*/
|
|
374
|
+
protected deviceId: string;
|
|
375
|
+
/**
|
|
376
|
+
* Passphrase for encryption
|
|
377
|
+
*/
|
|
378
|
+
protected passphrase: string;
|
|
358
379
|
/**
|
|
359
380
|
* Protected constructor
|
|
360
381
|
* @param settings Settings
|
|
@@ -364,6 +385,22 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
|
|
|
364
385
|
*/
|
|
365
386
|
protected constructor(settings: S, api: IApi, notifier: INotifier<N, C>, name: string);
|
|
366
387
|
protected setApi(api: IApi): void;
|
|
388
|
+
/**
|
|
389
|
+
* Init call
|
|
390
|
+
* @returns Result
|
|
391
|
+
*/
|
|
392
|
+
protected initCall(): Promise<void>;
|
|
393
|
+
/**
|
|
394
|
+
* Init call update
|
|
395
|
+
* @param data Result data
|
|
396
|
+
* @param timestamp Timestamp
|
|
397
|
+
*/
|
|
398
|
+
protected initCallUpdate(data: InitCallResultData, timestamp: number): void;
|
|
399
|
+
/**
|
|
400
|
+
* Init call update fields in local storage
|
|
401
|
+
* @returns Fields
|
|
402
|
+
*/
|
|
403
|
+
protected initCallUpdateFields(): string[];
|
|
367
404
|
/**
|
|
368
405
|
* Alert action result
|
|
369
406
|
* @param result Action result
|
|
@@ -390,9 +427,10 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
|
|
|
390
427
|
* Decrypt message
|
|
391
428
|
* @param messageEncrypted Encrypted message
|
|
392
429
|
* @param passphrase Secret passphrase
|
|
430
|
+
* @param durationSeconds Duration seconds, <= 12 will be considered as month
|
|
393
431
|
* @returns Pure text
|
|
394
432
|
*/
|
|
395
|
-
decrypt(messageEncrypted: string, passphrase
|
|
433
|
+
decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
|
|
396
434
|
/**
|
|
397
435
|
* Detect IP data, call only one time
|
|
398
436
|
* @param callback Callback will be called when the IP is ready
|
|
@@ -403,16 +441,17 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
|
|
|
403
441
|
* Encrypt message
|
|
404
442
|
* @param message Message
|
|
405
443
|
* @param passphrase Secret passphrase
|
|
444
|
+
* @param iterations Iterations, 1000 times, 1 - 99
|
|
406
445
|
* @returns Result
|
|
407
446
|
*/
|
|
408
|
-
encrypt(message: string, passphrase
|
|
447
|
+
encrypt(message: string, passphrase?: string, iterations?: number): string;
|
|
409
448
|
/**
|
|
410
449
|
* Enchance secret passphrase
|
|
411
450
|
* @param passphrase Secret passphrase
|
|
412
|
-
* @param
|
|
451
|
+
* @param timestamp Timestamp
|
|
413
452
|
* @returns Enhanced passphrase
|
|
414
453
|
*/
|
|
415
|
-
protected encryptionEnhance(passphrase: string,
|
|
454
|
+
protected encryptionEnhance(passphrase: string, timestamp: string): string;
|
|
416
455
|
/**
|
|
417
456
|
* Format date to string
|
|
418
457
|
* @param input Input date
|
|
@@ -488,6 +527,20 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
|
|
|
488
527
|
* @returns Time zone
|
|
489
528
|
*/
|
|
490
529
|
getTimeZone(): string | undefined;
|
|
530
|
+
/**
|
|
531
|
+
* Hash message, SHA3 or HmacSHA512, 512 as Base64
|
|
532
|
+
* https://cryptojs.gitbook.io/docs/
|
|
533
|
+
* @param message Message
|
|
534
|
+
* @param passphrase Secret passphrase
|
|
535
|
+
*/
|
|
536
|
+
hash(message: string, passphrase?: string): string;
|
|
537
|
+
/**
|
|
538
|
+
* Hash message Hex, SHA3 or HmacSHA512, 512 as Base64
|
|
539
|
+
* https://cryptojs.gitbook.io/docs/
|
|
540
|
+
* @param message Message
|
|
541
|
+
* @param passphrase Secret passphrase
|
|
542
|
+
*/
|
|
543
|
+
hashHex(message: string, passphrase?: string): string;
|
|
491
544
|
/**
|
|
492
545
|
* Check use has the specific role permission or not
|
|
493
546
|
* @param roles Roles to check
|
package/lib/cjs/app/CoreApp.js
CHANGED
|
@@ -34,10 +34,19 @@ class CoreApp {
|
|
|
34
34
|
* Token refresh count down seed
|
|
35
35
|
*/
|
|
36
36
|
this.refreshCountdownSeed = 0;
|
|
37
|
+
/**
|
|
38
|
+
* Device id field name
|
|
39
|
+
*/
|
|
40
|
+
this.deviceIdField = 'SmartERPDeviceId';
|
|
41
|
+
/**
|
|
42
|
+
* Passphrase for encryption
|
|
43
|
+
*/
|
|
44
|
+
this.passphrase = '***';
|
|
37
45
|
this.settings = settings;
|
|
38
46
|
this.api = api;
|
|
39
47
|
this.notifier = notifier;
|
|
40
48
|
this.name = name;
|
|
49
|
+
this.deviceId = shared_1.StorageUtils.getLocalData(this.deviceIdField, '');
|
|
41
50
|
this.setApi(api);
|
|
42
51
|
const { currentCulture, currentRegion } = settings;
|
|
43
52
|
this.changeCulture(currentCulture);
|
|
@@ -108,6 +117,81 @@ class CoreApp {
|
|
|
108
117
|
}
|
|
109
118
|
};
|
|
110
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Init call
|
|
122
|
+
* @returns Result
|
|
123
|
+
*/
|
|
124
|
+
async initCall() {
|
|
125
|
+
var _a;
|
|
126
|
+
const data = {
|
|
127
|
+
timestamp: new Date().getTime(),
|
|
128
|
+
deviceId: this.deviceId === '' ? undefined : this.deviceId
|
|
129
|
+
};
|
|
130
|
+
const result = await this.api.put('Auth/WebInitCall', data);
|
|
131
|
+
if (result == null)
|
|
132
|
+
return;
|
|
133
|
+
if (result.data == null) {
|
|
134
|
+
this.notifier.alert(this.get('noData'));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (!result.ok) {
|
|
138
|
+
const seconds = result.data.seconds;
|
|
139
|
+
const validSeconds = result.data.validSeconds;
|
|
140
|
+
if (result.title === 'timeDifferenceInvalid' &&
|
|
141
|
+
seconds != null &&
|
|
142
|
+
validSeconds != null) {
|
|
143
|
+
const title = (_a = this.get('timeDifferenceInvalid')) === null || _a === void 0 ? void 0 : _a.format(seconds.toString(), validSeconds.toString());
|
|
144
|
+
this.notifier.alert(title);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
this.alertResult(result);
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
this.initCallUpdate(result.data, data.timestamp);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Init call update
|
|
155
|
+
* @param data Result data
|
|
156
|
+
* @param timestamp Timestamp
|
|
157
|
+
*/
|
|
158
|
+
initCallUpdate(data, timestamp) {
|
|
159
|
+
if (data.deviceId == null || data.passphrase == null)
|
|
160
|
+
return;
|
|
161
|
+
// Decrypt
|
|
162
|
+
// Should be done within 120 seconds after returning from the backend
|
|
163
|
+
const passphrase = this.decrypt(data.passphrase, timestamp.toString(), 120);
|
|
164
|
+
if (passphrase == null)
|
|
165
|
+
return;
|
|
166
|
+
// Update device id and cache it
|
|
167
|
+
this.deviceId = data.deviceId;
|
|
168
|
+
shared_1.StorageUtils.setLocalData(this.deviceIdField, this.deviceId);
|
|
169
|
+
// Current passphrase
|
|
170
|
+
this.passphrase = passphrase;
|
|
171
|
+
// Previous passphrase
|
|
172
|
+
if (data.previousPassphrase) {
|
|
173
|
+
const prev = this.decrypt(data.previousPassphrase, timestamp.toString(), 120);
|
|
174
|
+
// Update
|
|
175
|
+
const fields = this.initCallUpdateFields();
|
|
176
|
+
for (const field of fields) {
|
|
177
|
+
const currentValue = shared_1.StorageUtils.getLocalData(field, '');
|
|
178
|
+
if (currentValue === '' || currentValue.indexOf('+') === -1)
|
|
179
|
+
continue;
|
|
180
|
+
const newValueSource = this.decrypt(currentValue, prev, 12);
|
|
181
|
+
if (newValueSource == null)
|
|
182
|
+
continue;
|
|
183
|
+
const newValue = this.encrypt(newValueSource);
|
|
184
|
+
shared_1.StorageUtils.setLocalData(field, newValue);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Init call update fields in local storage
|
|
190
|
+
* @returns Fields
|
|
191
|
+
*/
|
|
192
|
+
initCallUpdateFields() {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
111
195
|
/**
|
|
112
196
|
* Alert action result
|
|
113
197
|
* @param result Action result
|
|
@@ -200,13 +284,44 @@ class CoreApp {
|
|
|
200
284
|
* Decrypt message
|
|
201
285
|
* @param messageEncrypted Encrypted message
|
|
202
286
|
* @param passphrase Secret passphrase
|
|
287
|
+
* @param durationSeconds Duration seconds, <= 12 will be considered as month
|
|
203
288
|
* @returns Pure text
|
|
204
289
|
*/
|
|
205
|
-
decrypt(messageEncrypted, passphrase) {
|
|
290
|
+
decrypt(messageEncrypted, passphrase, durationSeconds) {
|
|
291
|
+
// Timestamp splitter
|
|
206
292
|
const pos = messageEncrypted.indexOf('+');
|
|
207
|
-
|
|
293
|
+
if (pos === -1 || messageEncrypted.length <= 66)
|
|
294
|
+
return undefined;
|
|
295
|
+
const timestamp = messageEncrypted.substring(0, pos);
|
|
208
296
|
const message = messageEncrypted.substring(pos + 1);
|
|
209
|
-
|
|
297
|
+
if (durationSeconds != null && durationSeconds > 0) {
|
|
298
|
+
const milseconds = shared_1.Utils.charsToNumber(timestamp);
|
|
299
|
+
if (isNaN(milseconds) || milseconds < 1)
|
|
300
|
+
return undefined;
|
|
301
|
+
const timespan = new Date().substract(new Date(milseconds));
|
|
302
|
+
if ((durationSeconds <= 12 &&
|
|
303
|
+
timespan.totalMonths > durationSeconds) ||
|
|
304
|
+
(durationSeconds > 12 &&
|
|
305
|
+
timespan.totalSeconds > durationSeconds))
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
// Iterations
|
|
309
|
+
const iterations = parseInt(message.substring(0, 2), 10);
|
|
310
|
+
if (isNaN(iterations))
|
|
311
|
+
return undefined;
|
|
312
|
+
const salt = crypto_js_1.enc.Hex.parse(message.substring(2, 34));
|
|
313
|
+
const iv = crypto_js_1.enc.Hex.parse(message.substring(34, 66));
|
|
314
|
+
const encrypted = message.substring(66);
|
|
315
|
+
const key = (0, crypto_js_1.PBKDF2)(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
|
|
316
|
+
keySize: 8,
|
|
317
|
+
hasher: crypto_js_1.algo.SHA256,
|
|
318
|
+
iterations: 1000 * iterations
|
|
319
|
+
});
|
|
320
|
+
return crypto_js_1.AES.decrypt(encrypted, key, {
|
|
321
|
+
iv,
|
|
322
|
+
padding: crypto_js_1.pad.Pkcs7,
|
|
323
|
+
mode: crypto_js_1.mode.CBC
|
|
324
|
+
}).toString(crypto_js_1.enc.Utf8);
|
|
210
325
|
}
|
|
211
326
|
/**
|
|
212
327
|
* Detect IP data, call only one time
|
|
@@ -245,25 +360,44 @@ class CoreApp {
|
|
|
245
360
|
* Encrypt message
|
|
246
361
|
* @param message Message
|
|
247
362
|
* @param passphrase Secret passphrase
|
|
363
|
+
* @param iterations Iterations, 1000 times, 1 - 99
|
|
248
364
|
* @returns Result
|
|
249
365
|
*/
|
|
250
|
-
encrypt(message, passphrase) {
|
|
251
|
-
|
|
252
|
-
|
|
366
|
+
encrypt(message, passphrase, iterations) {
|
|
367
|
+
// Default 1 * 1000
|
|
368
|
+
iterations !== null && iterations !== void 0 ? iterations : (iterations = 1);
|
|
369
|
+
// Timestamp
|
|
370
|
+
const timestamp = shared_1.Utils.numberToChars(new Date().getTime());
|
|
371
|
+
const bits = 16; // 128 / 8
|
|
372
|
+
const salt = crypto_js_1.lib.WordArray.random(bits);
|
|
373
|
+
const key = (0, crypto_js_1.PBKDF2)(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
|
|
374
|
+
keySize: 8,
|
|
375
|
+
hasher: crypto_js_1.algo.SHA256,
|
|
376
|
+
iterations: 1000 * iterations
|
|
377
|
+
});
|
|
378
|
+
const iv = crypto_js_1.lib.WordArray.random(bits);
|
|
379
|
+
return (timestamp +
|
|
253
380
|
'+' +
|
|
254
|
-
|
|
381
|
+
iterations.toString().padStart(2, '0') +
|
|
382
|
+
salt.toString(crypto_js_1.enc.Hex) +
|
|
383
|
+
iv.toString(crypto_js_1.enc.Hex) +
|
|
384
|
+
crypto_js_1.AES.encrypt(message, key, {
|
|
385
|
+
iv,
|
|
386
|
+
padding: crypto_js_1.pad.Pkcs7,
|
|
387
|
+
mode: crypto_js_1.mode.CBC
|
|
388
|
+
}).toString() // enc.Base64
|
|
389
|
+
);
|
|
255
390
|
}
|
|
256
391
|
/**
|
|
257
392
|
* Enchance secret passphrase
|
|
258
393
|
* @param passphrase Secret passphrase
|
|
259
|
-
* @param
|
|
394
|
+
* @param timestamp Timestamp
|
|
260
395
|
* @returns Enhanced passphrase
|
|
261
396
|
*/
|
|
262
|
-
encryptionEnhance(passphrase,
|
|
263
|
-
|
|
264
|
-
passphrase += miliseconds;
|
|
397
|
+
encryptionEnhance(passphrase, timestamp) {
|
|
398
|
+
passphrase += timestamp;
|
|
265
399
|
passphrase += passphrase.length.toString();
|
|
266
|
-
return passphrase
|
|
400
|
+
return passphrase;
|
|
267
401
|
}
|
|
268
402
|
/**
|
|
269
403
|
* Format date to string
|
|
@@ -325,7 +459,19 @@ class CoreApp {
|
|
|
325
459
|
* @param forceToLocal Force to local labels
|
|
326
460
|
*/
|
|
327
461
|
formatResult(result, forceToLocal) {
|
|
328
|
-
|
|
462
|
+
const title = result.title;
|
|
463
|
+
if (title && /^\w+$/.test(title)) {
|
|
464
|
+
const key = title.formatInitial(false);
|
|
465
|
+
const localTitle = this.get(key);
|
|
466
|
+
if (localTitle) {
|
|
467
|
+
result.title = localTitle;
|
|
468
|
+
// Hold the original title in type when type is null
|
|
469
|
+
if (result.type == null)
|
|
470
|
+
result.type = title;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
else if ((title == null || forceToLocal) && result.type != null) {
|
|
474
|
+
// Get label from type
|
|
329
475
|
const key = result.type.formatInitial(false);
|
|
330
476
|
result.title = this.get(key);
|
|
331
477
|
}
|
|
@@ -391,6 +537,30 @@ class CoreApp {
|
|
|
391
537
|
// settings.timeZone = Utils.getTimeZone()
|
|
392
538
|
return (_a = this.settings.timeZone) !== null && _a !== void 0 ? _a : (_b = this.ipData) === null || _b === void 0 ? void 0 : _b.timezone;
|
|
393
539
|
}
|
|
540
|
+
/**
|
|
541
|
+
* Hash message, SHA3 or HmacSHA512, 512 as Base64
|
|
542
|
+
* https://cryptojs.gitbook.io/docs/
|
|
543
|
+
* @param message Message
|
|
544
|
+
* @param passphrase Secret passphrase
|
|
545
|
+
*/
|
|
546
|
+
hash(message, passphrase) {
|
|
547
|
+
if (passphrase == null)
|
|
548
|
+
return (0, crypto_js_1.SHA3)(message, { outputLength: 512 }).toString(crypto_js_1.enc.Base64);
|
|
549
|
+
else
|
|
550
|
+
return (0, crypto_js_1.HmacSHA512)(message, passphrase).toString(crypto_js_1.enc.Base64);
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Hash message Hex, SHA3 or HmacSHA512, 512 as Base64
|
|
554
|
+
* https://cryptojs.gitbook.io/docs/
|
|
555
|
+
* @param message Message
|
|
556
|
+
* @param passphrase Secret passphrase
|
|
557
|
+
*/
|
|
558
|
+
hashHex(message, passphrase) {
|
|
559
|
+
if (passphrase == null)
|
|
560
|
+
return (0, crypto_js_1.SHA3)(message, { outputLength: 512 }).toString(crypto_js_1.enc.Hex);
|
|
561
|
+
else
|
|
562
|
+
return (0, crypto_js_1.HmacSHA512)(message, passphrase).toString(crypto_js_1.enc.Hex);
|
|
563
|
+
}
|
|
394
564
|
/**
|
|
395
565
|
* Check use has the specific role permission or not
|
|
396
566
|
* @param roles Roles to check
|
package/lib/cjs/i18n/en-US.json
CHANGED
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"status": "Status",
|
|
60
60
|
"submit": "Submit",
|
|
61
61
|
"success": "Success",
|
|
62
|
+
"timeDifferenceInvalid": "The time difference between the device and the server is {0}, which exceeds the limit of {1} seconds. Please adjust the device time. If it is abnormal, please inform the administrator",
|
|
62
63
|
"tokenExpiry": "Your session is about to expire. Click the Cancel button to continue",
|
|
63
64
|
"yes": "Yes",
|
|
64
65
|
"unknownError": "Unknown Error",
|
package/lib/cjs/i18n/zh-CN.json
CHANGED
package/lib/cjs/i18n/zh-HK.json
CHANGED
package/lib/cjs/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export * from './def/ListItem';
|
|
|
16
16
|
export * from './dto/IdDto';
|
|
17
17
|
export * from './dto/IdLabelDto';
|
|
18
18
|
export * from './dto/IdLabelPrimaryDto';
|
|
19
|
+
export * from './dto/InitCallDto';
|
|
19
20
|
export * from './dto/UpdateDto';
|
|
20
21
|
export * from './i18n/enUS';
|
|
21
22
|
export * from './i18n/zhCN';
|
|
@@ -25,6 +26,7 @@ export type { IApi, IApiPayload } from '@etsoo/restclient';
|
|
|
25
26
|
export * from './result/ActionResult';
|
|
26
27
|
export * from './result/ActionResultError';
|
|
27
28
|
export * from './result/IActionResult';
|
|
29
|
+
export * from './result/InitCallResult';
|
|
28
30
|
export * from './state/Culture';
|
|
29
31
|
export * from './state/State';
|
|
30
32
|
export * from './state/User';
|
package/lib/cjs/index.js
CHANGED
|
@@ -35,6 +35,7 @@ __exportStar(require("./def/ListItem"), exports);
|
|
|
35
35
|
__exportStar(require("./dto/IdDto"), exports);
|
|
36
36
|
__exportStar(require("./dto/IdLabelDto"), exports);
|
|
37
37
|
__exportStar(require("./dto/IdLabelPrimaryDto"), exports);
|
|
38
|
+
__exportStar(require("./dto/InitCallDto"), exports);
|
|
38
39
|
__exportStar(require("./dto/UpdateDto"), exports);
|
|
39
40
|
// i18n
|
|
40
41
|
__exportStar(require("./i18n/enUS"), exports);
|
|
@@ -48,6 +49,7 @@ Object.defineProperty(exports, "createClient", { enumerable: true, get: function
|
|
|
48
49
|
__exportStar(require("./result/ActionResult"), exports);
|
|
49
50
|
__exportStar(require("./result/ActionResultError"), exports);
|
|
50
51
|
__exportStar(require("./result/IActionResult"), exports);
|
|
52
|
+
__exportStar(require("./result/InitCallResult"), exports);
|
|
51
53
|
// state
|
|
52
54
|
__exportStar(require("./state/Culture"), exports);
|
|
53
55
|
__exportStar(require("./state/State"), exports);
|
|
@@ -48,11 +48,11 @@ export interface IActionResult<D extends IResultData = IResultData> {
|
|
|
48
48
|
/**
|
|
49
49
|
* Trace id
|
|
50
50
|
*/
|
|
51
|
-
|
|
51
|
+
traceId?: string;
|
|
52
52
|
/**
|
|
53
53
|
* Type
|
|
54
54
|
*/
|
|
55
|
-
|
|
55
|
+
type: string;
|
|
56
56
|
/**
|
|
57
57
|
* Success or not
|
|
58
58
|
*/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { IActionResult, IResultData } from './IActionResult';
|
|
2
|
+
/**
|
|
3
|
+
* Init call result data
|
|
4
|
+
*/
|
|
5
|
+
export interface InitCallResultData extends IResultData {
|
|
6
|
+
/**
|
|
7
|
+
* Device id
|
|
8
|
+
*/
|
|
9
|
+
deviceId?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Secret passphrase
|
|
12
|
+
*/
|
|
13
|
+
passphrase?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Previous secret passphrase
|
|
16
|
+
*/
|
|
17
|
+
previousPassphrase?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Actual seconds gap
|
|
20
|
+
*/
|
|
21
|
+
seconds?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Valid seconds gap
|
|
24
|
+
*/
|
|
25
|
+
validSeconds?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Init call result
|
|
29
|
+
*/
|
|
30
|
+
export declare type InitCallResult = IActionResult<InitCallResultData>;
|