@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.
@@ -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('FilesystemDirList');
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(['FilesystemDirList']);
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;AAMF,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,UAAU,CAAC,qBAAqB,CAAC;IAC5E,OAAO,CAAC,MAAM,CAAC,CAAgB;IAE/B,qBAAqB;IAIrB,IAAI;YAkCU,kBAAkB;YAalB,qBAAqB;YAgBrB,SAAS;IASjB,GAAG,IAAI,OAAO,CAAC,uBAAuB,CAAC;CA0D9C"}
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"}
@@ -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;AA8FF,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
+ {"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;AAS7D,eAAO,MAAM,wBAAwB,eACvB,UAAU,iBAAiB,CAAC,MAAM,CAAC,CAAC,EAAE,YACxC,eAAe,kNA0B1B,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.59",
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.59",
29
- "@onekeyfe/hd-transport": "1.2.0-alpha.59",
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": "98794c3032aab55e13fb2afedc645d8281141d5f"
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
  }