@onekeyfe/hd-core 1.2.0-alpha.59 → 1.2.0-alpha.60
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/__tests__/deviceUploadNft.test.ts +50 -3
- package/__tests__/protocol-v2-resources.test.ts +15 -0
- package/__tests__/uiPromiseRegistry.test.ts +12 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/uiPromiseRegistry.d.ts +1 -0
- package/dist/core/uiPromiseRegistry.d.ts.map +1 -1
- package/dist/index.js +14 -2
- package/package.json +4 -4
- package/src/api/protocol-v2/DeviceUploadNft.ts +14 -1
- package/src/core/index.ts +6 -1
- package/src/core/uiPromiseRegistry.ts +9 -0
- package/src/protocols/protocol-v2/resources.ts +1 -1
|
@@ -15,7 +15,7 @@ const createRgba = (width: number, height: number) => {
|
|
|
15
15
|
|
|
16
16
|
const createMethod = ({
|
|
17
17
|
typedCall,
|
|
18
|
-
supportedMessages = [60805, 60808, 61500],
|
|
18
|
+
supportedMessages = [60802, 60805, 60808, 61500],
|
|
19
19
|
useFullBundle = false,
|
|
20
20
|
}: {
|
|
21
21
|
typedCall: jest.Mock;
|
|
@@ -104,6 +104,9 @@ describe('DeviceUploadNft', () => {
|
|
|
104
104
|
|
|
105
105
|
test('uploads the triplet in order without creating the firmware-owned directory', async () => {
|
|
106
106
|
const typedCall = jest.fn((request: string, _response: string, params: any) => {
|
|
107
|
+
if (request === 'FilesystemPathInfoQuery') {
|
|
108
|
+
return { message: { exist: true, directory: true } };
|
|
109
|
+
}
|
|
107
110
|
if (request === 'FilesystemDirList') {
|
|
108
111
|
return { message: { path: 'vol1:/nft', child_files: '' } };
|
|
109
112
|
}
|
|
@@ -116,9 +119,16 @@ describe('DeviceUploadNft', () => {
|
|
|
116
119
|
const result = await method.run();
|
|
117
120
|
|
|
118
121
|
const requests = typedCall.mock.calls.map(call => call[0]);
|
|
119
|
-
expect(requests[0]).toBe('
|
|
122
|
+
expect(requests[0]).toBe('FilesystemPathInfoQuery');
|
|
120
123
|
expect(typedCall).toHaveBeenNthCalledWith(
|
|
121
124
|
1,
|
|
125
|
+
'FilesystemPathInfoQuery',
|
|
126
|
+
'FilesystemPathInfo',
|
|
127
|
+
{ path: 'vol1:/nft' },
|
|
128
|
+
{ timeoutMs: 15_000 }
|
|
129
|
+
);
|
|
130
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
131
|
+
2,
|
|
122
132
|
'FilesystemDirList',
|
|
123
133
|
'FilesystemDir',
|
|
124
134
|
{ path: 'vol1:/nft', depth: 1 },
|
|
@@ -160,11 +170,30 @@ describe('DeviceUploadNft', () => {
|
|
|
160
170
|
});
|
|
161
171
|
});
|
|
162
172
|
|
|
173
|
+
test('treats a missing NFT directory as empty before the first upload', async () => {
|
|
174
|
+
const typedCall = jest.fn((request: string, _response: string, params: any) => {
|
|
175
|
+
if (request === 'FilesystemPathInfoQuery') {
|
|
176
|
+
return { message: { exist: false, directory: false } };
|
|
177
|
+
}
|
|
178
|
+
if (request === 'FilesystemFileWrite') return fileWriteSuccess(params);
|
|
179
|
+
if (request === 'NftUpdate') return { message: { message: 'NFT updated' } };
|
|
180
|
+
throw new Error(`Unexpected request: ${request}`);
|
|
181
|
+
});
|
|
182
|
+
const method = createMethod({ typedCall });
|
|
183
|
+
|
|
184
|
+
await expect(method.run()).resolves.toMatchObject({ nftUpdated: true });
|
|
185
|
+
expect(typedCall.mock.calls.map(call => call[0])).not.toContain('FilesystemDirList');
|
|
186
|
+
expect(typedCall.mock.calls.some(call => call[0] === 'FilesystemFileWrite')).toBe(true);
|
|
187
|
+
});
|
|
188
|
+
|
|
163
189
|
test('does not retry a timed-out NftUpdate', async () => {
|
|
164
190
|
const timeout = Object.assign(new Error('Protocol V2 response timeout'), {
|
|
165
191
|
code: 'response-timeout',
|
|
166
192
|
});
|
|
167
193
|
const typedCall = jest.fn((request: string, _response: string, params: any) => {
|
|
194
|
+
if (request === 'FilesystemPathInfoQuery') {
|
|
195
|
+
return { message: { exist: true, directory: true } };
|
|
196
|
+
}
|
|
168
197
|
if (request === 'FilesystemDirList') {
|
|
169
198
|
return { message: { path: 'vol1:/nft', child_files: '' } };
|
|
170
199
|
}
|
|
@@ -182,6 +211,9 @@ describe('DeviceUploadNft', () => {
|
|
|
182
211
|
|
|
183
212
|
test('does not retry a non-timeout NftUpdate failure', async () => {
|
|
184
213
|
const typedCall = jest.fn((request: string, _response: string, params: any) => {
|
|
214
|
+
if (request === 'FilesystemPathInfoQuery') {
|
|
215
|
+
return { message: { exist: true, directory: true } };
|
|
216
|
+
}
|
|
185
217
|
if (request === 'FilesystemDirList') {
|
|
186
218
|
return { message: { path: 'vol1:/nft', child_files: '' } };
|
|
187
219
|
}
|
|
@@ -197,6 +229,9 @@ describe('DeviceUploadNft', () => {
|
|
|
197
229
|
|
|
198
230
|
test('does not publish when a file write fails', async () => {
|
|
199
231
|
const typedCall = jest.fn((request: string) => {
|
|
232
|
+
if (request === 'FilesystemPathInfoQuery') {
|
|
233
|
+
return { message: { exist: true, directory: true } };
|
|
234
|
+
}
|
|
200
235
|
if (request === 'FilesystemDirList') {
|
|
201
236
|
return { message: { path: 'vol1:/nft', child_files: '' } };
|
|
202
237
|
}
|
|
@@ -219,6 +254,9 @@ describe('DeviceUploadNft', () => {
|
|
|
219
254
|
|
|
220
255
|
test('rejects a new NFT before writing when ten complete NFT bundles exist', async () => {
|
|
221
256
|
const typedCall = jest.fn((request: string) => {
|
|
257
|
+
if (request === 'FilesystemPathInfoQuery') {
|
|
258
|
+
return { message: { exist: true, directory: true } };
|
|
259
|
+
}
|
|
222
260
|
if (request === 'FilesystemDirList') {
|
|
223
261
|
return { message: { path: 'vol1:/nft', child_files: nftFileList(10) } };
|
|
224
262
|
}
|
|
@@ -230,11 +268,17 @@ describe('DeviceUploadNft', () => {
|
|
|
230
268
|
errorCode: HardwareErrorCode.NftStorageLimitReached,
|
|
231
269
|
params: { count: 10, limit: 10 },
|
|
232
270
|
});
|
|
233
|
-
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
271
|
+
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
272
|
+
'FilesystemPathInfoQuery',
|
|
273
|
+
'FilesystemDirList',
|
|
274
|
+
]);
|
|
234
275
|
});
|
|
235
276
|
|
|
236
277
|
test('allows an idempotent retry for a basename already counted at the limit', async () => {
|
|
237
278
|
const typedCall = jest.fn((request: string, _response: string, params: any) => {
|
|
279
|
+
if (request === 'FilesystemPathInfoQuery') {
|
|
280
|
+
return { message: { exist: true, directory: true } };
|
|
281
|
+
}
|
|
238
282
|
if (request === 'FilesystemDirList') {
|
|
239
283
|
return { message: { path: 'vol1:/nft', child_files: nftFileList(10, 0) } };
|
|
240
284
|
}
|
|
@@ -250,6 +294,9 @@ describe('DeviceUploadNft', () => {
|
|
|
250
294
|
|
|
251
295
|
test('does not count unrelated or incomplete files as stored NFTs', async () => {
|
|
252
296
|
const typedCall = jest.fn((request: string, _response: string, params: any) => {
|
|
297
|
+
if (request === 'FilesystemPathInfoQuery') {
|
|
298
|
+
return { message: { exist: true, directory: true } };
|
|
299
|
+
}
|
|
253
300
|
if (request === 'FilesystemDirList') {
|
|
254
301
|
return {
|
|
255
302
|
message: {
|
|
@@ -146,6 +146,21 @@ describe('Pro2 resource configuration', () => {
|
|
|
146
146
|
},
|
|
147
147
|
})
|
|
148
148
|
).toThrow('devicePath');
|
|
149
|
+
|
|
150
|
+
for (const devicePath of [
|
|
151
|
+
'vol0:/assets/loaders\\bootloader_crest.bin',
|
|
152
|
+
'vol0:/assets/loaders\\\\bootloader_crest.bin',
|
|
153
|
+
]) {
|
|
154
|
+
expect(() =>
|
|
155
|
+
parseProtocolV2Resources({
|
|
156
|
+
stable: resources,
|
|
157
|
+
boot: {
|
|
158
|
+
...bootResources,
|
|
159
|
+
files: [{ ...bootResources.files[0], devicePath }],
|
|
160
|
+
},
|
|
161
|
+
})
|
|
162
|
+
).toThrow('devicePath');
|
|
163
|
+
}
|
|
149
164
|
});
|
|
150
165
|
|
|
151
166
|
test('downloads nothing when all resource identities match', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createDeferred } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
|
-
import { findUiPromiseForResponse } from '../src/core/uiPromiseRegistry';
|
|
3
|
+
import { findUiPromiseForResponse, rejectUiPromises } from '../src/core/uiPromiseRegistry';
|
|
4
4
|
import { UI_RESPONSE } from '../src/events';
|
|
5
5
|
|
|
6
6
|
import type { UiPromise, UiPromiseResponse } from '../src/events';
|
|
@@ -83,4 +83,15 @@ describe('UI response promise correlation', () => {
|
|
|
83
83
|
})
|
|
84
84
|
).toBe(promise);
|
|
85
85
|
});
|
|
86
|
+
|
|
87
|
+
test('rejects every pending UI promise removed during cleanup', async () => {
|
|
88
|
+
const deviceA = createPinPromise('interaction-a', 'device-a');
|
|
89
|
+
const deviceB = createPinPromise('interaction-b', 'device-b');
|
|
90
|
+
const cancellation = new Error('UI request was cancelled');
|
|
91
|
+
|
|
92
|
+
rejectUiPromises(asRegistry([deviceA, deviceB]), cancellation);
|
|
93
|
+
|
|
94
|
+
await expect(deviceA.promise).rejects.toBe(cancellation);
|
|
95
|
+
await expect(deviceB.promise).rejects.toBe(cancellation);
|
|
96
|
+
});
|
|
86
97
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceUploadNft.d.ts","sourceRoot":"","sources":["../../../src/api/protocol-v2/DeviceUploadNft.ts"],"names":[],"mappings":"AAIA,OAAO,EASL,KAAK,YAAY,EAGlB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,YAAY,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,IAAI,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;
|
|
1
|
+
{"version":3,"file":"DeviceUploadNft.d.ts","sourceRoot":"","sources":["../../../src/api/protocol-v2/DeviceUploadNft.ts"],"names":[],"mappings":"AAIA,OAAO,EASL,KAAK,YAAY,EAGlB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,YAAY,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,IAAI,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAOF,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,UAAU,CAAC,qBAAqB,CAAC;IAC5E,OAAO,CAAC,MAAM,CAAC,CAAgB;IAE/B,qBAAqB;IAIrB,IAAI;YAkCU,kBAAkB;YAiBlB,qBAAqB;YAwBrB,SAAS;IASjB,GAAG,IAAI,OAAO,CAAC,uBAAuB,CAAC;CA0D9C"}
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AA+BlC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB1C,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAYxD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAmD,MAAM,WAAW,CAAC;AAI9F,OAAO,KAAK,EACV,6BAA6B,EAG9B,MAAM,wBAAwB,CAAC;AAWhC,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAgE7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,iBAoFvE,CAAC;AA82BF,eAAO,MAAM,MAAM,YAAa,WAAW,cAAc,MAAM,SAkF9D,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AA+BlC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB1C,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAYxD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAmD,MAAM,WAAW,CAAC;AAI9F,OAAO,KAAK,EACV,6BAA6B,EAG9B,MAAM,wBAAwB,CAAC;AAWhC,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAgE7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,iBAoFvE,CAAC;AA82BF,eAAO,MAAM,MAAM,YAAa,WAAW,cAAc,MAAM,SAkF9D,CAAC;AAmGF,eAAO,MAAM,qBAAqB,gFAejC,CAAC;AAwKF,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,YAAY;IAC5C,OAAO,CAAC,cAAc,CAAoB;IAE1C,SAAgB,aAAa,EAAE,MAAM,CAAC;IAEtC,OAAO,CAAC,YAAY,CAAsB;IAE1C,OAAO,CAAC,cAAc,CAAC,CAAgB;IAGvC,OAAO,CAAC,qBAAqB,CAA4B;IAEzD,OAAO,CAAC,iBAAiB,CAAoB;;IAS7C,OAAO,CAAC,cAAc;IAoBhB,aAAa,CAAC,OAAO,EAAE,WAAW;IAuExC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAOV,gBAAgB;CAiC/B;AAED,eAAO,MAAM,QAAQ,YAIpB,CAAC;AAEF,eAAO,MAAM,aAAa,uBAYzB,CAAC;AAMF,eAAO,MAAM,IAAI,aACL,eAAe,aACd,GAAG,WACL,6BAA6B,8BAiBvC,CAAC;AAEF,eAAO,MAAM,eAAe;SAKrB,eAAe,CAAC,KAAK,CAAC;eAChB,GAAG;;UASf,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { UiPromise, UiPromiseResponse } from '../events/ui-promise';
|
|
2
2
|
import type { UiResponseEvent } from '../events/ui-response';
|
|
3
|
+
export declare const rejectUiPromises: (uiPromises: UiPromise<UiPromiseResponse['type']>[], error: Error) => void;
|
|
3
4
|
export declare const findUiPromiseForResponse: (uiPromises: UiPromise<UiPromiseResponse['type']>[], response: UiResponseEvent) => UiPromise<"ui-receive_pin" | "ui-receive_passphrase" | "ui-receive_select-device-in-bootloader-for-web-device" | "ui-receive_select-device-for-switch-firmware-web-device" | "device-disconnect"> | undefined;
|
|
4
5
|
//# sourceMappingURL=uiPromiseRegistry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uiPromiseRegistry.d.ts","sourceRoot":"","sources":["../../src/core/uiPromiseRegistry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"uiPromiseRegistry.d.ts","sourceRoot":"","sources":["../../src/core/uiPromiseRegistry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,eAAO,MAAM,gBAAgB,eACf,UAAU,iBAAiB,CAAC,MAAM,CAAC,CAAC,EAAE,SAC3C,KAAK,SAKb,CAAC;AASF,eAAO,MAAM,wBAAwB,eACvB,UAAU,iBAAiB,CAAC,MAAM,CAAC,CAAC,EAAE,YACxC,eAAe,kNA0B1B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -39663,7 +39663,7 @@ function validateBootResources(value) {
|
|
|
39663
39663
|
if (typeof file.devicePath !== 'string' ||
|
|
39664
39664
|
!file.devicePath.startsWith('vol0:/') ||
|
|
39665
39665
|
file.devicePath.includes('..') ||
|
|
39666
|
-
file.devicePath.includes('
|
|
39666
|
+
file.devicePath.includes('\\')) {
|
|
39667
39667
|
throw new Error(`Invalid Pro2 boot resource devicePath at files[${index}]`);
|
|
39668
39668
|
}
|
|
39669
39669
|
if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
|
|
@@ -51081,6 +51081,7 @@ class DeviceUploadWallpaper extends BaseMethod {
|
|
|
51081
51081
|
}
|
|
51082
51082
|
}
|
|
51083
51083
|
|
|
51084
|
+
const FILESYSTEM_PATH_INFO_QUERY_MESSAGE_TYPE = 60802;
|
|
51084
51085
|
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
|
|
51085
51086
|
const FILESYSTEM_DIR_LIST_MESSAGE_TYPE = 60808;
|
|
51086
51087
|
const NFT_UPDATE_MESSAGE_TYPE = 61500;
|
|
@@ -51111,15 +51112,19 @@ class DeviceUploadNft extends BaseMethod {
|
|
|
51111
51112
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51112
51113
|
const protocolInfo = yield this.device.ensureProtocolV2RuntimeContext();
|
|
51113
51114
|
const hasFileWrite = supportsProtocolV2Message(protocolInfo, FILESYSTEM_FILE_WRITE_MESSAGE_TYPE);
|
|
51115
|
+
const hasPathInfo = supportsProtocolV2Message(protocolInfo, FILESYSTEM_PATH_INFO_QUERY_MESSAGE_TYPE);
|
|
51114
51116
|
const hasDirList = supportsProtocolV2Message(protocolInfo, FILESYSTEM_DIR_LIST_MESSAGE_TYPE);
|
|
51115
51117
|
const hasNftUpdate = supportsProtocolV2Message(protocolInfo, NFT_UPDATE_MESSAGE_TYPE);
|
|
51116
|
-
if (!hasFileWrite || !hasDirList || !hasNftUpdate) {
|
|
51118
|
+
if (!hasFileWrite || !hasPathInfo || !hasDirList || !hasNftUpdate) {
|
|
51117
51119
|
throw hdShared.createDeviceNotSupportMethodError(this.name, this.device.getCurrentFirmwareType());
|
|
51118
51120
|
}
|
|
51119
51121
|
});
|
|
51120
51122
|
}
|
|
51121
51123
|
assertStorageCapacity(basename) {
|
|
51122
51124
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51125
|
+
const { message: pathInfo } = yield this.device.commands.typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', { path: PRO2_NFT_DIRECTORY }, { timeoutMs: this.params.timeoutMs });
|
|
51126
|
+
if (!pathInfo.exist)
|
|
51127
|
+
return;
|
|
51123
51128
|
const { message } = yield this.device.commands.typedCall('FilesystemDirList', 'FilesystemDir', { path: PRO2_NFT_DIRECTORY, depth: 1 }, { timeoutMs: this.params.timeoutMs });
|
|
51124
51129
|
const existingBasenames = getCompletePro2NftBasenames(message.child_files);
|
|
51125
51130
|
if (existingBasenames.size >= PRO2_NFT_MAX_ITEMS && !existingBasenames.has(basename)) {
|
|
@@ -61395,6 +61400,11 @@ class RequestQueue {
|
|
|
61395
61400
|
}
|
|
61396
61401
|
}
|
|
61397
61402
|
|
|
61403
|
+
const rejectUiPromises = (uiPromises, error) => {
|
|
61404
|
+
for (const uiPromise of uiPromises) {
|
|
61405
|
+
uiPromise.reject(error);
|
|
61406
|
+
}
|
|
61407
|
+
};
|
|
61398
61408
|
const isSensitiveUiResponse = (response) => response.type === UI_RESPONSE.RECEIVE_PIN || response.type === UI_RESPONSE.RECEIVE_PASSPHRASE;
|
|
61399
61409
|
const findUiPromiseForResponse = (uiPromises, response) => {
|
|
61400
61410
|
const candidates = uiPromises.filter(promise => promise.id === response.type);
|
|
@@ -62326,7 +62336,9 @@ const shouldCheckPassphraseState = (method, device) => {
|
|
|
62326
62336
|
return device.hasUsePassphrase();
|
|
62327
62337
|
};
|
|
62328
62338
|
const cleanup = () => {
|
|
62339
|
+
const pendingUiPromises = _uiPromises;
|
|
62329
62340
|
_uiPromises = [];
|
|
62341
|
+
rejectUiPromises(pendingUiPromises, hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.ActionCancelled, 'UI request was cancelled'));
|
|
62330
62342
|
Log.debug('Cleanup...');
|
|
62331
62343
|
};
|
|
62332
62344
|
const removeDeviceListener = (device) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-core",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.60",
|
|
4
4
|
"description": "Core processes and APIs for communicating with OneKey hardware devices.",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
29
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
28
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.60",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.60",
|
|
30
30
|
"axios": "1.15.2",
|
|
31
31
|
"bignumber.js": "^9.0.2",
|
|
32
32
|
"bytebuffer": "^5.0.1",
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"@types/w3c-web-usb": "^1.0.10",
|
|
45
45
|
"@types/web-bluetooth": "^0.0.21"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "bde29baa04ac87453fd0eff54fd1cafe905f0ec8"
|
|
48
48
|
}
|
|
@@ -40,6 +40,7 @@ export type DeviceUploadNftResponse = {
|
|
|
40
40
|
message?: string;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
+
const FILESYSTEM_PATH_INFO_QUERY_MESSAGE_TYPE = 60802;
|
|
43
44
|
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
|
|
44
45
|
const FILESYSTEM_DIR_LIST_MESSAGE_TYPE = 60808;
|
|
45
46
|
const NFT_UPDATE_MESSAGE_TYPE = 61500;
|
|
@@ -91,14 +92,26 @@ export default class DeviceUploadNft extends BaseMethod<DeviceUploadNftParams> {
|
|
|
91
92
|
protocolInfo,
|
|
92
93
|
FILESYSTEM_FILE_WRITE_MESSAGE_TYPE
|
|
93
94
|
);
|
|
95
|
+
const hasPathInfo = supportsProtocolV2Message(
|
|
96
|
+
protocolInfo,
|
|
97
|
+
FILESYSTEM_PATH_INFO_QUERY_MESSAGE_TYPE
|
|
98
|
+
);
|
|
94
99
|
const hasDirList = supportsProtocolV2Message(protocolInfo, FILESYSTEM_DIR_LIST_MESSAGE_TYPE);
|
|
95
100
|
const hasNftUpdate = supportsProtocolV2Message(protocolInfo, NFT_UPDATE_MESSAGE_TYPE);
|
|
96
|
-
if (!hasFileWrite || !hasDirList || !hasNftUpdate) {
|
|
101
|
+
if (!hasFileWrite || !hasPathInfo || !hasDirList || !hasNftUpdate) {
|
|
97
102
|
throw createDeviceNotSupportMethodError(this.name, this.device.getCurrentFirmwareType());
|
|
98
103
|
}
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
private async assertStorageCapacity(basename: string) {
|
|
107
|
+
const { message: pathInfo } = await this.device.commands.typedCall(
|
|
108
|
+
'FilesystemPathInfoQuery',
|
|
109
|
+
'FilesystemPathInfo',
|
|
110
|
+
{ path: PRO2_NFT_DIRECTORY },
|
|
111
|
+
{ timeoutMs: this.params.timeoutMs }
|
|
112
|
+
);
|
|
113
|
+
if (!pathInfo.exist) return;
|
|
114
|
+
|
|
102
115
|
const { message } = await this.device.commands.typedCall(
|
|
103
116
|
'FilesystemDirList',
|
|
104
117
|
'FilesystemDir',
|
package/src/core/index.ts
CHANGED
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
import TransportManager from '../data-manager/TransportManager';
|
|
55
55
|
import DeviceConnector from '../device/DeviceConnector';
|
|
56
56
|
import RequestQueue from './RequestQueue';
|
|
57
|
-
import { findUiPromiseForResponse } from './uiPromiseRegistry';
|
|
57
|
+
import { findUiPromiseForResponse, rejectUiPromises } from './uiPromiseRegistry';
|
|
58
58
|
import { registerHardwareUiEventListeners } from './deviceEventRegistration';
|
|
59
59
|
import { getSynchronize } from '../utils/getSynchronize';
|
|
60
60
|
import { runMethodWithUnlockPolicy } from '../protocols/protocol-v2/unlockPolicyRunner';
|
|
@@ -1226,7 +1226,12 @@ const shouldCheckPassphraseState = (method: BaseMethod, device: Device) => {
|
|
|
1226
1226
|
};
|
|
1227
1227
|
|
|
1228
1228
|
const cleanup = () => {
|
|
1229
|
+
const pendingUiPromises = _uiPromises;
|
|
1229
1230
|
_uiPromises = [];
|
|
1231
|
+
rejectUiPromises(
|
|
1232
|
+
pendingUiPromises,
|
|
1233
|
+
ERRORS.TypedError(HardwareErrorCode.ActionCancelled, 'UI request was cancelled')
|
|
1234
|
+
);
|
|
1230
1235
|
Log.debug('Cleanup...');
|
|
1231
1236
|
};
|
|
1232
1237
|
|
|
@@ -3,6 +3,15 @@ import { UI_RESPONSE } from '../events/ui-response';
|
|
|
3
3
|
import type { UiPromise, UiPromiseResponse } from '../events/ui-promise';
|
|
4
4
|
import type { UiResponseEvent } from '../events/ui-response';
|
|
5
5
|
|
|
6
|
+
export const rejectUiPromises = (
|
|
7
|
+
uiPromises: UiPromise<UiPromiseResponse['type']>[],
|
|
8
|
+
error: Error
|
|
9
|
+
) => {
|
|
10
|
+
for (const uiPromise of uiPromises) {
|
|
11
|
+
uiPromise.reject(error);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
6
15
|
const isSensitiveUiResponse = (
|
|
7
16
|
response: UiResponseEvent
|
|
8
17
|
): response is Extract<
|
|
@@ -272,7 +272,7 @@ function validateBootResources(value: unknown): IProtocolV2BootResources {
|
|
|
272
272
|
typeof file.devicePath !== 'string' ||
|
|
273
273
|
!file.devicePath.startsWith('vol0:/') ||
|
|
274
274
|
file.devicePath.includes('..') ||
|
|
275
|
-
file.devicePath.includes('
|
|
275
|
+
file.devicePath.includes('\\')
|
|
276
276
|
) {
|
|
277
277
|
throw new Error(`Invalid Pro2 boot resource devicePath at files[${index}]`);
|
|
278
278
|
}
|