@trezor/connect 9.5.3 → 9.5.4
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/CHANGELOG.md +38 -4
- package/README.md +1 -1
- package/lib/api/binance/api/binanceSignTransaction.js +1 -1
- package/lib/api/bitcoin/BitcoinFees.d.ts +4 -6
- package/lib/api/bitcoin/BitcoinFees.js +8 -2
- package/lib/api/bitcoin/signtxVerify.d.ts +1 -1
- package/lib/api/bitcoin/signtxVerify.js +3 -3
- package/lib/api/blockchainEstimateFee.js +13 -13
- package/lib/api/cardano/api/cardanoSignTransaction.js +1 -1
- package/lib/api/common/Discovery.d.ts +4 -4
- package/lib/api/common/Discovery.js +3 -4
- package/lib/api/common/MiscFees.d.ts +5 -9
- package/lib/api/common/MiscFees.js +6 -21
- package/lib/api/composeTransaction.js +4 -3
- package/lib/api/eos/api/eosSignTransaction.js +1 -1
- package/lib/api/eos/eosSignTx.d.ts +2 -2
- package/lib/api/ethereum/EthereumFees.d.ts +5 -8
- package/lib/api/ethereum/EthereumFees.js +24 -38
- package/lib/api/ethereum/api/ethereumGetAddress.d.ts +1 -5
- package/lib/api/ethereum/api/ethereumGetAddress.js +7 -8
- package/lib/api/ethereum/api/ethereumGetPublicKey.d.ts +11 -7
- package/lib/api/ethereum/api/ethereumGetPublicKey.js +12 -5
- package/lib/api/ethereum/api/ethereumSignTransaction.js +2 -2
- package/lib/api/ethereum/api/ethereumSignTypedData.d.ts +2 -4
- package/lib/api/ethereum/api/ethereumSignTypedData.js +1 -1
- package/lib/api/firmware/uploadFirmware.d.ts +2 -2
- package/lib/api/getAccountDescriptor.js +1 -3
- package/lib/api/getAccountInfo.js +4 -9
- package/lib/api/getAddress.js +6 -7
- package/lib/api/getCoinInfo.d.ts +12 -18
- package/lib/api/getPublicKey.d.ts +11 -7
- package/lib/api/resetDevice.js +1 -3
- package/lib/api/signTransaction.js +3 -3
- package/lib/api/stellar/api/stellarSignTransaction.js +1 -1
- package/lib/constants/errors.d.ts +1 -2
- package/lib/constants/errors.js +8 -3
- package/lib/core/index.js +36 -15
- package/lib/core/onCallFirmwareUpdate.js +6 -3
- package/lib/data/coinInfo.d.ts +44 -66
- package/lib/data/config.d.ts +10 -0
- package/lib/data/config.js +10 -0
- package/lib/data/deviceAuthenticityConfig.js +4 -1
- package/lib/data/version.d.ts +1 -1
- package/lib/data/version.js +1 -1
- package/lib/device/Device.d.ts +82 -16
- package/lib/device/Device.js +51 -61
- package/lib/device/DeviceCommands.d.ts +37 -4549
- package/lib/device/DeviceCommands.js +55 -264
- package/lib/device/DeviceCurrentSession.d.ts +4531 -0
- package/lib/device/DeviceCurrentSession.js +209 -0
- package/lib/device/DeviceList.js +4 -6
- package/lib/device/TransportManager.d.ts +1 -1
- package/lib/device/TransportManager.js +5 -4
- package/lib/events/ui-response.d.ts +3 -3
- package/lib/impl/dynamic.d.ts +4 -1
- package/lib/impl/dynamic.js +17 -4
- package/lib/tsconfig.lib.tsbuildinfo +1 -1
- package/lib/types/api/getPublicKey.d.ts +5 -3
- package/lib/types/api/getPublicKey.js +13 -12
- package/lib/types/coinInfo.d.ts +12 -24
- package/lib/types/fees.d.ts +2 -11
- package/lib/types/fees.js +3 -11
- package/lib/utils/versionCheck.js +1 -1
- package/package.json +9 -9
- package/lib/device/prompts.d.ts +0 -866
- package/lib/device/prompts.js +0 -60
package/lib/device/Device.js
CHANGED
|
@@ -8,8 +8,8 @@ const transport_1 = require("@trezor/transport");
|
|
|
8
8
|
const utils_1 = require("@trezor/utils");
|
|
9
9
|
const DeviceCommands_1 = require("./DeviceCommands");
|
|
10
10
|
const constants_1 = require("../constants");
|
|
11
|
+
const DeviceCurrentSession_1 = require("./DeviceCurrentSession");
|
|
11
12
|
const checkFirmwareRevision_1 = require("./checkFirmwareRevision");
|
|
12
|
-
const prompts_1 = require("./prompts");
|
|
13
13
|
const firmware_1 = require("../api/firmware");
|
|
14
14
|
const DataManager_1 = require("../data/DataManager");
|
|
15
15
|
const coinInfo_1 = require("../data/coinInfo");
|
|
@@ -20,6 +20,7 @@ const events_1 = require("../events");
|
|
|
20
20
|
const types_1 = require("../types");
|
|
21
21
|
const debug_1 = require("../utils/debug");
|
|
22
22
|
const deviceFeaturesUtils_1 = require("../utils/deviceFeaturesUtils");
|
|
23
|
+
const pathUtils_1 = require("../utils/pathUtils");
|
|
23
24
|
const _log = (0, debug_1.initLog)('Device');
|
|
24
25
|
exports.CANCEL_TIMEOUT = 1_000;
|
|
25
26
|
exports.GET_FEATURES_TIMEOUT = 3_000;
|
|
@@ -33,10 +34,10 @@ class Device extends utils_1.TypedEmitter {
|
|
|
33
34
|
transport;
|
|
34
35
|
protocol;
|
|
35
36
|
transportPath;
|
|
36
|
-
transportSessionOwner;
|
|
37
37
|
transportDescriptorType;
|
|
38
38
|
bluetoothProps;
|
|
39
39
|
session;
|
|
40
|
+
transportSessionOwner;
|
|
40
41
|
lastAcquiredHere;
|
|
41
42
|
unreadableError;
|
|
42
43
|
_firmwareStatus;
|
|
@@ -56,8 +57,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
56
57
|
releasePromise;
|
|
57
58
|
runPromise;
|
|
58
59
|
keepTransportSession = false;
|
|
59
|
-
|
|
60
|
-
cancelableAction;
|
|
60
|
+
currentSession;
|
|
61
61
|
loaded = false;
|
|
62
62
|
inconsistent = false;
|
|
63
63
|
firstRunPromise;
|
|
@@ -136,8 +136,8 @@ class Device extends utils_1.TypedEmitter {
|
|
|
136
136
|
if (result.success) {
|
|
137
137
|
this.session = result.payload;
|
|
138
138
|
this.lastAcquiredHere = true;
|
|
139
|
-
this.
|
|
140
|
-
this.
|
|
139
|
+
this.currentSession?.dispose();
|
|
140
|
+
this.currentSession = new DeviceCurrentSession_1.DeviceCurrentSession(this, this.transport, this.protocol, this.session);
|
|
141
141
|
return result;
|
|
142
142
|
}
|
|
143
143
|
else {
|
|
@@ -154,16 +154,11 @@ class Device extends utils_1.TypedEmitter {
|
|
|
154
154
|
return this.acquirePromise;
|
|
155
155
|
}
|
|
156
156
|
async release() {
|
|
157
|
-
const localSession = this.
|
|
157
|
+
const localSession = this.lastAcquiredHere ? this.session : null;
|
|
158
158
|
if (!localSession || this.keepTransportSession || this.releasePromise) {
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
|
-
|
|
162
|
-
this.commands.dispose();
|
|
163
|
-
if (this.commands.callPromise) {
|
|
164
|
-
await this.commands.callPromise;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
161
|
+
await this.currentSession?.dispose();
|
|
167
162
|
const sessionPromise = this.getSessionChangePromise();
|
|
168
163
|
this.releasePromise = this.transport
|
|
169
164
|
.release({ session: localSession, path: this.transportPath })
|
|
@@ -237,12 +232,13 @@ class Device extends utils_1.TypedEmitter {
|
|
|
237
232
|
this.usedElsewhere();
|
|
238
233
|
}
|
|
239
234
|
if (!descriptor.session) {
|
|
240
|
-
const methodStillRunning = !this.
|
|
235
|
+
const methodStillRunning = !this.currentSession?.isDisposed();
|
|
241
236
|
if (methodStillRunning) {
|
|
242
237
|
this.releaseTransportSession();
|
|
243
238
|
}
|
|
244
239
|
}
|
|
245
240
|
this.session = descriptor.session;
|
|
241
|
+
this.transportSessionOwner = descriptor.sessionOwner;
|
|
246
242
|
this.emitLifecycle(events_1.DEVICE.CHANGED);
|
|
247
243
|
}
|
|
248
244
|
run(fn, options) {
|
|
@@ -276,22 +272,10 @@ class Device extends utils_1.TypedEmitter {
|
|
|
276
272
|
await this.releasePromise;
|
|
277
273
|
}
|
|
278
274
|
}
|
|
279
|
-
setCancelableAction(callback) {
|
|
280
|
-
this.cancelableAction = (e) => callback(e)
|
|
281
|
-
.catch(e2 => {
|
|
282
|
-
_log.debug('cancelableAction error', e2);
|
|
283
|
-
})
|
|
284
|
-
.finally(() => {
|
|
285
|
-
this.clearCancelableAction();
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
clearCancelableAction() {
|
|
289
|
-
this.cancelableAction = undefined;
|
|
290
|
-
}
|
|
291
275
|
async interruptionFromUser(error) {
|
|
292
276
|
_log.debug('interruptionFromUser');
|
|
293
|
-
await this.
|
|
294
|
-
await this.
|
|
277
|
+
await this.currentSession?.abort(error);
|
|
278
|
+
await this.currentSession?.dispose();
|
|
295
279
|
if (this.runPromise) {
|
|
296
280
|
this.runPromise.reject(error);
|
|
297
281
|
delete this.runPromise;
|
|
@@ -304,9 +288,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
304
288
|
this.lastAcquiredHere = false;
|
|
305
289
|
this._featuresNeedsReload = true;
|
|
306
290
|
_log.debug('interruptionFromOutside');
|
|
307
|
-
|
|
308
|
-
this.commands.dispose();
|
|
309
|
-
}
|
|
291
|
+
this.currentSession?.dispose();
|
|
310
292
|
if (this.runPromise) {
|
|
311
293
|
this.runPromise.reject(constants_1.ERRORS.TypedError('Device_UsedElsewhere'));
|
|
312
294
|
delete this.runPromise;
|
|
@@ -319,7 +301,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
319
301
|
if (this.releasePromise) {
|
|
320
302
|
await this.releasePromise;
|
|
321
303
|
}
|
|
322
|
-
const acquireNeeded = !this.isUsedHere() || this.
|
|
304
|
+
const acquireNeeded = !this.isUsedHere() || this.currentSession?.isDisposed();
|
|
323
305
|
if (acquireNeeded) {
|
|
324
306
|
await this.acquire();
|
|
325
307
|
}
|
|
@@ -341,9 +323,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
341
323
|
![0, 2].includes(this.transportDescriptorType)) {
|
|
342
324
|
_log.debug('sending a preventive cancel on the first encounter with the device');
|
|
343
325
|
await Promise.race([
|
|
344
|
-
this.
|
|
345
|
-
.typedCall('Cancel', 'Failure', {})
|
|
346
|
-
.catch(() => { }),
|
|
326
|
+
this.getCurrentSession().cancelCall(),
|
|
347
327
|
new Promise((_, reject) => setTimeout(reject, cancelTimeout)),
|
|
348
328
|
]).catch(() => this.acquire());
|
|
349
329
|
}
|
|
@@ -351,10 +331,9 @@ class Device extends utils_1.TypedEmitter {
|
|
|
351
331
|
await Promise.race([
|
|
352
332
|
this.getFeatures().finally(() => clearTimeout(getFeaturesTimeoutId)),
|
|
353
333
|
new Promise((_resolve, reject) => {
|
|
354
|
-
getFeaturesTimeoutId = setTimeout(() => {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
});
|
|
334
|
+
getFeaturesTimeoutId = setTimeout(async () => {
|
|
335
|
+
await this.getCurrentSession().cancelCall(false);
|
|
336
|
+
reject(new Error('GetFeatures timeout'));
|
|
358
337
|
}, getFeaturesTimeout);
|
|
359
338
|
}),
|
|
360
339
|
]);
|
|
@@ -414,11 +393,14 @@ class Device extends utils_1.TypedEmitter {
|
|
|
414
393
|
this.firstRunPromise.resolve(true);
|
|
415
394
|
}
|
|
416
395
|
}
|
|
417
|
-
|
|
418
|
-
if (!this.
|
|
396
|
+
getCurrentSession() {
|
|
397
|
+
if (!this.currentSession) {
|
|
419
398
|
throw constants_1.ERRORS.TypedError('Runtime', `Device: commands not defined`);
|
|
420
399
|
}
|
|
421
|
-
return this.
|
|
400
|
+
return this.currentSession;
|
|
401
|
+
}
|
|
402
|
+
getCommands() {
|
|
403
|
+
return (0, DeviceCommands_1.DeviceCommands)(this.getCurrentSession());
|
|
422
404
|
}
|
|
423
405
|
setInstance(instance = 0) {
|
|
424
406
|
if (this.instance !== instance) {
|
|
@@ -458,8 +440,12 @@ class Device extends utils_1.TypedEmitter {
|
|
|
458
440
|
}
|
|
459
441
|
}
|
|
460
442
|
const expectedState = this.getState()?.staticSessionId;
|
|
461
|
-
const
|
|
462
|
-
|
|
443
|
+
const { message } = await this.getCurrentSession().typedCall('GetAddress', 'Address', {
|
|
444
|
+
address_n: [(0, pathUtils_1.toHardened)(44), (0, pathUtils_1.toHardened)(1), (0, pathUtils_1.toHardened)(0), 0, 0],
|
|
445
|
+
coin_name: 'Testnet',
|
|
446
|
+
script_type: 'SPENDADDRESS',
|
|
447
|
+
});
|
|
448
|
+
const uniqueState = `${message.address}@${this.features.device_id}:${this.instance}`;
|
|
463
449
|
if (this.features.session_id) {
|
|
464
450
|
this.setState({ sessionId: this.features.session_id });
|
|
465
451
|
}
|
|
@@ -481,7 +467,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
481
467
|
payload.session_id = sessionId;
|
|
482
468
|
}
|
|
483
469
|
}
|
|
484
|
-
const { message } = await this.
|
|
470
|
+
const { message } = await this.getCurrentSession().typedCall('Initialize', 'Features', payload);
|
|
485
471
|
this._updateFeatures(message);
|
|
486
472
|
this.setState({ deriveCardano: payload?.derive_cardano });
|
|
487
473
|
}
|
|
@@ -490,7 +476,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
490
476
|
this.setState(storage.loadState(this));
|
|
491
477
|
}
|
|
492
478
|
async getFeatures() {
|
|
493
|
-
const { message } = await this.
|
|
479
|
+
const { message } = await this.getCurrentSession().typedCall('GetFeatures', 'Features', {});
|
|
494
480
|
this._updateFeatures(message);
|
|
495
481
|
}
|
|
496
482
|
async checkFirmwareHashWithRetries() {
|
|
@@ -548,7 +534,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
548
534
|
const strippedBinary = (0, firmware_1.stripFwHeaders)(binary);
|
|
549
535
|
const { hash: expectedHash, challenge } = (0, firmware_1.calculateFirmwareHash)(this.features.major_version, strippedBinary, (0, crypto_1.randomBytes)(32));
|
|
550
536
|
try {
|
|
551
|
-
const deviceResponse = await this.
|
|
537
|
+
const deviceResponse = await this.getCurrentSession().typedCall('GetFirmwareHash', 'FirmwareHash', { challenge });
|
|
552
538
|
if (!deviceResponse?.message?.hash) {
|
|
553
539
|
return createFailResult('other-error', 'Device response is missing hash');
|
|
554
540
|
}
|
|
@@ -612,20 +598,17 @@ class Device extends utils_1.TypedEmitter {
|
|
|
612
598
|
return this._uploadTranslationData(downloadedBinary);
|
|
613
599
|
}
|
|
614
600
|
async _uploadTranslationData(payload) {
|
|
615
|
-
if (!this.commands) {
|
|
616
|
-
throw constants_1.ERRORS.TypedError('Runtime', 'uploadTranslationData: device.commands is not set');
|
|
617
|
-
}
|
|
618
601
|
if (payload === null) {
|
|
619
|
-
const response = await this.
|
|
602
|
+
const response = await this.getCurrentSession().typedCall('ChangeLanguage', ['Success'], { data_length: 0 });
|
|
620
603
|
return response.message;
|
|
621
604
|
}
|
|
622
605
|
const length = payload.byteLength;
|
|
623
|
-
let response = await this.
|
|
606
|
+
let response = await this.getCurrentSession().typedCall('ChangeLanguage', ['TranslationDataRequest', 'Success'], { data_length: length });
|
|
624
607
|
while (response.type !== 'Success') {
|
|
625
608
|
const start = response.message.data_offset;
|
|
626
609
|
const end = response.message.data_offset + response.message.data_length;
|
|
627
610
|
const chunk = payload.slice(start, end);
|
|
628
|
-
response = await this.
|
|
611
|
+
response = await this.getCurrentSession().typedCall('TranslationDataAck', ['TranslationDataRequest', 'Success'], {
|
|
629
612
|
data_chunk: Buffer.from(chunk).toString('hex'),
|
|
630
613
|
});
|
|
631
614
|
}
|
|
@@ -693,6 +676,20 @@ class Device extends utils_1.TypedEmitter {
|
|
|
693
676
|
}
|
|
694
677
|
}
|
|
695
678
|
}
|
|
679
|
+
prompt(type, args) {
|
|
680
|
+
return new Promise(callback => {
|
|
681
|
+
if (!this.listenerCount(type)) {
|
|
682
|
+
const payload = {
|
|
683
|
+
success: false,
|
|
684
|
+
error: new Error(`${type} callback not configured`),
|
|
685
|
+
};
|
|
686
|
+
callback(payload);
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
this.emit(type, { callback, ...args });
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
696
693
|
isUnacquired() {
|
|
697
694
|
return this.features === undefined;
|
|
698
695
|
}
|
|
@@ -752,9 +749,6 @@ class Device extends utils_1.TypedEmitter {
|
|
|
752
749
|
waitForFirstRun() {
|
|
753
750
|
return this.firstRunPromise.promise;
|
|
754
751
|
}
|
|
755
|
-
getLocalSession() {
|
|
756
|
-
return this.lastAcquiredHere ? this.session : null;
|
|
757
|
-
}
|
|
758
752
|
getUniquePath() {
|
|
759
753
|
return this.uniquePath;
|
|
760
754
|
}
|
|
@@ -781,11 +775,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
781
775
|
dispose() {
|
|
782
776
|
this.removeAllListeners();
|
|
783
777
|
if (this.session && this.lastAcquiredHere) {
|
|
784
|
-
|
|
785
|
-
session: this.session,
|
|
786
|
-
path: this.transportPath,
|
|
787
|
-
onClose: true,
|
|
788
|
-
});
|
|
778
|
+
this.transport.releaseSync(this.session);
|
|
789
779
|
}
|
|
790
780
|
}
|
|
791
781
|
getMode() {
|