@trezor/connect 9.6.0 → 9.6.1-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 +37 -8
- package/README.md +1 -1
- package/lib/api/blockchainEstimateFee.js +1 -0
- package/lib/api/discoverAccounts.js +10 -2
- package/lib/api/eos/eosSignTx.d.ts +3 -3
- package/lib/api/ethereum/api/ethereumSignMessage.js +1 -1
- package/lib/api/ethereum/api/ethereumSignTypedData.d.ts +1 -1
- package/lib/api/firmware/getBinary.js +2 -2
- package/lib/api/getAddress.d.ts +1 -0
- package/lib/api/getAddress.js +1 -0
- package/lib/api/getCoinInfo.d.ts +3 -3
- package/lib/api/getNonce.d.ts +9 -0
- package/lib/api/getNonce.js +15 -0
- package/lib/api/index.d.ts +1 -0
- package/lib/api/index.js +4 -2
- package/lib/api/nem/nemSignTx.d.ts +1 -1
- package/lib/api/resetDevice.d.ts +2 -3
- package/lib/api/resetDevice.js +47 -49
- package/lib/api/signMessage.js +1 -1
- package/lib/api/signTransaction.js +6 -1
- package/lib/backend/Blockchain.d.ts +1 -0
- package/lib/backend/fees/BitcoinFeeLevels.d.ts +2 -4
- package/lib/backend/fees/BitcoinFeeLevels.js +11 -73
- package/lib/backend/fees/EthereumFeeLevels.d.ts +1 -3
- package/lib/backend/fees/EthereumFeeLevels.js +8 -5
- package/lib/backend/fees/MiscFeeLevels.d.ts +0 -3
- package/lib/backend/fees/MiscFeeLevels.js +2 -2
- package/lib/constants/errors.d.ts +1 -0
- package/lib/constants/errors.js +1 -0
- package/lib/core/AbstractMethod.d.ts +1 -1
- package/lib/core/index.js +43 -53
- package/lib/core/onCallFirmwareUpdate.js +2 -2
- package/lib/data/coinInfo.d.ts +11 -11
- package/lib/data/coinInfo.js +1 -1
- package/lib/data/connectSettings.js +0 -3
- package/lib/data/defaultFeeLevels.d.ts +3 -1
- package/lib/data/defaultFeeLevels.js +22 -12
- package/lib/data/deviceAuthenticityConfig.js +4 -1
- package/lib/data/firmwareInfo.d.ts +1 -0
- package/lib/data/firmwareInfo.js +14 -1
- package/lib/data/version.d.ts +1 -1
- package/lib/data/version.js +1 -1
- package/lib/device/Device.d.ts +20 -21
- package/lib/device/Device.js +78 -123
- package/lib/device/DeviceCurrentSession.d.ts +441 -4027
- package/lib/device/DeviceCurrentSession.js +75 -44
- package/lib/device/DeviceList.d.ts +3 -8
- package/lib/device/DeviceList.js +21 -77
- package/lib/device/TransportManager.d.ts +2 -6
- package/lib/device/TransportManager.js +11 -7
- package/lib/device/checkFirmwareRevision.js +2 -2
- package/lib/device/workflow/index.d.ts +2 -0
- package/lib/device/workflow/index.js +6 -0
- package/lib/device/workflow/validateState.d.ts +3 -0
- package/lib/device/workflow/validateState.js +97 -0
- package/lib/events/device.d.ts +19 -1
- package/lib/events/device.js +2 -0
- package/lib/events/index.d.ts +4 -0
- package/lib/events/ui-request.d.ts +24 -3
- package/lib/events/ui-request.js +3 -0
- package/lib/events/ui-response.d.ts +11 -1
- package/lib/events/ui-response.js +1 -0
- package/lib/factory.js +1 -0
- package/lib/tsconfig.lib.tsbuildinfo +1 -1
- package/lib/types/api/applySettings.d.ts +1 -0
- package/lib/types/api/discoverAccounts.d.ts +17 -4
- package/lib/types/api/discoverAccounts.js +2 -0
- package/lib/types/api/getNonce.d.ts +4 -0
- package/lib/types/api/getNonce.js +3 -0
- package/lib/types/api/index.d.ts +2 -0
- package/lib/types/coinInfo.d.ts +6 -6
- package/lib/types/coinInfo.js +2 -0
- package/lib/types/device.d.ts +3 -4
- package/lib/types/fees.d.ts +1 -1
- package/lib/types/fees.js +1 -1
- package/lib/types/params.d.ts +1 -0
- package/lib/types/settings.d.ts +0 -1
- package/lib/types/workflow.d.ts +8 -0
- package/lib/types/workflow.js +3 -0
- package/lib/utils/formatUtils.d.ts +1 -0
- package/lib/utils/formatUtils.js +9 -1
- package/lib/utils/uiPromiseManager.d.ts +2 -0
- package/package.json +17 -17
- package/lib/data/downloadReleasesMetadata.d.ts +0 -7
- package/lib/data/downloadReleasesMetadata.js +0 -18
- package/lib/data/models.d.ts +0 -8
- package/lib/data/models.js +0 -49
package/lib/data/firmwareInfo.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getRelease = exports.getReleaseInfo = exports.getFirmwareStatus = exports.getInfo = exports.getReleases = exports.parseFirmwareReleases = void 0;
|
|
3
|
+
exports.getRelease = exports.getReleaseInfo = exports.getFirmwareStatus = exports.getInfo = exports.getOnlineReleases = exports.getReleases = exports.parseFirmwareReleases = void 0;
|
|
4
4
|
const device_utils_1 = require("@trezor/device-utils");
|
|
5
5
|
const utils_1 = require("@trezor/utils");
|
|
6
|
+
const assets_1 = require("../utils/assets");
|
|
6
7
|
const firmwareUtils_1 = require("../utils/firmwareUtils");
|
|
7
8
|
const releases = Object.values(device_utils_1.DeviceModelInternal).reduce((acc, key) => ({ ...acc, [key]: [] }), {});
|
|
8
9
|
const parseFirmwareReleases = (json, deviceModel) => {
|
|
@@ -16,6 +17,18 @@ const parseFirmwareReleases = (json, deviceModel) => {
|
|
|
16
17
|
exports.parseFirmwareReleases = parseFirmwareReleases;
|
|
17
18
|
const getReleases = (deviceModel) => releases[deviceModel] || [];
|
|
18
19
|
exports.getReleases = getReleases;
|
|
20
|
+
const getOnlineReleases = async (internalModel) => {
|
|
21
|
+
const url = `https://data.trezor.io/firmware/${internalModel.toLowerCase()}/releases.json`;
|
|
22
|
+
const response = await (0, assets_1.httpRequest)(url, 'json', {
|
|
23
|
+
signal: AbortSignal.timeout(10000),
|
|
24
|
+
skipLocalForceDownload: true,
|
|
25
|
+
});
|
|
26
|
+
if ((0, firmwareUtils_1.isValidReleases)(response)) {
|
|
27
|
+
return response;
|
|
28
|
+
}
|
|
29
|
+
return [];
|
|
30
|
+
};
|
|
31
|
+
exports.getOnlineReleases = getOnlineReleases;
|
|
19
32
|
const getChangelog = (releases2, features) => {
|
|
20
33
|
if (features.bootloader_mode) {
|
|
21
34
|
if (features.firmware_present && features.major_version === 1) {
|
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.1-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
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { TransportProtocol } from '@trezor/protocol';
|
|
1
|
+
import { TransportProtocol, thp as protocolThp } from '@trezor/protocol';
|
|
2
2
|
import { Session } from '@trezor/transport';
|
|
3
3
|
import { type Descriptor, type Transport } from '@trezor/transport';
|
|
4
4
|
import { TypedEmitter } from '@trezor/utils';
|
|
5
5
|
import { PROTO } from '../constants';
|
|
6
6
|
import { TypedCallProvider } from './DeviceCurrentSession';
|
|
7
7
|
import { IStateStorage } from './StateStorage';
|
|
8
|
-
import { DEVICE, DeviceButtonRequestPayload, DeviceVersionChanged, UiResponsePassphrase, UiResponsePin, UiResponseWord } from '../events';
|
|
8
|
+
import { DEVICE, DeviceButtonRequestPayload, DeviceThpCredentialsChangedPayload, DeviceThpPairingPayload, DeviceVersionChanged, UiResponsePassphrase, UiResponsePin, UiResponseThpPairingTag, UiResponseWord } from '../events';
|
|
9
9
|
import { DeviceFirmwareStatus, DeviceState, Device as DeviceTyped, DeviceUniquePath, FirmwareType, ReleaseInfo, UnavailableCapabilities, VersionArray } from '../types';
|
|
10
10
|
type RunOptions = {
|
|
11
11
|
skipFinalReload?: boolean;
|
|
@@ -42,6 +42,11 @@ export interface DeviceEvents {
|
|
|
42
42
|
payload: DeviceButtonRequestPayload;
|
|
43
43
|
};
|
|
44
44
|
[DEVICE.FIRMWARE_VERSION_CHANGED]: DeviceVersionChanged['payload'];
|
|
45
|
+
[DEVICE.THP_PAIRING]: {
|
|
46
|
+
payload: DeviceThpPairingPayload;
|
|
47
|
+
callback: (response: Result<UiResponseThpPairingTag['payload']>) => void;
|
|
48
|
+
};
|
|
49
|
+
[DEVICE.THP_CREDENTIALS_CHANGED]: DeviceThpCredentialsChangedPayload;
|
|
45
50
|
}
|
|
46
51
|
type DeviceLifecycle = typeof DEVICE.CONNECT | typeof DEVICE.CONNECT_UNACQUIRED | typeof DEVICE.DISCONNECT | typeof DEVICE.CHANGED;
|
|
47
52
|
type DeviceLifecycleListener = (lifecycle: DeviceLifecycle) => void;
|
|
@@ -53,16 +58,16 @@ type DeviceParams = {
|
|
|
53
58
|
};
|
|
54
59
|
export declare class Device extends TypedEmitter<DeviceEvents> {
|
|
55
60
|
readonly transport: Transport;
|
|
56
|
-
readonly protocol: TransportProtocol;
|
|
57
61
|
readonly transportPath: import("@trezor/transport/lib/types").PathPublic;
|
|
58
62
|
readonly bluetoothProps: {
|
|
59
63
|
id: string;
|
|
60
64
|
} | undefined;
|
|
61
65
|
private thp;
|
|
62
|
-
private readonly
|
|
63
|
-
private
|
|
64
|
-
private
|
|
65
|
-
|
|
66
|
+
private readonly possibleHIDdevice;
|
|
67
|
+
private sessionAcquired;
|
|
68
|
+
private _protocol;
|
|
69
|
+
get protocol(): TransportProtocol;
|
|
70
|
+
getThpState(): protocolThp.ThpState | undefined;
|
|
66
71
|
private unreadableError?;
|
|
67
72
|
private _firmwareStatus;
|
|
68
73
|
get firmwareStatus(): DeviceFirmwareStatus;
|
|
@@ -123,14 +128,13 @@ export declare class Device extends TypedEmitter<DeviceEvents> {
|
|
|
123
128
|
experimental_features: boolean | null;
|
|
124
129
|
internal_model: PROTO.DeviceModelInternal;
|
|
125
130
|
};
|
|
126
|
-
private
|
|
131
|
+
private wasUsedElsewhere;
|
|
127
132
|
private acquirePromise?;
|
|
128
133
|
private releasePromise?;
|
|
129
134
|
private runAbort?;
|
|
130
135
|
private runPromise?;
|
|
131
136
|
private keepTransportSession;
|
|
132
137
|
private currentSession?;
|
|
133
|
-
private inconsistent;
|
|
134
138
|
private instance;
|
|
135
139
|
private state;
|
|
136
140
|
private stateStorage?;
|
|
@@ -147,20 +151,18 @@ export declare class Device extends TypedEmitter<DeviceEvents> {
|
|
|
147
151
|
private sessionDfd?;
|
|
148
152
|
handshakeFinished: boolean;
|
|
149
153
|
constructor({ id, transport, descriptor, listener }: DeviceParams);
|
|
154
|
+
private readonly onTransportStopped;
|
|
155
|
+
private readonly onTransportDeviceEvent;
|
|
150
156
|
private getSessionChangePromise;
|
|
151
157
|
private waitAndCompareSession;
|
|
152
158
|
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">;
|
|
153
|
-
release():
|
|
154
|
-
success: false;
|
|
155
|
-
error: "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";
|
|
156
|
-
message?: string;
|
|
157
|
-
} | undefined>;
|
|
159
|
+
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;
|
|
158
160
|
handshake(delay?: number): Promise<void>;
|
|
159
|
-
updateDescriptor
|
|
161
|
+
private updateDescriptor;
|
|
160
162
|
run(fn?: () => Promise<void>, options?: RunOptions): Promise<void>;
|
|
161
163
|
interrupt(reason: Error): Promise<void>;
|
|
162
164
|
get currentRun(): Promise<void> | undefined;
|
|
163
|
-
usedElsewhere
|
|
165
|
+
private usedElsewhere;
|
|
164
166
|
private _runInner;
|
|
165
167
|
getCurrentSession(): TypedCallProvider;
|
|
166
168
|
getCommands(): {
|
|
@@ -228,7 +230,6 @@ export declare class Device extends TypedEmitter<DeviceEvents> {
|
|
|
228
230
|
getInstance(): number;
|
|
229
231
|
getState(): DeviceState | undefined;
|
|
230
232
|
setState(state?: Partial<DeviceState>): void;
|
|
231
|
-
validateState(preauthorized?: boolean): Promise<`${string}@${string}:${number}` | undefined>;
|
|
232
233
|
initialize(useCardanoDerivation: boolean): Promise<void>;
|
|
233
234
|
initStorage(storage: IStateStorage): void;
|
|
234
235
|
getFeatures(): Promise<void>;
|
|
@@ -247,14 +248,13 @@ export declare class Device extends TypedEmitter<DeviceEvents> {
|
|
|
247
248
|
}>;
|
|
248
249
|
private _uploadTranslationData;
|
|
249
250
|
private _updateFeatures;
|
|
250
|
-
prompt<T extends typeof DEVICE.PIN | typeof DEVICE.PASSPHRASE | typeof DEVICE.WORD>(type: T, args: Omit<DeviceEvents[T], 'callback'>): Promise<Parameters<DeviceEvents[T]["callback"]>[0]>;
|
|
251
|
+
prompt<T extends typeof DEVICE.PIN | typeof DEVICE.PASSPHRASE | typeof DEVICE.WORD | typeof DEVICE.THP_PAIRING>(type: T, args: Omit<DeviceEvents[T], 'callback'>): Promise<Parameters<DeviceEvents[T]["callback"]>[0]>;
|
|
251
252
|
isUnacquired(): boolean;
|
|
252
253
|
isUnreadable(): boolean;
|
|
253
|
-
disconnect
|
|
254
|
+
private disconnect;
|
|
254
255
|
isBootloader(): boolean;
|
|
255
256
|
isInitialized(): boolean;
|
|
256
257
|
isSeedless(): boolean;
|
|
257
|
-
isInconsistent(): boolean;
|
|
258
258
|
getVersion(): VersionArray | undefined;
|
|
259
259
|
atLeast(versions: string[] | string): boolean;
|
|
260
260
|
isUsed(): boolean;
|
|
@@ -263,7 +263,6 @@ export declare class Device extends TypedEmitter<DeviceEvents> {
|
|
|
263
263
|
getUniquePath(): DeviceUniquePath;
|
|
264
264
|
isT1(): boolean;
|
|
265
265
|
hasUnexpectedMode(allow: string[], require: string[]): "ui-device_bootloader_mode" | "ui-device_not_in_bootloader_mode" | "ui-device_not_initialized" | "ui-device_seedless" | null;
|
|
266
|
-
dispose(): void;
|
|
267
266
|
private getMode;
|
|
268
267
|
toMessageObject(): DeviceTyped;
|
|
269
268
|
}
|
package/lib/device/Device.js
CHANGED
|
@@ -15,26 +15,28 @@ const DataManager_1 = require("../data/DataManager");
|
|
|
15
15
|
const coinInfo_1 = require("../data/coinInfo");
|
|
16
16
|
const firmwareInfo_1 = require("../data/firmwareInfo");
|
|
17
17
|
const getLanguage_1 = require("../data/getLanguage");
|
|
18
|
-
const models_1 = require("../data/models");
|
|
19
18
|
const events_1 = require("../events");
|
|
20
19
|
const types_1 = require("../types");
|
|
21
20
|
const debug_1 = require("../utils/debug");
|
|
22
21
|
const deviceFeaturesUtils_1 = require("../utils/deviceFeaturesUtils");
|
|
23
|
-
const pathUtils_1 = require("../utils/pathUtils");
|
|
24
22
|
const _log = (0, debug_1.initLog)('Device');
|
|
25
23
|
exports.CANCEL_TIMEOUT = 1_000;
|
|
26
24
|
exports.GET_FEATURES_TIMEOUT = 3_000;
|
|
27
25
|
exports.GET_FEATURES_TIMEOUT_REACT_NATIVE = 20_000;
|
|
28
26
|
class Device extends utils_1.TypedEmitter {
|
|
29
27
|
transport;
|
|
30
|
-
protocol;
|
|
31
28
|
transportPath;
|
|
32
29
|
bluetoothProps;
|
|
33
30
|
thp;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
possibleHIDdevice;
|
|
32
|
+
sessionAcquired;
|
|
33
|
+
_protocol;
|
|
34
|
+
get protocol() {
|
|
35
|
+
return this._protocol;
|
|
36
|
+
}
|
|
37
|
+
getThpState() {
|
|
38
|
+
return this.thp;
|
|
39
|
+
}
|
|
38
40
|
unreadableError;
|
|
39
41
|
_firmwareStatus;
|
|
40
42
|
get firmwareStatus() {
|
|
@@ -48,14 +50,13 @@ class Device extends utils_1.TypedEmitter {
|
|
|
48
50
|
get features() {
|
|
49
51
|
return this._features;
|
|
50
52
|
}
|
|
51
|
-
|
|
53
|
+
wasUsedElsewhere = false;
|
|
52
54
|
acquirePromise;
|
|
53
55
|
releasePromise;
|
|
54
56
|
runAbort;
|
|
55
57
|
runPromise;
|
|
56
58
|
keepTransportSession = false;
|
|
57
59
|
currentSession;
|
|
58
|
-
inconsistent = false;
|
|
59
60
|
instance = 0;
|
|
60
61
|
state = [];
|
|
61
62
|
stateStorage = undefined;
|
|
@@ -81,16 +82,28 @@ class Device extends utils_1.TypedEmitter {
|
|
|
81
82
|
constructor({ id, transport, descriptor, listener }) {
|
|
82
83
|
super();
|
|
83
84
|
this.emitLifecycle = listener;
|
|
84
|
-
this.
|
|
85
|
+
this._protocol = protocol_1.v1;
|
|
85
86
|
this.uniquePath = id;
|
|
86
87
|
this.transport = transport;
|
|
87
88
|
this.transportPath = descriptor.path;
|
|
88
|
-
this.
|
|
89
|
-
this.transportDescriptorType = descriptor.type;
|
|
89
|
+
this.possibleHIDdevice = [0, 2].includes(descriptor.type);
|
|
90
90
|
this.bluetoothProps = descriptor.id ? { id: descriptor.id } : undefined;
|
|
91
|
-
this.
|
|
92
|
-
this.
|
|
93
|
-
|
|
91
|
+
this.sessionAcquired = null;
|
|
92
|
+
transport.on(transport_1.TRANSPORT.STOPPED, this.onTransportStopped);
|
|
93
|
+
transport.deviceEvents.on(this.transportPath, this.onTransportDeviceEvent);
|
|
94
|
+
}
|
|
95
|
+
onTransportStopped = () => this.disconnect();
|
|
96
|
+
onTransportDeviceEvent = (event) => {
|
|
97
|
+
switch (event.type) {
|
|
98
|
+
case transport_1.TRANSPORT.DEVICE_SESSION_CHANGED:
|
|
99
|
+
return this.updateDescriptor(event.descriptor);
|
|
100
|
+
case transport_1.TRANSPORT.DEVICE_REQUEST_RELEASE:
|
|
101
|
+
return this.usedElsewhere();
|
|
102
|
+
case transport_1.TRANSPORT.DEVICE_DISCONNECTED: {
|
|
103
|
+
return this.disconnect();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
94
107
|
getSessionChangePromise() {
|
|
95
108
|
if (!this.sessionDfd) {
|
|
96
109
|
this.sessionDfd = (0, utils_1.createDeferred)();
|
|
@@ -123,15 +136,15 @@ class Device extends utils_1.TypedEmitter {
|
|
|
123
136
|
}
|
|
124
137
|
acquire() {
|
|
125
138
|
const sessionPromise = this.getSessionChangePromise();
|
|
139
|
+
const previous = this.transport.getDescriptor(this.transportPath)?.session ?? null;
|
|
126
140
|
this.acquirePromise = this.transport
|
|
127
|
-
.acquire({ input: { path: this.transportPath, previous
|
|
141
|
+
.acquire({ input: { path: this.transportPath, previous } })
|
|
128
142
|
.then(result => this.waitAndCompareSession(result, sessionPromise))
|
|
129
143
|
.then(result => {
|
|
130
144
|
if (result.success) {
|
|
131
|
-
this.
|
|
132
|
-
this.
|
|
133
|
-
this.currentSession
|
|
134
|
-
this.currentSession = new DeviceCurrentSession_1.DeviceCurrentSession(this, this.transport, this.protocol, this.session);
|
|
145
|
+
this.wasUsedElsewhere = false;
|
|
146
|
+
this.sessionAcquired = result.payload;
|
|
147
|
+
this.currentSession = new DeviceCurrentSession_1.DeviceCurrentSession(this, this.transport, this.sessionAcquired);
|
|
135
148
|
return result;
|
|
136
149
|
}
|
|
137
150
|
else {
|
|
@@ -143,19 +156,17 @@ class Device extends utils_1.TypedEmitter {
|
|
|
143
156
|
});
|
|
144
157
|
return this.acquirePromise;
|
|
145
158
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (!localSession || this.keepTransportSession || this.releasePromise) {
|
|
159
|
+
release() {
|
|
160
|
+
if (!this.sessionAcquired || this.keepTransportSession || this.releasePromise) {
|
|
149
161
|
return;
|
|
150
162
|
}
|
|
151
|
-
await this.currentSession?.dispose();
|
|
152
163
|
const sessionPromise = this.getSessionChangePromise();
|
|
153
164
|
this.releasePromise = this.transport
|
|
154
|
-
.release({ session:
|
|
165
|
+
.release({ session: this.sessionAcquired, path: this.transportPath })
|
|
155
166
|
.then(result => this.waitAndCompareSession(result, sessionPromise))
|
|
156
167
|
.then(result => {
|
|
157
168
|
if (result.success) {
|
|
158
|
-
this.
|
|
169
|
+
this.sessionAcquired = null;
|
|
159
170
|
}
|
|
160
171
|
return result;
|
|
161
172
|
})
|
|
@@ -184,15 +195,17 @@ class Device extends utils_1.TypedEmitter {
|
|
|
184
195
|
error.message === transport_1.TRANSPORT_ERROR.DEVICE_DISCONNECTED_DURING_ACTION ||
|
|
185
196
|
error.message === transport_1.TRANSPORT_ERROR.HTTP_ERROR) {
|
|
186
197
|
}
|
|
187
|
-
else if (
|
|
188
|
-
error.message === transport_1.TRANSPORT_ERROR.
|
|
189
|
-
error.
|
|
190
|
-
|
|
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;
|
|
191
202
|
this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
|
|
192
203
|
}
|
|
193
204
|
else if (error.message === transport_1.TRANSPORT_ERROR.INTERFACE_UNABLE_TO_OPEN_DEVICE ||
|
|
194
|
-
error.message
|
|
195
|
-
|
|
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') {
|
|
196
209
|
this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
|
|
197
210
|
}
|
|
198
211
|
else {
|
|
@@ -208,17 +221,12 @@ class Device extends utils_1.TypedEmitter {
|
|
|
208
221
|
async updateDescriptor(descriptor) {
|
|
209
222
|
this.sessionDfd?.resolve(descriptor.session);
|
|
210
223
|
await Promise.all([this.acquirePromise, this.releasePromise]);
|
|
211
|
-
if (descriptor.session && descriptor.session !== this.
|
|
224
|
+
if (descriptor.session && descriptor.session !== this.sessionAcquired) {
|
|
212
225
|
this.usedElsewhere();
|
|
213
226
|
}
|
|
214
227
|
if (!descriptor.session) {
|
|
215
|
-
|
|
216
|
-
if (methodStillRunning) {
|
|
217
|
-
this.keepTransportSession = false;
|
|
218
|
-
}
|
|
228
|
+
this.keepTransportSession = false;
|
|
219
229
|
}
|
|
220
|
-
this.session = descriptor.session;
|
|
221
|
-
this.transportSessionOwner = descriptor.sessionOwner;
|
|
222
230
|
this.emitLifecycle(events_1.DEVICE.CHANGED);
|
|
223
231
|
}
|
|
224
232
|
run(fn, options = {}) {
|
|
@@ -230,7 +238,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
230
238
|
this.runAbort = new AbortController();
|
|
231
239
|
const { signal } = this.runAbort;
|
|
232
240
|
this.runPromise = Promise.race([
|
|
233
|
-
this._runInner(fn, options),
|
|
241
|
+
this._runInner(fn, options, signal),
|
|
234
242
|
new Promise((_, reject) => {
|
|
235
243
|
signal.addEventListener('abort', () => reject(signal.reason));
|
|
236
244
|
}),
|
|
@@ -253,7 +261,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
253
261
|
return this.runPromise;
|
|
254
262
|
}
|
|
255
263
|
async interrupt(reason) {
|
|
256
|
-
await this.currentSession?.abort(reason
|
|
264
|
+
await this.currentSession?.abort(reason);
|
|
257
265
|
this.runAbort?.abort(reason);
|
|
258
266
|
await this.currentRun;
|
|
259
267
|
}
|
|
@@ -261,19 +269,16 @@ class Device extends utils_1.TypedEmitter {
|
|
|
261
269
|
return this.runPromise?.catch(() => { });
|
|
262
270
|
}
|
|
263
271
|
usedElsewhere() {
|
|
264
|
-
|
|
272
|
+
this.wasUsedElsewhere = true;
|
|
273
|
+
if (!this.sessionAcquired) {
|
|
265
274
|
return;
|
|
266
275
|
}
|
|
267
|
-
this.
|
|
268
|
-
this.
|
|
276
|
+
this.transport.releaseDevice(this.sessionAcquired);
|
|
277
|
+
this.sessionAcquired = null;
|
|
269
278
|
_log.debug('interruptionFromOutside');
|
|
270
|
-
this.currentSession?.dispose();
|
|
271
279
|
this.runAbort?.abort(constants_1.ERRORS.TypedError('Device_UsedElsewhere'));
|
|
272
|
-
if (this.session) {
|
|
273
|
-
this.transport.releaseDevice(this.session);
|
|
274
|
-
}
|
|
275
280
|
}
|
|
276
|
-
async _runInner(fn, options) {
|
|
281
|
+
async _runInner(fn, options, abortSignal) {
|
|
277
282
|
if (this.releasePromise) {
|
|
278
283
|
await this.releasePromise;
|
|
279
284
|
}
|
|
@@ -281,6 +286,8 @@ class Device extends utils_1.TypedEmitter {
|
|
|
281
286
|
if (acquireNeeded) {
|
|
282
287
|
await this.acquire();
|
|
283
288
|
}
|
|
289
|
+
if (abortSignal.aborted)
|
|
290
|
+
throw abortSignal.reason;
|
|
284
291
|
const { staticSessionId, deriveCardano } = this.getState() || {};
|
|
285
292
|
if (acquireNeeded || !staticSessionId || (!deriveCardano && options.useCardanoDerivation)) {
|
|
286
293
|
try {
|
|
@@ -289,43 +296,21 @@ class Device extends utils_1.TypedEmitter {
|
|
|
289
296
|
}
|
|
290
297
|
else {
|
|
291
298
|
const isNative = DataManager_1.DataManager.getSettings('env') === 'react-native';
|
|
292
|
-
const getFeaturesTimeout = isNative
|
|
293
|
-
? exports.GET_FEATURES_TIMEOUT_REACT_NATIVE
|
|
294
|
-
: exports.GET_FEATURES_TIMEOUT;
|
|
295
299
|
const cancelTimeout = isNative
|
|
296
300
|
? exports.GET_FEATURES_TIMEOUT_REACT_NATIVE
|
|
297
301
|
: exports.CANCEL_TIMEOUT;
|
|
298
|
-
if (['v1', 'bridge'].includes(this.protocol.name) &&
|
|
299
|
-
![0, 2].includes(this.transportDescriptorType)) {
|
|
302
|
+
if (['v1', 'bridge'].includes(this.protocol.name) && !this.possibleHIDdevice) {
|
|
300
303
|
_log.debug('sending a preventive cancel on the first encounter with the device');
|
|
301
304
|
await Promise.race([
|
|
302
305
|
this.getCurrentSession().cancelCall(),
|
|
303
306
|
new Promise((_, reject) => setTimeout(reject, cancelTimeout)),
|
|
304
307
|
]).catch(() => this.acquire());
|
|
305
308
|
}
|
|
306
|
-
|
|
307
|
-
await Promise.race([
|
|
308
|
-
this.getFeatures().finally(() => clearTimeout(getFeaturesTimeoutId)),
|
|
309
|
-
new Promise((_resolve, reject) => {
|
|
310
|
-
getFeaturesTimeoutId = setTimeout(async () => {
|
|
311
|
-
await this.getCurrentSession().cancelCall(false);
|
|
312
|
-
reject(new Error('GetFeatures timeout'));
|
|
313
|
-
}, getFeaturesTimeout);
|
|
314
|
-
}),
|
|
315
|
-
]);
|
|
309
|
+
await this.getFeatures();
|
|
316
310
|
}
|
|
317
311
|
}
|
|
318
312
|
catch (error) {
|
|
319
313
|
_log.warn('Device._runInner error: ', error.message);
|
|
320
|
-
if (!this.inconsistent &&
|
|
321
|
-
(error.message === 'GetFeatures timeout' || error.message === 'Unknown message')) {
|
|
322
|
-
this.inconsistent = true;
|
|
323
|
-
return this._runInner(() => Promise.resolve({}), options);
|
|
324
|
-
}
|
|
325
|
-
if (transport_1.TRANSPORT_ERROR.ABORTED_BY_TIMEOUT === error.message) {
|
|
326
|
-
this.unreadableError = 'Connection timeout';
|
|
327
|
-
}
|
|
328
|
-
this.inconsistent = true;
|
|
329
314
|
return Promise.reject(constants_1.ERRORS.TypedError('Device_InitializeFailed', `Initialize failed: ${error.message}${error.code ? `, code: ${error.code}` : ''}`));
|
|
330
315
|
}
|
|
331
316
|
}
|
|
@@ -372,7 +357,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
372
357
|
setInstance(instance = 0) {
|
|
373
358
|
if (this.instance !== instance) {
|
|
374
359
|
if (this.keepTransportSession) {
|
|
375
|
-
this.
|
|
360
|
+
this.sessionAcquired = null;
|
|
376
361
|
this.keepTransportSession = false;
|
|
377
362
|
}
|
|
378
363
|
}
|
|
@@ -398,31 +383,6 @@ class Device extends utils_1.TypedEmitter {
|
|
|
398
383
|
this.stateStorage?.saveState(this, newState);
|
|
399
384
|
}
|
|
400
385
|
}
|
|
401
|
-
async validateState(preauthorized = false) {
|
|
402
|
-
if (!this.features)
|
|
403
|
-
return;
|
|
404
|
-
if (!this.features.unlocked && preauthorized) {
|
|
405
|
-
if (await this.getCommands().preauthorize(false)) {
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
const expectedState = this.getState()?.staticSessionId;
|
|
410
|
-
const { message } = await this.getCurrentSession().typedCall('GetAddress', 'Address', {
|
|
411
|
-
address_n: [(0, pathUtils_1.toHardened)(44), (0, pathUtils_1.toHardened)(1), (0, pathUtils_1.toHardened)(0), 0, 0],
|
|
412
|
-
coin_name: 'Testnet',
|
|
413
|
-
script_type: 'SPENDADDRESS',
|
|
414
|
-
});
|
|
415
|
-
const uniqueState = `${message.address}@${this.features.device_id}:${this.instance}`;
|
|
416
|
-
if (this.features.session_id) {
|
|
417
|
-
this.setState({ sessionId: this.features.session_id });
|
|
418
|
-
}
|
|
419
|
-
if (expectedState && expectedState !== uniqueState) {
|
|
420
|
-
return uniqueState;
|
|
421
|
-
}
|
|
422
|
-
if (!expectedState) {
|
|
423
|
-
this.setState({ staticSessionId: uniqueState });
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
386
|
async initialize(useCardanoDerivation) {
|
|
427
387
|
let payload;
|
|
428
388
|
if (this.features) {
|
|
@@ -570,12 +530,12 @@ class Device extends utils_1.TypedEmitter {
|
|
|
570
530
|
return response.message;
|
|
571
531
|
}
|
|
572
532
|
const length = payload.byteLength;
|
|
573
|
-
let response = await this.getCurrentSession().typedCall('ChangeLanguage', ['
|
|
533
|
+
let response = await this.getCurrentSession().typedCall('ChangeLanguage', ['DataChunkRequest', 'Success'], { data_length: length });
|
|
574
534
|
while (response.type !== 'Success') {
|
|
575
535
|
const start = response.message.data_offset;
|
|
576
536
|
const end = response.message.data_offset + response.message.data_length;
|
|
577
537
|
const chunk = payload.slice(start, end);
|
|
578
|
-
response = await this.getCurrentSession().typedCall('
|
|
538
|
+
response = await this.getCurrentSession().typedCall('DataChunkAck', ['DataChunkRequest', 'Success'], {
|
|
579
539
|
data_chunk: Buffer.from(chunk).toString('hex'),
|
|
580
540
|
});
|
|
581
541
|
}
|
|
@@ -616,7 +576,6 @@ class Device extends utils_1.TypedEmitter {
|
|
|
616
576
|
this.availableTranslations = this.firmwareRelease?.translations ?? [];
|
|
617
577
|
}
|
|
618
578
|
this._features = feat;
|
|
619
|
-
this._featuresNeedsReload = false;
|
|
620
579
|
if (feat.fw_vendor === 'Trezor Bitcoin-only') {
|
|
621
580
|
this._firmwareType = types_1.FirmwareType.BitcoinOnly;
|
|
622
581
|
}
|
|
@@ -631,7 +590,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
631
590
|
? types_1.FirmwareType.BitcoinOnly
|
|
632
591
|
: types_1.FirmwareType.Regular;
|
|
633
592
|
}
|
|
634
|
-
const deviceInfo =
|
|
593
|
+
const deviceInfo = device_utils_1.models[feat.internal_model] ?? {
|
|
635
594
|
name: `Unknown ${feat.internal_model}`,
|
|
636
595
|
colors: {},
|
|
637
596
|
};
|
|
@@ -665,8 +624,14 @@ class Device extends utils_1.TypedEmitter {
|
|
|
665
624
|
}
|
|
666
625
|
disconnect() {
|
|
667
626
|
_log.debug('Disconnect cleanup');
|
|
627
|
+
this.transport.off(transport_1.TRANSPORT.STOPPED, this.onTransportStopped);
|
|
628
|
+
this.transport.deviceEvents.off(this.transportPath, this.onTransportDeviceEvent);
|
|
629
|
+
this.removeAllListeners();
|
|
668
630
|
this.sessionDfd?.reject(new Error());
|
|
669
|
-
this.
|
|
631
|
+
if (this.sessionAcquired) {
|
|
632
|
+
this.transport.releaseSync(this.sessionAcquired);
|
|
633
|
+
this.sessionAcquired = null;
|
|
634
|
+
}
|
|
670
635
|
this.emitLifecycle(events_1.DEVICE.DISCONNECT);
|
|
671
636
|
this.emitLifecycle = () => { };
|
|
672
637
|
return this.interrupt(constants_1.ERRORS.TypedError('Device_Disconnected'));
|
|
@@ -680,9 +645,6 @@ class Device extends utils_1.TypedEmitter {
|
|
|
680
645
|
isSeedless() {
|
|
681
646
|
return this.features && !!this.features.no_backup;
|
|
682
647
|
}
|
|
683
|
-
isInconsistent() {
|
|
684
|
-
return this.inconsistent;
|
|
685
|
-
}
|
|
686
648
|
getVersion() {
|
|
687
649
|
if (!this.features)
|
|
688
650
|
return;
|
|
@@ -700,13 +662,13 @@ class Device extends utils_1.TypedEmitter {
|
|
|
700
662
|
return utils_1.versionUtils.isNewerOrEqual(version, modelVersion);
|
|
701
663
|
}
|
|
702
664
|
isUsed() {
|
|
703
|
-
return
|
|
665
|
+
return !!this.transport.getDescriptor(this.transportPath)?.session;
|
|
704
666
|
}
|
|
705
667
|
isUsedHere() {
|
|
706
|
-
return this.
|
|
668
|
+
return !!this.sessionAcquired;
|
|
707
669
|
}
|
|
708
670
|
isUsedElsewhere() {
|
|
709
|
-
return this.isUsed() && !this.
|
|
671
|
+
return this.isUsed() && !this.isUsedHere();
|
|
710
672
|
}
|
|
711
673
|
getUniquePath() {
|
|
712
674
|
return this.uniquePath;
|
|
@@ -731,12 +693,6 @@ class Device extends utils_1.TypedEmitter {
|
|
|
731
693
|
}
|
|
732
694
|
return null;
|
|
733
695
|
}
|
|
734
|
-
dispose() {
|
|
735
|
-
this.removeAllListeners();
|
|
736
|
-
if (this.session && this.lastAcquiredHere) {
|
|
737
|
-
this.transport.releaseSync(this.session);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
696
|
getMode() {
|
|
741
697
|
if (this.features.bootloader_mode)
|
|
742
698
|
return 'bootloader';
|
|
@@ -755,27 +711,26 @@ class Device extends utils_1.TypedEmitter {
|
|
|
755
711
|
type: 'unreadable',
|
|
756
712
|
error: this.unreadableError,
|
|
757
713
|
label: 'Unreadable device',
|
|
758
|
-
|
|
714
|
+
hid: this.possibleHIDdevice,
|
|
759
715
|
};
|
|
760
716
|
}
|
|
761
717
|
if (this.isUnacquired()) {
|
|
718
|
+
const sessionOwner = this.transport.getDescriptor(this.transportPath)?.sessionOwner;
|
|
762
719
|
return {
|
|
763
720
|
...base,
|
|
764
721
|
type: 'unacquired',
|
|
765
722
|
label: 'Unacquired device',
|
|
766
723
|
name: this.name,
|
|
767
|
-
transportSessionOwner: this.
|
|
768
|
-
? undefined
|
|
769
|
-
: this.transportSessionOwner,
|
|
724
|
+
transportSessionOwner: this.sessionAcquired ? undefined : sessionOwner,
|
|
770
725
|
bluetoothProps: this.bluetoothProps,
|
|
771
726
|
thp: this.thp?.serialize(),
|
|
772
727
|
};
|
|
773
728
|
}
|
|
774
729
|
const defaultLabel = 'My Trezor';
|
|
775
730
|
const label = this.features.label === '' || !this.features.label ? defaultLabel : this.features.label;
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
731
|
+
const status = this.isUsedElsewhere()
|
|
732
|
+
? 'occupied'
|
|
733
|
+
: (this.wasUsedElsewhere && 'used') || 'available';
|
|
779
734
|
return {
|
|
780
735
|
...base,
|
|
781
736
|
type: 'acquired',
|