@etsoo/appscript 1.1.67 → 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.
@@ -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: string): string;
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
@@ -136,7 +134,7 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
136
134
  * @param iterations Iterations, 1000 times, 1 - 99
137
135
  * @returns Result
138
136
  */
139
- encrypt(message: string, passphrase: string, iterations?: number): string;
137
+ encrypt(message: string, passphrase?: string, iterations?: number): string;
140
138
  /**
141
139
  * Format date to string
142
140
  * @param input Input date
@@ -224,6 +222,13 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
224
222
  * @param passphrase Secret passphrase
225
223
  */
226
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;
227
232
  /**
228
233
  * Check use has the specific role permission or not
229
234
  * @param roles Roles to check
@@ -335,10 +340,6 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
335
340
  * User data
336
341
  */
337
342
  userData?: IUserData;
338
- /**
339
- * Passphrase for encryption
340
- */
341
- passphrase?: string;
342
343
  /**
343
344
  * Response token header field name
344
345
  */
@@ -363,6 +364,18 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
363
364
  * Token refresh count down seed
364
365
  */
365
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;
366
379
  /**
367
380
  * Protected constructor
368
381
  * @param settings Settings
@@ -372,6 +385,22 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
372
385
  */
373
386
  protected constructor(settings: S, api: IApi, notifier: INotifier<N, C>, name: string);
374
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[];
375
404
  /**
376
405
  * Alert action result
377
406
  * @param result Action result
@@ -398,9 +427,10 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
398
427
  * Decrypt message
399
428
  * @param messageEncrypted Encrypted message
400
429
  * @param passphrase Secret passphrase
430
+ * @param durationSeconds Duration seconds, <= 12 will be considered as month
401
431
  * @returns Pure text
402
432
  */
403
- decrypt(messageEncrypted: string, passphrase: string): string;
433
+ decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
404
434
  /**
405
435
  * Detect IP data, call only one time
406
436
  * @param callback Callback will be called when the IP is ready
@@ -414,7 +444,7 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
414
444
  * @param iterations Iterations, 1000 times, 1 - 99
415
445
  * @returns Result
416
446
  */
417
- encrypt(message: string, passphrase: string, iterations?: number): string;
447
+ encrypt(message: string, passphrase?: string, iterations?: number): string;
418
448
  /**
419
449
  * Enchance secret passphrase
420
450
  * @param passphrase Secret passphrase
@@ -504,6 +534,13 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
504
534
  * @param passphrase Secret passphrase
505
535
  */
506
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;
507
544
  /**
508
545
  * Check use has the specific role permission or not
509
546
  * @param roles Roles to check
@@ -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,19 +284,35 @@ 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) {
206
291
  // Timestamp splitter
207
292
  const pos = messageEncrypted.indexOf('+');
293
+ if (pos === -1 || messageEncrypted.length <= 66)
294
+ return undefined;
208
295
  const timestamp = messageEncrypted.substring(0, pos);
209
296
  const message = messageEncrypted.substring(pos + 1);
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
+ }
210
308
  // Iterations
211
309
  const iterations = parseInt(message.substring(0, 2), 10);
310
+ if (isNaN(iterations))
311
+ return undefined;
212
312
  const salt = crypto_js_1.enc.Hex.parse(message.substring(2, 34));
213
313
  const iv = crypto_js_1.enc.Hex.parse(message.substring(34, 66));
214
314
  const encrypted = message.substring(66);
215
- const key = (0, crypto_js_1.PBKDF2)(this.encryptionEnhance(passphrase, timestamp), salt, {
315
+ const key = (0, crypto_js_1.PBKDF2)(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
216
316
  keySize: 8,
217
317
  hasher: crypto_js_1.algo.SHA256,
218
318
  iterations: 1000 * iterations
@@ -270,7 +370,7 @@ class CoreApp {
270
370
  const timestamp = shared_1.Utils.numberToChars(new Date().getTime());
271
371
  const bits = 16; // 128 / 8
272
372
  const salt = crypto_js_1.lib.WordArray.random(bits);
273
- const key = (0, crypto_js_1.PBKDF2)(this.encryptionEnhance(passphrase, timestamp), salt, {
373
+ const key = (0, crypto_js_1.PBKDF2)(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
274
374
  keySize: 8,
275
375
  hasher: crypto_js_1.algo.SHA256,
276
376
  iterations: 1000 * iterations
@@ -295,10 +395,9 @@ class CoreApp {
295
395
  * @returns Enhanced passphrase
296
396
  */
297
397
  encryptionEnhance(passphrase, timestamp) {
298
- var _a;
299
398
  passphrase += timestamp;
300
399
  passphrase += passphrase.length.toString();
301
- return passphrase + ((_a = this.passphrase) !== null && _a !== void 0 ? _a : '');
400
+ return passphrase;
302
401
  }
303
402
  /**
304
403
  * Format date to string
@@ -360,7 +459,19 @@ class CoreApp {
360
459
  * @param forceToLocal Force to local labels
361
460
  */
362
461
  formatResult(result, forceToLocal) {
363
- if ((result.title == null || forceToLocal) && result.type != null) {
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
364
475
  const key = result.type.formatInitial(false);
365
476
  result.title = this.get(key);
366
477
  }
@@ -438,6 +549,18 @@ class CoreApp {
438
549
  else
439
550
  return (0, crypto_js_1.HmacSHA512)(message, passphrase).toString(crypto_js_1.enc.Base64);
440
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
+ }
441
564
  /**
442
565
  * Check use has the specific role permission or not
443
566
  * @param roles Roles to check
@@ -587,7 +710,6 @@ class CoreApp {
587
710
  */
588
711
  userLogin(user, refreshToken, keep = false) {
589
712
  this.userData = user;
590
- this.passphrase = user.passphrase;
591
713
  this.authorize(user.token, refreshToken, keep);
592
714
  }
593
715
  /**
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Init call dto
3
+ */
4
+ export declare type InitCallDto = {
5
+ /**
6
+ * Device id
7
+ */
8
+ deviceId?: string;
9
+ /**
10
+ * Timestamp
11
+ */
12
+ timestamp: number;
13
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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';
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,11 +48,11 @@ export interface IActionResult<D extends IResultData = IResultData> {
48
48
  /**
49
49
  * Trace id
50
50
  */
51
- readonly traceId?: string;
51
+ traceId?: string;
52
52
  /**
53
53
  * Type
54
54
  */
55
- readonly type: string;
55
+ type: string;
56
56
  /**
57
57
  * Success or not
58
58
  */
@@ -1,20 +1,28 @@
1
1
  import { IActionResult, IResultData } from './IActionResult';
2
2
  /**
3
- * Result data with id, follow this style to extend for specific model
3
+ * Init call result data
4
4
  */
5
5
  export interface InitCallResultData extends IResultData {
6
+ /**
7
+ * Device id
8
+ */
9
+ deviceId?: string;
6
10
  /**
7
11
  * Secret passphrase
8
12
  */
9
- passphrase: string;
13
+ passphrase?: string;
14
+ /**
15
+ * Previous secret passphrase
16
+ */
17
+ previousPassphrase?: string;
10
18
  /**
11
19
  * Actual seconds gap
12
20
  */
13
- seconds: number;
21
+ seconds?: number;
14
22
  /**
15
23
  * Valid seconds gap
16
24
  */
17
- validSeconds: number;
25
+ validSeconds?: number;
18
26
  }
19
27
  /**
20
28
  * Init call result
@@ -27,10 +27,6 @@ export interface IUserData {
27
27
  * Access token
28
28
  */
29
29
  readonly token: string;
30
- /**
31
- * Secret passphrase
32
- */
33
- readonly passphrase: string;
34
30
  }
35
31
  /**
36
32
  * User interface
@@ -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: string): string;
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
@@ -136,7 +134,7 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
136
134
  * @param iterations Iterations, 1000 times, 1 - 99
137
135
  * @returns Result
138
136
  */
139
- encrypt(message: string, passphrase: string, iterations?: number): string;
137
+ encrypt(message: string, passphrase?: string, iterations?: number): string;
140
138
  /**
141
139
  * Format date to string
142
140
  * @param input Input date
@@ -224,6 +222,13 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
224
222
  * @param passphrase Secret passphrase
225
223
  */
226
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;
227
232
  /**
228
233
  * Check use has the specific role permission or not
229
234
  * @param roles Roles to check
@@ -335,10 +340,6 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
335
340
  * User data
336
341
  */
337
342
  userData?: IUserData;
338
- /**
339
- * Passphrase for encryption
340
- */
341
- passphrase?: string;
342
343
  /**
343
344
  * Response token header field name
344
345
  */
@@ -363,6 +364,18 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
363
364
  * Token refresh count down seed
364
365
  */
365
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;
366
379
  /**
367
380
  * Protected constructor
368
381
  * @param settings Settings
@@ -372,6 +385,22 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
372
385
  */
373
386
  protected constructor(settings: S, api: IApi, notifier: INotifier<N, C>, name: string);
374
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[];
375
404
  /**
376
405
  * Alert action result
377
406
  * @param result Action result
@@ -398,9 +427,10 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
398
427
  * Decrypt message
399
428
  * @param messageEncrypted Encrypted message
400
429
  * @param passphrase Secret passphrase
430
+ * @param durationSeconds Duration seconds, <= 12 will be considered as month
401
431
  * @returns Pure text
402
432
  */
403
- decrypt(messageEncrypted: string, passphrase: string): string;
433
+ decrypt(messageEncrypted: string, passphrase?: string, durationSeconds?: number): string | undefined;
404
434
  /**
405
435
  * Detect IP data, call only one time
406
436
  * @param callback Callback will be called when the IP is ready
@@ -414,7 +444,7 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
414
444
  * @param iterations Iterations, 1000 times, 1 - 99
415
445
  * @returns Result
416
446
  */
417
- encrypt(message: string, passphrase: string, iterations?: number): string;
447
+ encrypt(message: string, passphrase?: string, iterations?: number): string;
418
448
  /**
419
449
  * Enchance secret passphrase
420
450
  * @param passphrase Secret passphrase
@@ -504,6 +534,13 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
504
534
  * @param passphrase Secret passphrase
505
535
  */
506
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;
507
544
  /**
508
545
  * Check use has the specific role permission or not
509
546
  * @param roles Roles to check
@@ -31,10 +31,19 @@ export class CoreApp {
31
31
  * Token refresh count down seed
32
32
  */
33
33
  this.refreshCountdownSeed = 0;
34
+ /**
35
+ * Device id field name
36
+ */
37
+ this.deviceIdField = 'SmartERPDeviceId';
38
+ /**
39
+ * Passphrase for encryption
40
+ */
41
+ this.passphrase = '***';
34
42
  this.settings = settings;
35
43
  this.api = api;
36
44
  this.notifier = notifier;
37
45
  this.name = name;
46
+ this.deviceId = StorageUtils.getLocalData(this.deviceIdField, '');
38
47
  this.setApi(api);
39
48
  const { currentCulture, currentRegion } = settings;
40
49
  this.changeCulture(currentCulture);
@@ -105,6 +114,81 @@ export class CoreApp {
105
114
  }
106
115
  };
107
116
  }
117
+ /**
118
+ * Init call
119
+ * @returns Result
120
+ */
121
+ async initCall() {
122
+ var _a;
123
+ const data = {
124
+ timestamp: new Date().getTime(),
125
+ deviceId: this.deviceId === '' ? undefined : this.deviceId
126
+ };
127
+ const result = await this.api.put('Auth/WebInitCall', data);
128
+ if (result == null)
129
+ return;
130
+ if (result.data == null) {
131
+ this.notifier.alert(this.get('noData'));
132
+ return;
133
+ }
134
+ if (!result.ok) {
135
+ const seconds = result.data.seconds;
136
+ const validSeconds = result.data.validSeconds;
137
+ if (result.title === 'timeDifferenceInvalid' &&
138
+ seconds != null &&
139
+ validSeconds != null) {
140
+ const title = (_a = this.get('timeDifferenceInvalid')) === null || _a === void 0 ? void 0 : _a.format(seconds.toString(), validSeconds.toString());
141
+ this.notifier.alert(title);
142
+ }
143
+ else {
144
+ this.alertResult(result);
145
+ }
146
+ return;
147
+ }
148
+ this.initCallUpdate(result.data, data.timestamp);
149
+ }
150
+ /**
151
+ * Init call update
152
+ * @param data Result data
153
+ * @param timestamp Timestamp
154
+ */
155
+ initCallUpdate(data, timestamp) {
156
+ if (data.deviceId == null || data.passphrase == null)
157
+ return;
158
+ // Decrypt
159
+ // Should be done within 120 seconds after returning from the backend
160
+ const passphrase = this.decrypt(data.passphrase, timestamp.toString(), 120);
161
+ if (passphrase == null)
162
+ return;
163
+ // Update device id and cache it
164
+ this.deviceId = data.deviceId;
165
+ StorageUtils.setLocalData(this.deviceIdField, this.deviceId);
166
+ // Current passphrase
167
+ this.passphrase = passphrase;
168
+ // Previous passphrase
169
+ if (data.previousPassphrase) {
170
+ const prev = this.decrypt(data.previousPassphrase, timestamp.toString(), 120);
171
+ // Update
172
+ const fields = this.initCallUpdateFields();
173
+ for (const field of fields) {
174
+ const currentValue = StorageUtils.getLocalData(field, '');
175
+ if (currentValue === '' || currentValue.indexOf('+') === -1)
176
+ continue;
177
+ const newValueSource = this.decrypt(currentValue, prev, 12);
178
+ if (newValueSource == null)
179
+ continue;
180
+ const newValue = this.encrypt(newValueSource);
181
+ StorageUtils.setLocalData(field, newValue);
182
+ }
183
+ }
184
+ }
185
+ /**
186
+ * Init call update fields in local storage
187
+ * @returns Fields
188
+ */
189
+ initCallUpdateFields() {
190
+ return [];
191
+ }
108
192
  /**
109
193
  * Alert action result
110
194
  * @param result Action result
@@ -197,19 +281,35 @@ export class CoreApp {
197
281
  * Decrypt message
198
282
  * @param messageEncrypted Encrypted message
199
283
  * @param passphrase Secret passphrase
284
+ * @param durationSeconds Duration seconds, <= 12 will be considered as month
200
285
  * @returns Pure text
201
286
  */
202
- decrypt(messageEncrypted, passphrase) {
287
+ decrypt(messageEncrypted, passphrase, durationSeconds) {
203
288
  // Timestamp splitter
204
289
  const pos = messageEncrypted.indexOf('+');
290
+ if (pos === -1 || messageEncrypted.length <= 66)
291
+ return undefined;
205
292
  const timestamp = messageEncrypted.substring(0, pos);
206
293
  const message = messageEncrypted.substring(pos + 1);
294
+ if (durationSeconds != null && durationSeconds > 0) {
295
+ const milseconds = Utils.charsToNumber(timestamp);
296
+ if (isNaN(milseconds) || milseconds < 1)
297
+ return undefined;
298
+ const timespan = new Date().substract(new Date(milseconds));
299
+ if ((durationSeconds <= 12 &&
300
+ timespan.totalMonths > durationSeconds) ||
301
+ (durationSeconds > 12 &&
302
+ timespan.totalSeconds > durationSeconds))
303
+ return undefined;
304
+ }
207
305
  // Iterations
208
306
  const iterations = parseInt(message.substring(0, 2), 10);
307
+ if (isNaN(iterations))
308
+ return undefined;
209
309
  const salt = enc.Hex.parse(message.substring(2, 34));
210
310
  const iv = enc.Hex.parse(message.substring(34, 66));
211
311
  const encrypted = message.substring(66);
212
- const key = PBKDF2(this.encryptionEnhance(passphrase, timestamp), salt, {
312
+ const key = PBKDF2(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
213
313
  keySize: 8,
214
314
  hasher: algo.SHA256,
215
315
  iterations: 1000 * iterations
@@ -267,7 +367,7 @@ export class CoreApp {
267
367
  const timestamp = Utils.numberToChars(new Date().getTime());
268
368
  const bits = 16; // 128 / 8
269
369
  const salt = lib.WordArray.random(bits);
270
- const key = PBKDF2(this.encryptionEnhance(passphrase, timestamp), salt, {
370
+ const key = PBKDF2(this.encryptionEnhance(passphrase !== null && passphrase !== void 0 ? passphrase : this.passphrase, timestamp), salt, {
271
371
  keySize: 8,
272
372
  hasher: algo.SHA256,
273
373
  iterations: 1000 * iterations
@@ -292,10 +392,9 @@ export class CoreApp {
292
392
  * @returns Enhanced passphrase
293
393
  */
294
394
  encryptionEnhance(passphrase, timestamp) {
295
- var _a;
296
395
  passphrase += timestamp;
297
396
  passphrase += passphrase.length.toString();
298
- return passphrase + ((_a = this.passphrase) !== null && _a !== void 0 ? _a : '');
397
+ return passphrase;
299
398
  }
300
399
  /**
301
400
  * Format date to string
@@ -357,7 +456,19 @@ export class CoreApp {
357
456
  * @param forceToLocal Force to local labels
358
457
  */
359
458
  formatResult(result, forceToLocal) {
360
- if ((result.title == null || forceToLocal) && result.type != null) {
459
+ const title = result.title;
460
+ if (title && /^\w+$/.test(title)) {
461
+ const key = title.formatInitial(false);
462
+ const localTitle = this.get(key);
463
+ if (localTitle) {
464
+ result.title = localTitle;
465
+ // Hold the original title in type when type is null
466
+ if (result.type == null)
467
+ result.type = title;
468
+ }
469
+ }
470
+ else if ((title == null || forceToLocal) && result.type != null) {
471
+ // Get label from type
361
472
  const key = result.type.formatInitial(false);
362
473
  result.title = this.get(key);
363
474
  }
@@ -435,6 +546,18 @@ export class CoreApp {
435
546
  else
436
547
  return HmacSHA512(message, passphrase).toString(enc.Base64);
437
548
  }
549
+ /**
550
+ * Hash message Hex, SHA3 or HmacSHA512, 512 as Base64
551
+ * https://cryptojs.gitbook.io/docs/
552
+ * @param message Message
553
+ * @param passphrase Secret passphrase
554
+ */
555
+ hashHex(message, passphrase) {
556
+ if (passphrase == null)
557
+ return SHA3(message, { outputLength: 512 }).toString(enc.Hex);
558
+ else
559
+ return HmacSHA512(message, passphrase).toString(enc.Hex);
560
+ }
438
561
  /**
439
562
  * Check use has the specific role permission or not
440
563
  * @param roles Roles to check
@@ -584,7 +707,6 @@ export class CoreApp {
584
707
  */
585
708
  userLogin(user, refreshToken, keep = false) {
586
709
  this.userData = user;
587
- this.passphrase = user.passphrase;
588
710
  this.authorize(user.token, refreshToken, keep);
589
711
  }
590
712
  /**
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Init call dto
3
+ */
4
+ export declare type InitCallDto = {
5
+ /**
6
+ * Device id
7
+ */
8
+ deviceId?: string;
9
+ /**
10
+ * Timestamp
11
+ */
12
+ timestamp: number;
13
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -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';
package/lib/mjs/index.js CHANGED
@@ -22,6 +22,7 @@ export * from './def/ListItem';
22
22
  export * from './dto/IdDto';
23
23
  export * from './dto/IdLabelDto';
24
24
  export * from './dto/IdLabelPrimaryDto';
25
+ export * from './dto/InitCallDto';
25
26
  export * from './dto/UpdateDto';
26
27
  // i18n
27
28
  export * from './i18n/enUS';
@@ -48,11 +48,11 @@ export interface IActionResult<D extends IResultData = IResultData> {
48
48
  /**
49
49
  * Trace id
50
50
  */
51
- readonly traceId?: string;
51
+ traceId?: string;
52
52
  /**
53
53
  * Type
54
54
  */
55
- readonly type: string;
55
+ type: string;
56
56
  /**
57
57
  * Success or not
58
58
  */
@@ -1,20 +1,28 @@
1
1
  import { IActionResult, IResultData } from './IActionResult';
2
2
  /**
3
- * Result data with id, follow this style to extend for specific model
3
+ * Init call result data
4
4
  */
5
5
  export interface InitCallResultData extends IResultData {
6
+ /**
7
+ * Device id
8
+ */
9
+ deviceId?: string;
6
10
  /**
7
11
  * Secret passphrase
8
12
  */
9
- passphrase: string;
13
+ passphrase?: string;
14
+ /**
15
+ * Previous secret passphrase
16
+ */
17
+ previousPassphrase?: string;
10
18
  /**
11
19
  * Actual seconds gap
12
20
  */
13
- seconds: number;
21
+ seconds?: number;
14
22
  /**
15
23
  * Valid seconds gap
16
24
  */
17
- validSeconds: number;
25
+ validSeconds?: number;
18
26
  }
19
27
  /**
20
28
  * Init call result
@@ -27,10 +27,6 @@ export interface IUserData {
27
27
  * Access token
28
28
  */
29
29
  readonly token: string;
30
- /**
31
- * Secret passphrase
32
- */
33
- readonly passphrase: string;
34
30
  }
35
31
  /**
36
32
  * User interface
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/appscript",
3
- "version": "1.1.67",
3
+ "version": "1.1.68",
4
4
  "description": "Applications shared TypeScript framework",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -28,8 +28,10 @@ import {
28
28
  } from 'crypto-js';
29
29
  import { AddressRegion } from '../address/AddressRegion';
30
30
  import { AddressUtils } from '../address/AddressUtils';
31
+ import { InitCallDto } from '../dto/InitCallDto';
31
32
  import { ActionResultError } from '../result/ActionResultError';
32
33
  import { IActionResult } from '../result/IActionResult';
34
+ import { InitCallResult, InitCallResultData } from '../result/InitCallResult';
33
35
  import { IUserData } from '../state/User';
34
36
  import { IAppSettings } from './AppSettings';
35
37
  import { UserRole } from './UserRole';
@@ -140,11 +142,6 @@ export interface ICoreApp<
140
142
  */
141
143
  userData?: IUserData;
142
144
 
143
- /**
144
- * Passphrase for encryption
145
- */
146
- passphrase?: string;
147
-
148
145
  /**
149
146
  * Search input element
150
147
  */
@@ -180,9 +177,14 @@ export interface ICoreApp<
180
177
  * Decrypt message
181
178
  * @param messageEncrypted Encrypted message
182
179
  * @param passphrase Secret passphrase
180
+ * @param durationSeconds Duration seconds, <= 12 will be considered as month
183
181
  * @returns Pure text
184
182
  */
185
- decrypt(messageEncrypted: string, passphrase: string): string;
183
+ decrypt(
184
+ messageEncrypted: string,
185
+ passphrase?: string,
186
+ durationSeconds?: number
187
+ ): string | undefined;
186
188
 
187
189
  /**
188
190
  * Detect IP data, call only one time
@@ -197,7 +199,7 @@ export interface ICoreApp<
197
199
  * @param iterations Iterations, 1000 times, 1 - 99
198
200
  * @returns Result
199
201
  */
200
- encrypt(message: string, passphrase: string, iterations?: number): string;
202
+ encrypt(message: string, passphrase?: string, iterations?: number): string;
201
203
 
202
204
  /**
203
205
  * Format date to string
@@ -309,6 +311,14 @@ export interface ICoreApp<
309
311
  */
310
312
  hash(message: string, passphrase?: string): string;
311
313
 
314
+ /**
315
+ * Hash message Hex, SHA3 or HmacSHA512, 512 as Base64
316
+ * https://cryptojs.gitbook.io/docs/
317
+ * @param message Message
318
+ * @param passphrase Secret passphrase
319
+ */
320
+ hashHex(message: string, passphrase?: string): string;
321
+
312
322
  /**
313
323
  * Check use has the specific role permission or not
314
324
  * @param roles Roles to check
@@ -457,11 +467,6 @@ export abstract class CoreApp<
457
467
  */
458
468
  userData?: IUserData;
459
469
 
460
- /**
461
- * Passphrase for encryption
462
- */
463
- passphrase?: string;
464
-
465
470
  /**
466
471
  * Response token header field name
467
472
  */
@@ -499,6 +504,21 @@ export abstract class CoreApp<
499
504
  */
500
505
  protected refreshCountdownSeed = 0;
501
506
 
507
+ /**
508
+ * Device id field name
509
+ */
510
+ protected deviceIdField: string = 'SmartERPDeviceId';
511
+
512
+ /**
513
+ * Device id
514
+ */
515
+ protected deviceId: string;
516
+
517
+ /**
518
+ * Passphrase for encryption
519
+ */
520
+ protected passphrase: string = '***';
521
+
502
522
  /**
503
523
  * Protected constructor
504
524
  * @param settings Settings
@@ -517,6 +537,11 @@ export abstract class CoreApp<
517
537
  this.notifier = notifier;
518
538
  this.name = name;
519
539
 
540
+ this.deviceId = StorageUtils.getLocalData<string>(
541
+ this.deviceIdField,
542
+ ''
543
+ );
544
+
520
545
  this.setApi(api);
521
546
 
522
547
  const { currentCulture, currentRegion } = settings;
@@ -561,6 +586,108 @@ export abstract class CoreApp<
561
586
  };
562
587
  }
563
588
 
589
+ /**
590
+ * Init call
591
+ * @returns Result
592
+ */
593
+ protected async initCall() {
594
+ const data: InitCallDto = {
595
+ timestamp: new Date().getTime(),
596
+ deviceId: this.deviceId === '' ? undefined : this.deviceId
597
+ };
598
+ const result = await this.api.put<InitCallResult>(
599
+ 'Auth/WebInitCall',
600
+ data
601
+ );
602
+ if (result == null) return;
603
+
604
+ if (result.data == null) {
605
+ this.notifier.alert(this.get<string>('noData')!);
606
+ return;
607
+ }
608
+
609
+ if (!result.ok) {
610
+ const seconds = result.data.seconds;
611
+ const validSeconds = result.data.validSeconds;
612
+ if (
613
+ result.title === 'timeDifferenceInvalid' &&
614
+ seconds != null &&
615
+ validSeconds != null
616
+ ) {
617
+ const title = this.get('timeDifferenceInvalid')?.format(
618
+ seconds.toString(),
619
+ validSeconds.toString()
620
+ );
621
+ this.notifier.alert(title!);
622
+ } else {
623
+ this.alertResult(result);
624
+ }
625
+
626
+ return;
627
+ }
628
+
629
+ this.initCallUpdate(result.data, data.timestamp);
630
+ }
631
+
632
+ /**
633
+ * Init call update
634
+ * @param data Result data
635
+ * @param timestamp Timestamp
636
+ */
637
+ protected initCallUpdate(data: InitCallResultData, timestamp: number) {
638
+ if (data.deviceId == null || data.passphrase == null) return;
639
+
640
+ // Decrypt
641
+ // Should be done within 120 seconds after returning from the backend
642
+ const passphrase = this.decrypt(
643
+ data.passphrase,
644
+ timestamp.toString(),
645
+ 120
646
+ );
647
+ if (passphrase == null) return;
648
+
649
+ // Update device id and cache it
650
+ this.deviceId = data.deviceId;
651
+ StorageUtils.setLocalData(this.deviceIdField, this.deviceId);
652
+
653
+ // Current passphrase
654
+ this.passphrase = passphrase;
655
+
656
+ // Previous passphrase
657
+ if (data.previousPassphrase) {
658
+ const prev = this.decrypt(
659
+ data.previousPassphrase,
660
+ timestamp.toString(),
661
+ 120
662
+ );
663
+
664
+ // Update
665
+ const fields = this.initCallUpdateFields();
666
+ for (const field of fields) {
667
+ const currentValue = StorageUtils.getLocalData<string>(
668
+ field,
669
+ ''
670
+ );
671
+ if (currentValue === '' || currentValue.indexOf('+') === -1)
672
+ continue;
673
+
674
+ const newValueSource = this.decrypt(currentValue, prev, 12);
675
+ if (newValueSource == null) continue;
676
+
677
+ const newValue = this.encrypt(newValueSource);
678
+ StorageUtils.setLocalData(field, newValue);
679
+ }
680
+ }
681
+ }
682
+
683
+ /**
684
+ * Init call update fields in local storage
685
+ * @returns Fields
686
+ */
687
+ protected initCallUpdateFields(): string[] {
688
+ return [];
689
+ }
690
+
564
691
  /**
565
692
  * Alert action result
566
693
  * @param result Action result
@@ -676,23 +803,44 @@ export abstract class CoreApp<
676
803
  * Decrypt message
677
804
  * @param messageEncrypted Encrypted message
678
805
  * @param passphrase Secret passphrase
806
+ * @param durationSeconds Duration seconds, <= 12 will be considered as month
679
807
  * @returns Pure text
680
808
  */
681
- decrypt(messageEncrypted: string, passphrase: string) {
809
+ decrypt(
810
+ messageEncrypted: string,
811
+ passphrase?: string,
812
+ durationSeconds?: number
813
+ ) {
682
814
  // Timestamp splitter
683
815
  const pos = messageEncrypted.indexOf('+');
816
+ if (pos === -1 || messageEncrypted.length <= 66) return undefined;
817
+
684
818
  const timestamp = messageEncrypted.substring(0, pos);
685
819
  const message = messageEncrypted.substring(pos + 1);
686
820
 
821
+ if (durationSeconds != null && durationSeconds > 0) {
822
+ const milseconds = Utils.charsToNumber(timestamp);
823
+ if (isNaN(milseconds) || milseconds < 1) return undefined;
824
+ const timespan = new Date().substract(new Date(milseconds));
825
+ if (
826
+ (durationSeconds <= 12 &&
827
+ timespan.totalMonths > durationSeconds) ||
828
+ (durationSeconds > 12 &&
829
+ timespan.totalSeconds > durationSeconds)
830
+ )
831
+ return undefined;
832
+ }
833
+
687
834
  // Iterations
688
835
  const iterations = parseInt(message.substring(0, 2), 10);
836
+ if (isNaN(iterations)) return undefined;
689
837
 
690
838
  const salt = enc.Hex.parse(message.substring(2, 34));
691
839
  const iv = enc.Hex.parse(message.substring(34, 66));
692
840
  const encrypted = message.substring(66);
693
841
 
694
842
  const key = PBKDF2(
695
- this.encryptionEnhance(passphrase, timestamp),
843
+ this.encryptionEnhance(passphrase ?? this.passphrase, timestamp),
696
844
  salt,
697
845
  {
698
846
  keySize: 8, // 256 / 32
@@ -755,7 +903,7 @@ export abstract class CoreApp<
755
903
  * @param iterations Iterations, 1000 times, 1 - 99
756
904
  * @returns Result
757
905
  */
758
- encrypt(message: string, passphrase: string, iterations?: number) {
906
+ encrypt(message: string, passphrase?: string, iterations?: number) {
759
907
  // Default 1 * 1000
760
908
  iterations ??= 1;
761
909
 
@@ -765,7 +913,7 @@ export abstract class CoreApp<
765
913
  const bits = 16; // 128 / 8
766
914
  const salt = lib.WordArray.random(bits);
767
915
  const key = PBKDF2(
768
- this.encryptionEnhance(passphrase, timestamp),
916
+ this.encryptionEnhance(passphrase ?? this.passphrase, timestamp),
769
917
  salt,
770
918
  {
771
919
  keySize: 8, // 256 / 32
@@ -798,7 +946,7 @@ export abstract class CoreApp<
798
946
  protected encryptionEnhance(passphrase: string, timestamp: string) {
799
947
  passphrase += timestamp;
800
948
  passphrase += passphrase.length.toString();
801
- return passphrase + (this.passphrase ?? '');
949
+ return passphrase;
802
950
  }
803
951
 
804
952
  /**
@@ -880,7 +1028,18 @@ export abstract class CoreApp<
880
1028
  * @param forceToLocal Force to local labels
881
1029
  */
882
1030
  formatResult(result: IActionResult, forceToLocal?: boolean) {
883
- if ((result.title == null || forceToLocal) && result.type != null) {
1031
+ const title = result.title;
1032
+ if (title && /^\w+$/.test(title)) {
1033
+ const key = title.formatInitial(false);
1034
+ const localTitle = this.get(key);
1035
+ if (localTitle) {
1036
+ result.title = localTitle;
1037
+
1038
+ // Hold the original title in type when type is null
1039
+ if (result.type == null) result.type = title;
1040
+ }
1041
+ } else if ((title == null || forceToLocal) && result.type != null) {
1042
+ // Get label from type
884
1043
  const key = result.type.formatInitial(false);
885
1044
  result.title = this.get(key);
886
1045
  }
@@ -918,7 +1077,10 @@ export abstract class CoreApp<
918
1077
  * @returns Cached token
919
1078
  */
920
1079
  getCacheToken(): string | null {
921
- let refreshToken = StorageUtils.getLocalData(this.headerTokenField, '');
1080
+ let refreshToken = StorageUtils.getLocalData<string>(
1081
+ this.headerTokenField,
1082
+ ''
1083
+ );
922
1084
  if (refreshToken === '')
923
1085
  refreshToken = StorageUtils.getSessionData(
924
1086
  this.headerTokenField,
@@ -971,6 +1133,18 @@ export abstract class CoreApp<
971
1133
  else return HmacSHA512(message, passphrase).toString(enc.Base64);
972
1134
  }
973
1135
 
1136
+ /**
1137
+ * Hash message Hex, SHA3 or HmacSHA512, 512 as Base64
1138
+ * https://cryptojs.gitbook.io/docs/
1139
+ * @param message Message
1140
+ * @param passphrase Secret passphrase
1141
+ */
1142
+ hashHex(message: string, passphrase?: string) {
1143
+ if (passphrase == null)
1144
+ return SHA3(message, { outputLength: 512 }).toString(enc.Hex);
1145
+ else return HmacSHA512(message, passphrase).toString(enc.Hex);
1146
+ }
1147
+
974
1148
  /**
975
1149
  * Check use has the specific role permission or not
976
1150
  * @param roles Roles to check
@@ -1139,7 +1313,6 @@ export abstract class CoreApp<
1139
1313
  */
1140
1314
  userLogin(user: IUserData, refreshToken: string, keep: boolean = false) {
1141
1315
  this.userData = user;
1142
- this.passphrase = user.passphrase;
1143
1316
  this.authorize(user.token, refreshToken, keep);
1144
1317
  }
1145
1318
 
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Init call dto
3
+ */
4
+ export type InitCallDto = {
5
+ /**
6
+ * Device id
7
+ */
8
+ deviceId?: string;
9
+
10
+ /**
11
+ * Timestamp
12
+ */
13
+ timestamp: number;
14
+ };
package/src/index.ts CHANGED
@@ -27,6 +27,7 @@ export * from './def/ListItem';
27
27
  export * from './dto/IdDto';
28
28
  export * from './dto/IdLabelDto';
29
29
  export * from './dto/IdLabelPrimaryDto';
30
+ export * from './dto/InitCallDto';
30
31
  export * from './dto/UpdateDto';
31
32
 
32
33
  // i18n
@@ -56,12 +56,12 @@ export interface IActionResult<D extends IResultData = IResultData> {
56
56
  /**
57
57
  * Trace id
58
58
  */
59
- readonly traceId?: string;
59
+ traceId?: string;
60
60
 
61
61
  /**
62
62
  * Type
63
63
  */
64
- readonly type: string;
64
+ type: string;
65
65
 
66
66
  /**
67
67
  * Success or not
@@ -1,23 +1,33 @@
1
1
  import { IActionResult, IResultData } from './IActionResult';
2
2
 
3
3
  /**
4
- * Result data with id, follow this style to extend for specific model
4
+ * Init call result data
5
5
  */
6
6
  export interface InitCallResultData extends IResultData {
7
+ /**
8
+ * Device id
9
+ */
10
+ deviceId?: string;
11
+
7
12
  /**
8
13
  * Secret passphrase
9
14
  */
10
- passphrase: string;
15
+ passphrase?: string;
16
+
17
+ /**
18
+ * Previous secret passphrase
19
+ */
20
+ previousPassphrase?: string;
11
21
 
12
22
  /**
13
23
  * Actual seconds gap
14
24
  */
15
- seconds: number;
25
+ seconds?: number;
16
26
 
17
27
  /**
18
28
  * Valid seconds gap
19
29
  */
20
- validSeconds: number;
30
+ validSeconds?: number;
21
31
  }
22
32
 
23
33
  /**
package/src/state/User.ts CHANGED
@@ -33,11 +33,6 @@ export interface IUserData {
33
33
  * Access token
34
34
  */
35
35
  readonly token: string;
36
-
37
- /**
38
- * Secret passphrase
39
- */
40
- readonly passphrase: string;
41
36
  }
42
37
 
43
38
  /**