@onekeyfe/hd-core 1.2.0-alpha.77 → 1.2.0-alpha.79
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__/check-all-firmware-release-protocol-v2.test.ts +12 -71
- package/__tests__/device-state-mapper.test.ts +16 -1
- package/__tests__/device-state-projector.test.ts +20 -0
- package/__tests__/device-state-store.test.ts +27 -0
- package/__tests__/homescreen.test.ts +17 -0
- package/__tests__/method-protocol-support.test.ts +13 -1
- package/__tests__/protocol-v2-resources.test.ts +113 -222
- package/__tests__/protocol-v2.test.ts +110 -380
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +0 -6
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/utils.d.ts +2 -0
- package/dist/api/utils.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +1 -2
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts.map +1 -1
- package/dist/device/DeviceStateProjector.d.ts.map +1 -1
- package/dist/device/DeviceStateStore.d.ts.map +1 -1
- package/dist/index.d.ts +96 -33
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +515 -597
- package/dist/inject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts +31 -28
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +1 -0
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +1 -0
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +2 -0
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2ResourceManifest.d.ts +17 -0
- package/dist/types/api/protocolV2ResourceManifest.d.ts.map +1 -0
- package/dist/types/device.d.ts +8 -0
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/settings.d.ts +30 -21
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/homescreen.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +5 -34
- package/src/api/FirmwareUpdateV4.ts +48 -220
- package/src/api/UploadPortfolio.ts +18 -0
- package/src/api/utils.ts +25 -0
- package/src/data-manager/DataManager.ts +17 -6
- package/src/device/DeviceStateMapper.ts +42 -0
- package/src/device/DeviceStateProjector.ts +58 -0
- package/src/device/DeviceStateStore.ts +31 -0
- package/src/index.ts +8 -0
- package/src/inject.ts +2 -0
- package/src/protocols/protocol-v2/resources.ts +193 -324
- package/src/types/api/checkAllFirmwareRelease.ts +1 -0
- package/src/types/api/export.ts +4 -0
- package/src/types/api/index.ts +2 -0
- package/src/types/api/protocolV2ResourceManifest.ts +19 -0
- package/src/types/device.ts +16 -0
- package/src/types/settings.ts +30 -36
- package/src/utils/homescreen.ts +5 -1
|
@@ -5,7 +5,6 @@ import CheckAllFirmwareRelease, {
|
|
|
5
5
|
} from '../src/api/CheckAllFirmwareRelease';
|
|
6
6
|
import { DataManager } from '../src/data-manager';
|
|
7
7
|
import { createCoreApi } from '../src/inject';
|
|
8
|
-
import { PROTOCOL_V2_RESOURCE_DEVICE_PATHS } from '../src/protocols/protocol-v2/resources';
|
|
9
8
|
|
|
10
9
|
import type { CoreApi } from '../src/types/api';
|
|
11
10
|
import type { DeviceStateVersions, IFirmwareReleaseInfo } from '../src/types';
|
|
@@ -73,67 +72,8 @@ const release: IFirmwareReleaseInfo = {
|
|
|
73
72
|
],
|
|
74
73
|
};
|
|
75
74
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
type,
|
|
79
|
-
url: `https://example.com/${type}.okpkg`,
|
|
80
|
-
size: 0x52a0 + index + 1,
|
|
81
|
-
fileHash: 'a'.repeat(64),
|
|
82
|
-
headerHash: index.toString(16).padStart(128, '0'),
|
|
83
|
-
})
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
const createFilesystemTypedCall = (missingAll = false) => {
|
|
87
|
-
const resourceByPath = new Map(
|
|
88
|
-
stableResources.map(resource => [
|
|
89
|
-
PROTOCOL_V2_RESOURCE_DEVICE_PATHS[
|
|
90
|
-
resource.type as keyof typeof PROTOCOL_V2_RESOURCE_DEVICE_PATHS
|
|
91
|
-
],
|
|
92
|
-
resource,
|
|
93
|
-
])
|
|
94
|
-
);
|
|
95
|
-
return jest.fn((requestType: string, _responseType: string, payload: Record<string, any>) => {
|
|
96
|
-
if (requestType === 'ResourceInventoryGet') {
|
|
97
|
-
throw new Error('ResourceInventoryGet is unavailable on released firmware');
|
|
98
|
-
}
|
|
99
|
-
if (requestType === 'FilesystemPathInfoQuery') {
|
|
100
|
-
const resource = resourceByPath.get(payload.path);
|
|
101
|
-
return {
|
|
102
|
-
message: {
|
|
103
|
-
exist: Boolean(resource) && !missingAll,
|
|
104
|
-
directory: false,
|
|
105
|
-
size: missingAll ? 0 : resource?.size,
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
if (requestType === 'FilesystemFileRead') {
|
|
110
|
-
const resource = resourceByPath.get(payload.file.path);
|
|
111
|
-
if (!resource || missingAll) throw new Error('missing resource');
|
|
112
|
-
const header = new Uint8Array(0x52a0);
|
|
113
|
-
const view = new DataView(header.buffer);
|
|
114
|
-
'OKPP'.split('').forEach((char, index) => {
|
|
115
|
-
header[index] = char.charCodeAt(0);
|
|
116
|
-
});
|
|
117
|
-
'RESC'.split('').forEach((char, index) => {
|
|
118
|
-
header[0x08 + index] = char.charCodeAt(0);
|
|
119
|
-
});
|
|
120
|
-
view.setUint32(0x0c, header.byteLength, true);
|
|
121
|
-
for (let index = 0; index < resource.headerHash.length / 2; index++) {
|
|
122
|
-
header[0x240 + index] = Number.parseInt(
|
|
123
|
-
resource.headerHash.slice(index * 2, index * 2 + 2),
|
|
124
|
-
16
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
const offset = Number(payload.file.offset);
|
|
128
|
-
const chunkLength = Number(payload.chunk_len);
|
|
129
|
-
return {
|
|
130
|
-
message: {
|
|
131
|
-
data: header.slice(offset, offset + chunkLength),
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
throw new Error(`Unexpected request: ${requestType}`);
|
|
136
|
-
});
|
|
75
|
+
const resourceSource = {
|
|
76
|
+
manifestUrl: 'https://example.com/pro2-resource/manifest.json',
|
|
137
77
|
};
|
|
138
78
|
|
|
139
79
|
describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
@@ -370,7 +310,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
370
310
|
status: { mode: 'normal' },
|
|
371
311
|
versions: currentVersions,
|
|
372
312
|
});
|
|
373
|
-
const typedCall =
|
|
313
|
+
const typedCall = jest.fn();
|
|
374
314
|
method.device = {
|
|
375
315
|
isProtocolV2: () => true,
|
|
376
316
|
features: {
|
|
@@ -381,13 +321,14 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
381
321
|
getCommands: () => ({ typedCall }),
|
|
382
322
|
} as unknown as CheckAllFirmwareRelease['device'];
|
|
383
323
|
jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(release);
|
|
384
|
-
jest.spyOn(DataManager, '
|
|
324
|
+
jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue(resourceSource);
|
|
385
325
|
|
|
386
326
|
await expect(method.run()).resolves.toMatchObject({
|
|
387
327
|
protocol: 'V2',
|
|
388
328
|
deviceType: 'pro2',
|
|
389
329
|
status: 'required',
|
|
390
330
|
resourceStatus: 'unknown',
|
|
331
|
+
resourceManifestUrl: resourceSource.manifestUrl,
|
|
391
332
|
targetsToUpdate: ['boot', 'app_v1'],
|
|
392
333
|
firmware: {
|
|
393
334
|
status: 'required',
|
|
@@ -437,7 +378,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
437
378
|
getCommands: () => ({ typedCall: jest.fn() }),
|
|
438
379
|
} as unknown as CheckAllFirmwareRelease['device'];
|
|
439
380
|
jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(packageSet);
|
|
440
|
-
jest.spyOn(DataManager, '
|
|
381
|
+
jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue(undefined);
|
|
441
382
|
|
|
442
383
|
await expect(method.run()).resolves.toMatchObject({
|
|
443
384
|
status: 'outdated',
|
|
@@ -449,7 +390,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
449
390
|
});
|
|
450
391
|
|
|
451
392
|
test.each(['bootloader', 'romloader'] as const)(
|
|
452
|
-
'
|
|
393
|
+
'does not read vol0 resource inventory in %s mode',
|
|
453
394
|
async mode => {
|
|
454
395
|
const method = new CheckAllFirmwareRelease({
|
|
455
396
|
id: 1,
|
|
@@ -459,7 +400,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
459
400
|
},
|
|
460
401
|
});
|
|
461
402
|
method.init();
|
|
462
|
-
const typedCall =
|
|
403
|
+
const typedCall = jest.fn();
|
|
463
404
|
method.device = {
|
|
464
405
|
isProtocolV2: () => true,
|
|
465
406
|
features: { deviceType: 'pro2', firmwareVersion: '1.0.0' },
|
|
@@ -471,15 +412,15 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
471
412
|
getCommands: () => ({ typedCall }),
|
|
472
413
|
} as unknown as CheckAllFirmwareRelease['device'];
|
|
473
414
|
jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(release);
|
|
474
|
-
jest.spyOn(DataManager, '
|
|
415
|
+
jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue(resourceSource);
|
|
475
416
|
|
|
476
417
|
await expect(method.run()).resolves.toMatchObject({
|
|
477
418
|
protocol: 'V2',
|
|
478
|
-
resourceStatus: '
|
|
419
|
+
resourceStatus: 'unknown',
|
|
420
|
+
resourceManifestUrl: resourceSource.manifestUrl,
|
|
479
421
|
targetsToUpdate: ['boot', 'app_v1'],
|
|
480
422
|
});
|
|
481
|
-
expect(typedCall.
|
|
482
|
-
expect(typedCall.mock.calls.some(call => call[0] === 'FilesystemFileRead')).toBe(true);
|
|
423
|
+
expect(typedCall).not.toHaveBeenCalled();
|
|
483
424
|
}
|
|
484
425
|
);
|
|
485
426
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
DeviceSEState,
|
|
4
|
+
DeviceSeType,
|
|
5
|
+
DeviceType,
|
|
6
|
+
Enum_SafetyCheckLevel,
|
|
7
|
+
} from '@onekeyfe/hd-transport';
|
|
3
8
|
|
|
4
9
|
import {
|
|
5
10
|
mapApplySettingsToState,
|
|
@@ -119,6 +124,11 @@ describe('DeviceStateMapper', () => {
|
|
|
119
124
|
bt_adv_name: 'Pro2 1234',
|
|
120
125
|
application: { version: '1.2.3' },
|
|
121
126
|
},
|
|
127
|
+
se1: {
|
|
128
|
+
type: DeviceSeType.THD89,
|
|
129
|
+
state: DeviceSEState.APP,
|
|
130
|
+
application: { version: '3.0.0', build_id: 'se1-build', hash: [0x05, 0x06] },
|
|
131
|
+
},
|
|
122
132
|
} as ProtocolV2DeviceInfo,
|
|
123
133
|
'normal'
|
|
124
134
|
);
|
|
@@ -140,6 +150,11 @@ describe('DeviceStateMapper', () => {
|
|
|
140
150
|
applicationP1Hash: '0102',
|
|
141
151
|
applicationP2BuildId: 'p2-build',
|
|
142
152
|
applicationP2Hash: '0304',
|
|
153
|
+
se01BuildId: 'se1-build',
|
|
154
|
+
se01Hash: '0506',
|
|
155
|
+
});
|
|
156
|
+
expect(patch.securityElements).toMatchObject({
|
|
157
|
+
se01: { type: 'THD89', state: 'APP' },
|
|
143
158
|
});
|
|
144
159
|
expect(patch).toMatchObject({ protocolVersion: 2 });
|
|
145
160
|
expect(patch.status?.unlocked).toBeUndefined();
|
|
@@ -33,6 +33,17 @@ describe('DeviceStateProjector', () => {
|
|
|
33
33
|
firmware: '5.0.0',
|
|
34
34
|
bootloader: '2.0.0',
|
|
35
35
|
ble: '1.2.3',
|
|
36
|
+
se01: '3.1.0',
|
|
37
|
+
se01Boot: '1.0.2',
|
|
38
|
+
};
|
|
39
|
+
state.verification = {
|
|
40
|
+
firmwareBuildId: 'firmware-build',
|
|
41
|
+
firmwareHash: 'firmware-hash',
|
|
42
|
+
se01BuildId: 'se01-build',
|
|
43
|
+
se01Hash: 'se01-hash',
|
|
44
|
+
};
|
|
45
|
+
state.securityElements = {
|
|
46
|
+
se01: { type: 'THD89', state: 'APP' },
|
|
36
47
|
};
|
|
37
48
|
|
|
38
49
|
const features = projectFeatures(state);
|
|
@@ -43,6 +54,15 @@ describe('DeviceStateProjector', () => {
|
|
|
43
54
|
unlocked: true,
|
|
44
55
|
brightness: 80,
|
|
45
56
|
firmwareVersion: '5.0.0',
|
|
57
|
+
onekey_firmware_version: '5.0.0',
|
|
58
|
+
onekey_firmware_build_id: 'firmware-build',
|
|
59
|
+
onekey_firmware_hash: 'firmware-hash',
|
|
60
|
+
onekey_se_type: 'THD89',
|
|
61
|
+
onekey_se01_version: '3.1.0',
|
|
62
|
+
onekey_se01_build_id: 'se01-build',
|
|
63
|
+
onekey_se01_hash: 'se01-hash',
|
|
64
|
+
onekey_se01_state: 'APP',
|
|
65
|
+
onekey_se01_boot_version: '1.0.2',
|
|
46
66
|
});
|
|
47
67
|
});
|
|
48
68
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import { DeviceStateStore, createEmptyDeviceState } from '../src/device/DeviceStateStore';
|
|
4
|
+
import { projectFeatures } from '../src/device/DeviceStateProjector';
|
|
4
5
|
|
|
5
6
|
describe('DeviceStateStore', () => {
|
|
6
7
|
test('merges identity patches and ignores undefined', () => {
|
|
@@ -79,4 +80,30 @@ describe('DeviceStateStore', () => {
|
|
|
79
80
|
protocolV2DeviceInfo: deviceInfo,
|
|
80
81
|
});
|
|
81
82
|
});
|
|
83
|
+
|
|
84
|
+
test('merges partial secure-element patches without discarding existing metadata', () => {
|
|
85
|
+
const store = new DeviceStateStore(createEmptyDeviceState());
|
|
86
|
+
|
|
87
|
+
store.update(
|
|
88
|
+
{
|
|
89
|
+
securityElements: {
|
|
90
|
+
se01: { type: 'THD89', state: 'APP' },
|
|
91
|
+
se02: { type: 'SE608A', state: 'APP' },
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
'device-info'
|
|
95
|
+
);
|
|
96
|
+
const result = store.update({ securityElements: { se01: { state: 'BOOT' } } }, 'device-status');
|
|
97
|
+
|
|
98
|
+
expect(result.state.securityElements).toEqual({
|
|
99
|
+
se01: { type: 'THD89', state: 'BOOT' },
|
|
100
|
+
se02: { type: 'SE608A', state: 'APP' },
|
|
101
|
+
});
|
|
102
|
+
expect(result.changedKeys).toContain('securityElements');
|
|
103
|
+
expect(projectFeatures(result.state)).toMatchObject({
|
|
104
|
+
onekey_se_type: 'THD89',
|
|
105
|
+
onekey_se01_state: 'BOOT',
|
|
106
|
+
onekey_se02_state: 'APP',
|
|
107
|
+
});
|
|
108
|
+
});
|
|
82
109
|
});
|
|
@@ -22,6 +22,15 @@ describe('getHomeScreenSize', () => {
|
|
|
22
22
|
).toBeUndefined();
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
+
it('uses the Protocol V2 wallpaper dimensions for Neo', () => {
|
|
26
|
+
expect(
|
|
27
|
+
getHomeScreenSize({
|
|
28
|
+
deviceType: EDeviceType.Neo,
|
|
29
|
+
homeScreenType: 'WallPaper',
|
|
30
|
+
})
|
|
31
|
+
).toEqual({ width: 604, height: 1024 });
|
|
32
|
+
});
|
|
33
|
+
|
|
25
34
|
it('does not reuse the wallpaper homeScreenType for Pro 2 NFT dimensions', () => {
|
|
26
35
|
expect(
|
|
27
36
|
getHomeScreenSize({
|
|
@@ -49,6 +58,14 @@ describe('getNftSize', () => {
|
|
|
49
58
|
});
|
|
50
59
|
});
|
|
51
60
|
|
|
61
|
+
it('uses the Protocol V2 NFT dimensions for Neo', () => {
|
|
62
|
+
expect(getNftSize({ deviceType: EDeviceType.Neo })).toEqual({ width: 540, height: 540 });
|
|
63
|
+
expect(getNftSize({ deviceType: EDeviceType.Neo, thumbnail: true })).toEqual({
|
|
64
|
+
width: 263,
|
|
65
|
+
height: 263,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
52
69
|
it('preserves the legacy NFT dimensions', () => {
|
|
53
70
|
expect(getNftSize({ deviceType: EDeviceType.Touch })).toEqual({ width: 480, height: 800 });
|
|
54
71
|
expect(getNftSize({ deviceType: EDeviceType.Touch, thumbnail: true })).toEqual({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import { BaseMethod } from '../src/api/BaseMethod';
|
|
4
|
-
import { findMethod } from '../src/api/utils';
|
|
4
|
+
import { findMethod, getMethodSupportedProtocols } from '../src/api/utils';
|
|
5
5
|
import BTCGetAddress from '../src/api/btc/BTCGetAddress';
|
|
6
6
|
import DeviceReboot from '../src/api/protocol-v2/DeviceReboot';
|
|
7
7
|
import SolGetAddress from '../src/api/solana/SolGetAddress';
|
|
@@ -129,4 +129,16 @@ describe('method protocol support', () => {
|
|
|
129
129
|
expect(bitcoin.getVersionRange().pro2).toBeUndefined();
|
|
130
130
|
expect(neurai.getVersionRange().pro2).toBeUndefined();
|
|
131
131
|
});
|
|
132
|
+
|
|
133
|
+
test('exposes the dispatcher protocol contract for callers that need a preflight', () => {
|
|
134
|
+
expect(getMethodSupportedProtocols('solGetAddress')).toEqual(['V1', 'V2']);
|
|
135
|
+
expect(getMethodSupportedProtocols('stellarGetAddress')).toEqual(['V1']);
|
|
136
|
+
expect(
|
|
137
|
+
getMethodSupportedProtocols('btcGetAddress', {
|
|
138
|
+
path: "m/44'/1900'/0'/0/0",
|
|
139
|
+
coin: 'Neurai',
|
|
140
|
+
showOnOneKey: false,
|
|
141
|
+
})
|
|
142
|
+
).toEqual(['V1']);
|
|
143
|
+
});
|
|
132
144
|
});
|