@trezor/connect 9.6.1 → 9.6.2-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.
- package/CHANGELOG.md +29 -11
- package/README.md +1 -1
- package/lib/api/applyFlags.js +1 -0
- package/lib/api/applySettings.js +1 -0
- package/lib/api/authenticateDevice.js +1 -0
- package/lib/api/backupDevice.js +1 -0
- package/lib/api/bitcoin/signtxVerify.d.ts +10 -4
- package/lib/api/bitcoin/signtxVerify.js +23 -72
- package/lib/api/bleUnpair.js +1 -0
- package/lib/api/changeLanguage.js +1 -0
- package/lib/api/changePin.js +1 -0
- package/lib/api/changeWipeCode.js +1 -0
- package/lib/api/composeTransaction.js +15 -6
- package/lib/api/ethereum/api/ethereumSignTypedData.js +1 -1
- package/lib/api/firmware/uploadFirmware.js +5 -0
- package/lib/api/loadDevice.js +1 -0
- package/lib/api/recoveryDevice.js +1 -0
- package/lib/api/resetDevice.js +1 -0
- package/lib/api/setBrightness.js +1 -0
- package/lib/api/setBusy.js +1 -0
- package/lib/api/signTransaction.js +19 -6
- package/lib/api/wipeDevice.js +1 -0
- package/lib/constants/errors.d.ts +1 -0
- package/lib/constants/errors.js +1 -0
- package/lib/core/AbstractMethod.js +1 -1
- package/lib/core/onCallFirmwareUpdate.js +1 -3
- package/lib/data/DataManager.d.ts +2 -1
- package/lib/data/DataManager.js +7 -6
- package/lib/data/coinInfo.d.ts +0 -64
- package/lib/data/coinInfo.js +1 -40
- package/lib/data/firmwareInfo.d.ts +1 -1
- package/lib/data/firmwareInfo.js +5 -3
- package/lib/data/version.d.ts +1 -1
- package/lib/data/version.js +1 -1
- package/lib/device/Device.d.ts +10 -10
- package/lib/device/Device.js +53 -62
- package/lib/device/DeviceCurrentSession.d.ts +38 -1
- package/lib/device/DeviceCurrentSession.js +28 -4
- package/lib/device/DeviceList.js +23 -39
- package/lib/device/TransportList.d.ts +2 -2
- package/lib/device/thp/index.d.ts +3 -0
- package/lib/device/thp/index.js +11 -0
- package/lib/device/workflow/handshake.d.ts +10 -0
- package/lib/device/workflow/handshake.js +57 -0
- package/lib/events/index.d.ts +1 -0
- package/lib/events/ui-request.d.ts +6 -1
- package/lib/events/ui-request.js +1 -0
- package/lib/tsconfig.lib.tsbuildinfo +1 -1
- package/lib/utils/assetUtils.d.ts +2 -1
- package/lib/utils/assetUtils.js +2 -1
- package/lib/utils/firmwareReleaseConfigUtils.d.ts +7 -0
- package/lib/utils/firmwareReleaseConfigUtils.js +83 -0
- package/package.json +20 -17
package/lib/data/coinInfo.d.ts
CHANGED
|
@@ -229,70 +229,6 @@ export declare const fixCoinInfoNetwork: (ci: BitcoinNetworkInfo, path: number[]
|
|
|
229
229
|
};
|
|
230
230
|
isBitcoin: boolean;
|
|
231
231
|
};
|
|
232
|
-
export declare const getCoinInfoByHash: (hash: string, networkInfo: any) => {
|
|
233
|
-
blockchainLink?: {
|
|
234
|
-
type: string;
|
|
235
|
-
url: string[];
|
|
236
|
-
} | undefined;
|
|
237
|
-
label: string;
|
|
238
|
-
blockTime: number;
|
|
239
|
-
minFee: number;
|
|
240
|
-
maxFee: number;
|
|
241
|
-
minPriorityFee: number;
|
|
242
|
-
name: string;
|
|
243
|
-
shortcut: string;
|
|
244
|
-
slip44: number;
|
|
245
|
-
support: {
|
|
246
|
-
T1B1: string | false;
|
|
247
|
-
T2T1: string | false;
|
|
248
|
-
T2B1: string | false;
|
|
249
|
-
T3B1: string | false;
|
|
250
|
-
T3T1: string | false;
|
|
251
|
-
T3W1: string | false;
|
|
252
|
-
UNKNOWN: string | false;
|
|
253
|
-
connect: boolean;
|
|
254
|
-
};
|
|
255
|
-
decimals: number;
|
|
256
|
-
defaultFees: {
|
|
257
|
-
feePerTx?: string | undefined;
|
|
258
|
-
feeLimit?: string | undefined;
|
|
259
|
-
baseFeePerGas?: string | undefined;
|
|
260
|
-
maxFeePerGas?: string | undefined;
|
|
261
|
-
maxPriorityFeePerGas?: string | undefined;
|
|
262
|
-
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
263
|
-
blocks: number;
|
|
264
|
-
feePerUnit: string;
|
|
265
|
-
}[];
|
|
266
|
-
} & {
|
|
267
|
-
cashAddrPrefix?: string | undefined;
|
|
268
|
-
xPubMagicSegwitNative?: number | undefined;
|
|
269
|
-
xPubMagicSegwit?: number | undefined;
|
|
270
|
-
taproot?: boolean | undefined;
|
|
271
|
-
type: "bitcoin";
|
|
272
|
-
dustLimit: number;
|
|
273
|
-
curveName: string;
|
|
274
|
-
forceBip143: boolean;
|
|
275
|
-
hashGenesisBlock: string;
|
|
276
|
-
maxAddressLength: number;
|
|
277
|
-
maxFeeSatoshiKb: number;
|
|
278
|
-
minAddressLength: number;
|
|
279
|
-
minFeeSatoshiKb: number;
|
|
280
|
-
segwit: boolean;
|
|
281
|
-
xPubMagic: number;
|
|
282
|
-
network: {
|
|
283
|
-
forkId?: number | undefined;
|
|
284
|
-
messagePrefix: string;
|
|
285
|
-
bech32: string;
|
|
286
|
-
bip32: {
|
|
287
|
-
public: number;
|
|
288
|
-
private: number;
|
|
289
|
-
};
|
|
290
|
-
pubKeyHash: number;
|
|
291
|
-
scriptHash: number;
|
|
292
|
-
wif: number;
|
|
293
|
-
};
|
|
294
|
-
isBitcoin: boolean;
|
|
295
|
-
};
|
|
296
232
|
export declare const getCoinInfo: (currency: string) => ({
|
|
297
233
|
blockchainLink?: {
|
|
298
234
|
type: string;
|
package/lib/data/coinInfo.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getAllNetworks = exports.getUniqueNetworks = exports.parseCoinsJson = exports.ethereumNetworkInfoBase = exports.getCoinName = exports.getCoinInfo = exports.
|
|
3
|
+
exports.getAllNetworks = exports.getUniqueNetworks = exports.parseCoinsJson = exports.ethereumNetworkInfoBase = exports.getCoinName = exports.getCoinInfo = exports.fixCoinInfoNetwork = exports.getBech32Network = exports.getSegwitNetwork = exports.getMiscNetwork = exports.getEthereumNetwork = exports.getBitcoinNetwork = void 0;
|
|
4
4
|
const utils_1 = require("@trezor/utils");
|
|
5
5
|
const defaultFeeLevels_1 = require("./defaultFeeLevels");
|
|
6
|
-
const constants_1 = require("../constants");
|
|
7
6
|
const pathUtils_1 = require("../utils/pathUtils");
|
|
8
7
|
const bitcoinNetworks = [];
|
|
9
8
|
const ethereumNetworks = [];
|
|
@@ -86,44 +85,6 @@ const fixCoinInfoNetwork = (ci, path) => {
|
|
|
86
85
|
return coinInfo;
|
|
87
86
|
};
|
|
88
87
|
exports.fixCoinInfoNetwork = fixCoinInfoNetwork;
|
|
89
|
-
const detectBtcVersion = (data) => {
|
|
90
|
-
if (data.subversion == null) {
|
|
91
|
-
return 'btc';
|
|
92
|
-
}
|
|
93
|
-
if (data.subversion.startsWith('/Bitcoin ABC')) {
|
|
94
|
-
return 'bch';
|
|
95
|
-
}
|
|
96
|
-
if (data.subversion.startsWith('/Bitcoin Cash')) {
|
|
97
|
-
return 'bch';
|
|
98
|
-
}
|
|
99
|
-
if (data.subversion.startsWith('/Bitcoin Gold')) {
|
|
100
|
-
return 'btg';
|
|
101
|
-
}
|
|
102
|
-
return 'btc';
|
|
103
|
-
};
|
|
104
|
-
const getCoinInfoByHash = (hash, networkInfo) => {
|
|
105
|
-
const networks = (0, utils_1.cloneObject)(bitcoinNetworks);
|
|
106
|
-
const result = networks.find(info => hash.toLowerCase() === info.hashGenesisBlock.toLowerCase());
|
|
107
|
-
if (!result) {
|
|
108
|
-
throw constants_1.ERRORS.TypedError('Method_UnknownCoin', `Coin info not found for hash: ${hash} ${networkInfo.hashGenesisBlock}`);
|
|
109
|
-
}
|
|
110
|
-
if (result.isBitcoin) {
|
|
111
|
-
const btcVersion = detectBtcVersion(networkInfo);
|
|
112
|
-
let fork;
|
|
113
|
-
if (btcVersion === 'bch') {
|
|
114
|
-
fork = networks.find(info => info.name === 'Bcash');
|
|
115
|
-
}
|
|
116
|
-
else if (btcVersion === 'btg') {
|
|
117
|
-
fork = networks.find(info => info.name === 'Bgold');
|
|
118
|
-
}
|
|
119
|
-
if (fork) {
|
|
120
|
-
return fork;
|
|
121
|
-
}
|
|
122
|
-
throw constants_1.ERRORS.TypedError('Method_UnknownCoin', `Coin info not found for hash: ${hash} ${networkInfo.hashGenesisBlock} BTC version:${btcVersion}`);
|
|
123
|
-
}
|
|
124
|
-
return result;
|
|
125
|
-
};
|
|
126
|
-
exports.getCoinInfoByHash = getCoinInfoByHash;
|
|
127
88
|
const getCoinInfo = (currency) => (0, exports.getBitcoinNetwork)(currency) || (0, exports.getEthereumNetwork)(currency) || (0, exports.getMiscNetwork)(currency);
|
|
128
89
|
exports.getCoinInfo = getCoinInfo;
|
|
129
90
|
const getCoinName = (path) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DeviceModelInternal, FirmwareRelease, VersionArray } from '@trezor/device-utils';
|
|
2
2
|
import type { Features, ReleaseInfo } from '../types';
|
|
3
|
-
export declare const parseFirmwareReleases: (
|
|
3
|
+
export declare const parseFirmwareReleases: (modelReleases: FirmwareRelease[], deviceModel: DeviceModelInternal) => void;
|
|
4
4
|
export declare const getReleases: (deviceModel: DeviceModelInternal) => FirmwareRelease[];
|
|
5
5
|
export declare const getOnlineReleases: (internalModel: DeviceModelInternal) => Promise<FirmwareRelease[]>;
|
|
6
6
|
export interface GetInfoProps {
|
package/lib/data/firmwareInfo.js
CHANGED
|
@@ -6,9 +6,11 @@ const utils_1 = require("@trezor/utils");
|
|
|
6
6
|
const assets_1 = require("../utils/assets");
|
|
7
7
|
const firmwareUtils_1 = require("../utils/firmwareUtils");
|
|
8
8
|
const releases = Object.values(device_utils_1.DeviceModelInternal).reduce((acc, key) => ({ ...acc, [key]: [] }), {});
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const bundledReleases = {};
|
|
10
|
+
const parseFirmwareReleases = (modelReleases, deviceModel) => {
|
|
11
|
+
const [latestRelease] = modelReleases;
|
|
12
|
+
bundledReleases[deviceModel] = latestRelease;
|
|
13
|
+
modelReleases.forEach(release => {
|
|
12
14
|
releases[deviceModel]?.push({
|
|
13
15
|
...release,
|
|
14
16
|
});
|
package/lib/data/version.d.ts
CHANGED
package/lib/data/version.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DEEPLINK_VERSION = exports.CONTENT_SCRIPT_VERSION = exports.DEFAULT_DOMAIN = exports.VERSION = void 0;
|
|
4
|
-
exports.VERSION = '9.6.
|
|
4
|
+
exports.VERSION = '9.6.2-beta.2';
|
|
5
5
|
const versionN = exports.VERSION.split('.').map(s => parseInt(s, 10));
|
|
6
6
|
const isBeta = exports.VERSION.includes('beta');
|
|
7
7
|
exports.DEFAULT_DOMAIN = isBeta
|
package/lib/device/Device.d.ts
CHANGED
|
@@ -14,9 +14,6 @@ type RunOptions = {
|
|
|
14
14
|
skipFirmwareChecks?: boolean;
|
|
15
15
|
skipLanguageChecks?: boolean;
|
|
16
16
|
};
|
|
17
|
-
export declare const CANCEL_TIMEOUT = 1000;
|
|
18
|
-
export declare const GET_FEATURES_TIMEOUT = 3000;
|
|
19
|
-
export declare const GET_FEATURES_TIMEOUT_REACT_NATIVE = 20000;
|
|
20
17
|
type Result<T> = {
|
|
21
18
|
success: true;
|
|
22
19
|
payload: T;
|
|
@@ -48,13 +45,16 @@ export interface DeviceEvents {
|
|
|
48
45
|
};
|
|
49
46
|
[DEVICE.THP_CREDENTIALS_CHANGED]: DeviceThpCredentialsChangedPayload;
|
|
50
47
|
}
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
interface DeviceLifecycleEvents {
|
|
49
|
+
[DEVICE.CONNECT]: void;
|
|
50
|
+
[DEVICE.CONNECT_UNACQUIRED]: void;
|
|
51
|
+
[DEVICE.CHANGED]: void;
|
|
52
|
+
[DEVICE.DISCONNECT]: void;
|
|
53
|
+
}
|
|
53
54
|
type DeviceParams = {
|
|
54
55
|
id: DeviceUniquePath;
|
|
55
56
|
transport: Transport;
|
|
56
57
|
descriptor: Descriptor;
|
|
57
|
-
listener: DeviceLifecycleListener;
|
|
58
58
|
};
|
|
59
59
|
export declare class Device extends TypedEmitter<DeviceEvents> {
|
|
60
60
|
readonly transport: Transport;
|
|
@@ -147,17 +147,17 @@ export declare class Device extends TypedEmitter<DeviceEvents> {
|
|
|
147
147
|
private availableTranslations;
|
|
148
148
|
private authenticityChecks;
|
|
149
149
|
private readonly uniquePath;
|
|
150
|
-
|
|
150
|
+
readonly lifecycle: TypedEmitter<DeviceLifecycleEvents>;
|
|
151
151
|
private sessionDfd?;
|
|
152
|
-
|
|
153
|
-
constructor({ id, transport, descriptor, listener }: DeviceParams);
|
|
152
|
+
constructor({ id, transport, descriptor }: DeviceParams);
|
|
154
153
|
private readonly onTransportStopped;
|
|
155
154
|
private readonly onTransportDeviceEvent;
|
|
156
155
|
private getSessionChangePromise;
|
|
157
156
|
private waitAndCompareSession;
|
|
158
157
|
acquire(): import("@trezor/transport/lib/types").AsyncResultWithTypedError<Session, "Network request failed" | "Wrong result type." | "device disconnected during action" | "unexpected error" | "Aborted by timeout" | "Aborted by signal" | "This transport can not be used in this environment" | "device not found" | "Unable to open device" | "wrong previous session" | "LIBUSB_ERROR_ACCESS">;
|
|
159
158
|
release(): import("@trezor/transport/lib/types").AsyncResultWithTypedError<null, "Network request failed" | "Wrong result type." | "device disconnected during action" | "unexpected error" | "session not found" | "Aborted by timeout" | "Aborted by signal" | "This transport can not be used in this environment" | "device not found" | "Unable to open device" | "wrong previous session"> | undefined;
|
|
160
|
-
|
|
159
|
+
setupThp(): Promise<void>;
|
|
160
|
+
handshake(): Promise<boolean>;
|
|
161
161
|
private updateDescriptor;
|
|
162
162
|
run(fn?: () => Promise<void>, options?: RunOptions): Promise<void>;
|
|
163
163
|
interrupt(reason: Error): Promise<void>;
|
package/lib/device/Device.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Device =
|
|
3
|
+
exports.Device = void 0;
|
|
4
4
|
const crypto_1 = require("crypto");
|
|
5
5
|
const device_utils_1 = require("@trezor/device-utils");
|
|
6
6
|
const protocol_1 = require("@trezor/protocol");
|
|
@@ -10,6 +10,7 @@ const DeviceCommands_1 = require("./DeviceCommands");
|
|
|
10
10
|
const constants_1 = require("../constants");
|
|
11
11
|
const DeviceCurrentSession_1 = require("./DeviceCurrentSession");
|
|
12
12
|
const checkFirmwareRevision_1 = require("./checkFirmwareRevision");
|
|
13
|
+
const thp_1 = require("./thp");
|
|
13
14
|
const firmware_1 = require("../api/firmware");
|
|
14
15
|
const DataManager_1 = require("../data/DataManager");
|
|
15
16
|
const coinInfo_1 = require("../data/coinInfo");
|
|
@@ -17,12 +18,10 @@ const firmwareInfo_1 = require("../data/firmwareInfo");
|
|
|
17
18
|
const getLanguage_1 = require("../data/getLanguage");
|
|
18
19
|
const events_1 = require("../events");
|
|
19
20
|
const types_1 = require("../types");
|
|
21
|
+
const handshake_1 = require("./workflow/handshake");
|
|
20
22
|
const debug_1 = require("../utils/debug");
|
|
21
23
|
const deviceFeaturesUtils_1 = require("../utils/deviceFeaturesUtils");
|
|
22
24
|
const _log = (0, debug_1.initLog)('Device');
|
|
23
|
-
exports.CANCEL_TIMEOUT = 1_000;
|
|
24
|
-
exports.GET_FEATURES_TIMEOUT = 3_000;
|
|
25
|
-
exports.GET_FEATURES_TIMEOUT_REACT_NATIVE = 20_000;
|
|
26
25
|
class Device extends utils_1.TypedEmitter {
|
|
27
26
|
transport;
|
|
28
27
|
transportPath;
|
|
@@ -76,12 +75,10 @@ class Device extends utils_1.TypedEmitter {
|
|
|
76
75
|
firmwareHash: null,
|
|
77
76
|
};
|
|
78
77
|
uniquePath;
|
|
79
|
-
|
|
78
|
+
lifecycle = new utils_1.TypedEmitter();
|
|
80
79
|
sessionDfd;
|
|
81
|
-
|
|
82
|
-
constructor({ id, transport, descriptor, listener }) {
|
|
80
|
+
constructor({ id, transport, descriptor }) {
|
|
83
81
|
super();
|
|
84
|
-
this.emitLifecycle = listener;
|
|
85
82
|
this._protocol = protocol_1.v1;
|
|
86
83
|
this.uniquePath = id;
|
|
87
84
|
this.transport = transport;
|
|
@@ -175,49 +172,47 @@ class Device extends utils_1.TypedEmitter {
|
|
|
175
172
|
});
|
|
176
173
|
return this.releasePromise;
|
|
177
174
|
}
|
|
178
|
-
async
|
|
179
|
-
|
|
180
|
-
|
|
175
|
+
async setupThp() {
|
|
176
|
+
_log.info('Setup THP device');
|
|
177
|
+
this._protocol = protocol_1.v2;
|
|
178
|
+
if (this.transport.name === 'BridgeTransport' &&
|
|
179
|
+
!utils_1.versionUtils.isNewerOrEqual(this.transport.version, '3.0.0')) {
|
|
180
|
+
this.unreadableError = 'THP incompatible with bridge ' + this.transport.version;
|
|
181
181
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
this.
|
|
182
|
+
else {
|
|
183
|
+
try {
|
|
184
|
+
await this.transport.loadMessages('thp', protocol_1.thp.getProtobufDefinitions);
|
|
185
|
+
this.thp = new protocol_1.thp.ThpState();
|
|
185
186
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
await this.run();
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
_log.warn(`device.run error.message: ${error.message}, code: ${error.code}`);
|
|
192
|
-
if (error.code === 'Device_NotFound' ||
|
|
193
|
-
error.code === 'Device_Disconnected' ||
|
|
194
|
-
error.message === transport_1.TRANSPORT_ERROR.DEVICE_NOT_FOUND ||
|
|
195
|
-
error.message === transport_1.TRANSPORT_ERROR.DEVICE_DISCONNECTED_DURING_ACTION ||
|
|
196
|
-
error.message === transport_1.TRANSPORT_ERROR.HTTP_ERROR) {
|
|
197
|
-
}
|
|
198
|
-
else if ((this.possibleHIDdevice &&
|
|
199
|
-
error.message === transport_1.TRANSPORT_ERROR.INTERFACE_UNABLE_TO_OPEN_DEVICE) ||
|
|
200
|
-
error.message === transport_1.TRANSPORT_ERROR.LIBUSB_ERROR_ACCESS) {
|
|
201
|
-
this.unreadableError = error.message;
|
|
202
|
-
this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
|
|
203
|
-
}
|
|
204
|
-
else if (error.message === transport_1.TRANSPORT_ERROR.INTERFACE_UNABLE_TO_OPEN_DEVICE ||
|
|
205
|
-
error.message === transport_1.TRANSPORT_ERROR.UNEXPECTED_ERROR ||
|
|
206
|
-
error.message === transport_1.TRANSPORT_ERROR.SESSION_WRONG_PREVIOUS ||
|
|
207
|
-
error.code === 'Device_UsedElsewhere' ||
|
|
208
|
-
error.code === 'Device_InitializeFailed') {
|
|
209
|
-
this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
await (0, utils_1.resolveAfter)(501);
|
|
213
|
-
continue;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
this.unreadableError = error.message;
|
|
216
189
|
}
|
|
217
|
-
this.handshakeFinished = true;
|
|
218
|
-
return;
|
|
219
190
|
}
|
|
220
191
|
}
|
|
192
|
+
async handshake() {
|
|
193
|
+
if (this.isUsedElsewhere()) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
await this.run();
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
_log.warn(`device.run error.message: ${error.message}, code: ${error.code}`);
|
|
201
|
+
if (error.code === 'Device_NotFound' ||
|
|
202
|
+
error.code === 'Device_Disconnected' ||
|
|
203
|
+
error.message === transport_1.TRANSPORT_ERROR.DEVICE_NOT_FOUND ||
|
|
204
|
+
error.message === transport_1.TRANSPORT_ERROR.DEVICE_DISCONNECTED_DURING_ACTION ||
|
|
205
|
+
error.message === transport_1.TRANSPORT_ERROR.HTTP_ERROR) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
if ((this.possibleHIDdevice &&
|
|
209
|
+
error.message === transport_1.TRANSPORT_ERROR.INTERFACE_UNABLE_TO_OPEN_DEVICE) ||
|
|
210
|
+
error.message === transport_1.TRANSPORT_ERROR.LIBUSB_ERROR_ACCESS) {
|
|
211
|
+
this.unreadableError = error.message;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
221
216
|
async updateDescriptor(descriptor) {
|
|
222
217
|
this.sessionDfd?.resolve(descriptor.session);
|
|
223
218
|
await Promise.all([this.acquirePromise, this.releasePromise]);
|
|
@@ -227,7 +222,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
227
222
|
if (!descriptor.session) {
|
|
228
223
|
this.keepTransportSession = false;
|
|
229
224
|
}
|
|
230
|
-
this.
|
|
225
|
+
this.lifecycle.emit(events_1.DEVICE.CHANGED);
|
|
231
226
|
}
|
|
232
227
|
run(fn, options = {}) {
|
|
233
228
|
if (this.runPromise) {
|
|
@@ -255,7 +250,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
255
250
|
})
|
|
256
251
|
.then(() => {
|
|
257
252
|
if (wasUnacquired && !this.isUnacquired()) {
|
|
258
|
-
this.
|
|
253
|
+
this.lifecycle.emit(events_1.DEVICE.CONNECT);
|
|
259
254
|
}
|
|
260
255
|
});
|
|
261
256
|
return this.runPromise;
|
|
@@ -291,26 +286,23 @@ class Device extends utils_1.TypedEmitter {
|
|
|
291
286
|
const { staticSessionId, deriveCardano } = this.getState() || {};
|
|
292
287
|
if (acquireNeeded || !staticSessionId || (!deriveCardano && options.useCardanoDerivation)) {
|
|
293
288
|
try {
|
|
294
|
-
|
|
289
|
+
await (0, handshake_1.handshakeCancel)({ device: this, logger: _log, signal: abortSignal });
|
|
290
|
+
if (this.protocol.name === 'v2') {
|
|
291
|
+
const withInteraction = !!fn;
|
|
292
|
+
await (0, thp_1.getThpChannel)(this, withInteraction);
|
|
293
|
+
}
|
|
294
|
+
else if (fn) {
|
|
295
295
|
await this.initialize(!!options.useCardanoDerivation);
|
|
296
296
|
}
|
|
297
297
|
else {
|
|
298
|
-
const isNative = DataManager_1.DataManager.getSettings('env') === 'react-native';
|
|
299
|
-
const cancelTimeout = isNative
|
|
300
|
-
? exports.GET_FEATURES_TIMEOUT_REACT_NATIVE
|
|
301
|
-
: exports.CANCEL_TIMEOUT;
|
|
302
|
-
if (['v1', 'bridge'].includes(this.protocol.name) && !this.possibleHIDdevice) {
|
|
303
|
-
_log.debug('sending a preventive cancel on the first encounter with the device');
|
|
304
|
-
await Promise.race([
|
|
305
|
-
this.getCurrentSession().cancelCall(),
|
|
306
|
-
new Promise((_, reject) => setTimeout(reject, cancelTimeout)),
|
|
307
|
-
]).catch(() => this.acquire());
|
|
308
|
-
}
|
|
309
298
|
await this.getFeatures();
|
|
310
299
|
}
|
|
311
300
|
}
|
|
312
301
|
catch (error) {
|
|
313
302
|
_log.warn('Device._runInner error: ', error.message);
|
|
303
|
+
if (error.code === 'Device_ThpPairingTagInvalid') {
|
|
304
|
+
return Promise.reject(error);
|
|
305
|
+
}
|
|
314
306
|
return Promise.reject(constants_1.ERRORS.TypedError('Device_InitializeFailed', `Initialize failed: ${error.message}${error.code ? `, code: ${error.code}` : ''}`));
|
|
315
307
|
}
|
|
316
308
|
}
|
|
@@ -632,8 +624,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
632
624
|
this.transport.releaseSync(this.sessionAcquired);
|
|
633
625
|
this.sessionAcquired = null;
|
|
634
626
|
}
|
|
635
|
-
this.
|
|
636
|
-
this.emitLifecycle = () => { };
|
|
627
|
+
this.lifecycle.emit(events_1.DEVICE.DISCONNECT);
|
|
637
628
|
return this.interrupt(constants_1.ERRORS.TypedError('Device_Disconnected'));
|
|
638
629
|
}
|
|
639
630
|
isBootloader() {
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { MessagesSchema as Messages } from '@trezor/protobuf';
|
|
2
2
|
import { MessageResponse, Session, Transport } from '@trezor/transport';
|
|
3
3
|
import { Device } from './Device';
|
|
4
|
+
type AbortableOptions = {
|
|
5
|
+
timeout?: number;
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
};
|
|
4
8
|
export interface TypedCallProvider {
|
|
5
9
|
typedCall: Messages.TypedCall;
|
|
6
10
|
cancelCall: DeviceCurrentSession['cancelCall'];
|
|
7
11
|
isDisposed: () => boolean;
|
|
12
|
+
call: DeviceCurrentSession['call'];
|
|
13
|
+
send: DeviceCurrentSession['send'];
|
|
14
|
+
receive: DeviceCurrentSession['receive'];
|
|
8
15
|
}
|
|
9
16
|
export declare class DeviceCurrentSession implements TypedCallProvider {
|
|
10
17
|
private readonly device;
|
|
@@ -465,6 +472,15 @@ export declare class DeviceCurrentSession implements TypedCallProvider {
|
|
|
465
472
|
} | {
|
|
466
473
|
type: "ECDHSessionKey";
|
|
467
474
|
message: import("@trezor/protobuf/lib/messages").ECDHSessionKey;
|
|
475
|
+
} | {
|
|
476
|
+
type: "DebugLinkGetPairingInfo";
|
|
477
|
+
message: import("@trezor/protobuf/lib/messages").DebugLinkGetPairingInfo;
|
|
478
|
+
} | {
|
|
479
|
+
type: "DebugLinkPairingInfo";
|
|
480
|
+
message: import("@trezor/protobuf/lib/messages").DebugLinkPairingInfo;
|
|
481
|
+
} | {
|
|
482
|
+
type: "DebugLinkToggleThpPairingDialog";
|
|
483
|
+
message: import("@trezor/protobuf/lib/messages").DebugLinkToggleThpPairingDialog;
|
|
468
484
|
} | {
|
|
469
485
|
type: "DebugLinkResetDebugEvents";
|
|
470
486
|
message: import("@trezor/protobuf/lib/messages").DebugLinkResetDebugEvents;
|
|
@@ -819,7 +835,27 @@ export declare class DeviceCurrentSession implements TypedCallProvider {
|
|
|
819
835
|
}>;
|
|
820
836
|
private needCancelWorkaround;
|
|
821
837
|
private callLoop;
|
|
822
|
-
|
|
838
|
+
call<T extends Messages.MessageKey>(name: T, data: Messages.MessagePayload<T>, options?: AbortableOptions): Promise<{
|
|
839
|
+
success: false;
|
|
840
|
+
error: Error;
|
|
841
|
+
} | {
|
|
842
|
+
success: true;
|
|
843
|
+
payload: MessageResponse;
|
|
844
|
+
}>;
|
|
845
|
+
send<T extends Messages.MessageKey>(name: T, data: Messages.MessagePayload<T>, options?: AbortableOptions): Promise<{
|
|
846
|
+
success: false;
|
|
847
|
+
error: Error;
|
|
848
|
+
} | {
|
|
849
|
+
success: true;
|
|
850
|
+
payload: undefined;
|
|
851
|
+
}>;
|
|
852
|
+
receive(options?: AbortableOptions): Promise<{
|
|
853
|
+
success: false;
|
|
854
|
+
error: Error;
|
|
855
|
+
} | {
|
|
856
|
+
success: true;
|
|
857
|
+
payload: MessageResponse;
|
|
858
|
+
}>;
|
|
823
859
|
cancelCall(): Promise<{
|
|
824
860
|
success: false;
|
|
825
861
|
error: Error;
|
|
@@ -829,4 +865,5 @@ export declare class DeviceCurrentSession implements TypedCallProvider {
|
|
|
829
865
|
}>;
|
|
830
866
|
abort(reason: Error): Promise<void>;
|
|
831
867
|
}
|
|
868
|
+
export {};
|
|
832
869
|
//# sourceMappingURL=DeviceCurrentSession.d.ts.map
|
|
@@ -99,7 +99,7 @@ class DeviceCurrentSession {
|
|
|
99
99
|
let pinUnlocked = false;
|
|
100
100
|
while (true) {
|
|
101
101
|
const timeout = name === 'GetFeatures' ? getFeaturesTimeout() : undefined;
|
|
102
|
-
const callPromise = this.call(name, data, timeout);
|
|
102
|
+
const callPromise = this.call(name, data, { timeout });
|
|
103
103
|
const [abortedDuringCall, response] = await Promise.race([
|
|
104
104
|
callPromise.then(res => [false, res]),
|
|
105
105
|
abortPromise.then(res => [true, res]),
|
|
@@ -206,7 +206,7 @@ class DeviceCurrentSession {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
|
-
async call(name, data,
|
|
209
|
+
async call(name, data, options = {}) {
|
|
210
210
|
if (this.disposed)
|
|
211
211
|
return Promise.resolve(error(this.disposed));
|
|
212
212
|
logger.debug('Sending', name, filterForLog(name, data));
|
|
@@ -216,7 +216,7 @@ class DeviceCurrentSession {
|
|
|
216
216
|
session: this.session,
|
|
217
217
|
protocol: this.device.protocol,
|
|
218
218
|
thpState: this.device.getThpState(),
|
|
219
|
-
|
|
219
|
+
...options,
|
|
220
220
|
});
|
|
221
221
|
if (result.success) {
|
|
222
222
|
const { type, message } = result.payload;
|
|
@@ -225,7 +225,31 @@ class DeviceCurrentSession {
|
|
|
225
225
|
else {
|
|
226
226
|
logger.warn('Received transport error', result.error, result.message);
|
|
227
227
|
}
|
|
228
|
-
return result.success ? success(result.payload) : fail(result.error);
|
|
228
|
+
return result.success ? success(result.payload) : fail(result.message || result.error);
|
|
229
|
+
}
|
|
230
|
+
async send(name, data, options = {}) {
|
|
231
|
+
if (this.disposed)
|
|
232
|
+
return Promise.resolve(error(this.disposed));
|
|
233
|
+
const result = await this.transport.send({
|
|
234
|
+
name,
|
|
235
|
+
data,
|
|
236
|
+
session: this.session,
|
|
237
|
+
protocol: this.device.protocol,
|
|
238
|
+
thpState: this.device.getThpState(),
|
|
239
|
+
...options,
|
|
240
|
+
});
|
|
241
|
+
return result.success ? success(result.payload) : fail(result.message || result.error);
|
|
242
|
+
}
|
|
243
|
+
async receive(options = {}) {
|
|
244
|
+
if (this.disposed)
|
|
245
|
+
return Promise.resolve(error(this.disposed));
|
|
246
|
+
const result = await this.transport.receive({
|
|
247
|
+
session: this.session,
|
|
248
|
+
protocol: this.device.protocol,
|
|
249
|
+
thpState: this.device.getThpState(),
|
|
250
|
+
...options,
|
|
251
|
+
});
|
|
252
|
+
return result.success ? success(result.payload) : fail(result.message || result.error);
|
|
229
253
|
}
|
|
230
254
|
cancelCall() {
|
|
231
255
|
return this.call('Cancel', {});
|
package/lib/device/DeviceList.js
CHANGED
|
@@ -79,29 +79,27 @@ class DeviceList extends utils_1.TypedEmitter {
|
|
|
79
79
|
id: manifest?.appName || manifest?.appUrl || 'unknown app',
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
|
-
onDeviceConnected(descriptor, transport) {
|
|
82
|
+
async onDeviceConnected(descriptor, transport) {
|
|
83
83
|
const id = (this.deviceCounter++).toString(16).slice(-8);
|
|
84
|
-
const device = new Device_1.Device({
|
|
85
|
-
id: (0, types_1.DeviceUniquePath)(id),
|
|
86
|
-
transport,
|
|
87
|
-
descriptor,
|
|
88
|
-
listener: lifecycle => {
|
|
89
|
-
if (lifecycle === events_1.DEVICE.DISCONNECT) {
|
|
90
|
-
this.authPenaltyManager.remove(device);
|
|
91
|
-
const index = this.devices.indexOf(device);
|
|
92
|
-
if (index >= 0)
|
|
93
|
-
this.devices.splice(index, 1);
|
|
94
|
-
}
|
|
95
|
-
this.emit(lifecycle, device);
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
this.devices.push(device);
|
|
84
|
+
const device = new Device_1.Device({ id: (0, types_1.DeviceUniquePath)(id), transport, descriptor });
|
|
99
85
|
const penalty = this.authPenaltyManager.get();
|
|
100
|
-
this.handshakeLock(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
86
|
+
const stillConnected = await this.handshakeLock(() => (0, utils_1.resolveAfter)(penalty && penalty + 501).then(() => device.handshake()));
|
|
87
|
+
if (!stillConnected) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
this.devices.push(device);
|
|
91
|
+
device.lifecycle.on(events_1.DEVICE.CONNECT, () => this.emit(events_1.DEVICE.CONNECT, device));
|
|
92
|
+
device.lifecycle.on(events_1.DEVICE.CHANGED, () => this.emit(events_1.DEVICE.CHANGED, device));
|
|
93
|
+
device.lifecycle.on(events_1.DEVICE.CONNECT_UNACQUIRED, () => this.emit(events_1.DEVICE.CONNECT_UNACQUIRED, device));
|
|
94
|
+
device.lifecycle.on(events_1.DEVICE.DISCONNECT, () => {
|
|
95
|
+
device.lifecycle.removeAllListeners();
|
|
96
|
+
this.authPenaltyManager.remove(device);
|
|
97
|
+
const index = this.devices.indexOf(device);
|
|
98
|
+
if (index >= 0)
|
|
99
|
+
this.devices.splice(index, 1);
|
|
100
|
+
this.emit(events_1.DEVICE.DISCONNECT, device);
|
|
104
101
|
});
|
|
102
|
+
this.emit(device.isUnacquired() ? events_1.DEVICE.CONNECT_UNACQUIRED : events_1.DEVICE.CONNECT, device);
|
|
105
103
|
}
|
|
106
104
|
getOrCreateTransportManager(apiType) {
|
|
107
105
|
if (!this.transportManagers[apiType]) {
|
|
@@ -132,38 +130,24 @@ class DeviceList extends utils_1.TypedEmitter {
|
|
|
132
130
|
throw new Error(enumerateResult.error);
|
|
133
131
|
}
|
|
134
132
|
const descriptors = enumerateResult.payload;
|
|
135
|
-
const waitForDevicesPromise = pendingTransportEvent && descriptors.length
|
|
136
|
-
? this.waitForDevices(transport, descriptors, signal)
|
|
137
|
-
: Promise.resolve();
|
|
138
133
|
transport.handleDescriptorsChange(descriptors);
|
|
139
134
|
transport.listen();
|
|
140
|
-
|
|
135
|
+
if (pendingTransportEvent && descriptors.length) {
|
|
136
|
+
await this.waitForDevices(transport, signal);
|
|
137
|
+
}
|
|
141
138
|
}
|
|
142
|
-
waitForDevices(transport,
|
|
139
|
+
waitForDevices(transport, signal) {
|
|
143
140
|
const { promise, reject, resolve } = (0, utils_1.createDeferred)();
|
|
144
141
|
const onAbort = () => reject(signal.reason);
|
|
145
142
|
signal.addEventListener('abort', onAbort);
|
|
146
143
|
const onError = (error) => reject(new Error(error));
|
|
147
144
|
transport.once(transport_1.TRANSPORT.ERROR, onError);
|
|
148
145
|
const autoResolveTransportEventTimeout = setTimeout(resolve, 10000);
|
|
149
|
-
|
|
150
|
-
const onDeviceEvent = (device) => {
|
|
151
|
-
const index = remaining.findIndex(d => d.path === device.transportPath && transport === device.transport);
|
|
152
|
-
if (index >= 0)
|
|
153
|
-
remaining.splice(index, 1);
|
|
154
|
-
if (!remaining.length)
|
|
155
|
-
resolve();
|
|
156
|
-
};
|
|
157
|
-
this.on(events_1.DEVICE.CONNECT, onDeviceEvent);
|
|
158
|
-
this.on(events_1.DEVICE.CONNECT_UNACQUIRED, onDeviceEvent);
|
|
159
|
-
this.on(events_1.DEVICE.DISCONNECT, onDeviceEvent);
|
|
146
|
+
this.handshakeLock(resolve);
|
|
160
147
|
return promise.finally(() => {
|
|
161
148
|
transport.off(transport_1.TRANSPORT.ERROR, onError);
|
|
162
149
|
signal.removeEventListener('abort', onAbort);
|
|
163
150
|
clearTimeout(autoResolveTransportEventTimeout);
|
|
164
|
-
this.off(events_1.DEVICE.CONNECT, onDeviceEvent);
|
|
165
|
-
this.off(events_1.DEVICE.CONNECT_UNACQUIRED, onDeviceEvent);
|
|
166
|
-
this.off(events_1.DEVICE.DISCONNECT, onDeviceEvent);
|
|
167
151
|
});
|
|
168
152
|
}
|
|
169
153
|
getDeviceCount() {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Transport } from '@trezor/transport';
|
|
1
|
+
import { NodeUsbTransport, Transport, UdpTransport } from '@trezor/transport';
|
|
2
2
|
import type { AbstractTransportParams } from '@trezor/transport/lib/transports/abstract';
|
|
3
3
|
import { ConnectSettingsTransport } from '../types';
|
|
4
4
|
type Params = AbstractTransportParams & {
|
|
5
5
|
sessionsBackgroundUrl?: string | null;
|
|
6
6
|
};
|
|
7
|
-
export declare const createTransportList: (params: Params) => (existing: Transport[], transports?: ConnectSettingsTransport[]) => Transport[];
|
|
7
|
+
export declare const createTransportList: (params: Params) => (existing: Transport[], transports?: ConnectSettingsTransport[]) => (Transport | NodeUsbTransport | UdpTransport)[];
|
|
8
8
|
export {};
|
|
9
9
|
//# sourceMappingURL=TransportList.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getThpChannel = void 0;
|
|
4
|
+
const constants_1 = require("../../constants");
|
|
5
|
+
const getThpChannel = async (_device, _withInteraction) => {
|
|
6
|
+
await new Promise((_, reject) => {
|
|
7
|
+
reject(constants_1.ERRORS.TypedError('Device_ThpStateMissing'));
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
exports.getThpChannel = getThpChannel;
|
|
11
|
+
//# sourceMappingURL=index.js.map
|