0
# Configuration and Security
1
2
Methods for configuring transport behavior, timeouts, and security settings. This includes scramble key management for app-specific encryption, timeout configuration for communication reliability, and debug settings.
3
4
## Capabilities
5
6
### Scramble Key Management
7
8
Sets the encryption key used for secure communication with specific Ledger applications. Each app typically has its own scramble key for security isolation.
9
10
```typescript { .api }
11
/**
12
* Set the "scramble key" for the next exchanges with the device
13
* Each App can have a different scramble key and they internally set it at instantiation
14
* @param key The scramble key string
15
*/
16
setScrambleKey(key: string): void;
17
```
18
19
**Usage Example:**
20
21
```javascript
22
import Transport from "@ledgerhq/hw-transport";
23
24
const transport = await MyTransport.create();
25
26
// Set scramble key for Bitcoin app
27
transport.setScrambleKey("BTC");
28
29
// Now all APDU exchanges will use the Bitcoin scramble key
30
const response = await transport.send(0xE0, 0x40, 0x00, 0x00);
31
32
// Switch to Ethereum app
33
transport.setScrambleKey("ETH");
34
const ethResponse = await transport.send(0xE0, 0x02, 0x00, 0x00);
35
```
36
37
**Common Scramble Keys:**
38
- `"BTC"` - Bitcoin and Bitcoin-based cryptocurrencies
39
- `"ETH"` - Ethereum and ERC-20 tokens
40
- `"XRP"` - Ripple
41
- `"ADA"` - Cardano
42
- `""` (empty string) - No scrambling (for system commands)
43
44
### Exchange Timeout Configuration
45
46
Controls how long to wait for APDU command responses before timing out. This helps prevent hanging operations when devices become unresponsive.
47
48
```typescript { .api }
49
/**
50
* Set a timeout (in milliseconds) for the exchange call
51
* Only some transport implementations might implement it (e.g. U2F)
52
* @param exchangeTimeout Timeout in milliseconds
53
*/
54
setExchangeTimeout(exchangeTimeout: number): void;
55
```
56
57
**Usage Example:**
58
59
```javascript
60
const transport = await MyTransport.create();
61
62
// Set 10 second timeout for slow operations
63
transport.setExchangeTimeout(10000);
64
65
// This command will timeout after 10 seconds if no response
66
try {
67
const response = await transport.send(0xE0, 0x04, 0x00, 0x00, transactionData);
68
} catch (error) {
69
// Handle timeout or other errors
70
console.error("Command timed out or failed:", error);
71
}
72
73
// Reset to default timeout (30 seconds)
74
transport.setExchangeTimeout(30000);
75
```
76
77
### Unresponsive Detection Timeout
78
79
Configures how long to wait before emitting "unresponsive" events when a device stops responding during operations.
80
81
```typescript { .api }
82
/**
83
* Define the delay before emitting "unresponsive" on an exchange that does not respond
84
* @param unresponsiveTimeout Timeout in milliseconds
85
*/
86
setExchangeUnresponsiveTimeout(unresponsiveTimeout: number): void;
87
```
88
89
**Usage Example:**
90
91
```javascript
92
const transport = await MyTransport.create();
93
94
// Monitor for unresponsiveness after 5 seconds
95
transport.setExchangeUnresponsiveTimeout(5000);
96
97
// Listen for unresponsive events
98
transport.on("unresponsive", () => {
99
console.warn("Device appears unresponsive - please check connection");
100
// Show user feedback about unresponsive device
101
});
102
103
transport.on("responsive", () => {
104
console.log("Device is responding again");
105
// Hide unresponsive warning
106
});
107
108
// Start a potentially slow operation
109
const signature = await transport.send(0xE0, 0x04, 0x01, 0x00, largeTransaction);
110
```
111
112
### Debug Mode (Deprecated)
113
114
Legacy method for enabling debug logging. This method is deprecated and no longer emits logs.
115
116
```typescript { .api }
117
/**
118
* Enable or not logs of the binary exchange
119
* @deprecated Use @ledgerhq/logs instead. No logs are emitted in this anymore.
120
*/
121
setDebugMode(): void;
122
```
123
124
**Migration Example:**
125
126
```javascript
127
// Old approach (deprecated)
128
transport.setDebugMode();
129
130
// New approach - use @ledgerhq/logs
131
import { setDebugMode } from "@ledgerhq/logs";
132
setDebugMode(true);
133
```
134
135
## Configuration Properties
136
137
### Default Timeout Values
138
139
The Transport class provides default timeout configurations:
140
141
```javascript { .api }
142
class Transport<Descriptor> {
143
/** Default timeout for APDU exchanges (30 seconds) */
144
exchangeTimeout: number = 30000;
145
146
/** Default timeout for unresponsive detection (15 seconds) */
147
unresponsiveTimeout: number = 15000;
148
149
/** Connected device model information */
150
deviceModel: DeviceModel | null = null;
151
152
/** Internal lock to prevent concurrent app API operations */
153
_appAPIlock: string | null = null;
154
155
/** Promise tracking current exchange operation for race condition prevention */
156
exchangeBusyPromise: Promise<void> | null = null;
157
}
158
```
159
160
### Accessing Configuration
161
162
```javascript
163
const transport = await MyTransport.create();
164
165
console.log("Current exchange timeout:", transport.exchangeTimeout);
166
console.log("Current unresponsive timeout:", transport.unresponsiveTimeout);
167
console.log("Connected device:", transport.deviceModel?.productName);
168
169
// Modify timeouts
170
transport.setExchangeTimeout(60000); // 1 minute
171
transport.setExchangeUnresponsiveTimeout(10000); // 10 seconds
172
173
console.log("New exchange timeout:", transport.exchangeTimeout);
174
```
175
176
## Security Considerations
177
178
### Scramble Key Best Practices
179
180
1. **App-Specific Keys**: Always use the appropriate scramble key for the target application
181
2. **Key Management**: Store scramble keys securely and don't hardcode them in public repositories
182
3. **Key Rotation**: Some applications may require different keys for different operations
183
184
```javascript
185
// Example: Context-aware scramble key usage
186
class LedgerWalletManager {
187
constructor(transport) {
188
this.transport = transport;
189
}
190
191
async switchToApp(appName) {
192
const scrambleKeys = {
193
'bitcoin': 'BTC',
194
'ethereum': 'ETH',
195
'ripple': 'XRP'
196
};
197
198
const key = scrambleKeys[appName];
199
if (!key) {
200
throw new Error(`Unknown app: ${appName}`);
201
}
202
203
this.transport.setScrambleKey(key);
204
return this.waitForApp(appName);
205
}
206
}
207
```
208
209
### Timeout Configuration Guidelines
210
211
1. **Exchange Timeout**: Set based on expected operation complexity
212
- Simple queries: 5-10 seconds
213
- Transaction signing: 30-60 seconds
214
- Firmware operations: 2-5 minutes
215
216
2. **Unresponsive Timeout**: Balance user experience with false positives
217
- Interactive operations: 5-10 seconds
218
- Background operations: 15-30 seconds
219
220
```javascript
221
// Example: Operation-specific timeout configuration
222
async function performComplexOperation(transport, operationType) {
223
const timeouts = {
224
'quick_query': { exchange: 5000, unresponsive: 3000 },
225
'transaction_sign': { exchange: 30000, unresponsive: 10000 },
226
'firmware_update': { exchange: 300000, unresponsive: 60000 }
227
};
228
229
const config = timeouts[operationType];
230
if (config) {
231
transport.setExchangeTimeout(config.exchange);
232
transport.setExchangeUnresponsiveTimeout(config.unresponsive);
233
}
234
235
// Perform the operation...
236
}
237
```
238
239
## Environment-Specific Configuration
240
241
Different transport implementations may handle configuration differently:
242
243
```javascript
244
// WebUSB transport - timeout affects browser API calls
245
import TransportWebUSB from "@ledgerhq/hw-transport-webusb";
246
const webTransport = await TransportWebUSB.create();
247
webTransport.setExchangeTimeout(15000); // Browser timeout
248
249
// Node.js HID transport - timeout affects system calls
250
import TransportNodeHid from "@ledgerhq/hw-transport-node-hid";
251
const hidTransport = await TransportNodeHid.create();
252
hidTransport.setExchangeTimeout(10000); // System timeout
253
```
254
255
## App API Decoration Methods
256
257
### Batch Method Decoration
258
259
Decorates multiple methods on an object with app API locking and scramble key management.
260
261
```javascript { .api }
262
/**
263
* Decorates multiple methods on an object with app API locking and scramble key management
264
* @param self The object containing methods to decorate
265
* @param methods Array of method names to decorate
266
* @param scrambleKey The scramble key to use for these methods
267
*/
268
decorateAppAPIMethods(
269
self: Object,
270
methods: Array<string>,
271
scrambleKey: string
272
): void;
273
```
274
275
### Single Method Decoration
276
277
Decorates a single method with app API locking and scramble key management.
278
279
```javascript { .api }
280
/**
281
* Decorates a single method with app API locking and scramble key management
282
* @param methodName Name of the method for error reporting
283
* @param f The function to decorate
284
* @param ctx The context (this) to bind the function to
285
* @param scrambleKey The scramble key to use for this method
286
* @returns Decorated function with locking and scramble key management
287
*/
288
decorateAppAPIMethod<R, A: any[]>(
289
methodName: string,
290
f: (...args: A) => Promise<R>,
291
ctx: any,
292
scrambleKey: string
293
): (...args: A) => Promise<R>;
294
```
295
296
**Usage Example:**
297
298
```javascript
299
import Transport from "@ledgerhq/hw-transport";
300
301
class MyLedgerApp {
302
constructor(transport) {
303
this.transport = transport;
304
305
// Decorate multiple methods at once
306
this.transport.decorateAppAPIMethods(
307
this,
308
['getVersion', 'getPublicKey', 'signTransaction'],
309
'BTC'
310
);
311
312
// Or decorate individual methods
313
this.getAddress = this.transport.decorateAppAPIMethod(
314
'getAddress',
315
this._getRawAddress.bind(this),
316
this,
317
'BTC'
318
);
319
}
320
321
// These methods will be automatically decorated with locking
322
async getVersion() {
323
return await this.transport.send(0xB0, 0x01, 0x00, 0x00);
324
}
325
326
async getPublicKey(path) {
327
return await this.transport.send(0xE0, 0x40, 0x00, 0x00, path);
328
}
329
330
async signTransaction(txData) {
331
return await this.transport.send(0xE0, 0x44, 0x00, 0x00, txData);
332
}
333
334
// Raw method that gets decorated
335
async _getRawAddress(path, display) {
336
return await this.transport.send(0xE0, 0x42, display ? 0x01 : 0x00, 0x00, path);
337
}
338
}
339
```
340
341
### App API Lock Property
342
343
The transport maintains an internal lock to prevent concurrent app API operations.
344
345
```javascript { .api }
346
class Transport<Descriptor> {
347
/** Internal lock to prevent concurrent app API operations */
348
_appAPIlock: string | null = null;
349
}
350
```
351
352
When methods are decorated, they automatically:
353
1. Check if another operation is in progress (`_appAPIlock`)
354
2. Set the lock with the method name
355
3. Set the appropriate scramble key
356
4. Execute the method
357
5. Clear the lock when complete
358
359
This prevents race conditions and ensures proper scramble key isolation between different app operations.