@trezor/connect 9.4.2 → 9.4.3-beta.2

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.
Files changed (214) hide show
  1. package/CHANGELOG.md +90 -9
  2. package/README.md +1 -1
  3. package/lib/api/applyFlags.js +1 -1
  4. package/lib/api/applySettings.js +1 -1
  5. package/lib/api/authenticateDevice.js +1 -1
  6. package/lib/api/authorizeCoinjoin.js +1 -1
  7. package/lib/api/backupDevice.js +1 -1
  8. package/lib/api/binance/api/binanceGetAddress.js +2 -1
  9. package/lib/api/binance/api/binanceGetPublicKey.js +2 -1
  10. package/lib/api/binance/api/binanceSignTransaction.js +2 -1
  11. package/lib/api/binance/binanceSignTx.js +1 -1
  12. package/lib/api/bitcoin/Fees.js +2 -2
  13. package/lib/api/bitcoin/TransactionComposer.d.ts +3 -3
  14. package/lib/api/bitcoin/TransactionComposer.js +2 -2
  15. package/lib/api/bitcoin/refTx.js +1 -1
  16. package/lib/api/blockchainDisconnect.js +1 -1
  17. package/lib/api/blockchainEvmRpcCall.d.ts +16 -0
  18. package/lib/api/blockchainEvmRpcCall.js +45 -0
  19. package/lib/api/cancelCoinjoinAuthorization.js +1 -1
  20. package/lib/api/cardano/api/cardanoGetAddress.js +2 -1
  21. package/lib/api/cardano/api/cardanoGetNativeScriptHash.js +2 -1
  22. package/lib/api/cardano/api/cardanoGetPublicKey.js +2 -1
  23. package/lib/api/cardano/api/cardanoSignTransaction.js +2 -1
  24. package/lib/api/cardano/cardanoAddressParameters.js +1 -1
  25. package/lib/api/cardano/cardanoAuxiliaryData.js +1 -1
  26. package/lib/api/cardano/cardanoCertificate.js +1 -1
  27. package/lib/api/cardano/cardanoInputs.d.ts +8 -8
  28. package/lib/api/cardano/cardanoInputs.js +1 -1
  29. package/lib/api/cardano/cardanoOutputs.d.ts +22 -22
  30. package/lib/api/cardano/cardanoOutputs.js +1 -1
  31. package/lib/api/cardano/cardanoTokenBundle.d.ts +6 -6
  32. package/lib/api/cardano/cardanoTokenBundle.js +1 -1
  33. package/lib/api/changeLanguage.js +1 -1
  34. package/lib/api/changePin.js +1 -1
  35. package/lib/api/cipherKeyValue.js +1 -1
  36. package/lib/api/common/paramsValidator.js +1 -1
  37. package/lib/api/composeTransaction.d.ts +9 -3
  38. package/lib/api/composeTransaction.js +7 -4
  39. package/lib/api/eos/api/eosGetPublicKey.js +2 -1
  40. package/lib/api/eos/api/eosSignTransaction.js +2 -1
  41. package/lib/api/eos/eosSignTx.d.ts +3 -3
  42. package/lib/api/ethereum/api/ethereumGetAddress.js +2 -1
  43. package/lib/api/ethereum/api/ethereumGetPublicKey.js +2 -1
  44. package/lib/api/ethereum/api/ethereumSignMessage.d.ts +1 -1
  45. package/lib/api/ethereum/api/ethereumSignMessage.js +2 -1
  46. package/lib/api/ethereum/api/ethereumSignTransaction.d.ts +1 -1
  47. package/lib/api/ethereum/api/ethereumSignTransaction.js +13 -7
  48. package/lib/api/ethereum/api/ethereumSignTypedData.d.ts +58 -57
  49. package/lib/api/ethereum/api/ethereumSignTypedData.js +3 -2
  50. package/lib/api/ethereum/api/ethereumVerifyMessage.js +2 -1
  51. package/lib/api/ethereum/ethereumDefinitions.d.ts +21 -21
  52. package/lib/api/ethereum/ethereumDefinitions.js +6 -5
  53. package/lib/api/firmware/getBinary.d.ts +4 -5
  54. package/lib/api/firmware/getBinary.js +12 -13
  55. package/lib/api/firmware/getBinaryForFirmwareUpgrade.d.ts +3 -3
  56. package/lib/api/firmware/getBinaryForFirmwareUpgrade.js +2 -2
  57. package/lib/api/firmware/index.d.ts +1 -1
  58. package/lib/api/firmware/index.js +2 -1
  59. package/lib/api/firmware/x509certificate.js +3 -5
  60. package/lib/api/getAccountDescriptor.js +1 -1
  61. package/lib/api/getAddress.js +1 -1
  62. package/lib/api/getCoinInfo.d.ts +3 -0
  63. package/lib/api/getCoinInfo.js +1 -1
  64. package/lib/api/getFirmwareHash.js +1 -1
  65. package/lib/api/getOwnershipId.js +1 -1
  66. package/lib/api/getOwnershipProof.js +1 -1
  67. package/lib/api/getPublicKey.js +1 -1
  68. package/lib/api/index.d.ts +2 -1
  69. package/lib/api/index.js +5 -3
  70. package/lib/api/loadDevice.d.ts +14 -0
  71. package/lib/api/loadDevice.js +44 -0
  72. package/lib/api/nem/api/nemGetAddress.js +2 -1
  73. package/lib/api/nem/api/nemSignTransaction.js +2 -1
  74. package/lib/api/pushTransaction.js +1 -1
  75. package/lib/api/rebootToBootloader.js +1 -1
  76. package/lib/api/recoveryDevice.js +1 -1
  77. package/lib/api/requestLogin.js +1 -1
  78. package/lib/api/resetDevice.js +1 -2
  79. package/lib/api/ripple/api/rippleGetAddress.js +2 -1
  80. package/lib/api/ripple/api/rippleSignTransaction.js +2 -1
  81. package/lib/api/setBrightness.js +1 -1
  82. package/lib/api/setBusy.js +1 -1
  83. package/lib/api/signMessage.js +1 -1
  84. package/lib/api/solana/api/solanaGetAddress.js +2 -1
  85. package/lib/api/solana/api/solanaGetPublicKey.js +2 -1
  86. package/lib/api/solana/api/solanaSignTransaction.js +2 -1
  87. package/lib/api/stellar/api/stellarGetAddress.js +2 -1
  88. package/lib/api/stellar/api/stellarSignTransaction.js +2 -1
  89. package/lib/api/stellar/stellarSignTx.js +1 -1
  90. package/lib/api/tezos/api/tezosGetAddress.js +2 -1
  91. package/lib/api/tezos/api/tezosGetPublicKey.js +2 -1
  92. package/lib/api/tezos/api/tezosSignTransaction.js +2 -1
  93. package/lib/api/tezos/tezosSignTx.js +1 -1
  94. package/lib/api/unlockPath.js +1 -1
  95. package/lib/api/verifyMessage.js +1 -1
  96. package/lib/backend/Blockchain.d.ts +3 -0
  97. package/lib/backend/Blockchain.js +6 -6
  98. package/lib/constants/errors.d.ts +49 -38
  99. package/lib/constants/errors.js +10 -0
  100. package/lib/constants/firmware.d.ts +2 -0
  101. package/lib/constants/firmware.js +5 -0
  102. package/lib/constants/index.d.ts +2 -0
  103. package/lib/constants/index.js +4 -1
  104. package/lib/constants/nem.d.ts +3 -3
  105. package/lib/constants/utxo.d.ts +3 -0
  106. package/lib/constants/utxo.js +5 -0
  107. package/lib/core/AbstractMethod.d.ts +13 -5
  108. package/lib/core/AbstractMethod.js +50 -24
  109. package/lib/core/index.js +41 -30
  110. package/lib/core/onCallFirmwareUpdate.d.ts +2 -2
  111. package/lib/core/onCallFirmwareUpdate.js +6 -6
  112. package/lib/data/DataManager.d.ts +0 -181
  113. package/lib/data/DataManager.js +40 -6
  114. package/lib/data/analyticsInfo.js +4 -2
  115. package/lib/data/coinInfo.d.ts +14 -0
  116. package/lib/data/config.d.ts +20 -22
  117. package/lib/data/config.js +15 -40
  118. package/lib/data/connectSettings.js +10 -4
  119. package/lib/data/deviceAuthenticityConfig.js +20 -0
  120. package/lib/data/deviceAuthenticityConfigTypes.d.ts +32 -23
  121. package/lib/data/firmwareInfo.d.ts +1 -1
  122. package/lib/data/models.d.ts +9 -0
  123. package/lib/data/models.js +9 -0
  124. package/lib/data/version.d.ts +2 -1
  125. package/lib/data/version.js +3 -2
  126. package/lib/device/Device.d.ts +144 -36
  127. package/lib/device/Device.js +270 -113
  128. package/lib/device/DeviceCommands.js +4 -4
  129. package/lib/device/DeviceList.d.ts +13 -21
  130. package/lib/device/DeviceList.js +54 -168
  131. package/lib/device/checkFirmwareRevision.js +4 -4
  132. package/lib/device/prompts.js +3 -2
  133. package/lib/device/resolveDescriptorForTaproot.d.ts +1 -1
  134. package/lib/events/call.d.ts +5 -5
  135. package/lib/events/call.js +2 -2
  136. package/lib/events/core.d.ts +4 -3
  137. package/lib/events/device.d.ts +0 -6
  138. package/lib/events/device.js +0 -6
  139. package/lib/events/transport.d.ts +1 -1
  140. package/lib/factory.d.ts +6 -6
  141. package/lib/factory.js +132 -136
  142. package/lib/impl/dynamic.d.ts +33 -0
  143. package/lib/impl/dynamic.js +75 -0
  144. package/lib/index-browser.d.ts +3 -1
  145. package/lib/index-browser.js +0 -3
  146. package/lib/index.d.ts +3 -1
  147. package/lib/index.js +1 -13
  148. package/lib/types/api/applySettings.d.ts +13 -13
  149. package/lib/types/api/authenticateDevice.d.ts +33 -24
  150. package/lib/types/api/authorizeCoinjoin.d.ts +10 -10
  151. package/lib/types/api/binance/index.d.ts +143 -143
  152. package/lib/types/api/binance/index.js +1 -1
  153. package/lib/types/api/bitcoin/index.d.ts +11 -11
  154. package/lib/types/api/bitcoin/index.js +1 -1
  155. package/lib/types/api/blockchainEvmRpcCall.d.ts +4 -0
  156. package/lib/types/api/{checkFirmwareAuthenticity.js → blockchainEvmRpcCall.js} +1 -1
  157. package/lib/types/api/cancelCoinjoinAuthorization.d.ts +1 -1
  158. package/lib/types/api/cardano/index.d.ts +507 -507
  159. package/lib/types/api/changeLanguage.d.ts +6 -6
  160. package/lib/types/api/cipherKeyValue.d.ts +8 -8
  161. package/lib/types/api/cipherKeyValue.js +1 -1
  162. package/lib/types/api/composeTransaction.d.ts +13 -7
  163. package/lib/types/api/eos/index.d.ts +525 -525
  164. package/lib/types/api/eos/index.js +1 -1
  165. package/lib/types/api/ethereum/index.d.ts +100 -100
  166. package/lib/types/api/firmwareUpdate.d.ts +5 -5
  167. package/lib/types/api/getAccountDescriptor.d.ts +4 -4
  168. package/lib/types/api/getAddress.d.ts +32 -32
  169. package/lib/types/api/getOwnershipId.d.ts +24 -24
  170. package/lib/types/api/getOwnershipProof.d.ts +28 -28
  171. package/lib/types/api/getPublicKey.d.ts +24 -24
  172. package/lib/types/api/getPublicKey.js +1 -1
  173. package/lib/types/api/index.d.ts +4 -8
  174. package/lib/types/api/init.d.ts +4 -2
  175. package/lib/types/api/loadDevice.d.ts +4 -0
  176. package/lib/types/api/loadDevice.js +3 -0
  177. package/lib/types/api/nem/index.d.ts +612 -612
  178. package/lib/types/api/nem/index.js +1 -1
  179. package/lib/types/api/nemGetAddress.d.ts +6 -6
  180. package/lib/types/api/pushTransaction.d.ts +3 -3
  181. package/lib/types/api/recoveryDevice.d.ts +9 -9
  182. package/lib/types/api/requestLogin.d.ts +25 -25
  183. package/lib/types/api/ripple/index.d.ts +21 -21
  184. package/lib/types/api/ripple/index.js +1 -1
  185. package/lib/types/api/solana/index.d.ts +23 -23
  186. package/lib/types/api/solana/index.js +1 -1
  187. package/lib/types/api/stellar/index.d.ts +582 -582
  188. package/lib/types/api/stellar/index.js +1 -1
  189. package/lib/types/api/tezos/index.d.ts +120 -120
  190. package/lib/types/api/tezos/index.js +1 -1
  191. package/lib/types/api/unlockPath.d.ts +2 -2
  192. package/lib/types/coinInfo.d.ts +231 -224
  193. package/lib/types/device.d.ts +33 -14
  194. package/lib/types/device.js +3 -1
  195. package/lib/types/fees.d.ts +19 -19
  196. package/lib/types/firmware.d.ts +1 -1
  197. package/lib/types/params.d.ts +23 -19
  198. package/lib/types/settings.d.ts +17 -10
  199. package/lib/types/utils.d.ts +1 -0
  200. package/lib/types/utils.js +3 -0
  201. package/lib/utils/addressUtils.js +2 -2
  202. package/lib/utils/assetUtils.d.ts +1 -1
  203. package/lib/utils/assetUtils.js +6 -6
  204. package/lib/utils/assets.js +1 -1
  205. package/lib/utils/assets.native.js +1 -1
  206. package/lib/utils/deviceFeaturesUtils.js +1 -1
  207. package/lib/utils/proxy-event-emitter.d.ts +21 -0
  208. package/lib/utils/proxy-event-emitter.js +65 -0
  209. package/lib/utils/uiPromiseManager.d.ts +2 -1
  210. package/lib/utils/uiPromiseManager.js +3 -3
  211. package/package.json +12 -12
  212. package/lib/api/checkFirmwareAuthenticity.d.ts +0 -11
  213. package/lib/api/checkFirmwareAuthenticity.js +0 -56
  214. package/lib/types/api/checkFirmwareAuthenticity.d.ts +0 -11
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Device = exports.GET_FEATURES_TIMEOUT_REACT_NATIVE = exports.GET_FEATURES_TIMEOUT = void 0;
4
+ const crypto_1 = require("crypto");
4
5
  const utils_1 = require("@trezor/utils");
5
6
  const protocol_1 = require("@trezor/protocol");
7
+ const transport_1 = require("@trezor/transport");
6
8
  const DeviceCommands_1 = require("./DeviceCommands");
7
9
  const constants_1 = require("../constants");
8
10
  const events_1 = require("../events");
@@ -11,11 +13,11 @@ const DataManager_1 = require("../data/DataManager");
11
13
  const firmwareInfo_1 = require("../data/firmwareInfo");
12
14
  const deviceFeaturesUtils_1 = require("../utils/deviceFeaturesUtils");
13
15
  const debug_1 = require("../utils/debug");
14
- const transport_1 = require("@trezor/transport");
15
16
  const types_1 = require("../types");
16
17
  const models_1 = require("../data/models");
17
18
  const getLanguage_1 = require("../data/getLanguage");
18
19
  const checkFirmwareRevision_1 = require("./checkFirmwareRevision");
20
+ const firmware_1 = require("../api/firmware");
19
21
  const _log = (0, debug_1.initLog)('Device');
20
22
  exports.GET_FEATURES_TIMEOUT = 3000;
21
23
  exports.GET_FEATURES_TIMEOUT_REACT_NATIVE = 20000;
@@ -25,98 +27,192 @@ const parseRunOptions = (options) => {
25
27
  return options;
26
28
  };
27
29
  class Device extends utils_1.TypedEmitter {
28
- constructor(transport, descriptor) {
30
+ get firmwareStatus() {
31
+ return this._firmwareStatus;
32
+ }
33
+ get firmwareRelease() {
34
+ return this._firmwareRelease;
35
+ }
36
+ get features() {
37
+ return this._features;
38
+ }
39
+ get unavailableCapabilities() {
40
+ return this._unavailableCapabilities;
41
+ }
42
+ get firmwareType() {
43
+ return this._firmwareType;
44
+ }
45
+ constructor({ id, transport, descriptor, listener }) {
29
46
  super();
30
- this.featuresNeedsReload = false;
47
+ this._featuresNeedsReload = false;
31
48
  this.keepTransportSession = false;
32
49
  this.loaded = false;
33
50
  this.inconsistent = false;
34
51
  this.instance = 0;
35
52
  this.state = [];
36
53
  this.stateStorage = undefined;
37
- this.unavailableCapabilities = {};
38
- this.networkTypeState = [];
54
+ this._unavailableCapabilities = {};
39
55
  this.name = 'Trezor';
40
56
  this.availableTranslations = [];
41
57
  this.authenticityChecks = {
42
58
  firmwareRevision: null,
59
+ firmwareHash: null,
43
60
  };
44
- this.useCardanoDerivation = false;
61
+ this.emitLifecycle = listener;
45
62
  this.protocol = protocol_1.v1;
63
+ this.uniquePath = id;
46
64
  this.transport = transport;
47
- this.originalDescriptor = descriptor;
65
+ this.transportPath = descriptor.path;
66
+ this.transportSessionOwner = descriptor.sessionOwner;
67
+ this.transportDescriptorType = descriptor.type;
68
+ this.session = descriptor.session;
69
+ this.lastAcquiredHere = false;
48
70
  this.firstRunPromise = (0, utils_1.createDeferred)();
49
71
  }
50
- static fromDescriptor(transport, originalDescriptor) {
51
- const descriptor = { ...originalDescriptor, session: null };
52
- try {
53
- const device = new Device(transport, descriptor);
54
- return device;
55
- }
56
- catch (error) {
57
- _log.error('Device.fromDescriptor', error);
58
- throw error;
72
+ getSessionChangePromise() {
73
+ if (!this.sessionDfd) {
74
+ this.sessionDfd = (0, utils_1.createDeferred)();
75
+ this.sessionDfd.promise.finally(() => {
76
+ this.sessionDfd = undefined;
77
+ });
59
78
  }
79
+ return this.sessionDfd.promise;
60
80
  }
61
- static createUnacquired(transport, descriptor, unreadableError) {
62
- const device = new Device(transport, descriptor);
63
- device.unreadableError = unreadableError;
64
- return device;
65
- }
66
- async acquire() {
67
- this.acquirePromise = this.transport.acquire({
68
- input: {
69
- path: this.originalDescriptor.path,
70
- previous: this.originalDescriptor.session,
71
- },
72
- });
73
- const acquireResult = await this.acquirePromise;
74
- this.acquirePromise = undefined;
75
- if (!acquireResult.success) {
76
- if (this.runPromise) {
77
- this.runPromise.reject(new Error(acquireResult.error));
78
- delete this.runPromise;
81
+ async waitAndCompareSession(response, sessionPromise) {
82
+ if (response.success) {
83
+ try {
84
+ if ((await sessionPromise) !== response.payload) {
85
+ return {
86
+ success: false,
87
+ error: transport_1.TRANSPORT_ERROR.SESSION_WRONG_PREVIOUS,
88
+ };
89
+ }
90
+ }
91
+ catch {
92
+ return {
93
+ success: false,
94
+ error: transport_1.TRANSPORT_ERROR.DEVICE_DISCONNECTED_DURING_ACTION,
95
+ };
96
+ }
97
+ }
98
+ return response;
99
+ }
100
+ acquire() {
101
+ const sessionPromise = this.getSessionChangePromise();
102
+ this.acquirePromise = this.transport
103
+ .acquire({ input: { path: this.transportPath, previous: this.session } })
104
+ .then(result => this.waitAndCompareSession(result, sessionPromise))
105
+ .then(result => {
106
+ var _a;
107
+ if (result.success) {
108
+ this.session = result.payload;
109
+ this.lastAcquiredHere = true;
110
+ (_a = this.commands) === null || _a === void 0 ? void 0 : _a.dispose();
111
+ this.commands = new DeviceCommands_1.DeviceCommands(this, this.transport, this.session);
112
+ return result;
113
+ }
114
+ else {
115
+ if (this.runPromise) {
116
+ this.runPromise.reject(new Error(result.error));
117
+ delete this.runPromise;
118
+ }
119
+ throw result.error;
79
120
  }
80
- throw acquireResult.error;
121
+ })
122
+ .finally(() => {
123
+ this.acquirePromise = undefined;
124
+ });
125
+ return this.acquirePromise;
126
+ }
127
+ async release() {
128
+ const localSession = this.getLocalSession();
129
+ if (!localSession || this.keepTransportSession || this.releasePromise) {
130
+ return;
81
131
  }
82
- const transportSession = acquireResult.payload;
83
- _log.debug('Expected workflow id:', transportSession);
84
- this.transportSession = transportSession;
85
- this.originalDescriptor.session = transportSession;
86
132
  if (this.commands) {
87
133
  this.commands.dispose();
134
+ if (this.commands.callPromise) {
135
+ await this.commands.callPromise;
136
+ }
88
137
  }
89
- this.commands = new DeviceCommands_1.DeviceCommands(this, this.transport, transportSession);
90
- }
91
- async release() {
92
- if (this.isUsedHere() &&
93
- this.transportSession &&
94
- !this.keepTransportSession &&
95
- !this.releasePromise) {
96
- if (this.commands) {
97
- this.commands.dispose();
98
- if (this.commands.callPromise) {
99
- await this.commands.callPromise;
100
- }
138
+ const sessionPromise = this.getSessionChangePromise();
139
+ this.releasePromise = this.transport
140
+ .release({ session: localSession, path: this.transportPath })
141
+ .then(result => this.waitAndCompareSession(result, sessionPromise))
142
+ .then(result => {
143
+ if (result.success) {
144
+ this.session = null;
101
145
  }
102
- this.releasePromise = this.transport.release({
103
- session: this.transportSession,
104
- path: this.originalDescriptor.path,
105
- });
106
- const releaseResponse = await this.releasePromise;
146
+ return result;
147
+ })
148
+ .finally(() => {
107
149
  this.releasePromise = undefined;
108
- if (releaseResponse.success) {
109
- this.transportSession = null;
110
- this.originalDescriptor.session = null;
111
- }
112
- }
150
+ });
151
+ return this.releasePromise;
152
+ }
153
+ releaseTransportSession() {
154
+ this.keepTransportSession = false;
113
155
  }
114
156
  async cleanup() {
115
- const acquiredListeners = this.listeners(events_1.DEVICE.ACQUIRED);
116
- this.removeAllListeners();
157
+ this.eventNames().forEach(e => this.removeAllListeners(e));
117
158
  delete this.runPromise;
118
159
  await this.release();
119
- acquiredListeners.forEach(l => this.once(events_1.DEVICE.ACQUIRED, l));
160
+ }
161
+ async handshake(delay) {
162
+ var _a;
163
+ if (delay) {
164
+ await (0, utils_1.createTimeoutPromise)(501 + delay);
165
+ }
166
+ while (true) {
167
+ if (this.isUsedElsewhere()) {
168
+ this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
169
+ }
170
+ else {
171
+ try {
172
+ await this.run();
173
+ }
174
+ catch (error) {
175
+ if (error.code === 'Device_NotFound' ||
176
+ error.message === transport_1.TRANSPORT_ERROR.DEVICE_NOT_FOUND ||
177
+ error.message === transport_1.TRANSPORT_ERROR.DEVICE_DISCONNECTED_DURING_ACTION ||
178
+ error.message === transport_1.TRANSPORT_ERROR.UNEXPECTED_ERROR ||
179
+ error.message === transport_1.TRANSPORT_ERROR.DESCRIPTOR_NOT_FOUND ||
180
+ error.message === transport_1.TRANSPORT_ERROR.HTTP_ERROR) {
181
+ }
182
+ else if (error.message === transport_1.TRANSPORT_ERROR.SESSION_WRONG_PREVIOUS ||
183
+ error.code === 'Device_UsedElsewhere') {
184
+ this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
185
+ }
186
+ else if (error.message === transport_1.TRANSPORT_ERROR.INTERFACE_UNABLE_TO_OPEN_DEVICE ||
187
+ ((_a = error.message) === null || _a === void 0 ? void 0 : _a.indexOf(constants_1.ERRORS.LIBUSB_ERROR_MESSAGE)) >= 0 ||
188
+ error.code === 'Device_InitializeFailed') {
189
+ this.unreadableError = error === null || error === void 0 ? void 0 : error.message;
190
+ this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
191
+ }
192
+ else {
193
+ await (0, utils_1.createTimeoutPromise)(501);
194
+ continue;
195
+ }
196
+ }
197
+ }
198
+ return;
199
+ }
200
+ }
201
+ async updateDescriptor(descriptor) {
202
+ var _a, _b;
203
+ (_a = this.sessionDfd) === null || _a === void 0 ? void 0 : _a.resolve(descriptor.session);
204
+ await Promise.all([this.acquirePromise, this.releasePromise]);
205
+ if (descriptor.session && descriptor.session !== this.session) {
206
+ this.usedElsewhere();
207
+ }
208
+ if (!descriptor.session) {
209
+ const methodStillRunning = !((_b = this.commands) === null || _b === void 0 ? void 0 : _b.isDisposed());
210
+ if (methodStillRunning) {
211
+ this.releaseTransportSession();
212
+ }
213
+ }
214
+ this.session = descriptor.session;
215
+ this.emitLifecycle(events_1.DEVICE.CHANGED);
120
216
  }
121
217
  run(fn, options) {
122
218
  if (this.runPromise) {
@@ -124,9 +220,16 @@ class Device extends utils_1.TypedEmitter {
124
220
  throw constants_1.ERRORS.TypedError('Device_CallInProgress');
125
221
  }
126
222
  options = parseRunOptions(options);
223
+ const wasUnacquired = this.isUnacquired();
127
224
  const runPromise = (0, utils_1.createDeferred)();
128
225
  this.runPromise = runPromise;
129
- this._runInner(fn, options).catch(err => {
226
+ this._runInner(fn, options)
227
+ .then(() => {
228
+ if (wasUnacquired && !this.isUnacquired()) {
229
+ this.emitLifecycle(events_1.DEVICE.CONNECT);
230
+ }
231
+ })
232
+ .catch(err => {
130
233
  runPromise.reject(err);
131
234
  });
132
235
  return runPromise.promise;
@@ -164,7 +267,12 @@ class Device extends utils_1.TypedEmitter {
164
267
  delete this.runPromise;
165
268
  }
166
269
  }
167
- interruptionFromOutside() {
270
+ usedElsewhere() {
271
+ if (!this.lastAcquiredHere) {
272
+ return;
273
+ }
274
+ this.lastAcquiredHere = false;
275
+ this._featuresNeedsReload = true;
168
276
  _log.debug('interruptionFromOutside');
169
277
  if (this.commands) {
170
278
  this.commands.dispose();
@@ -173,19 +281,20 @@ class Device extends utils_1.TypedEmitter {
173
281
  this.runPromise.reject(constants_1.ERRORS.TypedError('Device_UsedElsewhere'));
174
282
  delete this.runPromise;
175
283
  }
176
- if (this.originalDescriptor.session) {
177
- this.transport.releaseDevice(this.originalDescriptor.session);
284
+ if (this.session) {
285
+ this.transport.releaseDevice(this.session);
178
286
  }
179
287
  }
180
288
  async _runInner(fn, options) {
181
- var _a, _b;
289
+ var _a;
182
290
  if (this.releasePromise) {
183
291
  await this.releasePromise;
184
292
  }
293
+ const { staticSessionId, deriveCardano } = this.getState() || {};
185
294
  if (!this.isUsedHere() ||
186
295
  ((_a = this.commands) === null || _a === void 0 ? void 0 : _a.disposed) ||
187
- !((_b = this.getState()) === null || _b === void 0 ? void 0 : _b.staticSessionId) ||
188
- this.useCardanoDerivation != !!options.useCardanoDerivation) {
296
+ !staticSessionId ||
297
+ (!deriveCardano && options.useCardanoDerivation)) {
189
298
  await this.acquire();
190
299
  try {
191
300
  if (fn) {
@@ -218,9 +327,6 @@ class Device extends utils_1.TypedEmitter {
218
327
  if (options.keepSession) {
219
328
  this.keepTransportSession = true;
220
329
  }
221
- if (this.listeners(events_1.DEVICE.ACQUIRED).length > 0) {
222
- this.emit(events_1.DEVICE.ACQUIRED);
223
- }
224
330
  if (fn) {
225
331
  await fn();
226
332
  }
@@ -250,7 +356,7 @@ class Device extends utils_1.TypedEmitter {
250
356
  setInstance(instance = 0) {
251
357
  if (this.instance !== instance) {
252
358
  if (this.keepTransportSession) {
253
- this.transportSession = null;
359
+ this.lastAcquiredHere = false;
254
360
  this.keepTransportSession = false;
255
361
  }
256
362
  }
@@ -300,19 +406,19 @@ class Device extends utils_1.TypedEmitter {
300
406
  }
301
407
  }
302
408
  async initialize(useCardanoDerivation) {
303
- var _a;
304
409
  let payload;
305
410
  if (this.features) {
306
- const sessionId = (_a = this.getState()) === null || _a === void 0 ? void 0 : _a.sessionId;
307
- payload = {};
308
- payload.derive_cardano = useCardanoDerivation;
309
- this.useCardanoDerivation = useCardanoDerivation;
411
+ const { sessionId, deriveCardano } = this.getState() || {};
412
+ payload = {
413
+ derive_cardano: deriveCardano || useCardanoDerivation,
414
+ };
310
415
  if (sessionId) {
311
416
  payload.session_id = sessionId;
312
417
  }
313
418
  }
314
419
  const { message } = await this.getCommands().typedCall('Initialize', 'Features', payload);
315
420
  this._updateFeatures(message);
421
+ this.setState({ deriveCardano: payload === null || payload === void 0 ? void 0 : payload.derive_cardano });
316
422
  }
317
423
  initStorage(storage) {
318
424
  this.stateStorage = storage;
@@ -321,9 +427,12 @@ class Device extends utils_1.TypedEmitter {
321
427
  async getFeatures() {
322
428
  const { message } = await this.getCommands().typedCall('GetFeatures', 'Features', {});
323
429
  this._updateFeatures(message);
430
+ if (this.authenticityChecks.firmwareHash === null) {
431
+ this.authenticityChecks.firmwareHash = await this.checkFirmwareHash();
432
+ }
324
433
  if (this.authenticityChecks.firmwareRevision === null ||
325
434
  (this.authenticityChecks.firmwareRevision.success === false &&
326
- this.authenticityChecks.firmwareRevision.error === 'cannot-perform-check-offline')) {
435
+ ['cannot-perform-check-offline', 'other-error'].includes(this.authenticityChecks.firmwareRevision.error))) {
327
436
  await this.checkFirmwareRevision();
328
437
  }
329
438
  if (!this.features.language_version_matches &&
@@ -338,6 +447,51 @@ class Device extends utils_1.TypedEmitter {
338
447
  }
339
448
  }
340
449
  }
450
+ async checkFirmwareHash() {
451
+ var _a;
452
+ const createFailResult = (error) => ({ success: false, error });
453
+ const baseUrl = DataManager_1.DataManager.getSettings('binFilesBaseUrl');
454
+ const enabled = DataManager_1.DataManager.getSettings('enableFirmwareHashCheck');
455
+ if (!enabled || baseUrl === undefined)
456
+ return createFailResult('check-skipped');
457
+ const firmwareVersion = this.getVersion();
458
+ if (firmwareVersion === undefined || !this.features || this.features.bootloader_mode) {
459
+ return null;
460
+ }
461
+ const checkSupported = this.atLeast(constants_1.FIRMWARE.FW_HASH_SUPPORTED_VERSIONS);
462
+ if (!checkSupported)
463
+ return createFailResult('check-unsupported');
464
+ const release = (0, firmwareInfo_1.getReleases)(this.features.internal_model).find(r => utils_1.versionUtils.isEqual(r.version, firmwareVersion));
465
+ if (release === undefined)
466
+ return createFailResult('unknown-release');
467
+ const btcOnly = this.firmwareType === types_1.FirmwareType.BitcoinOnly;
468
+ const binary = await (0, firmware_1.getBinaryOptional)({ baseUrl, btcOnly, release });
469
+ if (binary === null) {
470
+ return createFailResult('check-unsupported');
471
+ }
472
+ if (binary.byteLength < 200) {
473
+ _log.warn(`Firmware binary for hash check suspiciously small (< 200 b)`);
474
+ return createFailResult('check-unsupported');
475
+ }
476
+ const strippedBinary = (0, firmware_1.stripFwHeaders)(binary);
477
+ const { hash: expectedHash, challenge } = (0, firmware_1.calculateFirmwareHash)(this.features.major_version, strippedBinary, (0, crypto_1.randomBytes)(32));
478
+ const getFirmwareHashOptional = async () => {
479
+ try {
480
+ return await this.getCommands().typedCall('GetFirmwareHash', 'FirmwareHash', {
481
+ challenge,
482
+ });
483
+ }
484
+ catch {
485
+ return null;
486
+ }
487
+ };
488
+ const deviceResponse = await getFirmwareHashOptional();
489
+ if (!((_a = deviceResponse === null || deviceResponse === void 0 ? void 0 : deviceResponse.message) === null || _a === void 0 ? void 0 : _a.hash))
490
+ return createFailResult('other-error');
491
+ if (deviceResponse.message.hash !== expectedHash)
492
+ return createFailResult('hash-mismatch');
493
+ return { success: true };
494
+ }
341
495
  async checkFirmwareRevision() {
342
496
  const firmwareVersion = this.getVersion();
343
497
  if (!firmwareVersion || !this.features) {
@@ -421,21 +575,21 @@ class Device extends utils_1.TypedEmitter {
421
575
  feat.patch_version,
422
576
  ];
423
577
  if (!version || !utils_1.versionUtils.isEqual(version, newVersion)) {
424
- this.unavailableCapabilities = (0, deviceFeaturesUtils_1.getUnavailableCapabilities)(feat, (0, coinInfo_1.getAllNetworks)());
425
- this.firmwareStatus = (0, firmwareInfo_1.getFirmwareStatus)(feat);
426
- this.firmwareRelease = (0, firmwareInfo_1.getRelease)(feat);
578
+ this._unavailableCapabilities = (0, deviceFeaturesUtils_1.getUnavailableCapabilities)(feat, (0, coinInfo_1.getAllNetworks)());
579
+ this._firmwareStatus = (0, firmwareInfo_1.getFirmwareStatus)(feat);
580
+ this._firmwareRelease = (0, firmwareInfo_1.getRelease)(feat);
427
581
  this.availableTranslations = (_c = (_b = this.firmwareRelease) === null || _b === void 0 ? void 0 : _b.translations) !== null && _c !== void 0 ? _c : [];
428
582
  }
429
- this.features = feat;
430
- this.featuresNeedsReload = false;
583
+ this._features = feat;
584
+ this._featuresNeedsReload = false;
431
585
  if (feat.fw_vendor === 'Trezor Bitcoin-only') {
432
- this.firmwareType = types_1.FirmwareType.BitcoinOnly;
586
+ this._firmwareType = types_1.FirmwareType.BitcoinOnly;
433
587
  }
434
588
  else if (feat.fw_vendor === 'Trezor') {
435
- this.firmwareType = types_1.FirmwareType.Regular;
589
+ this._firmwareType = types_1.FirmwareType.Regular;
436
590
  }
437
591
  else if (this.getMode() !== 'bootloader') {
438
- this.firmwareType =
592
+ this._firmwareType =
439
593
  feat.capabilities &&
440
594
  feat.capabilities.length > 0 &&
441
595
  !feat.capabilities.includes('Capability_Bitcoin_like')
@@ -457,9 +611,15 @@ class Device extends utils_1.TypedEmitter {
457
611
  isUnacquired() {
458
612
  return this.features === undefined;
459
613
  }
614
+ isUnreadable() {
615
+ return !!this.unreadableError;
616
+ }
460
617
  disconnect() {
618
+ var _a;
461
619
  _log.debug('Disconnect cleanup');
462
- this.transportSession = null;
620
+ (_a = this.sessionDfd) === null || _a === void 0 ? void 0 : _a.reject(new Error());
621
+ this.lastAcquiredHere = false;
622
+ this.emitLifecycle(events_1.DEVICE.DISCONNECT);
463
623
  return this.interruptionFromUser(constants_1.ERRORS.TypedError('Device_Disconnected'));
464
624
  }
465
625
  isBootloader() {
@@ -491,13 +651,13 @@ class Device extends utils_1.TypedEmitter {
491
651
  return utils_1.versionUtils.isNewerOrEqual(version, modelVersion);
492
652
  }
493
653
  isUsed() {
494
- return typeof this.originalDescriptor.session === 'string';
654
+ return typeof this.session === 'string';
495
655
  }
496
656
  isUsedHere() {
497
- return this.isUsed() && this.originalDescriptor.session === this.transportSession;
657
+ return this.isUsed() && this.lastAcquiredHere;
498
658
  }
499
659
  isUsedElsewhere() {
500
- return this.isUsed() && !this.isUsedHere();
660
+ return this.isUsed() && !this.lastAcquiredHere;
501
661
  }
502
662
  isRunning() {
503
663
  return !!this.runPromise;
@@ -508,8 +668,11 @@ class Device extends utils_1.TypedEmitter {
508
668
  waitForFirstRun() {
509
669
  return this.firstRunPromise.promise;
510
670
  }
511
- getDevicePath() {
512
- return this.originalDescriptor.path;
671
+ getLocalSession() {
672
+ return this.lastAcquiredHere ? this.session : null;
673
+ }
674
+ getUniquePath() {
675
+ return this.uniquePath;
513
676
  }
514
677
  isT1() {
515
678
  return this.features ? this.features.major_version === 1 : false;
@@ -531,28 +694,20 @@ class Device extends utils_1.TypedEmitter {
531
694
  }
532
695
  return null;
533
696
  }
534
- updateDescriptor(descriptor) {
535
- this.originalDescriptor = {
536
- session: descriptor.session,
537
- path: descriptor.path,
538
- product: descriptor.product,
539
- type: descriptor.type,
540
- };
541
- }
542
697
  async dispose() {
543
698
  var _a, _b;
544
699
  this.removeAllListeners();
545
- if (this.isUsedHere() && this.transportSession) {
700
+ if (this.session && this.lastAcquiredHere) {
546
701
  try {
547
702
  await ((_a = this.cancelableAction) === null || _a === void 0 ? void 0 : _a.call(this));
548
703
  await ((_b = this.commands) === null || _b === void 0 ? void 0 : _b.cancel());
549
704
  return this.transport.release({
550
- session: this.transportSession,
551
- path: this.originalDescriptor.path,
705
+ session: this.session,
706
+ path: this.transportPath,
552
707
  onClose: true,
553
708
  });
554
709
  }
555
- catch (err) {
710
+ catch {
556
711
  }
557
712
  }
558
713
  }
@@ -567,38 +722,40 @@ class Device extends utils_1.TypedEmitter {
567
722
  }
568
723
  toMessageObject() {
569
724
  var _a;
725
+ const { name, uniquePath: path } = this;
726
+ const base = { path, name };
570
727
  if (this.unreadableError) {
571
728
  return {
729
+ ...base,
572
730
  type: 'unreadable',
573
- path: this.originalDescriptor.path,
574
731
  error: this.unreadableError,
575
732
  label: 'Unreadable device',
576
- name: this.name,
733
+ transportDescriptorType: this.transportDescriptorType,
577
734
  };
578
735
  }
579
736
  if (this.isUnacquired()) {
580
737
  return {
738
+ ...base,
581
739
  type: 'unacquired',
582
- path: this.originalDescriptor.path,
583
740
  label: 'Unacquired device',
584
741
  name: this.name,
742
+ transportSessionOwner: this.transportSessionOwner,
585
743
  };
586
744
  }
587
745
  const defaultLabel = 'My Trezor';
588
746
  const label = this.features.label === '' || !this.features.label ? defaultLabel : this.features.label;
589
747
  let status = this.isUsedElsewhere() ? 'occupied' : 'available';
590
- if (this.featuresNeedsReload)
748
+ if (this._featuresNeedsReload)
591
749
  status = 'used';
592
750
  return {
751
+ ...base,
593
752
  type: 'acquired',
594
753
  id: this.features.device_id,
595
- path: this.originalDescriptor.path,
596
754
  label,
597
755
  _state: this.getState(),
598
756
  state: (_a = this.getState()) === null || _a === void 0 ? void 0 : _a.staticSessionId,
599
757
  status,
600
758
  mode: this.getMode(),
601
- name: this.name,
602
759
  color: this.color,
603
760
  firmware: this.firmwareStatus,
604
761
  firmwareRelease: this.firmwareRelease,
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const crypto_1 = require("crypto");
6
6
  const protobuf_1 = require("@trezor/protobuf");
7
7
  const utils_1 = require("@trezor/utils");
8
+ const schema_utils_1 = require("@trezor/schema-utils");
8
9
  const constants_1 = require("../constants");
9
10
  const events_1 = require("../events");
10
11
  const hdnodeUtils = tslib_1.__importStar(require("../utils/hdnodeUtils"));
@@ -12,7 +13,6 @@ const pathUtils_1 = require("../utils/pathUtils");
12
13
  const accountUtils_1 = require("../utils/accountUtils");
13
14
  const coinInfo_1 = require("../data/coinInfo");
14
15
  const debug_1 = require("../utils/debug");
15
- const schema_utils_1 = require("@trezor/schema-utils");
16
16
  const resolveDescriptorForTaproot_1 = require("./resolveDescriptorForTaproot");
17
17
  const prompts_1 = require("./prompts");
18
18
  const logger = (0, debug_1.initLog)('DeviceCommands');
@@ -26,7 +26,7 @@ const generateEntropy = (len) => {
26
26
  try {
27
27
  return (0, crypto_1.randomBytes)(len);
28
28
  }
29
- catch (err) {
29
+ catch {
30
30
  throw constants_1.ERRORS.TypedError('Runtime', 'generateEntropy: Environment does not support crypto random');
31
31
  }
32
32
  };
@@ -236,10 +236,10 @@ class DeviceCommands {
236
236
  return response;
237
237
  }
238
238
  async _commonCall(type, msg) {
239
- const resp = await this.call(type, msg);
240
239
  if (this.disposed) {
241
240
  throw constants_1.ERRORS.TypedError('Runtime', 'typedCall: DeviceCommands already disposed');
242
241
  }
242
+ const resp = await this.call(type, msg);
243
243
  return this._filterCommonTypes(resp);
244
244
  }
245
245
  _filterCommonTypes(res) {
@@ -361,7 +361,7 @@ class DeviceCommands {
361
361
  await this.device.acquire();
362
362
  await (0, prompts_1.cancelPrompt)(this.device, false);
363
363
  }
364
- catch (err) {
364
+ catch {
365
365
  }
366
366
  }
367
367
  else {