@ledgerhq/hw-transport 6.30.0 → 6.30.1-next.0
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 +23 -0
- package/LICENSE.txt +21 -0
- package/README.md +39 -5
- package/lib/Transport.d.ts +31 -4
- package/lib/Transport.d.ts.map +1 -1
- package/lib/Transport.js +77 -39
- package/lib/Transport.js.map +1 -1
- package/lib-es/Transport.d.ts +31 -4
- package/lib-es/Transport.d.ts.map +1 -1
- package/lib-es/Transport.js +77 -39
- package/lib-es/Transport.js.map +1 -1
- package/package.json +6 -6
- package/src/Transport.ts +54 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @ledgerhq/hw-transport
|
|
2
2
|
|
|
3
|
+
## 6.30.1-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#5171](https://github.com/LedgerHQ/ledger-live/pull/5171) [`52a3732`](https://github.com/LedgerHQ/ledger-live/commit/52a373273dee3b2cb5a3e8d2d4b05f90616d71a2) Thanks [@alexandremgo](https://github.com/alexandremgo)! - Feat: new abort timeout on opening transport and APDU exchange
|
|
8
|
+
|
|
9
|
+
On `@ledgerhq/hw-transport`
|
|
10
|
+
|
|
11
|
+
- `exchange` adding an optional `abortTimeoutMs` arg to its definition
|
|
12
|
+
- `send` taking an optional `abortTimeoutMs` and passing it to `exchange`
|
|
13
|
+
- Some documentation and tracing
|
|
14
|
+
|
|
15
|
+
On `@ledgerhq/react-native-hw-transport-ble`
|
|
16
|
+
|
|
17
|
+
- `open`: enabling optional timeout when opening a transport instance
|
|
18
|
+
- `exchange`: enabling optional timeout on APDU exchange, calling `cancelPendingOperations` on timeout
|
|
19
|
+
- `cancelPendingOperations`: using a `currentTransactionIds` array of transactions id for each `write`, we can try to abort completely pending writes
|
|
20
|
+
- More documentation + tracing + simple unit tests
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [[`52a3732`](https://github.com/LedgerHQ/ledger-live/commit/52a373273dee3b2cb5a3e8d2d4b05f90616d71a2), [`4d1aade`](https://github.com/LedgerHQ/ledger-live/commit/4d1aade53cd33f8e7548ce340f54fbb834bdcdcb), [`52a3732`](https://github.com/LedgerHQ/ledger-live/commit/52a373273dee3b2cb5a3e8d2d4b05f90616d71a2)]:
|
|
23
|
+
- @ledgerhq/errors@6.16.1-next.0
|
|
24
|
+
- @ledgerhq/devices@8.2.0-next.0
|
|
25
|
+
|
|
3
26
|
## 6.30.0
|
|
4
27
|
|
|
5
28
|
### Minor Changes
|
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017-present Ledger https://www.ledger.com/
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -39,20 +39,24 @@
|
|
|
39
39
|
* [Parameters](#parameters-7)
|
|
40
40
|
* [send](#send)
|
|
41
41
|
* [Parameters](#parameters-8)
|
|
42
|
-
* [
|
|
42
|
+
* [exchangeAtomicImpl](#exchangeatomicimpl)
|
|
43
43
|
* [Parameters](#parameters-9)
|
|
44
|
+
* [setTraceContext](#settracecontext)
|
|
45
|
+
* [Parameters](#parameters-10)
|
|
46
|
+
* [updateTraceContext](#updatetracecontext)
|
|
47
|
+
* [Parameters](#parameters-11)
|
|
44
48
|
* [getTraceContext](#gettracecontext)
|
|
45
49
|
* [isSupported](#issupported)
|
|
46
50
|
* [list](#list)
|
|
47
51
|
* [Examples](#examples)
|
|
48
52
|
* [listen](#listen)
|
|
49
|
-
* [Parameters](#parameters-
|
|
53
|
+
* [Parameters](#parameters-12)
|
|
50
54
|
* [Examples](#examples-1)
|
|
51
55
|
* [open](#open)
|
|
52
|
-
* [Parameters](#parameters-
|
|
56
|
+
* [Parameters](#parameters-13)
|
|
53
57
|
* [Examples](#examples-2)
|
|
54
58
|
* [create](#create)
|
|
55
|
-
* [Parameters](#parameters-
|
|
59
|
+
* [Parameters](#parameters-14)
|
|
56
60
|
* [Examples](#examples-3)
|
|
57
61
|
|
|
58
62
|
### Subscription
|
|
@@ -102,6 +106,10 @@ It's recommended to use the "send" method for a higher level API.
|
|
|
102
106
|
##### Parameters
|
|
103
107
|
|
|
104
108
|
* `_apdu` **[Buffer](https://nodejs.org/api/buffer.html)** 
|
|
109
|
+
* `options` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Contains optional options for the exchange function* abortTimeoutMs: stop the exchange after a given timeout. Another timeout exists
|
|
110
|
+
to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange. (optional, default `{}`)
|
|
111
|
+
|
|
112
|
+
* `options.abortTimeoutMs`  
|
|
105
113
|
* `apdu` **[Buffer](https://nodejs.org/api/buffer.html)** The data to send.
|
|
106
114
|
|
|
107
115
|
Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Buffer](https://nodejs.org/api/buffer.html)>** A promise that resolves with the response data from the device.
|
|
@@ -197,12 +205,28 @@ Send data to the device using the higher level API.
|
|
|
197
205
|
* `p2` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** The second parameter for the instruction.
|
|
198
206
|
* `data` **[Buffer](https://nodejs.org/api/buffer.html)** The data to be sent. Defaults to an empty buffer. (optional, default `Buffer.alloc(0)`)
|
|
199
207
|
* `statusList` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)>** A list of acceptable status codes for the response. Defaults to \[StatusCodes.OK]. (optional, default `[StatusCodes.OK]`)
|
|
208
|
+
* `options` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Contains optional options for the exchange function* abortTimeoutMs: stop the send after a given timeout. Another timeout exists
|
|
209
|
+
to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange. (optional, default `{}`)
|
|
210
|
+
|
|
211
|
+
* `options.abortTimeoutMs`  
|
|
200
212
|
|
|
201
213
|
Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Buffer](https://nodejs.org/api/buffer.html)>** A promise that resolves with the response data from the device.
|
|
202
214
|
|
|
215
|
+
#### exchangeAtomicImpl
|
|
216
|
+
|
|
217
|
+
Wrapper to make an exchange "atomic" (blocking any other exchange)
|
|
218
|
+
|
|
219
|
+
It also handles "unresponsiveness" by emitting "unresponsive" and "responsive" events.
|
|
220
|
+
|
|
221
|
+
##### Parameters
|
|
222
|
+
|
|
223
|
+
* `f` **function (): [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<Output>** The exchange job, using the transport to run
|
|
224
|
+
|
|
225
|
+
Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<Output>** a Promise resolving with the output of the given job
|
|
226
|
+
|
|
203
227
|
#### setTraceContext
|
|
204
228
|
|
|
205
|
-
|
|
229
|
+
Sets the context used by the logging/tracing mechanism
|
|
206
230
|
|
|
207
231
|
Useful when re-using (cached) the same Transport instance,
|
|
208
232
|
but with a new tracing context.
|
|
@@ -211,6 +235,16 @@ but with a new tracing context.
|
|
|
211
235
|
|
|
212
236
|
* `context` **TraceContext?** A TraceContext, that can undefined to reset the context
|
|
213
237
|
|
|
238
|
+
#### updateTraceContext
|
|
239
|
+
|
|
240
|
+
Updates the context used by the logging/tracing mechanism
|
|
241
|
+
|
|
242
|
+
The update only overrides the key-value that are already defined in the current context.
|
|
243
|
+
|
|
244
|
+
##### Parameters
|
|
245
|
+
|
|
246
|
+
* `contextToAdd` **TraceContext** A TraceContext that will be added to the current context
|
|
247
|
+
|
|
214
248
|
#### getTraceContext
|
|
215
249
|
|
|
216
250
|
Gets the tracing context of the transport instance
|
package/lib/Transport.d.ts
CHANGED
|
@@ -97,9 +97,14 @@ export default class Transport {
|
|
|
97
97
|
* Send data to the device using a low level API.
|
|
98
98
|
* It's recommended to use the "send" method for a higher level API.
|
|
99
99
|
* @param {Buffer} apdu - The data to send.
|
|
100
|
+
* @param {Object} options - Contains optional options for the exchange function
|
|
101
|
+
* - abortTimeoutMs: stop the exchange after a given timeout. Another timeout exists
|
|
102
|
+
* to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange.
|
|
100
103
|
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
101
104
|
*/
|
|
102
|
-
exchange(_apdu: Buffer
|
|
105
|
+
exchange(_apdu: Buffer, { abortTimeoutMs }?: {
|
|
106
|
+
abortTimeoutMs?: number;
|
|
107
|
+
}): Promise<Buffer>;
|
|
103
108
|
/**
|
|
104
109
|
* Send apdus in batch to the device using a low level API.
|
|
105
110
|
* The default implementation is to call exchange for each apdu.
|
|
@@ -150,15 +155,21 @@ export default class Transport {
|
|
|
150
155
|
setExchangeUnresponsiveTimeout(unresponsiveTimeout: number): void;
|
|
151
156
|
/**
|
|
152
157
|
* Send data to the device using the higher level API.
|
|
158
|
+
*
|
|
153
159
|
* @param {number} cla - The instruction class for the command.
|
|
154
160
|
* @param {number} ins - The instruction code for the command.
|
|
155
161
|
* @param {number} p1 - The first parameter for the instruction.
|
|
156
162
|
* @param {number} p2 - The second parameter for the instruction.
|
|
157
163
|
* @param {Buffer} data - The data to be sent. Defaults to an empty buffer.
|
|
158
164
|
* @param {Array<number>} statusList - A list of acceptable status codes for the response. Defaults to [StatusCodes.OK].
|
|
165
|
+
* @param {Object} options - Contains optional options for the exchange function
|
|
166
|
+
* - abortTimeoutMs: stop the send after a given timeout. Another timeout exists
|
|
167
|
+
* to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange.
|
|
159
168
|
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
160
169
|
*/
|
|
161
|
-
send: (cla: number, ins: number, p1: number, p2: number, data?: Buffer, statusList?: Array<number
|
|
170
|
+
send: (cla: number, ins: number, p1: number, p2: number, data?: Buffer, statusList?: Array<number>, { abortTimeoutMs }?: {
|
|
171
|
+
abortTimeoutMs?: number | undefined;
|
|
172
|
+
}) => Promise<Buffer>;
|
|
162
173
|
/**
|
|
163
174
|
* create() allows to open the first descriptor available or
|
|
164
175
|
* throw if there is none or if timeout is reached.
|
|
@@ -168,12 +179,20 @@ export default class Transport {
|
|
|
168
179
|
*/
|
|
169
180
|
static create(openTimeout?: number, listenTimeout?: number): Promise<Transport>;
|
|
170
181
|
exchangeBusyPromise: Promise<void> | null | undefined;
|
|
171
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Wrapper to make an exchange "atomic" (blocking any other exchange)
|
|
184
|
+
*
|
|
185
|
+
* It also handles "unresponsiveness" by emitting "unresponsive" and "responsive" events.
|
|
186
|
+
*
|
|
187
|
+
* @param f The exchange job, using the transport to run
|
|
188
|
+
* @returns a Promise resolving with the output of the given job
|
|
189
|
+
*/
|
|
190
|
+
exchangeAtomicImpl<Output>(f: () => Promise<Output>): Promise<Output>;
|
|
172
191
|
decorateAppAPIMethods(self: Record<string, any>, methods: Array<string>, scrambleKey: string): void;
|
|
173
192
|
_appAPIlock: string | null;
|
|
174
193
|
decorateAppAPIMethod<R, A extends any[]>(methodName: string, f: (...args: A) => Promise<R>, ctx: any, scrambleKey: string): (...args: A) => Promise<R>;
|
|
175
194
|
/**
|
|
176
|
-
*
|
|
195
|
+
* Sets the context used by the logging/tracing mechanism
|
|
177
196
|
*
|
|
178
197
|
* Useful when re-using (cached) the same Transport instance,
|
|
179
198
|
* but with a new tracing context.
|
|
@@ -181,6 +200,14 @@ export default class Transport {
|
|
|
181
200
|
* @param context A TraceContext, that can undefined to reset the context
|
|
182
201
|
*/
|
|
183
202
|
setTraceContext(context?: TraceContext): void;
|
|
203
|
+
/**
|
|
204
|
+
* Updates the context used by the logging/tracing mechanism
|
|
205
|
+
*
|
|
206
|
+
* The update only overrides the key-value that are already defined in the current context.
|
|
207
|
+
*
|
|
208
|
+
* @param contextToAdd A TraceContext that will be added to the current context
|
|
209
|
+
*/
|
|
210
|
+
updateTraceContext(contextToAdd: TraceContext): void;
|
|
184
211
|
/**
|
|
185
212
|
* Gets the tracing context of the transport instance
|
|
186
213
|
*/
|
package/lib/Transport.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Transport.d.ts","sourceRoot":"","sources":["../src/Transport.ts"],"names":[],"mappings":";;AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAEL,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"Transport.d.ts","sourceRoot":"","sources":["../src/Transport.ts"],"names":[],"mappings":"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"}
|
package/lib/Transport.js
CHANGED
|
@@ -34,60 +34,35 @@ class Transport {
|
|
|
34
34
|
this._events = new events_1.default();
|
|
35
35
|
/**
|
|
36
36
|
* Send data to the device using the higher level API.
|
|
37
|
+
*
|
|
37
38
|
* @param {number} cla - The instruction class for the command.
|
|
38
39
|
* @param {number} ins - The instruction code for the command.
|
|
39
40
|
* @param {number} p1 - The first parameter for the instruction.
|
|
40
41
|
* @param {number} p2 - The second parameter for the instruction.
|
|
41
42
|
* @param {Buffer} data - The data to be sent. Defaults to an empty buffer.
|
|
42
43
|
* @param {Array<number>} statusList - A list of acceptable status codes for the response. Defaults to [StatusCodes.OK].
|
|
44
|
+
* @param {Object} options - Contains optional options for the exchange function
|
|
45
|
+
* - abortTimeoutMs: stop the send after a given timeout. Another timeout exists
|
|
46
|
+
* to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange.
|
|
43
47
|
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
44
48
|
*/
|
|
45
|
-
this.send = (cla, ins, p1, p2, data = Buffer.alloc(0), statusList = [errors_1.StatusCodes.OK]) => __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
this.send = (cla, ins, p1, p2, data = Buffer.alloc(0), statusList = [errors_1.StatusCodes.OK], { abortTimeoutMs } = {}) => __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
const tracer = this.tracer.withUpdatedContext({ function: "send" });
|
|
46
51
|
if (data.length >= 256) {
|
|
52
|
+
tracer.trace("data.length exceeded 256 bytes limit", { dataLength: data.length });
|
|
47
53
|
throw new errors_1.TransportError("data.length exceed 256 bytes limit. Got: " + data.length, "DataLengthTooBig");
|
|
48
54
|
}
|
|
49
|
-
|
|
55
|
+
tracer.trace("Starting an exchange", { abortTimeoutMs });
|
|
56
|
+
const response = yield this.exchange(
|
|
57
|
+
// The size of the data is added in 1 byte just before `data`
|
|
58
|
+
Buffer.concat([Buffer.from([cla, ins, p1, p2]), Buffer.from([data.length]), data]), { abortTimeoutMs });
|
|
59
|
+
tracer.trace("Received response from exchange");
|
|
50
60
|
const sw = response.readUInt16BE(response.length - 2);
|
|
51
61
|
if (!statusList.some(s => s === sw)) {
|
|
52
62
|
throw new errors_1.TransportStatusError(sw);
|
|
53
63
|
}
|
|
54
64
|
return response;
|
|
55
65
|
});
|
|
56
|
-
this.exchangeAtomicImpl = (f) => __awaiter(this, void 0, void 0, function* () {
|
|
57
|
-
const tracer = this.tracer.withUpdatedContext({ function: "exchangeAtomicImpl" });
|
|
58
|
-
tracer.trace("Starting an atomic APDU exchange");
|
|
59
|
-
if (this.exchangeBusyPromise) {
|
|
60
|
-
tracer.trace("Atomic exchange is already busy");
|
|
61
|
-
throw new errors_1.TransportRaceCondition("An action was already pending on the Ledger device. Please deny or reconnect.");
|
|
62
|
-
}
|
|
63
|
-
// Sets the atomic guard
|
|
64
|
-
let resolveBusy;
|
|
65
|
-
const busyPromise = new Promise(r => {
|
|
66
|
-
resolveBusy = r;
|
|
67
|
-
});
|
|
68
|
-
this.exchangeBusyPromise = busyPromise;
|
|
69
|
-
let unresponsiveReached = false;
|
|
70
|
-
const timeout = setTimeout(() => {
|
|
71
|
-
tracer.trace(`Timeout reached, emitting Transport event "unresponsive"`);
|
|
72
|
-
unresponsiveReached = true;
|
|
73
|
-
this.emit("unresponsive");
|
|
74
|
-
}, this.unresponsiveTimeout);
|
|
75
|
-
try {
|
|
76
|
-
const res = yield f();
|
|
77
|
-
tracer.trace("Received a response from atomic exchange");
|
|
78
|
-
if (unresponsiveReached) {
|
|
79
|
-
tracer.trace("Device was unresponsive, emitting responsive");
|
|
80
|
-
this.emit("responsive");
|
|
81
|
-
}
|
|
82
|
-
return res;
|
|
83
|
-
}
|
|
84
|
-
finally {
|
|
85
|
-
clearTimeout(timeout);
|
|
86
|
-
if (resolveBusy)
|
|
87
|
-
resolveBusy();
|
|
88
|
-
this.exchangeBusyPromise = null;
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
66
|
this._appAPIlock = null;
|
|
92
67
|
this.tracer = new logs_1.LocalTracer(logType !== null && logType !== void 0 ? logType : DEFAULT_LOG_TYPE, context);
|
|
93
68
|
}
|
|
@@ -95,9 +70,12 @@ class Transport {
|
|
|
95
70
|
* Send data to the device using a low level API.
|
|
96
71
|
* It's recommended to use the "send" method for a higher level API.
|
|
97
72
|
* @param {Buffer} apdu - The data to send.
|
|
73
|
+
* @param {Object} options - Contains optional options for the exchange function
|
|
74
|
+
* - abortTimeoutMs: stop the exchange after a given timeout. Another timeout exists
|
|
75
|
+
* to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange.
|
|
98
76
|
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
99
77
|
*/
|
|
100
|
-
exchange(_apdu) {
|
|
78
|
+
exchange(_apdu, { abortTimeoutMs: _abortTimeoutMs } = {}) {
|
|
101
79
|
throw new Error("exchange not implemented");
|
|
102
80
|
}
|
|
103
81
|
/**
|
|
@@ -222,6 +200,56 @@ class Transport {
|
|
|
222
200
|
: null;
|
|
223
201
|
});
|
|
224
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Wrapper to make an exchange "atomic" (blocking any other exchange)
|
|
205
|
+
*
|
|
206
|
+
* It also handles "unresponsiveness" by emitting "unresponsive" and "responsive" events.
|
|
207
|
+
*
|
|
208
|
+
* @param f The exchange job, using the transport to run
|
|
209
|
+
* @returns a Promise resolving with the output of the given job
|
|
210
|
+
*/
|
|
211
|
+
exchangeAtomicImpl(f) {
|
|
212
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
213
|
+
const tracer = this.tracer.withUpdatedContext({ function: "exchangeAtomicImpl" });
|
|
214
|
+
tracer.trace("Starting an atomic APDU exchange", {
|
|
215
|
+
unresponsiveTimeout: this.unresponsiveTimeout,
|
|
216
|
+
});
|
|
217
|
+
if (this.exchangeBusyPromise) {
|
|
218
|
+
tracer.trace("Atomic exchange is already busy");
|
|
219
|
+
throw new errors_1.TransportRaceCondition("An action was already pending on the Ledger device. Please deny or reconnect.");
|
|
220
|
+
}
|
|
221
|
+
// Sets the atomic guard
|
|
222
|
+
let resolveBusy;
|
|
223
|
+
const busyPromise = new Promise(r => {
|
|
224
|
+
resolveBusy = r;
|
|
225
|
+
});
|
|
226
|
+
this.exchangeBusyPromise = busyPromise;
|
|
227
|
+
// The device unresponsiveness handler
|
|
228
|
+
let unresponsiveReached = false;
|
|
229
|
+
const timeout = setTimeout(() => {
|
|
230
|
+
tracer.trace(`Timeout reached, emitting Transport event "unresponsive"`, {
|
|
231
|
+
unresponsiveTimeout: this.unresponsiveTimeout,
|
|
232
|
+
});
|
|
233
|
+
unresponsiveReached = true;
|
|
234
|
+
this.emit("unresponsive");
|
|
235
|
+
}, this.unresponsiveTimeout);
|
|
236
|
+
try {
|
|
237
|
+
const res = yield f();
|
|
238
|
+
if (unresponsiveReached) {
|
|
239
|
+
tracer.trace("Device was unresponsive, emitting responsive");
|
|
240
|
+
this.emit("responsive");
|
|
241
|
+
}
|
|
242
|
+
return res;
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
tracer.trace("Finalize, clearing busy guard");
|
|
246
|
+
clearTimeout(timeout);
|
|
247
|
+
if (resolveBusy)
|
|
248
|
+
resolveBusy();
|
|
249
|
+
this.exchangeBusyPromise = null;
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
225
253
|
decorateAppAPIMethods(self, methods, scrambleKey) {
|
|
226
254
|
for (const methodName of methods) {
|
|
227
255
|
self[methodName] = this.decorateAppAPIMethod(methodName, self[methodName], self, scrambleKey);
|
|
@@ -244,7 +272,7 @@ class Transport {
|
|
|
244
272
|
});
|
|
245
273
|
}
|
|
246
274
|
/**
|
|
247
|
-
*
|
|
275
|
+
* Sets the context used by the logging/tracing mechanism
|
|
248
276
|
*
|
|
249
277
|
* Useful when re-using (cached) the same Transport instance,
|
|
250
278
|
* but with a new tracing context.
|
|
@@ -254,6 +282,16 @@ class Transport {
|
|
|
254
282
|
setTraceContext(context) {
|
|
255
283
|
this.tracer = this.tracer.withContext(context);
|
|
256
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* Updates the context used by the logging/tracing mechanism
|
|
287
|
+
*
|
|
288
|
+
* The update only overrides the key-value that are already defined in the current context.
|
|
289
|
+
*
|
|
290
|
+
* @param contextToAdd A TraceContext that will be added to the current context
|
|
291
|
+
*/
|
|
292
|
+
updateTraceContext(contextToAdd) {
|
|
293
|
+
this.tracer.updateContext(contextToAdd);
|
|
294
|
+
}
|
|
257
295
|
/**
|
|
258
296
|
* Gets the tracing context of the transport instance
|
|
259
297
|
*/
|
package/lib/Transport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Transport.js","sourceRoot":"","sources":["../src/Transport.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,oDAAkC;AAElC,6CAM0B;AAEjB,+FANP,uBAAc,OAMO;AAAwB,4FAL7C,oBAAW,OAK6C;AAAE,oGAJ1D,4BAAmB,OAI0D;AAAtD,qGAHvB,6BAAoB,OAGuB;AAD7C,yCAAoE;
|
|
1
|
+
{"version":3,"file":"Transport.js","sourceRoot":"","sources":["../src/Transport.ts"],"names":[],"mappings":"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"}
|
package/lib-es/Transport.d.ts
CHANGED
|
@@ -97,9 +97,14 @@ export default class Transport {
|
|
|
97
97
|
* Send data to the device using a low level API.
|
|
98
98
|
* It's recommended to use the "send" method for a higher level API.
|
|
99
99
|
* @param {Buffer} apdu - The data to send.
|
|
100
|
+
* @param {Object} options - Contains optional options for the exchange function
|
|
101
|
+
* - abortTimeoutMs: stop the exchange after a given timeout. Another timeout exists
|
|
102
|
+
* to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange.
|
|
100
103
|
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
101
104
|
*/
|
|
102
|
-
exchange(_apdu: Buffer
|
|
105
|
+
exchange(_apdu: Buffer, { abortTimeoutMs }?: {
|
|
106
|
+
abortTimeoutMs?: number;
|
|
107
|
+
}): Promise<Buffer>;
|
|
103
108
|
/**
|
|
104
109
|
* Send apdus in batch to the device using a low level API.
|
|
105
110
|
* The default implementation is to call exchange for each apdu.
|
|
@@ -150,15 +155,21 @@ export default class Transport {
|
|
|
150
155
|
setExchangeUnresponsiveTimeout(unresponsiveTimeout: number): void;
|
|
151
156
|
/**
|
|
152
157
|
* Send data to the device using the higher level API.
|
|
158
|
+
*
|
|
153
159
|
* @param {number} cla - The instruction class for the command.
|
|
154
160
|
* @param {number} ins - The instruction code for the command.
|
|
155
161
|
* @param {number} p1 - The first parameter for the instruction.
|
|
156
162
|
* @param {number} p2 - The second parameter for the instruction.
|
|
157
163
|
* @param {Buffer} data - The data to be sent. Defaults to an empty buffer.
|
|
158
164
|
* @param {Array<number>} statusList - A list of acceptable status codes for the response. Defaults to [StatusCodes.OK].
|
|
165
|
+
* @param {Object} options - Contains optional options for the exchange function
|
|
166
|
+
* - abortTimeoutMs: stop the send after a given timeout. Another timeout exists
|
|
167
|
+
* to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange.
|
|
159
168
|
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
160
169
|
*/
|
|
161
|
-
send: (cla: number, ins: number, p1: number, p2: number, data?: Buffer, statusList?: Array<number
|
|
170
|
+
send: (cla: number, ins: number, p1: number, p2: number, data?: Buffer, statusList?: Array<number>, { abortTimeoutMs }?: {
|
|
171
|
+
abortTimeoutMs?: number | undefined;
|
|
172
|
+
}) => Promise<Buffer>;
|
|
162
173
|
/**
|
|
163
174
|
* create() allows to open the first descriptor available or
|
|
164
175
|
* throw if there is none or if timeout is reached.
|
|
@@ -168,12 +179,20 @@ export default class Transport {
|
|
|
168
179
|
*/
|
|
169
180
|
static create(openTimeout?: number, listenTimeout?: number): Promise<Transport>;
|
|
170
181
|
exchangeBusyPromise: Promise<void> | null | undefined;
|
|
171
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Wrapper to make an exchange "atomic" (blocking any other exchange)
|
|
184
|
+
*
|
|
185
|
+
* It also handles "unresponsiveness" by emitting "unresponsive" and "responsive" events.
|
|
186
|
+
*
|
|
187
|
+
* @param f The exchange job, using the transport to run
|
|
188
|
+
* @returns a Promise resolving with the output of the given job
|
|
189
|
+
*/
|
|
190
|
+
exchangeAtomicImpl<Output>(f: () => Promise<Output>): Promise<Output>;
|
|
172
191
|
decorateAppAPIMethods(self: Record<string, any>, methods: Array<string>, scrambleKey: string): void;
|
|
173
192
|
_appAPIlock: string | null;
|
|
174
193
|
decorateAppAPIMethod<R, A extends any[]>(methodName: string, f: (...args: A) => Promise<R>, ctx: any, scrambleKey: string): (...args: A) => Promise<R>;
|
|
175
194
|
/**
|
|
176
|
-
*
|
|
195
|
+
* Sets the context used by the logging/tracing mechanism
|
|
177
196
|
*
|
|
178
197
|
* Useful when re-using (cached) the same Transport instance,
|
|
179
198
|
* but with a new tracing context.
|
|
@@ -181,6 +200,14 @@ export default class Transport {
|
|
|
181
200
|
* @param context A TraceContext, that can undefined to reset the context
|
|
182
201
|
*/
|
|
183
202
|
setTraceContext(context?: TraceContext): void;
|
|
203
|
+
/**
|
|
204
|
+
* Updates the context used by the logging/tracing mechanism
|
|
205
|
+
*
|
|
206
|
+
* The update only overrides the key-value that are already defined in the current context.
|
|
207
|
+
*
|
|
208
|
+
* @param contextToAdd A TraceContext that will be added to the current context
|
|
209
|
+
*/
|
|
210
|
+
updateTraceContext(contextToAdd: TraceContext): void;
|
|
184
211
|
/**
|
|
185
212
|
* Gets the tracing context of the transport instance
|
|
186
213
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Transport.d.ts","sourceRoot":"","sources":["../src/Transport.ts"],"names":[],"mappings":";;AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAEL,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"Transport.d.ts","sourceRoot":"","sources":["../src/Transport.ts"],"names":[],"mappings":"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"}
|
package/lib-es/Transport.js
CHANGED
|
@@ -25,60 +25,35 @@ class Transport {
|
|
|
25
25
|
this._events = new EventEmitter();
|
|
26
26
|
/**
|
|
27
27
|
* Send data to the device using the higher level API.
|
|
28
|
+
*
|
|
28
29
|
* @param {number} cla - The instruction class for the command.
|
|
29
30
|
* @param {number} ins - The instruction code for the command.
|
|
30
31
|
* @param {number} p1 - The first parameter for the instruction.
|
|
31
32
|
* @param {number} p2 - The second parameter for the instruction.
|
|
32
33
|
* @param {Buffer} data - The data to be sent. Defaults to an empty buffer.
|
|
33
34
|
* @param {Array<number>} statusList - A list of acceptable status codes for the response. Defaults to [StatusCodes.OK].
|
|
35
|
+
* @param {Object} options - Contains optional options for the exchange function
|
|
36
|
+
* - abortTimeoutMs: stop the send after a given timeout. Another timeout exists
|
|
37
|
+
* to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange.
|
|
34
38
|
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
35
39
|
*/
|
|
36
|
-
this.send = (cla, ins, p1, p2, data = Buffer.alloc(0), statusList = [StatusCodes.OK]) => __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
this.send = (cla, ins, p1, p2, data = Buffer.alloc(0), statusList = [StatusCodes.OK], { abortTimeoutMs } = {}) => __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
const tracer = this.tracer.withUpdatedContext({ function: "send" });
|
|
37
42
|
if (data.length >= 256) {
|
|
43
|
+
tracer.trace("data.length exceeded 256 bytes limit", { dataLength: data.length });
|
|
38
44
|
throw new TransportError("data.length exceed 256 bytes limit. Got: " + data.length, "DataLengthTooBig");
|
|
39
45
|
}
|
|
40
|
-
|
|
46
|
+
tracer.trace("Starting an exchange", { abortTimeoutMs });
|
|
47
|
+
const response = yield this.exchange(
|
|
48
|
+
// The size of the data is added in 1 byte just before `data`
|
|
49
|
+
Buffer.concat([Buffer.from([cla, ins, p1, p2]), Buffer.from([data.length]), data]), { abortTimeoutMs });
|
|
50
|
+
tracer.trace("Received response from exchange");
|
|
41
51
|
const sw = response.readUInt16BE(response.length - 2);
|
|
42
52
|
if (!statusList.some(s => s === sw)) {
|
|
43
53
|
throw new TransportStatusError(sw);
|
|
44
54
|
}
|
|
45
55
|
return response;
|
|
46
56
|
});
|
|
47
|
-
this.exchangeAtomicImpl = (f) => __awaiter(this, void 0, void 0, function* () {
|
|
48
|
-
const tracer = this.tracer.withUpdatedContext({ function: "exchangeAtomicImpl" });
|
|
49
|
-
tracer.trace("Starting an atomic APDU exchange");
|
|
50
|
-
if (this.exchangeBusyPromise) {
|
|
51
|
-
tracer.trace("Atomic exchange is already busy");
|
|
52
|
-
throw new TransportRaceCondition("An action was already pending on the Ledger device. Please deny or reconnect.");
|
|
53
|
-
}
|
|
54
|
-
// Sets the atomic guard
|
|
55
|
-
let resolveBusy;
|
|
56
|
-
const busyPromise = new Promise(r => {
|
|
57
|
-
resolveBusy = r;
|
|
58
|
-
});
|
|
59
|
-
this.exchangeBusyPromise = busyPromise;
|
|
60
|
-
let unresponsiveReached = false;
|
|
61
|
-
const timeout = setTimeout(() => {
|
|
62
|
-
tracer.trace(`Timeout reached, emitting Transport event "unresponsive"`);
|
|
63
|
-
unresponsiveReached = true;
|
|
64
|
-
this.emit("unresponsive");
|
|
65
|
-
}, this.unresponsiveTimeout);
|
|
66
|
-
try {
|
|
67
|
-
const res = yield f();
|
|
68
|
-
tracer.trace("Received a response from atomic exchange");
|
|
69
|
-
if (unresponsiveReached) {
|
|
70
|
-
tracer.trace("Device was unresponsive, emitting responsive");
|
|
71
|
-
this.emit("responsive");
|
|
72
|
-
}
|
|
73
|
-
return res;
|
|
74
|
-
}
|
|
75
|
-
finally {
|
|
76
|
-
clearTimeout(timeout);
|
|
77
|
-
if (resolveBusy)
|
|
78
|
-
resolveBusy();
|
|
79
|
-
this.exchangeBusyPromise = null;
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
57
|
this._appAPIlock = null;
|
|
83
58
|
this.tracer = new LocalTracer(logType !== null && logType !== void 0 ? logType : DEFAULT_LOG_TYPE, context);
|
|
84
59
|
}
|
|
@@ -86,9 +61,12 @@ class Transport {
|
|
|
86
61
|
* Send data to the device using a low level API.
|
|
87
62
|
* It's recommended to use the "send" method for a higher level API.
|
|
88
63
|
* @param {Buffer} apdu - The data to send.
|
|
64
|
+
* @param {Object} options - Contains optional options for the exchange function
|
|
65
|
+
* - abortTimeoutMs: stop the exchange after a given timeout. Another timeout exists
|
|
66
|
+
* to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange.
|
|
89
67
|
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
90
68
|
*/
|
|
91
|
-
exchange(_apdu) {
|
|
69
|
+
exchange(_apdu, { abortTimeoutMs: _abortTimeoutMs } = {}) {
|
|
92
70
|
throw new Error("exchange not implemented");
|
|
93
71
|
}
|
|
94
72
|
/**
|
|
@@ -213,6 +191,56 @@ class Transport {
|
|
|
213
191
|
: null;
|
|
214
192
|
});
|
|
215
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* Wrapper to make an exchange "atomic" (blocking any other exchange)
|
|
196
|
+
*
|
|
197
|
+
* It also handles "unresponsiveness" by emitting "unresponsive" and "responsive" events.
|
|
198
|
+
*
|
|
199
|
+
* @param f The exchange job, using the transport to run
|
|
200
|
+
* @returns a Promise resolving with the output of the given job
|
|
201
|
+
*/
|
|
202
|
+
exchangeAtomicImpl(f) {
|
|
203
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
204
|
+
const tracer = this.tracer.withUpdatedContext({ function: "exchangeAtomicImpl" });
|
|
205
|
+
tracer.trace("Starting an atomic APDU exchange", {
|
|
206
|
+
unresponsiveTimeout: this.unresponsiveTimeout,
|
|
207
|
+
});
|
|
208
|
+
if (this.exchangeBusyPromise) {
|
|
209
|
+
tracer.trace("Atomic exchange is already busy");
|
|
210
|
+
throw new TransportRaceCondition("An action was already pending on the Ledger device. Please deny or reconnect.");
|
|
211
|
+
}
|
|
212
|
+
// Sets the atomic guard
|
|
213
|
+
let resolveBusy;
|
|
214
|
+
const busyPromise = new Promise(r => {
|
|
215
|
+
resolveBusy = r;
|
|
216
|
+
});
|
|
217
|
+
this.exchangeBusyPromise = busyPromise;
|
|
218
|
+
// The device unresponsiveness handler
|
|
219
|
+
let unresponsiveReached = false;
|
|
220
|
+
const timeout = setTimeout(() => {
|
|
221
|
+
tracer.trace(`Timeout reached, emitting Transport event "unresponsive"`, {
|
|
222
|
+
unresponsiveTimeout: this.unresponsiveTimeout,
|
|
223
|
+
});
|
|
224
|
+
unresponsiveReached = true;
|
|
225
|
+
this.emit("unresponsive");
|
|
226
|
+
}, this.unresponsiveTimeout);
|
|
227
|
+
try {
|
|
228
|
+
const res = yield f();
|
|
229
|
+
if (unresponsiveReached) {
|
|
230
|
+
tracer.trace("Device was unresponsive, emitting responsive");
|
|
231
|
+
this.emit("responsive");
|
|
232
|
+
}
|
|
233
|
+
return res;
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
tracer.trace("Finalize, clearing busy guard");
|
|
237
|
+
clearTimeout(timeout);
|
|
238
|
+
if (resolveBusy)
|
|
239
|
+
resolveBusy();
|
|
240
|
+
this.exchangeBusyPromise = null;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
216
244
|
decorateAppAPIMethods(self, methods, scrambleKey) {
|
|
217
245
|
for (const methodName of methods) {
|
|
218
246
|
self[methodName] = this.decorateAppAPIMethod(methodName, self[methodName], self, scrambleKey);
|
|
@@ -235,7 +263,7 @@ class Transport {
|
|
|
235
263
|
});
|
|
236
264
|
}
|
|
237
265
|
/**
|
|
238
|
-
*
|
|
266
|
+
* Sets the context used by the logging/tracing mechanism
|
|
239
267
|
*
|
|
240
268
|
* Useful when re-using (cached) the same Transport instance,
|
|
241
269
|
* but with a new tracing context.
|
|
@@ -245,6 +273,16 @@ class Transport {
|
|
|
245
273
|
setTraceContext(context) {
|
|
246
274
|
this.tracer = this.tracer.withContext(context);
|
|
247
275
|
}
|
|
276
|
+
/**
|
|
277
|
+
* Updates the context used by the logging/tracing mechanism
|
|
278
|
+
*
|
|
279
|
+
* The update only overrides the key-value that are already defined in the current context.
|
|
280
|
+
*
|
|
281
|
+
* @param contextToAdd A TraceContext that will be added to the current context
|
|
282
|
+
*/
|
|
283
|
+
updateTraceContext(contextToAdd) {
|
|
284
|
+
this.tracer.updateContext(contextToAdd);
|
|
285
|
+
}
|
|
248
286
|
/**
|
|
249
287
|
* Gets the tracing context of the transport instance
|
|
250
288
|
*/
|
package/lib-es/Transport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Transport.js","sourceRoot":"","sources":["../src/Transport.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAElC,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAyB,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"Transport.js","sourceRoot":"","sources":["../src/Transport.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ledgerhq/hw-transport",
|
|
3
|
-
"version": "6.30.0",
|
|
3
|
+
"version": "6.30.1-next.0",
|
|
4
4
|
"description": "Ledger Hardware Wallet common interface of the communication layer",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ledger",
|
|
@@ -26,19 +26,19 @@
|
|
|
26
26
|
"license": "Apache-2.0",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"events": "^3.3.0",
|
|
29
|
-
"@ledgerhq/devices": "^8.
|
|
30
|
-
"@ledgerhq/errors": "^6.16.0",
|
|
29
|
+
"@ledgerhq/devices": "^8.2.0-next.0",
|
|
30
|
+
"@ledgerhq/errors": "^6.16.1-next.0",
|
|
31
31
|
"@ledgerhq/logs": "^6.12.0"
|
|
32
32
|
},
|
|
33
33
|
"gitHead": "dd0dea64b58e5a9125c8a422dcffd29e5ef6abec",
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@types/jest": "^29.5.
|
|
35
|
+
"@types/jest": "^29.5.10",
|
|
36
36
|
"@types/node": "^20.8.10",
|
|
37
37
|
"documentation": "14.0.2",
|
|
38
|
-
"jest": "^
|
|
38
|
+
"jest": "^29.7.0",
|
|
39
39
|
"rimraf": "^4.4.1",
|
|
40
40
|
"source-map-support": "^0.5.21",
|
|
41
|
-
"ts-jest": "^
|
|
41
|
+
"ts-jest": "^29.1.1",
|
|
42
42
|
"ts-node": "^10.4.0"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
package/src/Transport.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "@ledgerhq/errors";
|
|
10
10
|
import { LocalTracer, TraceContext, LogType } from "@ledgerhq/logs";
|
|
11
11
|
export { TransportError, TransportStatusError, StatusCodes, getAltStatusMessage };
|
|
12
|
+
|
|
12
13
|
const DEFAULT_LOG_TYPE = "transport";
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -116,9 +117,15 @@ export default class Transport {
|
|
|
116
117
|
* Send data to the device using a low level API.
|
|
117
118
|
* It's recommended to use the "send" method for a higher level API.
|
|
118
119
|
* @param {Buffer} apdu - The data to send.
|
|
120
|
+
* @param {Object} options - Contains optional options for the exchange function
|
|
121
|
+
* - abortTimeoutMs: stop the exchange after a given timeout. Another timeout exists
|
|
122
|
+
* to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange.
|
|
119
123
|
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
120
124
|
*/
|
|
121
|
-
exchange(
|
|
125
|
+
exchange(
|
|
126
|
+
_apdu: Buffer,
|
|
127
|
+
{ abortTimeoutMs: _abortTimeoutMs }: { abortTimeoutMs?: number } = {},
|
|
128
|
+
): Promise<Buffer> {
|
|
122
129
|
throw new Error("exchange not implemented");
|
|
123
130
|
}
|
|
124
131
|
|
|
@@ -223,12 +230,16 @@ export default class Transport {
|
|
|
223
230
|
|
|
224
231
|
/**
|
|
225
232
|
* Send data to the device using the higher level API.
|
|
233
|
+
*
|
|
226
234
|
* @param {number} cla - The instruction class for the command.
|
|
227
235
|
* @param {number} ins - The instruction code for the command.
|
|
228
236
|
* @param {number} p1 - The first parameter for the instruction.
|
|
229
237
|
* @param {number} p2 - The second parameter for the instruction.
|
|
230
238
|
* @param {Buffer} data - The data to be sent. Defaults to an empty buffer.
|
|
231
239
|
* @param {Array<number>} statusList - A list of acceptable status codes for the response. Defaults to [StatusCodes.OK].
|
|
240
|
+
* @param {Object} options - Contains optional options for the exchange function
|
|
241
|
+
* - abortTimeoutMs: stop the send after a given timeout. Another timeout exists
|
|
242
|
+
* to detect unresponsive device (see `unresponsiveTimeout`). This timeout aborts the exchange.
|
|
232
243
|
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
233
244
|
*/
|
|
234
245
|
send = async (
|
|
@@ -238,17 +249,25 @@ export default class Transport {
|
|
|
238
249
|
p2: number,
|
|
239
250
|
data: Buffer = Buffer.alloc(0),
|
|
240
251
|
statusList: Array<number> = [StatusCodes.OK],
|
|
252
|
+
{ abortTimeoutMs }: { abortTimeoutMs?: number } = {},
|
|
241
253
|
): Promise<Buffer> => {
|
|
254
|
+
const tracer = this.tracer.withUpdatedContext({ function: "send" });
|
|
255
|
+
|
|
242
256
|
if (data.length >= 256) {
|
|
257
|
+
tracer.trace("data.length exceeded 256 bytes limit", { dataLength: data.length });
|
|
243
258
|
throw new TransportError(
|
|
244
259
|
"data.length exceed 256 bytes limit. Got: " + data.length,
|
|
245
260
|
"DataLengthTooBig",
|
|
246
261
|
);
|
|
247
262
|
}
|
|
248
263
|
|
|
264
|
+
tracer.trace("Starting an exchange", { abortTimeoutMs });
|
|
249
265
|
const response = await this.exchange(
|
|
266
|
+
// The size of the data is added in 1 byte just before `data`
|
|
250
267
|
Buffer.concat([Buffer.from([cla, ins, p1, p2]), Buffer.from([data.length]), data]),
|
|
268
|
+
{ abortTimeoutMs },
|
|
251
269
|
);
|
|
270
|
+
tracer.trace("Received response from exchange");
|
|
252
271
|
const sw = response.readUInt16BE(response.length - 2);
|
|
253
272
|
|
|
254
273
|
if (!statusList.some(s => s === sw)) {
|
|
@@ -296,10 +315,22 @@ export default class Transport {
|
|
|
296
315
|
});
|
|
297
316
|
}
|
|
298
317
|
|
|
318
|
+
// Blocks other exchange to happen concurrently
|
|
299
319
|
exchangeBusyPromise: Promise<void> | null | undefined;
|
|
300
|
-
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Wrapper to make an exchange "atomic" (blocking any other exchange)
|
|
323
|
+
*
|
|
324
|
+
* It also handles "unresponsiveness" by emitting "unresponsive" and "responsive" events.
|
|
325
|
+
*
|
|
326
|
+
* @param f The exchange job, using the transport to run
|
|
327
|
+
* @returns a Promise resolving with the output of the given job
|
|
328
|
+
*/
|
|
329
|
+
async exchangeAtomicImpl<Output>(f: () => Promise<Output>): Promise<Output> {
|
|
301
330
|
const tracer = this.tracer.withUpdatedContext({ function: "exchangeAtomicImpl" });
|
|
302
|
-
tracer.trace("Starting an atomic APDU exchange"
|
|
331
|
+
tracer.trace("Starting an atomic APDU exchange", {
|
|
332
|
+
unresponsiveTimeout: this.unresponsiveTimeout,
|
|
333
|
+
});
|
|
303
334
|
|
|
304
335
|
if (this.exchangeBusyPromise) {
|
|
305
336
|
tracer.trace("Atomic exchange is already busy");
|
|
@@ -314,16 +345,19 @@ export default class Transport {
|
|
|
314
345
|
resolveBusy = r;
|
|
315
346
|
});
|
|
316
347
|
this.exchangeBusyPromise = busyPromise;
|
|
348
|
+
|
|
349
|
+
// The device unresponsiveness handler
|
|
317
350
|
let unresponsiveReached = false;
|
|
318
351
|
const timeout = setTimeout(() => {
|
|
319
|
-
tracer.trace(`Timeout reached, emitting Transport event "unresponsive"
|
|
352
|
+
tracer.trace(`Timeout reached, emitting Transport event "unresponsive"`, {
|
|
353
|
+
unresponsiveTimeout: this.unresponsiveTimeout,
|
|
354
|
+
});
|
|
320
355
|
unresponsiveReached = true;
|
|
321
356
|
this.emit("unresponsive");
|
|
322
357
|
}, this.unresponsiveTimeout);
|
|
323
358
|
|
|
324
359
|
try {
|
|
325
360
|
const res = await f();
|
|
326
|
-
tracer.trace("Received a response from atomic exchange");
|
|
327
361
|
|
|
328
362
|
if (unresponsiveReached) {
|
|
329
363
|
tracer.trace("Device was unresponsive, emitting responsive");
|
|
@@ -332,11 +366,13 @@ export default class Transport {
|
|
|
332
366
|
|
|
333
367
|
return res;
|
|
334
368
|
} finally {
|
|
369
|
+
tracer.trace("Finalize, clearing busy guard");
|
|
370
|
+
|
|
335
371
|
clearTimeout(timeout);
|
|
336
372
|
if (resolveBusy) resolveBusy();
|
|
337
373
|
this.exchangeBusyPromise = null;
|
|
338
374
|
}
|
|
339
|
-
}
|
|
375
|
+
}
|
|
340
376
|
|
|
341
377
|
decorateAppAPIMethods(self: Record<string, any>, methods: Array<string>, scrambleKey: string) {
|
|
342
378
|
for (const methodName of methods) {
|
|
@@ -372,7 +408,7 @@ export default class Transport {
|
|
|
372
408
|
}
|
|
373
409
|
|
|
374
410
|
/**
|
|
375
|
-
*
|
|
411
|
+
* Sets the context used by the logging/tracing mechanism
|
|
376
412
|
*
|
|
377
413
|
* Useful when re-using (cached) the same Transport instance,
|
|
378
414
|
* but with a new tracing context.
|
|
@@ -383,6 +419,17 @@ export default class Transport {
|
|
|
383
419
|
this.tracer = this.tracer.withContext(context);
|
|
384
420
|
}
|
|
385
421
|
|
|
422
|
+
/**
|
|
423
|
+
* Updates the context used by the logging/tracing mechanism
|
|
424
|
+
*
|
|
425
|
+
* The update only overrides the key-value that are already defined in the current context.
|
|
426
|
+
*
|
|
427
|
+
* @param contextToAdd A TraceContext that will be added to the current context
|
|
428
|
+
*/
|
|
429
|
+
updateTraceContext(contextToAdd: TraceContext) {
|
|
430
|
+
this.tracer.updateContext(contextToAdd);
|
|
431
|
+
}
|
|
432
|
+
|
|
386
433
|
/**
|
|
387
434
|
* Gets the tracing context of the transport instance
|
|
388
435
|
*/
|