@onekeyfe/hd-core 1.2.0-alpha.145 → 1.2.0-alpha.147

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.
@@ -1,12 +1,7 @@
1
1
  import { EDeviceType, ERRORS, HardwareErrorCode, createDeferred } from '@onekeyfe/hd-shared';
2
2
  import { DeviceType, TRANSPORT_EVENT } from '@onekeyfe/hd-transport';
3
3
 
4
- import {
5
- initConnector,
6
- initCore,
7
- isMissingDetectedProtocolV2Error,
8
- isRetryableBleProtocolV2ProbeError,
9
- } from '../src/core';
4
+ import { initConnector, initCore, isMissingDetectedProtocolV2Error } from '../src/core';
10
5
  import { DataManager } from '../src/data-manager';
11
6
  import TransportManager from '../src/data-manager/TransportManager';
12
7
  import { Device } from '../src/device/Device';
@@ -274,23 +269,6 @@ describe('public device lifecycle events', () => {
274
269
  }
275
270
  );
276
271
 
277
- test.each([
278
- [HardwareErrorCode.RuntimeError, true],
279
- [HardwareErrorCode.BleDeviceBondError, false],
280
- ] as const)(
281
- 'retries a Protocol V2 probe mismatch with error code %s: %s',
282
- (errorCode, expected) => {
283
- const method = { payload: { connectProtocol: 'V2' } } as never;
284
- const error = {
285
- errorCode,
286
- message:
287
- 'Device protocol mismatch: expected V2, but device did not respond to expected protocol',
288
- };
289
-
290
- expect(isRetryableBleProtocolV2ProbeError(method, error)).toBe(expected);
291
- }
292
- );
293
-
294
272
  test('converts an internal transport disconnect into a public KnownDevice snapshot', () => {
295
273
  jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
296
274
  core = initCore();
@@ -123,14 +123,6 @@ describe('device feature selectors', () => {
123
123
  test('recognizes Neo discovery names before initialization', () => {
124
124
  expect(getDeviceTypeByBleName('OneKey Neo 1234')).toBe(EDeviceType.Neo);
125
125
  expect(getDeviceTypeByBleName('Neo 1234')).toBe(EDeviceType.Neo);
126
- expect(getDeviceTypeByBleName('Neo22D8')).toBe(EDeviceType.Neo);
127
- expect(getDeviceTypeByBleName('OneKeyNeo22D8')).toBe(EDeviceType.Neo);
128
- });
129
-
130
- test('recognizes compact Pro2 discovery names before initialization', () => {
131
- expect(getDeviceTypeByBleName('Pro2 A1B2')).toBe(EDeviceType.Pro2);
132
- expect(getDeviceTypeByBleName('Pro2A1B2')).toBe(EDeviceType.Pro2);
133
- expect(getDeviceTypeByBleName('OneKeyPro2A1B2')).toBe(EDeviceType.Pro2);
134
126
  });
135
127
 
136
128
  test.each([EDeviceType.Pro2, EDeviceType.Neo])(
@@ -1,5 +1,4 @@
1
1
  import { HardwareErrorCode } from '@onekeyfe/hd-shared';
2
- import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
3
2
  import { encode as encodeJpeg } from 'jpeg-js';
4
3
 
5
4
  import DeviceUploadNft from '../src/api/protocol-v2/DeviceUploadNft';
@@ -111,8 +110,6 @@ describe('DeviceUploadNft', () => {
111
110
 
112
111
  method.init();
113
112
 
114
- expect(method.unlockPolicy).toBe('unlock-before-run');
115
- expect(method.protocolV2PreUnlockPinType).toBe(DeviceSessionPinType.Any);
116
113
  expect((method as any).params).toMatchObject({
117
114
  chunkSize: 2048,
118
115
  paceMs: 0,
@@ -1,9 +1,10 @@
1
1
  import axios from 'axios';
2
+ import { sha256 } from '@noble/hashes/sha256';
2
3
  import { EDeviceType, EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shared';
3
4
 
4
5
  import { DataManager } from '../src/data-manager';
5
6
  import {
6
- parseProtocolV2ResourcePackage,
7
+ parseProtocolV2ResourceManifest,
7
8
  parseProtocolV2Resources,
8
9
  } from '../src/protocols/protocol-v2/resources';
9
10
 
@@ -15,6 +16,9 @@ jest.mock('../src/data/config', () => ({
15
16
  DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0-test/',
16
17
  }));
17
18
 
19
+ const bytesToHex = (bytes: Uint8Array) =>
20
+ Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
21
+
18
22
  const resourceSource = {
19
23
  archiveUrl: 'https://example.com/resource/pro2-resource.zip',
20
24
  archiveSha256: 'a'.repeat(64),
@@ -27,21 +31,65 @@ const neoResourceSource = {
27
31
  archiveSize: 12_345_678,
28
32
  };
29
33
 
30
- const createResourcePackage = (devicePath: string) => {
31
- const headerSize = 0x5f90;
32
- const bytes = new Uint8Array(headerSize + 1);
33
- bytes.set(new TextEncoder().encode('OKPP'), 0);
34
- bytes.set(new TextEncoder().encode('RESC'), 0x08);
35
- bytes.set(new TextEncoder().encode(devicePath), 0x6c);
36
- const view = new DataView(bytes.buffer);
37
- view.setUint32(0x04, 1, true);
38
- view.setUint32(0x0c, headerSize, true);
39
- view.setUint32(0x10, 0x010203, true);
40
- view.setUint32(0x14, 1, true);
41
- bytes.fill(0x11, 0x200, 0x240);
42
- bytes.fill(0x22, 0x240, 0x280);
43
- bytes[headerSize] = 0xaa;
44
- return bytes;
34
+ const manifestFiles = [
35
+ ['bundles/firmware_logo-build.okpkg', 'firmware_logo.okpkg', 'vol0:/bundles/firmware_logo.okpkg'],
36
+ ['bundles/font/noto-build.okpkg', 'noto.okpkg', 'vol0:/bundles/font/noto.okpkg'],
37
+ ['bundles/font/roobert-build.okpkg', 'roobert.okpkg', 'vol0:/bundles/font/roobert.okpkg'],
38
+ [
39
+ 'bundles/images/animation-build.okpkg',
40
+ 'animation.okpkg',
41
+ 'vol0:/bundles/images/animation.okpkg',
42
+ ],
43
+ ['bundles/images/images-build.okpkg', 'images.okpkg', 'vol0:/bundles/images/images.okpkg'],
44
+ [
45
+ 'bundles/images/wallpaper-build.okpkg',
46
+ 'wallpaper.okpkg',
47
+ 'vol0:/bundles/images/wallpaper.okpkg',
48
+ ],
49
+ [
50
+ 'bundles/translations/translations-build.okpkg',
51
+ 'translations.okpkg',
52
+ 'vol0:/bundles/translations/translations.okpkg',
53
+ ],
54
+ [
55
+ 'loaders/bootloader/boot_resource-build.okpkg',
56
+ 'boot_resource.okpkg',
57
+ 'vol0:/loaders/bootloader/boot_resource.okpkg',
58
+ ],
59
+ ['loaders/rom/params-build.okpkg', 'params.okpkg', 'vol0:/loaders/rom/params.okpkg'],
60
+ ].map(([archive_path, original_name, device_path], index) => {
61
+ const binary = new Uint8Array([index + 1]).buffer;
62
+ return {
63
+ archive_path,
64
+ original_name,
65
+ device_path,
66
+ size: 1,
67
+ sha256: bytesToHex(sha256(new Uint8Array(binary))),
68
+ signed: true,
69
+ sig_algo: device_path.startsWith('vol0:/bundles/') ? 'ed25519' : 'mldsa65',
70
+ payload_version: '1.0.0',
71
+ binary,
72
+ };
73
+ });
74
+
75
+ const resourceManifest = {
76
+ schema: 1,
77
+ artifact_name: 'pro2-resource-build',
78
+ release_name: 'resource-build',
79
+ variant: 'resource',
80
+ commit: 'a'.repeat(40),
81
+ short_sha: 'aaaaaaa',
82
+ timestamp_utc: '20260807_091424',
83
+ core_version: '1.0.0',
84
+ key_set: 'dev',
85
+ device_root: 'vol0:',
86
+ restore_mode: 'bootloader_update',
87
+ trees: [
88
+ { path: 'bundles', device: 'vol0:/bundles' },
89
+ { path: 'loaders/bootloader', device: 'vol0:/loaders/bootloader' },
90
+ { path: 'loaders/rom', device: 'vol0:/loaders/rom' },
91
+ ],
92
+ files: manifestFiles.map(({ binary: _binary, ...file }) => file),
45
93
  };
46
94
 
47
95
  const createSettings = (configFetcher: ConnectSettings['configFetcher']): ConnectSettings =>
@@ -98,36 +146,34 @@ describe('Pro2 resource configuration', () => {
98
146
  DataManager.lastCheckTimestamp = 0;
99
147
  });
100
148
 
101
- test('accepts the release archive source', () => {
149
+ test('accepts the manifest source and the CI schema 1 file set', () => {
102
150
  expect(parseProtocolV2Resources({ source: resourceSource })).toEqual({
103
151
  source: resourceSource,
104
152
  });
153
+ expect(parseProtocolV2ResourceManifest(resourceManifest).files).toHaveLength(9);
105
154
  });
106
155
 
107
- test('reads the version, hashes, and direct device path from a RESC package', () => {
156
+ test('uses only the resource file list from a manifest', () => {
108
157
  expect(
109
- parseProtocolV2ResourcePackage(createResourcePackage('vol0:/bundles/images.okpkg'))
110
- ).toEqual({
111
- version: [1, 2, 3],
112
- payloadLength: 1,
113
- devicePath: 'vol0:/bundles/images.okpkg',
114
- payloadHash: '11'.repeat(64),
115
- headerHash: '22'.repeat(64),
116
- });
158
+ parseProtocolV2ResourceManifest({
159
+ files: resourceManifest.files,
160
+ })
161
+ ).toEqual({ files: resourceManifest.files });
117
162
  });
118
163
 
119
- test('accepts the boot resource staging path and rejects paths outside resource roots', () => {
164
+ test('ignores release metadata and accepts a partial resource file set', () => {
120
165
  expect(
121
- parseProtocolV2ResourcePackage(
122
- createResourcePackage('vol0:/loaders/bootloader/boot_resource.okpkg.staging')
123
- ).devicePath
124
- ).toBe('vol0:/loaders/bootloader/boot_resource.okpkg.staging');
125
- expect(() =>
126
- parseProtocolV2ResourcePackage(createResourcePackage('vol0:/unexpected/images.okpkg'))
127
- ).toThrow('device path');
166
+ parseProtocolV2ResourceManifest({
167
+ schema: 1,
168
+ variant: 'dev_resource',
169
+ restore_mode: 'bootloader_update',
170
+ trees: [],
171
+ files: [resourceManifest.files[0]],
172
+ })
173
+ ).toEqual({ files: [resourceManifest.files[0]] });
128
174
  });
129
175
 
130
- test('rejects missing or malformed release sources', () => {
176
+ test('rejects missing source and malformed manifest paths', () => {
131
177
  expect(() => parseProtocolV2Resources({})).toThrow('source is required');
132
178
  expect(() =>
133
179
  parseProtocolV2Resources({
@@ -147,6 +193,14 @@ describe('Pro2 resource configuration', () => {
147
193
  source: { ...resourceSource, archiveSize: 0 },
148
194
  })
149
195
  ).toThrow('positive integer');
196
+ expect(() =>
197
+ parseProtocolV2ResourceManifest({
198
+ ...resourceManifest,
199
+ files: resourceManifest.files.map((file, index) =>
200
+ index === 0 ? { ...file, archive_path: '../outside.okpkg' } : file
201
+ ),
202
+ })
203
+ ).toThrow('archive_path');
150
204
  });
151
205
 
152
206
  test('applies a validated pre-release config and exposes its archive source', async () => {
@@ -1,5 +1,4 @@
1
1
  import TransportUtils, { DeviceSessionPinType } from '@onekeyfe/hd-transport';
2
- import { encode as encodeJpeg } from 'jpeg-js';
3
2
 
4
3
  import ConfluxSignMessageCIP23 from '../src/api/conflux/ConfluxSignMessageCIP23';
5
4
  import DeviceChangePin from '../src/api/device/DeviceChangePin';
@@ -7,8 +6,6 @@ import DeviceLock from '../src/api/device/DeviceLock';
7
6
  import DeviceSettings from '../src/api/device/DeviceSettings';
8
7
  import DeviceVerify from '../src/api/device/DeviceVerify';
9
8
  import DeviceWipe from '../src/api/device/DeviceWipe';
10
- import DeviceUploadNft from '../src/api/protocol-v2/DeviceUploadNft';
11
- import DeviceUploadWallpaper from '../src/api/protocol-v2/DeviceUploadWallpaper';
12
9
  import FirmwareUpdateV4 from '../src/api/FirmwareUpdateV4';
13
10
  import OpenWalletSession from '../src/api/OpenWalletSession';
14
11
  import DataManager from '../src/data-manager/DataManager';
@@ -19,12 +16,6 @@ jest.mock('../src/data/config', () => ({
19
16
  getSDKVersion: () => '0.0.0-test',
20
17
  }));
21
18
 
22
- const createJpegBase64 = (width: number, height: number) => {
23
- const data = new Uint8Array(width * height * 4);
24
- for (let index = 3; index < data.length; index += 4) data[index] = 0xff;
25
- return encodeJpeg({ width, height, data }, 80).data.toString('base64');
26
- };
27
-
28
19
  describe('Protocol V2 unlock semantics', () => {
29
20
  test('serializes genuine-device verification with Protocol V2 certificate messages', async () => {
30
21
  const method = new DeviceVerify({
@@ -267,32 +258,6 @@ describe('Protocol V2 unlock semantics', () => {
267
258
  payload: { method: 'deviceVerify', dataHex: '00' },
268
259
  }),
269
260
  ],
270
- [
271
- 'wallpaper uploads',
272
- () =>
273
- new DeviceUploadWallpaper({
274
- id: 1,
275
- payload: {
276
- method: 'deviceUploadWallpaper',
277
- jpegBase64: createJpegBase64(604, 1024),
278
- },
279
- }),
280
- ],
281
- [
282
- 'NFT uploads',
283
- () =>
284
- new DeviceUploadNft({
285
- id: 1,
286
- payload: {
287
- method: 'deviceUploadNft',
288
- imageJpegBase64: createJpegBase64(540, 540),
289
- thumbnailJpegBase64: createJpegBase64(263, 263),
290
- title: 'NFT',
291
- subtitle: '',
292
- timestampMs: 1,
293
- },
294
- }),
295
- ],
296
261
  ])('allows either PIN type when pre-unlocking %s', async (_name, createMethod) => {
297
262
  const method = createMethod();
298
263
  method.init();