@onekeyfe/hd-core 1.2.0-alpha.20 → 1.2.0-alpha.22

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.
Files changed (226) hide show
  1. package/__tests__/DeviceCommands.test.ts +87 -2
  2. package/__tests__/connectSettings.test.ts +47 -5
  3. package/__tests__/device-identity.test.ts +24 -2
  4. package/__tests__/device-lifecycle-events.test.ts +1 -1
  5. package/__tests__/device-settings.test.ts +111 -6
  6. package/__tests__/device-state-events.test.ts +3 -3
  7. package/__tests__/device-state-mapper.test.ts +15 -3
  8. package/__tests__/device-state-store.test.ts +1 -1
  9. package/__tests__/device-wallet-session-store.test.ts +111 -7
  10. package/__tests__/deviceSettings.test.ts +55 -15
  11. package/__tests__/evmLedgerLegacySafety.test.ts +6 -5
  12. package/__tests__/firmware-update/firmware-artifact-source.test.ts +119 -0
  13. package/__tests__/firmware-update/firmware-host-binding.test.ts +70 -0
  14. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
  15. package/__tests__/firmware-update/firmware-update-plan.test.ts +326 -0
  16. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +200 -0
  17. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +39 -30
  18. package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
  19. package/__tests__/get-device-state.test.ts +7 -0
  20. package/__tests__/open-wallet-session.test.ts +253 -13
  21. package/__tests__/pro2Wallpaper.test.ts +7 -18
  22. package/__tests__/protocol-v2-unlock-policy.test.ts +45 -0
  23. package/__tests__/protocol-v2.test.ts +439 -282
  24. package/__tests__/public-device-state-api.test.ts +79 -68
  25. package/__tests__/public-pro2-api-boundary.test.ts +22 -29
  26. package/dist/api/BaseMethod.d.ts +2 -4
  27. package/dist/api/BaseMethod.d.ts.map +1 -1
  28. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  29. package/dist/api/ClearSessionCache.d.ts.map +1 -1
  30. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  31. package/dist/api/FirmwareUpdateV2.d.ts +11 -0
  32. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  33. package/dist/api/FirmwareUpdateV3.d.ts +7 -3
  34. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  35. package/dist/api/FirmwareUpdateV4.d.ts +29 -10
  36. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  37. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  38. package/dist/api/UploadPortfolio.d.ts +0 -1
  39. package/dist/api/UploadPortfolio.d.ts.map +1 -1
  40. package/dist/api/conflux/ConfluxGetAddress.d.ts +1 -0
  41. package/dist/api/conflux/ConfluxGetAddress.d.ts.map +1 -1
  42. package/dist/api/conflux/ConfluxSignMessage.d.ts +1 -0
  43. package/dist/api/conflux/ConfluxSignMessage.d.ts.map +1 -1
  44. package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts +1 -0
  45. package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts.map +1 -1
  46. package/dist/api/conflux/ConfluxSignTransaction.d.ts +1 -0
  47. package/dist/api/conflux/ConfluxSignTransaction.d.ts.map +1 -1
  48. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  49. package/dist/api/device/DeviceUpdateBootloader.d.ts +5 -1
  50. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  51. package/dist/api/firmware/FirmwareArtifactSource.d.ts +26 -0
  52. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -0
  53. package/dist/api/firmware/FirmwareHostBinding.d.ts +6 -0
  54. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -0
  55. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +7 -0
  56. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  57. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +3 -0
  58. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +1 -0
  59. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +24 -0
  60. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -0
  61. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +25 -0
  62. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
  63. package/dist/api/firmware/getBinary.d.ts +7 -0
  64. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  65. package/dist/api/firmware/updateBootloader.d.ts +2 -0
  66. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  67. package/dist/api/firmware/uploadFirmware.d.ts +9 -1
  68. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  69. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  70. package/dist/api/index.d.ts +0 -20
  71. package/dist/api/index.d.ts.map +1 -1
  72. package/dist/api/nexa/NexaSignTransaction.d.ts +1 -0
  73. package/dist/api/nexa/NexaSignTransaction.d.ts.map +1 -1
  74. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  75. package/dist/core/RequestQueue.d.ts +1 -19
  76. package/dist/core/RequestQueue.d.ts.map +1 -1
  77. package/dist/core/index.d.ts +0 -1
  78. package/dist/core/index.d.ts.map +1 -1
  79. package/dist/data-manager/DataManager.d.ts +1 -0
  80. package/dist/data-manager/DataManager.d.ts.map +1 -1
  81. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  82. package/dist/device/Device.d.ts +1 -1
  83. package/dist/device/Device.d.ts.map +1 -1
  84. package/dist/device/DeviceCommands.d.ts.map +1 -1
  85. package/dist/device/DeviceFeaturesState.d.ts +0 -1
  86. package/dist/device/DeviceFeaturesState.d.ts.map +1 -1
  87. package/dist/device/DeviceStateMapper.d.ts.map +1 -1
  88. package/dist/device/DeviceStateProjector.d.ts.map +1 -1
  89. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  90. package/dist/events/call.d.ts +0 -7
  91. package/dist/events/call.d.ts.map +1 -1
  92. package/dist/events/core.d.ts +2 -2
  93. package/dist/events/core.d.ts.map +1 -1
  94. package/dist/events/iframe.d.ts +0 -1
  95. package/dist/events/iframe.d.ts.map +1 -1
  96. package/dist/events/logBlockEvent.d.ts.map +1 -1
  97. package/dist/index.d.ts +320 -277
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +3210 -1856
  100. package/dist/inject.d.ts +2 -3
  101. package/dist/inject.d.ts.map +1 -1
  102. package/dist/lowLevelInject.d.ts +1 -2
  103. package/dist/lowLevelInject.d.ts.map +1 -1
  104. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
  105. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +4 -0
  106. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -0
  107. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
  108. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  109. package/dist/topLevelInject.d.ts.map +1 -1
  110. package/dist/types/api/checkAllFirmwareRelease.d.ts +3 -0
  111. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  112. package/dist/types/api/deviceSettings.d.ts +2 -2
  113. package/dist/types/api/deviceSettings.d.ts.map +1 -1
  114. package/dist/types/api/deviceUpdateBootloader.d.ts +6 -0
  115. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  116. package/dist/types/api/export.d.ts +4 -1
  117. package/dist/types/api/export.d.ts.map +1 -1
  118. package/dist/types/api/firmwareUpdate.d.ts +69 -0
  119. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  120. package/dist/types/api/firmwareUpdateCapabilities.d.ts +9 -0
  121. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +1 -0
  122. package/dist/types/api/firmwareUpdatePlan.d.ts +27 -0
  123. package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -0
  124. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +42 -0
  125. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +1 -0
  126. package/dist/types/api/index.d.ts +10 -23
  127. package/dist/types/api/index.d.ts.map +1 -1
  128. package/dist/types/api/openWalletSession.d.ts +1 -0
  129. package/dist/types/api/openWalletSession.d.ts.map +1 -1
  130. package/dist/types/api/protocolV2.d.ts +3 -84
  131. package/dist/types/api/protocolV2.d.ts.map +1 -1
  132. package/dist/types/api/sessionCache.d.ts +4 -1
  133. package/dist/types/api/sessionCache.d.ts.map +1 -1
  134. package/dist/types/device.d.ts +4 -4
  135. package/dist/types/device.d.ts.map +1 -1
  136. package/dist/types/settings.d.ts +13 -0
  137. package/dist/types/settings.d.ts.map +1 -1
  138. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  139. package/dist/utils/deviceSettings.d.ts +36 -7
  140. package/dist/utils/deviceSettings.d.ts.map +1 -1
  141. package/dist/utils/index.d.ts +2 -1
  142. package/dist/utils/index.d.ts.map +1 -1
  143. package/dist/utils/patch.d.ts +1 -1
  144. package/dist/utils/patch.d.ts.map +1 -1
  145. package/package.json +4 -4
  146. package/src/api/BaseMethod.ts +11 -12
  147. package/src/api/CheckAllFirmwareRelease.ts +16 -3
  148. package/src/api/ClearSessionCache.ts +4 -0
  149. package/src/api/FirmwareUpdate.ts +8 -1
  150. package/src/api/FirmwareUpdateV2.ts +284 -119
  151. package/src/api/FirmwareUpdateV3.ts +248 -55
  152. package/src/api/FirmwareUpdateV4.ts +816 -328
  153. package/src/api/OpenWalletSession.ts +74 -25
  154. package/src/api/UploadPortfolio.ts +3 -13
  155. package/src/api/conflux/ConfluxGetAddress.ts +2 -0
  156. package/src/api/conflux/ConfluxSignMessage.ts +2 -0
  157. package/src/api/conflux/ConfluxSignMessageCIP23.ts +2 -0
  158. package/src/api/conflux/ConfluxSignTransaction.ts +2 -0
  159. package/src/api/device/DeviceChangePin.ts +1 -1
  160. package/src/api/device/DeviceSettings.ts +66 -5
  161. package/src/api/device/DeviceUpdateBootloader.ts +114 -6
  162. package/src/api/device/DeviceWipe.ts +1 -1
  163. package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
  164. package/src/api/firmware/FirmwareHostBinding.ts +100 -0
  165. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +50 -0
  166. package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
  167. package/src/api/firmware/FirmwareUpdatePlan.ts +621 -0
  168. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +378 -0
  169. package/src/api/firmware/updateBootloader.ts +19 -4
  170. package/src/api/firmware/uploadFirmware.ts +140 -22
  171. package/src/api/helpers/protocolV2FileWrite.ts +6 -0
  172. package/src/api/index.ts +0 -21
  173. package/src/api/nexa/NexaSignTransaction.ts +2 -0
  174. package/src/api/protocol-v2/DeviceUploadWallpaper.ts +1 -1
  175. package/src/core/RequestQueue.ts +4 -123
  176. package/src/core/index.ts +25 -31
  177. package/src/data/messages/messages-protocol-v2.json +77 -4
  178. package/src/data-manager/DataManager.ts +33 -33
  179. package/src/data-manager/connectSettings.ts +11 -0
  180. package/src/device/Device.ts +51 -61
  181. package/src/device/DeviceCommands.ts +58 -14
  182. package/src/device/DeviceFeaturesState.ts +0 -9
  183. package/src/device/DeviceStateMapper.ts +26 -8
  184. package/src/device/DeviceStateProjector.ts +7 -1
  185. package/src/deviceProfile/buildDeviceFeatures.ts +2 -1
  186. package/src/events/call.ts +0 -6
  187. package/src/events/core.ts +0 -2
  188. package/src/events/iframe.ts +0 -1
  189. package/src/events/logBlockEvent.ts +1 -0
  190. package/src/index.ts +5 -4
  191. package/src/inject.ts +22 -35
  192. package/src/lowLevelInject.ts +5 -4
  193. package/src/protocols/protocol-v2/deviceSession.ts +1 -1
  194. package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +2 -2
  195. package/src/protocols/protocol-v2/unlockPolicy.ts +105 -0
  196. package/src/protocols/protocol-v2/unlockRetry.ts +1 -3
  197. package/src/protocols/protocol-v2/walletSession.ts +68 -12
  198. package/src/topLevelInject.ts +5 -3
  199. package/src/types/api/checkAllFirmwareRelease.ts +3 -0
  200. package/src/types/api/deviceSettings.ts +17 -2
  201. package/src/types/api/deviceUpdateBootloader.ts +6 -0
  202. package/src/types/api/export.ts +18 -0
  203. package/src/types/api/firmwareUpdate.ts +76 -0
  204. package/src/types/api/firmwareUpdateCapabilities.ts +9 -0
  205. package/src/types/api/firmwareUpdatePlan.ts +36 -0
  206. package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
  207. package/src/types/api/index.ts +14 -41
  208. package/src/types/api/openWalletSession.ts +2 -0
  209. package/src/types/api/protocolV2.ts +3 -187
  210. package/src/types/api/sessionCache.ts +9 -4
  211. package/src/types/device.ts +5 -3
  212. package/src/types/settings.ts +13 -0
  213. package/src/utils/deviceFeaturesUtils.ts +5 -1
  214. package/src/utils/deviceSettings.ts +130 -56
  215. package/src/utils/index.ts +18 -1
  216. package/__tests__/RequestQueue.test.ts +0 -140
  217. package/__tests__/UploadPortfolio.test.ts +0 -46
  218. package/dist/api/protocol-v2/DeviceSettingsGet.d.ts +0 -6
  219. package/dist/api/protocol-v2/DeviceSettingsGet.d.ts.map +0 -1
  220. package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts +0 -16
  221. package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts.map +0 -1
  222. package/dist/api/protocol-v2/DeviceSettingsSet.d.ts +0 -12
  223. package/dist/api/protocol-v2/DeviceSettingsSet.d.ts.map +0 -1
  224. package/src/api/protocol-v2/DeviceSettingsGet.ts +0 -18
  225. package/src/api/protocol-v2/DeviceSettingsPageShow.ts +0 -70
  226. package/src/api/protocol-v2/DeviceSettingsSet.ts +0 -44
@@ -0,0 +1,200 @@
1
+ import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
2
+
3
+ import { buildFirmwareUpdatePlan } from '../../src/api/firmware/FirmwareUpdatePlan';
4
+ import {
5
+ assertFirmwareUpdatePreparedPlanBinding,
6
+ prepareFirmwareUpdatePlan,
7
+ validateFirmwareUpdatePreparedPlan,
8
+ } from '../../src/api/firmware/FirmwareUpdatePreparedPlan';
9
+
10
+ import type { Features } from '../../src/types';
11
+
12
+ const buildPlan = () =>
13
+ buildFirmwareUpdatePlan({
14
+ features: {
15
+ deviceType: EDeviceType.Classic1s,
16
+ serialNo: 'classic1s-device-id',
17
+ firmwareVersion: '1.0.0',
18
+ bootloaderVersion: '1.0.0',
19
+ } as Features,
20
+ firmwareType: EFirmwareType.Universal,
21
+ platform: 'native',
22
+ firmware: {
23
+ status: 'outdated',
24
+ release: {
25
+ url: 'https://firmware.onekey.so/classic/firmware.bin',
26
+ expectedSize: 4,
27
+ fingerprint: 'a'.repeat(64),
28
+ version: [3, 0, 0],
29
+ resource: 'https://firmware.onekey.so/classic/resource.zip',
30
+ resourceExpectedSize: 8,
31
+ resourceFingerprint: 'b'.repeat(64),
32
+ },
33
+ },
34
+ ble: {
35
+ status: 'valid',
36
+ release: undefined,
37
+ },
38
+ bootloader: {
39
+ status: 'valid',
40
+ release: undefined,
41
+ },
42
+ });
43
+
44
+ const artifact = (sha256: string, size: number) => ({
45
+ artifactRef: `fw:${sha256}`,
46
+ size,
47
+ sha256,
48
+ });
49
+
50
+ describe('FirmwareUpdatePreparedPlan', () => {
51
+ test('binds all receipts into a URL-free, network-forbidden plan', () => {
52
+ const plan = buildPlan();
53
+ const prepared = prepareFirmwareUpdatePlan({
54
+ plan,
55
+ leaseRef: 'fwlease:00000000-0000-4000-8000-000000000001',
56
+ artifacts: [
57
+ {
58
+ artifactId: 'firmware',
59
+ artifact: artifact('a'.repeat(64), 4),
60
+ },
61
+ {
62
+ artifactId: 'resource',
63
+ artifact: artifact('b'.repeat(64), 8),
64
+ materializedEntries: [
65
+ {
66
+ entryName: 'resource/index.bin',
67
+ artifact: artifact('c'.repeat(64), 2),
68
+ },
69
+ ],
70
+ },
71
+ ],
72
+ });
73
+
74
+ expect(prepared.networkPolicy).toBe('forbid');
75
+ expect(prepared.planDigest).toBe(plan.planDigest);
76
+ expect(prepared.preparedPlanDigest).toMatch(/^[a-f0-9]{64}$/u);
77
+ expect(JSON.stringify(prepared)).not.toContain('https://');
78
+ expect(validateFirmwareUpdatePreparedPlan(prepared)).toEqual(prepared);
79
+ expect(
80
+ assertFirmwareUpdatePreparedPlanBinding({
81
+ preparedPlan: prepared,
82
+ executor: 'v2',
83
+ platform: 'native',
84
+ scopeTargets: ['firmware', 'resource'],
85
+ bindings: [
86
+ {
87
+ target: 'firmware',
88
+ artifact: artifact('a'.repeat(64), 4),
89
+ },
90
+ {
91
+ target: 'resource',
92
+ entryName: 'resource/index.bin',
93
+ artifact: artifact('c'.repeat(64), 2),
94
+ },
95
+ ],
96
+ })
97
+ ).toEqual(prepared);
98
+ expect(() =>
99
+ assertFirmwareUpdatePreparedPlanBinding({
100
+ preparedPlan: prepared,
101
+ executor: 'v2',
102
+ platform: 'native',
103
+ scopeTargets: ['firmware'],
104
+ bindings: [
105
+ {
106
+ target: 'firmware',
107
+ artifact: artifact('b'.repeat(64), 8),
108
+ },
109
+ ],
110
+ })
111
+ ).toThrow('artifact binding is invalid');
112
+ });
113
+
114
+ test('rejects receipt drift and a tampered update plan digest', () => {
115
+ const plan = buildPlan();
116
+ expect(() =>
117
+ prepareFirmwareUpdatePlan({
118
+ plan,
119
+ leaseRef: 'fwlease:00000000-0000-4000-8000-000000000001',
120
+ artifacts: [
121
+ {
122
+ artifactId: 'firmware',
123
+ artifact: artifact('d'.repeat(64), 4),
124
+ },
125
+ {
126
+ artifactId: 'resource',
127
+ artifact: artifact('b'.repeat(64), 8),
128
+ materializedEntries: [
129
+ {
130
+ entryName: 'resource/index.bin',
131
+ artifact: artifact('c'.repeat(64), 2),
132
+ },
133
+ ],
134
+ },
135
+ ],
136
+ })
137
+ ).toThrow('receipt does not match');
138
+
139
+ expect(() =>
140
+ prepareFirmwareUpdatePlan({
141
+ plan: { ...plan, planDigest: 'f'.repeat(64) },
142
+ leaseRef: 'fwlease:00000000-0000-4000-8000-000000000001',
143
+ artifacts: [],
144
+ })
145
+ ).toThrow('plan digest is invalid');
146
+ });
147
+
148
+ test('projects portable archive paths to unique device resource names', () => {
149
+ const plan = buildPlan();
150
+ const buildArtifacts = (entryNames: string[]) => [
151
+ {
152
+ artifactId: 'firmware',
153
+ artifact: artifact('a'.repeat(64), 4),
154
+ },
155
+ {
156
+ artifactId: 'resource',
157
+ artifact: artifact('b'.repeat(64), 8),
158
+ materializedEntries: entryNames.map((entryName, index) => ({
159
+ entryName,
160
+ artifact: artifact(String(index + 1).repeat(64), 2),
161
+ })),
162
+ },
163
+ ];
164
+
165
+ expect(() =>
166
+ prepareFirmwareUpdatePlan({
167
+ plan,
168
+ leaseRef: 'fwlease:00000000-0000-4000-8000-000000000001',
169
+ artifacts: buildArtifacts(['icons/index.bin', 'fonts/index.bin']),
170
+ })
171
+ ).toThrow('duplicate entry names');
172
+ expect(() =>
173
+ prepareFirmwareUpdatePlan({
174
+ plan,
175
+ leaseRef: 'fwlease:00000000-0000-4000-8000-000000000001',
176
+ artifacts: buildArtifacts(['../index.bin']),
177
+ })
178
+ ).toThrow('entry name is invalid');
179
+ });
180
+
181
+ test('rejects unknown fields even when a caller presents a plan-shaped object', () => {
182
+ const plan = buildPlan();
183
+ expect(() =>
184
+ prepareFirmwareUpdatePlan({
185
+ plan: {
186
+ ...plan,
187
+ artifacts: [
188
+ {
189
+ ...plan.artifacts[0],
190
+ unexpectedUrl: 'https://attacker.invalid/payload',
191
+ },
192
+ plan.artifacts[1],
193
+ ],
194
+ } as typeof plan,
195
+ leaseRef: 'fwlease:00000000-0000-4000-8000-000000000001',
196
+ artifacts: [],
197
+ })
198
+ ).toThrow('invalid field set');
199
+ });
200
+ });
@@ -2,7 +2,7 @@ import { EDeviceType, EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shar
2
2
 
3
3
  import FirmwareUpdateV2 from '../../src/api/FirmwareUpdateV2';
4
4
  import { getBinary } from '../../src/api/firmware/getBinary';
5
- import { uploadFirmware } from '../../src/api/firmware/uploadFirmware';
5
+ import { uploadFirmwareFromSource } from '../../src/api/firmware/uploadFirmware';
6
6
  import * as utils from '../../src/utils';
7
7
 
8
8
  jest.mock('../../src/data/config', () => ({
@@ -18,7 +18,8 @@ jest.mock('../../src/api/firmware/getBinary', () => ({
18
18
 
19
19
  jest.mock('../../src/api/firmware/uploadFirmware', () => ({
20
20
  updateResources: jest.fn(),
21
- uploadFirmware: jest.fn(),
21
+ updateResourcesFromSources: jest.fn(),
22
+ uploadFirmwareFromSource: jest.fn(),
22
23
  }));
23
24
 
24
25
  jest.mock('../../src/device/DevicePool', () => ({
@@ -29,7 +30,9 @@ jest.mock('../../src/device/DevicePool', () => ({
29
30
  }));
30
31
 
31
32
  const mockGetBinary = getBinary as jest.MockedFunction<typeof getBinary>;
32
- const mockUploadFirmware = uploadFirmware as jest.MockedFunction<typeof uploadFirmware>;
33
+ const mockUploadFirmwareFromSource = uploadFirmwareFromSource as jest.MockedFunction<
34
+ typeof uploadFirmwareFromSource
35
+ >;
33
36
 
34
37
  type DeviceType = 'CLASSIC1S' | 'PURE';
35
38
 
@@ -175,7 +178,7 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
175
178
  expect(mockGetBinary).toHaveBeenCalledTimes(1);
176
179
  expectNoFirmwareMutationCalls(typedCall);
177
180
  expect(acquire).not.toHaveBeenCalled();
178
- expect(mockUploadFirmware).not.toHaveBeenCalled();
181
+ expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
179
182
  });
180
183
 
181
184
  it.each([
@@ -216,9 +219,11 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
216
219
  binary: firmwareBinary,
217
220
  } as Awaited<ReturnType<typeof getBinary>>);
218
221
  });
219
- mockUploadFirmware.mockImplementation(() => {
222
+ mockUploadFirmwareFromSource.mockImplementation(() => {
220
223
  callOrder.push('upload');
221
- return Promise.resolve(expectedResponse as Awaited<ReturnType<typeof uploadFirmware>>);
224
+ return Promise.resolve(
225
+ expectedResponse as Awaited<ReturnType<typeof uploadFirmwareFromSource>>
226
+ );
222
227
  });
223
228
  const { method, typedCall } = createMethod({
224
229
  updateType,
@@ -248,15 +253,15 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
248
253
  },
249
254
  })
250
255
  );
251
- expect(mockUploadFirmware).toHaveBeenCalledWith(
256
+ expect(mockUploadFirmwareFromSource).toHaveBeenCalledWith(
252
257
  updateType,
253
258
  expect.any(Function),
254
259
  expect.any(Function),
255
260
  method.device,
256
- {
257
- payload: firmwareBinary,
258
- rebootOnSuccess: true,
259
- },
261
+ expect.objectContaining({
262
+ size: firmwareBinary.byteLength,
263
+ }),
264
+ true,
260
265
  isUpdateBootloader
261
266
  );
262
267
  }
@@ -271,11 +276,11 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
271
276
  binary: firmwareBinary,
272
277
  } as Awaited<ReturnType<typeof getBinary>>);
273
278
  });
274
- mockUploadFirmware.mockImplementation(() => {
279
+ mockUploadFirmwareFromSource.mockImplementation(() => {
275
280
  callOrder.push('upload');
276
281
  return Promise.resolve({
277
282
  success: true,
278
- } as Awaited<ReturnType<typeof uploadFirmware>>);
283
+ } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>);
279
284
  });
280
285
  const { method, typedCall, acquire } = createMethod({
281
286
  bootloaderMode: true,
@@ -300,9 +305,9 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
300
305
  resolveDownload = resolve;
301
306
  })
302
307
  );
303
- mockUploadFirmware.mockResolvedValue({
308
+ mockUploadFirmwareFromSource.mockResolvedValue({
304
309
  success: true,
305
- } as Awaited<ReturnType<typeof uploadFirmware>>);
310
+ } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>);
306
311
  const { method, typedCall } = createMethod();
307
312
 
308
313
  const runPromise = method.run();
@@ -333,7 +338,7 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
333
338
 
334
339
  expectNoFirmwareMutationCalls(typedCall);
335
340
  expect(acquire).not.toHaveBeenCalled();
336
- expect(mockUploadFirmware).not.toHaveBeenCalled();
341
+ expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
337
342
  });
338
343
 
339
344
  it.each([
@@ -342,23 +347,23 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
342
347
  ])(
343
348
  'keeps the non-empty %s binary overload and never downloads it again',
344
349
  async (_kind, binary) => {
345
- mockUploadFirmware.mockResolvedValue({
350
+ mockUploadFirmwareFromSource.mockResolvedValue({
346
351
  success: true,
347
- } as Awaited<ReturnType<typeof uploadFirmware>>);
352
+ } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>);
348
353
  const { method } = createMethod({ binary });
349
354
 
350
355
  await method.run();
351
356
 
352
357
  expect(mockGetBinary).not.toHaveBeenCalled();
353
- expect(mockUploadFirmware).toHaveBeenCalledWith(
358
+ expect(mockUploadFirmwareFromSource).toHaveBeenCalledWith(
354
359
  'firmware',
355
360
  expect.any(Function),
356
361
  expect.any(Function),
357
362
  method.device,
358
- {
359
- payload: binary,
360
- rebootOnSuccess: true,
361
- },
363
+ expect.objectContaining({
364
+ size: binary.byteLength,
365
+ }),
366
+ true,
362
367
  undefined
363
368
  );
364
369
  }
@@ -369,17 +374,21 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
369
374
  ['DataView', new DataView(new Uint8Array([9, 3, 4, 9]).buffer, 1, 2), [3, 4]],
370
375
  ['custom Buffer', createCustomBuffer(4), [1, 2, 3, 4]],
371
376
  ])('normalizes a non-empty %s before rebooting', async (_kind, binary, expectedBytes) => {
372
- mockUploadFirmware.mockResolvedValue({
373
- success: true,
374
- } as Awaited<ReturnType<typeof uploadFirmware>>);
377
+ let uploadedBytes: number[] = [];
378
+ mockUploadFirmwareFromSource.mockImplementation(
379
+ async (_updateType, _typedCall, _postMessage, _device, source) => {
380
+ uploadedBytes = Array.from(new Uint8Array(await source.readAt(0, source.size)));
381
+ return {
382
+ success: true,
383
+ } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>;
384
+ }
385
+ );
375
386
  const { method } = createMethod({ binary });
376
387
 
377
388
  await method.run();
378
389
 
379
390
  expect(mockGetBinary).not.toHaveBeenCalled();
380
- const normalizedBinary = mockUploadFirmware.mock.calls[0][4].payload;
381
- expect(normalizedBinary).toBeInstanceOf(ArrayBuffer);
382
- expect(Array.from(new Uint8Array(normalizedBinary))).toEqual(expectedBytes);
391
+ expect(uploadedBytes).toEqual(expectedBytes);
383
392
  });
384
393
 
385
394
  it.each([
@@ -397,6 +406,6 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
397
406
  expect(mockGetBinary).not.toHaveBeenCalled();
398
407
  expectNoFirmwareMutationCalls(typedCall);
399
408
  expect(acquire).not.toHaveBeenCalled();
400
- expect(mockUploadFirmware).not.toHaveBeenCalled();
409
+ expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
401
410
  });
402
411
  });
@@ -0,0 +1,70 @@
1
+ import { EDeviceType } from '@onekeyfe/hd-shared';
2
+
3
+ import { uploadFirmwareFromSource } from '../../src/api/firmware/uploadFirmware';
4
+
5
+ import type { Device } from '../../src/device/Device';
6
+ import type { FirmwareByteSource } from '../../src/api/firmware/FirmwareArtifactSource';
7
+
8
+ jest.mock('../../src/data/config', () => ({
9
+ getSDKVersion: jest.fn(() => '1.0.0'),
10
+ DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
11
+ }));
12
+
13
+ describe('uploadFirmwareFromSource', () => {
14
+ it('serves legacy Touch firmware requests without materializing the complete artifact', async () => {
15
+ const size = 700 * 1024;
16
+ const requestedRanges: Array<{ offset: number; length: number }> = [];
17
+ const source: FirmwareByteSource = {
18
+ size,
19
+ readAt: jest.fn((offset: number, length: number) => {
20
+ requestedRanges.push({ offset, length });
21
+ return Promise.resolve(new ArrayBuffer(length));
22
+ }),
23
+ close: jest.fn(() => Promise.resolve()),
24
+ };
25
+ let nextOffset = 0;
26
+ const requestedLength = 128 * 1024;
27
+ const typedCall = jest.fn((type: string) => {
28
+ if (type === 'FirmwareErase') {
29
+ return Promise.resolve({
30
+ type: 'FirmwareRequest',
31
+ message: {
32
+ offset: nextOffset,
33
+ length: Math.min(requestedLength, size - nextOffset),
34
+ },
35
+ });
36
+ }
37
+ if (type === 'FirmwareUpload') {
38
+ nextOffset += Math.min(requestedLength, size - nextOffset);
39
+ if (nextOffset < size) {
40
+ return Promise.resolve({
41
+ type: 'FirmwareRequest',
42
+ message: {
43
+ offset: nextOffset,
44
+ length: Math.min(requestedLength, size - nextOffset),
45
+ },
46
+ });
47
+ }
48
+ return Promise.resolve({
49
+ type: 'Success',
50
+ message: { message: 'installed' },
51
+ });
52
+ }
53
+ return Promise.reject(new Error(`Unexpected command: ${type}`));
54
+ });
55
+ const device = {
56
+ features: undefined,
57
+ emit: jest.fn(),
58
+ getCurrentDeviceType: () => EDeviceType.Touch,
59
+ toMessageObject: () => ({}),
60
+ } as unknown as Device;
61
+
62
+ await expect(
63
+ uploadFirmwareFromSource('firmware', typedCall as never, jest.fn(), device, source)
64
+ ).resolves.toEqual({ message: 'installed' });
65
+
66
+ expect(requestedRanges).toHaveLength(Math.ceil(size / requestedLength));
67
+ expect(requestedRanges.every(({ length }) => length <= 256 * 1024)).toBe(true);
68
+ expect(requestedRanges.some(({ length }) => length === size)).toBe(false);
69
+ });
70
+ });
@@ -1,6 +1,7 @@
1
1
  import { HardwareErrorCode } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import { Device } from '../src/device/Device';
4
+ import { DEVICE } from '../src/events';
4
5
 
5
6
  jest.mock('../src/data/config', () => ({
6
7
  getSDKVersion: jest.fn(() => '1.0.0'),
@@ -167,6 +168,8 @@ describe('getDeviceState', () => {
167
168
  });
168
169
  const device = createV2Device(typedCall);
169
170
  device.updateState({ protocol: 'V2', status: { mode: 'normal' } }, 'initialize');
171
+ const onState = jest.fn();
172
+ device.on(DEVICE.STATE, onState);
170
173
 
171
174
  const state = await device.getDeviceState({ refreshSections: ['settings'] });
172
175
 
@@ -179,6 +182,10 @@ describe('getDeviceState', () => {
179
182
  expect(state.identity.label).toBe('Renamed Pro 2');
180
183
  expect(state.settings.language).toBe('ja-JP');
181
184
  expect(state.settings.brightness).toBe(70);
185
+ expect(onState).toHaveBeenCalledWith(
186
+ device,
187
+ expect.objectContaining({ source: 'settings-read' })
188
+ );
182
189
  });
183
190
 
184
191
  test('refreshes Protocol V2 status before settings in a combined read', async () => {