@onekeyfe/hd-core 1.2.0-alpha.1 → 1.2.0-alpha.11

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 (210) hide show
  1. package/__tests__/DeviceCommands.test.ts +25 -0
  2. package/__tests__/RequestQueue.test.ts +34 -0
  3. package/__tests__/connectSettings.test.ts +19 -0
  4. package/__tests__/device-wallet-session-store.test.ts +131 -0
  5. package/__tests__/preInitialize.test.ts +33 -0
  6. package/__tests__/pro2Wallpaper.test.ts +50 -0
  7. package/__tests__/protocol-v2-firmware-targets.test.ts +19 -0
  8. package/__tests__/protocol-v2.test.ts +3253 -1605
  9. package/dist/api/BaseMethod.d.ts +4 -0
  10. package/dist/api/BaseMethod.d.ts.map +1 -1
  11. package/dist/api/ClearSessionCache.d.ts +9 -0
  12. package/dist/api/ClearSessionCache.d.ts.map +1 -0
  13. package/dist/api/FileRead.d.ts.map +1 -1
  14. package/dist/api/FileWrite.d.ts.map +1 -1
  15. package/dist/api/FirmwareUpdateV4.d.ts +20 -3
  16. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  17. package/dist/api/GetPassphraseState.d.ts +1 -6
  18. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  19. package/dist/api/UploadPortfolio.d.ts +18 -0
  20. package/dist/api/UploadPortfolio.d.ts.map +1 -0
  21. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +1 -0
  22. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  23. package/dist/api/firmware/getBinary.d.ts +4 -0
  24. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  25. package/dist/api/firmware/progressThrottle.d.ts +3 -0
  26. package/dist/api/firmware/progressThrottle.d.ts.map +1 -0
  27. package/dist/api/index.d.ts +13 -10
  28. package/dist/api/index.d.ts.map +1 -1
  29. package/dist/api/protocol-v2/DeviceFactoryInfoGet.d.ts +6 -0
  30. package/dist/api/protocol-v2/DeviceFactoryInfoGet.d.ts.map +1 -0
  31. package/dist/api/protocol-v2/DeviceFactoryInfoSet.d.ts +7 -0
  32. package/dist/api/protocol-v2/DeviceFactoryInfoSet.d.ts.map +1 -0
  33. package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts +1 -1
  34. package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts.map +1 -1
  35. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts +3 -2
  36. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
  37. package/dist/api/protocol-v2/{DeviceGetDeviceInfo.d.ts → DeviceInfoGet.d.ts} +10 -10
  38. package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -0
  39. package/dist/api/protocol-v2/DeviceSessionGet.d.ts +6 -0
  40. package/dist/api/protocol-v2/DeviceSessionGet.d.ts.map +1 -0
  41. package/dist/api/protocol-v2/DeviceSettingsGet.d.ts +6 -0
  42. package/dist/api/protocol-v2/DeviceSettingsGet.d.ts.map +1 -0
  43. package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts +16 -0
  44. package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts.map +1 -0
  45. package/dist/api/protocol-v2/DeviceSettingsSet.d.ts +12 -0
  46. package/dist/api/protocol-v2/DeviceSettingsSet.d.ts.map +1 -0
  47. package/dist/api/protocol-v2/DeviceStatusGet.d.ts +6 -0
  48. package/dist/api/protocol-v2/DeviceStatusGet.d.ts.map +1 -0
  49. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +26 -0
  50. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -0
  51. package/dist/api/protocol-v2/FilesystemFormat.d.ts.map +1 -1
  52. package/dist/api/protocol-v2/{FilesystemFixPermission.d.ts → FilesystemPermissionFix.d.ts} +2 -2
  53. package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts.map +1 -0
  54. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts +6 -0
  55. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -0
  56. package/dist/api/protocol-v2/helpers.d.ts +27 -18
  57. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  58. package/dist/api/ton/TonSignData.d.ts +1 -5
  59. package/dist/api/ton/TonSignData.d.ts.map +1 -1
  60. package/dist/api/tron/TronSignMessage.d.ts +0 -1
  61. package/dist/api/tron/TronSignMessage.d.ts.map +1 -1
  62. package/dist/api/tron/TronSignTransaction.d.ts +0 -1
  63. package/dist/api/tron/TronSignTransaction.d.ts.map +1 -1
  64. package/dist/core/RequestQueue.d.ts +2 -0
  65. package/dist/core/RequestQueue.d.ts.map +1 -1
  66. package/dist/core/index.d.ts +1 -0
  67. package/dist/core/index.d.ts.map +1 -1
  68. package/dist/data-manager/DataManager.d.ts +1 -1
  69. package/dist/data-manager/DataManager.d.ts.map +1 -1
  70. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  71. package/dist/device/Device.d.ts +6 -3
  72. package/dist/device/Device.d.ts.map +1 -1
  73. package/dist/device/DeviceCommands.d.ts +4 -4
  74. package/dist/device/DeviceCommands.d.ts.map +1 -1
  75. package/dist/device/DeviceWalletSessionStore.d.ts +15 -0
  76. package/dist/device/DeviceWalletSessionStore.d.ts.map +1 -0
  77. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  78. package/dist/deviceProfile/buildDeviceProfile.d.ts.map +1 -1
  79. package/dist/events/call.d.ts +7 -0
  80. package/dist/events/call.d.ts.map +1 -1
  81. package/dist/events/core.d.ts +2 -2
  82. package/dist/events/core.d.ts.map +1 -1
  83. package/dist/events/iframe.d.ts +1 -0
  84. package/dist/events/iframe.d.ts.map +1 -1
  85. package/dist/index.d.ts +166 -70
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +2659 -1750
  88. package/dist/inject.d.ts +3 -2
  89. package/dist/inject.d.ts.map +1 -1
  90. package/dist/lowLevelInject.d.ts +2 -1
  91. package/dist/lowLevelInject.d.ts.map +1 -1
  92. package/dist/protocols/protocol-v2/features.d.ts +12 -14
  93. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  94. package/dist/protocols/protocol-v2/firmware.d.ts +11 -9
  95. package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
  96. package/dist/protocols/protocol-v2/index.d.ts +1 -0
  97. package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
  98. package/dist/protocols/protocol-v2/unlockRetry.d.ts +9 -0
  99. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -0
  100. package/dist/protocols/protocol-v2/walletSession.d.ts +13 -0
  101. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -0
  102. package/dist/topLevelInject.d.ts.map +1 -1
  103. package/dist/types/api/firmwareUpdate.d.ts +6 -6
  104. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  105. package/dist/types/api/getDeviceInfo.d.ts +2 -0
  106. package/dist/types/api/getDeviceInfo.d.ts.map +1 -1
  107. package/dist/types/api/getPassphraseState.d.ts +2 -10
  108. package/dist/types/api/getPassphraseState.d.ts.map +1 -1
  109. package/dist/types/api/index.d.ts +18 -12
  110. package/dist/types/api/index.d.ts.map +1 -1
  111. package/dist/types/api/protocolV2.d.ts +31 -17
  112. package/dist/types/api/protocolV2.d.ts.map +1 -1
  113. package/dist/types/api/sessionCache.d.ts +10 -0
  114. package/dist/types/api/sessionCache.d.ts.map +1 -0
  115. package/dist/types/device.d.ts +1 -0
  116. package/dist/types/device.d.ts.map +1 -1
  117. package/dist/types/params.d.ts +1 -0
  118. package/dist/types/params.d.ts.map +1 -1
  119. package/dist/types/settings.d.ts +21 -2
  120. package/dist/types/settings.d.ts.map +1 -1
  121. package/dist/utils/deviceFeaturesUtils.d.ts +2 -2
  122. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  123. package/dist/utils/index.d.ts +2 -0
  124. package/dist/utils/index.d.ts.map +1 -1
  125. package/dist/utils/patch.d.ts +1 -1
  126. package/dist/utils/patch.d.ts.map +1 -1
  127. package/dist/utils/pro2Wallpaper.d.ts +12 -0
  128. package/dist/utils/pro2Wallpaper.d.ts.map +1 -0
  129. package/package.json +4 -4
  130. package/src/api/BaseMethod.ts +18 -0
  131. package/src/api/ClearSessionCache.ts +28 -0
  132. package/src/api/FileRead.ts +16 -3
  133. package/src/api/FileWrite.ts +22 -1
  134. package/src/api/FirmwareUpdateV4.ts +1006 -265
  135. package/src/api/GetOnekeyFeatures.ts +1 -1
  136. package/src/api/GetPassphraseState.ts +9 -15
  137. package/src/api/UploadPortfolio.ts +37 -0
  138. package/src/api/device/DeviceRebootToBoardloader.ts +4 -4
  139. package/src/api/device/DeviceRebootToBootloader.ts +4 -4
  140. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +18 -4
  141. package/src/api/firmware/progressThrottle.ts +44 -0
  142. package/src/api/index.ts +13 -10
  143. package/src/api/protocol-v2/{FactoryGetDeviceInfo.ts → DeviceFactoryInfoGet.ts} +3 -3
  144. package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +32 -0
  145. package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +3 -5
  146. package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +39 -5
  147. package/src/api/protocol-v2/{DeviceGetDeviceInfo.ts → DeviceInfoGet.ts} +52 -22
  148. package/src/api/protocol-v2/DeviceReboot.ts +1 -1
  149. package/src/api/protocol-v2/DeviceSessionGet.ts +15 -0
  150. package/src/api/protocol-v2/{DeviceGetOnboardingStatus.ts → DeviceSettingsGet.ts} +3 -3
  151. package/src/api/protocol-v2/DeviceSettingsPageShow.ts +59 -0
  152. package/src/api/protocol-v2/DeviceSettingsSet.ts +39 -0
  153. package/src/api/protocol-v2/DeviceStatusGet.ts +14 -0
  154. package/src/api/protocol-v2/DeviceUploadWallpaper.ts +160 -0
  155. package/src/api/protocol-v2/FilesystemFormat.ts +4 -1
  156. package/src/api/protocol-v2/{FilesystemFixPermission.ts → FilesystemPermissionFix.ts} +2 -2
  157. package/src/api/protocol-v2/{GetProtoVersion.ts → ProtocolInfoRequest.ts} +2 -2
  158. package/src/api/protocol-v2/helpers.ts +71 -47
  159. package/src/api/ton/TonSignData.ts +1 -5
  160. package/src/api/tron/TronSignMessage.ts +0 -1
  161. package/src/api/tron/TronSignTransaction.ts +0 -1
  162. package/src/core/RequestQueue.ts +19 -0
  163. package/src/core/index.ts +29 -6
  164. package/src/data/messages/messages-protocol-v2.json +760 -1110
  165. package/src/data/messages/messages.json +8 -0
  166. package/src/data-manager/DataManager.ts +7 -0
  167. package/src/data-manager/connectSettings.ts +2 -4
  168. package/src/device/Device.ts +103 -70
  169. package/src/device/DeviceCommands.ts +9 -3
  170. package/src/device/DeviceWalletSessionStore.ts +78 -0
  171. package/src/deviceProfile/buildDeviceFeatures.ts +60 -63
  172. package/src/deviceProfile/buildDeviceProfile.ts +77 -58
  173. package/src/events/call.ts +6 -0
  174. package/src/events/core.ts +2 -0
  175. package/src/events/iframe.ts +1 -0
  176. package/src/index.ts +4 -0
  177. package/src/inject.ts +26 -16
  178. package/src/lowLevelInject.ts +3 -0
  179. package/src/protocols/protocol-v2/features.ts +26 -63
  180. package/src/protocols/protocol-v2/firmware.ts +12 -36
  181. package/src/protocols/protocol-v2/index.ts +1 -0
  182. package/src/protocols/protocol-v2/unlockRetry.ts +46 -0
  183. package/src/protocols/protocol-v2/walletSession.ts +92 -0
  184. package/src/topLevelInject.ts +2 -0
  185. package/src/types/api/firmwareUpdate.ts +28 -20
  186. package/src/types/api/getDeviceInfo.ts +2 -0
  187. package/src/types/api/getPassphraseState.ts +2 -11
  188. package/src/types/api/index.ts +29 -21
  189. package/src/types/api/protocolV2.ts +74 -35
  190. package/src/types/api/sessionCache.ts +14 -0
  191. package/src/types/device.ts +1 -0
  192. package/src/types/params.ts +4 -0
  193. package/src/types/settings.ts +42 -35
  194. package/src/utils/deviceFeaturesUtils.ts +46 -20
  195. package/src/utils/index.ts +6 -0
  196. package/src/utils/pro2Wallpaper.ts +111 -0
  197. package/dist/api/protocol-v2/DevReboot.d.ts +0 -7
  198. package/dist/api/protocol-v2/DevReboot.d.ts.map +0 -1
  199. package/dist/api/protocol-v2/DeviceGetDeviceInfo.d.ts.map +0 -1
  200. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts +0 -6
  201. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts.map +0 -1
  202. package/dist/api/protocol-v2/FactoryDeviceInfoSettings.d.ts +0 -7
  203. package/dist/api/protocol-v2/FactoryDeviceInfoSettings.d.ts.map +0 -1
  204. package/dist/api/protocol-v2/FactoryGetDeviceInfo.d.ts +0 -6
  205. package/dist/api/protocol-v2/FactoryGetDeviceInfo.d.ts.map +0 -1
  206. package/dist/api/protocol-v2/FilesystemFixPermission.d.ts.map +0 -1
  207. package/dist/api/protocol-v2/GetProtoVersion.d.ts +0 -6
  208. package/dist/api/protocol-v2/GetProtoVersion.d.ts.map +0 -1
  209. package/src/api/protocol-v2/DevReboot.ts +0 -24
  210. package/src/api/protocol-v2/FactoryDeviceInfoSettings.ts +0 -29
@@ -0,0 +1,59 @@
1
+ import { DeviceSettingsPage } from '@onekeyfe/hd-transport';
2
+
3
+ import { BaseMethod } from '../BaseMethod';
4
+ import { invalidParameter } from '../helpers/filesystemValidation';
5
+
6
+ export type SupportedDeviceSettingsPage = DeviceSettingsPage;
7
+
8
+ export type DeviceSettingsPageShowParams = {
9
+ page?:
10
+ | SupportedDeviceSettingsPage
11
+ | 'DeviceReset'
12
+ | 'DevicePinChange'
13
+ | 'DevicePassphrase'
14
+ | 'DeviceAirgap';
15
+ fieldName?: string;
16
+ field_name?: string;
17
+ };
18
+
19
+ const SUPPORTED_PAGES = new Set<number>([
20
+ DeviceSettingsPage.DeviceReset,
21
+ DeviceSettingsPage.DevicePinChange,
22
+ DeviceSettingsPage.DevicePassphrase,
23
+ DeviceSettingsPage.DeviceAirgap,
24
+ ]);
25
+
26
+ function normalizePage(value: DeviceSettingsPageShowParams['page']): SupportedDeviceSettingsPage {
27
+ const page = typeof value === 'string' ? DeviceSettingsPage[value] : value;
28
+ if (page !== undefined && SUPPORTED_PAGES.has(page)) {
29
+ return page as SupportedDeviceSettingsPage;
30
+ }
31
+ throw invalidParameter(
32
+ 'Parameter [page] must be DeviceReset, DevicePinChange, DevicePassphrase, or DeviceAirgap.'
33
+ );
34
+ }
35
+
36
+ export default class DeviceSettingsPageShow extends BaseMethod<{
37
+ page: SupportedDeviceSettingsPage;
38
+ field_name?: string;
39
+ }> {
40
+ init() {
41
+ this.requireProtocolV2 = true;
42
+ this.unlockPolicy = 'retry-on-locked';
43
+ this.skipForceUpdateCheck = true;
44
+ this.useDevicePassphraseState = false;
45
+ this.params = {
46
+ page: normalizePage(this.payload.page),
47
+ field_name: this.payload.field_name ?? this.payload.fieldName,
48
+ };
49
+ }
50
+
51
+ async run() {
52
+ const res = await this.device.commands.typedCall(
53
+ 'DeviceSettingsPageShow',
54
+ 'Success',
55
+ this.params
56
+ );
57
+ return Promise.resolve(res.message);
58
+ }
59
+ }
@@ -0,0 +1,39 @@
1
+ import { BaseMethod } from '../BaseMethod';
2
+ import { invalidParameter } from '../helpers/filesystemValidation';
3
+
4
+ import type { DeviceSettings } from '@onekeyfe/hd-transport';
5
+
6
+ export type DeviceSettingsSetParams = {
7
+ settings?: Omit<DeviceSettings, 'passphrase_enable' | 'airgap_mode'>;
8
+ };
9
+
10
+ export default class DeviceSettingsSet extends BaseMethod<{
11
+ settings: Omit<DeviceSettings, 'passphrase_enable' | 'airgap_mode'>;
12
+ }> {
13
+ init() {
14
+ const settings = this.payload.settings;
15
+ if (!settings || typeof settings !== 'object' || Array.isArray(settings)) {
16
+ throw invalidParameter('Parameter [settings] must be an object.');
17
+ }
18
+
19
+ const {
20
+ passphrase_enable: _passphraseEnable,
21
+ airgap_mode: _airgapMode,
22
+ ...supported
23
+ } = settings as DeviceSettings;
24
+ if (Object.keys(supported).length === 0) {
25
+ throw invalidParameter('Parameter [settings] must contain at least one supported setting.');
26
+ }
27
+
28
+ this.requireProtocolV2 = true;
29
+ this.unlockPolicy = 'retry-on-locked';
30
+ this.skipForceUpdateCheck = true;
31
+ this.useDevicePassphraseState = false;
32
+ this.params = { settings: supported };
33
+ }
34
+
35
+ async run() {
36
+ const res = await this.device.commands.typedCall('DeviceSettingsSet', 'Success', this.params);
37
+ return Promise.resolve(res.message);
38
+ }
39
+ }
@@ -0,0 +1,14 @@
1
+ import { BaseMethod } from '../BaseMethod';
2
+
3
+ export default class DeviceStatusGet extends BaseMethod {
4
+ init() {
5
+ this.requireProtocolV2 = true;
6
+ this.useDevicePassphraseState = false;
7
+ this.skipForceUpdateCheck = true;
8
+ }
9
+
10
+ async run() {
11
+ const { message } = await this.device.commands.typedCall('DeviceStatusGet', 'DeviceStatus', {});
12
+ return message;
13
+ }
14
+ }
@@ -0,0 +1,160 @@
1
+ import { blake2s } from '@noble/hashes/blake2s';
2
+ import { bytesToHex } from '@noble/hashes/utils';
3
+ import {
4
+ PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
5
+ PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE,
6
+ WallpaperTarget,
7
+ } from '@onekeyfe/hd-transport';
8
+
9
+ import { BaseMethod } from '../BaseMethod';
10
+ import { invalidParameter } from '../helpers/filesystemValidation';
11
+ import { DataManager } from '../../data-manager';
12
+ import {
13
+ encodePro2Wallpaper,
14
+ PRO2_WALLPAPER_HEIGHT,
15
+ PRO2_WALLPAPER_WIDTH,
16
+ type Pro2WallpaperColorFormat,
17
+ } from '../../utils/pro2Wallpaper';
18
+
19
+ export type DeviceUploadWallpaperParams = {
20
+ width: number;
21
+ height: number;
22
+ rgba: Uint8Array | ArrayBuffer;
23
+ fileName?: string;
24
+ chunkSize?: number;
25
+ };
26
+
27
+ export type DeviceUploadWallpaperResponse = {
28
+ path: string;
29
+ size: number;
30
+ colorFormat: Pro2WallpaperColorFormat;
31
+ message?: string;
32
+ };
33
+
34
+ const WALLPAPER_DIRECTORY = 'vol0:/wallpapers/user';
35
+ const SAFE_FILE_NAME = /^[A-Za-z0-9_-]+(?:\.bin)?$/;
36
+
37
+ function getDefaultChunkSize(): number {
38
+ const env = DataManager.getSettings('env');
39
+ return env && DataManager.isBleConnect(env)
40
+ ? PROTOCOL_V2_BLE_FILE_CHUNK_SIZE
41
+ : PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
42
+ }
43
+
44
+ function normalizeFileName(fileName: string | undefined, data: Uint8Array): string {
45
+ if (fileName !== undefined && (!fileName || !SAFE_FILE_NAME.test(fileName))) {
46
+ throw invalidParameter(
47
+ 'Parameter [fileName] may only contain letters, numbers, underscores, hyphens and an optional .bin suffix.'
48
+ );
49
+ }
50
+ const baseName = fileName ?? `wallpaper-${bytesToHex(blake2s(data)).slice(0, 12)}`;
51
+ return baseName.endsWith('.bin') ? baseName : `${baseName}.bin`;
52
+ }
53
+
54
+ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpaperParams> {
55
+ private encoded?: { data: Uint8Array; colorFormat: Pro2WallpaperColorFormat };
56
+
57
+ private directoryReady = false;
58
+
59
+ private uploaded = false;
60
+
61
+ private path = '';
62
+
63
+ init() {
64
+ const { width, height, rgba, fileName, chunkSize } = this.payload;
65
+ if (width !== PRO2_WALLPAPER_WIDTH || height !== PRO2_WALLPAPER_HEIGHT) {
66
+ throw invalidParameter(
67
+ `Pro2 wallpaper dimensions must be ${PRO2_WALLPAPER_WIDTH}x${PRO2_WALLPAPER_HEIGHT}.`
68
+ );
69
+ }
70
+ if (!(rgba instanceof ArrayBuffer) && !ArrayBuffer.isView(rgba)) {
71
+ throw invalidParameter('Parameter [rgba] must be an ArrayBuffer or Uint8Array.');
72
+ }
73
+ if (chunkSize !== undefined && (!Number.isInteger(chunkSize) || chunkSize <= 0)) {
74
+ throw invalidParameter('Parameter [chunkSize] must be a positive integer.');
75
+ }
76
+
77
+ const rgbaBytes =
78
+ rgba instanceof ArrayBuffer
79
+ ? rgba
80
+ : new Uint8Array(rgba.buffer, rgba.byteOffset, rgba.byteLength);
81
+ this.encoded = encodePro2Wallpaper({ width, height, rgba: rgbaBytes });
82
+ this.path = `${WALLPAPER_DIRECTORY}/${normalizeFileName(fileName, this.encoded.data)}`;
83
+ this.params = { width, height, rgba: rgbaBytes, fileName, chunkSize };
84
+ this.requireProtocolV2 = true;
85
+ this.unlockPolicy = 'retry-on-locked';
86
+ this.skipForceUpdateCheck = true;
87
+ this.useDevicePassphraseState = false;
88
+ }
89
+
90
+ private async ensureDirectory() {
91
+ if (this.directoryReady) return;
92
+ try {
93
+ await this.device.commands.typedCall('FilesystemDirMake', 'Success', {
94
+ path: WALLPAPER_DIRECTORY,
95
+ });
96
+ } catch (error) {
97
+ const message = error instanceof Error ? error.message : String(error);
98
+ if (!/exist/i.test(message)) throw error;
99
+ }
100
+ this.directoryReady = true;
101
+ }
102
+
103
+ private async upload() {
104
+ if (this.uploaded) return;
105
+ const encoded = this.encoded;
106
+ if (!encoded) throw invalidParameter('Wallpaper data has not been initialized.');
107
+
108
+ const maxChunkSize = getDefaultChunkSize();
109
+ const requestedChunkSize = this.params.chunkSize ?? maxChunkSize;
110
+ const chunkSize = Math.min(Math.max(64, Math.floor(requestedChunkSize)), maxChunkSize);
111
+ let offset = 0;
112
+ while (offset < encoded.data.byteLength) {
113
+ const chunk = encoded.data.slice(offset, Math.min(offset + chunkSize, encoded.data.byteLength));
114
+ const response = await this.device.commands.typedCall(
115
+ 'FilesystemFileWrite',
116
+ 'FilesystemFile',
117
+ {
118
+ file: {
119
+ path: this.path,
120
+ offset,
121
+ total_size: encoded.data.byteLength,
122
+ data: chunk,
123
+ },
124
+ overwrite: offset === 0,
125
+ append: false,
126
+ ui_percentage: Math.min(
127
+ Math.ceil(((offset + chunk.byteLength) / encoded.data.byteLength) * 100),
128
+ 100
129
+ ),
130
+ },
131
+ { timeoutMs: undefined }
132
+ );
133
+ const processedByte = Number(response.message?.processed_byte);
134
+ offset = Number.isFinite(processedByte) && processedByte > offset
135
+ ? processedByte
136
+ : offset + chunk.byteLength;
137
+ if (offset > encoded.data.byteLength) {
138
+ throw invalidParameter(`Invalid processed_byte returned by device: ${processedByte}.`);
139
+ }
140
+ }
141
+ this.uploaded = true;
142
+ }
143
+
144
+ async run(): Promise<DeviceUploadWallpaperResponse> {
145
+ const encoded = this.encoded;
146
+ if (!encoded) throw invalidParameter('Wallpaper data has not been initialized.');
147
+ await this.ensureDirectory();
148
+ await this.upload();
149
+ const response = await this.device.commands.typedCall('SetWallpaper', 'Success', {
150
+ target: WallpaperTarget.Lock,
151
+ path: this.path,
152
+ });
153
+ return {
154
+ path: this.path,
155
+ size: encoded.data.byteLength,
156
+ colorFormat: encoded.colorFormat,
157
+ message: response.message?.message,
158
+ };
159
+ }
160
+ }
@@ -10,7 +10,10 @@ export default class FilesystemFormat extends BaseMethod {
10
10
  }
11
11
 
12
12
  async run() {
13
- const res = await this.device.commands.typedCall('FilesystemFormat', 'Success', {});
13
+ const res = await this.device.commands.typedCall('FilesystemFormat', 'Success', {
14
+ data: true,
15
+ user: true,
16
+ });
14
17
  return Promise.resolve(res.message);
15
18
  }
16
19
  }
@@ -1,6 +1,6 @@
1
1
  import { BaseMethod } from '../BaseMethod';
2
2
 
3
- export default class FilesystemFixPermission extends BaseMethod {
3
+ export default class FilesystemPermissionFix extends BaseMethod {
4
4
  init() {
5
5
  // Protocol V2 (Pro2) 专属方法,core 调度层统一做非 V2 设备守卫
6
6
  this.requireProtocolV2 = true;
@@ -10,7 +10,7 @@ export default class FilesystemFixPermission extends BaseMethod {
10
10
  }
11
11
 
12
12
  async run() {
13
- const res = await this.device.commands.typedCall('FilesystemFixPermission', 'Success', {});
13
+ const res = await this.device.commands.typedCall('FilesystemPermissionFix', 'Success', {});
14
14
  return Promise.resolve(res.message);
15
15
  }
16
16
  }
@@ -1,6 +1,6 @@
1
1
  import { BaseMethod } from '../BaseMethod';
2
2
 
3
- export default class GetProtoVersion extends BaseMethod {
3
+ export default class ProtocolInfoRequest extends BaseMethod {
4
4
  init() {
5
5
  // Protocol V2 (Pro2) 专属方法,core 调度层统一做非 V2 设备守卫
6
6
  this.requireProtocolV2 = true;
@@ -10,7 +10,7 @@ export default class GetProtoVersion extends BaseMethod {
10
10
  }
11
11
 
12
12
  async run() {
13
- const res = await this.device.commands.typedCall('GetProtoVersion', 'ProtoVersion', {});
13
+ const res = await this.device.commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {});
14
14
  return Promise.resolve(res.message);
15
15
  }
16
16
  }
@@ -1,18 +1,16 @@
1
- import { DevRebootType } from '@onekeyfe/hd-transport';
1
+ import { DeviceRebootType } from '@onekeyfe/hd-transport';
2
2
 
3
3
  import { invalidParameter, validateNonEmptyString } from '../helpers/filesystemValidation';
4
+ import { ProtocolV2FirmwareTargetType } from '../../protocols/protocol-v2/firmware';
4
5
 
5
6
  import type {
6
- DevFirmwareTarget,
7
- DevFirmwareTargetType,
7
+ DeviceFirmwareTarget,
8
+ DeviceFirmwareTargetType,
9
+ DeviceFirmwareUpdateRecordFields,
8
10
  TransportCallOptions,
9
11
  } from '@onekeyfe/hd-transport';
10
12
 
11
- export type RebootTypeInput =
12
- | DevRebootType
13
- | keyof typeof DevRebootType
14
- | string
15
- | number;
13
+ export type RebootTypeInput = DeviceRebootType | keyof typeof DeviceRebootType | string | number;
16
14
 
17
15
  export type DeviceRebootParams = {
18
16
  rebootType?: RebootTypeInput;
@@ -20,48 +18,58 @@ export type DeviceRebootParams = {
20
18
  };
21
19
 
22
20
  export type DeviceFirmwareTargetInput =
23
- | DevFirmwareTarget
21
+ | DeviceFirmwareTarget
24
22
  | {
25
- targetId?: DevFirmwareTargetType | string | number;
26
- target_id?: DevFirmwareTargetType | string | number;
23
+ targetId?: DeviceFirmwareTargetType | string | number;
24
+ target_id?: DeviceFirmwareTargetType | string | number;
27
25
  path: string;
28
26
  };
29
27
 
30
28
  export type DeviceFirmwareUpdateParams = {
31
29
  targets?: DeviceFirmwareTargetInput[];
32
- targetId?: DevFirmwareTargetType | string | number;
33
- target_id?: DevFirmwareTargetType | string | number;
30
+ targetId?: DeviceFirmwareTargetType | string | number;
31
+ target_id?: DeviceFirmwareTargetType | string | number;
34
32
  path?: string;
35
33
  };
36
34
 
37
- export type FactoryDeviceInfoSettingsParams = {
38
- serial_no?: string;
39
- serialNo?: string;
40
- cpu_info?: string;
41
- cpuInfo?: string;
42
- pre_firmware?: string;
43
- preFirmware?: string;
35
+ export type DeviceFirmwareUpdateStatusGetParams = {
36
+ fields?: DeviceFirmwareUpdateRecordFields;
44
37
  };
45
38
 
46
- const DEV_REBOOT_TYPES: Record<string, DevRebootType> = {
47
- Normal: DevRebootType.Normal,
48
- normal: DevRebootType.Normal,
49
- Romloader: DevRebootType.Boardloader,
50
- romloader: DevRebootType.Boardloader,
51
- Boardloader: DevRebootType.Boardloader,
52
- boardloader: DevRebootType.Boardloader,
53
- Bootloader: DevRebootType.Bootloader,
54
- bootloader: DevRebootType.Bootloader,
39
+ export type DeviceFactoryInfoSetParams = {
40
+ version?: number;
41
+ serial_number?: string;
42
+ burn_in_completed?: boolean;
43
+ factory_test_completed?: boolean;
44
+ manufacture_time?: {
45
+ year: number;
46
+ month: number;
47
+ day: number;
48
+ hour: number;
49
+ minute: number;
50
+ second: number;
51
+ };
52
+ };
53
+
54
+ const DEVICE_REBOOT_TYPES: Record<string, DeviceRebootType> = {
55
+ Normal: DeviceRebootType.Normal,
56
+ normal: DeviceRebootType.Normal,
57
+ Romloader: DeviceRebootType.Romloader,
58
+ romloader: DeviceRebootType.Romloader,
59
+ Boardloader: DeviceRebootType.Romloader,
60
+ boardloader: DeviceRebootType.Romloader,
61
+ Bootloader: DeviceRebootType.Bootloader,
62
+ bootloader: DeviceRebootType.Bootloader,
55
63
  };
56
64
 
57
65
  export const PROTOCOL_V2_FIRMWARE_UPDATE_OPTIONS: TransportCallOptions = {
58
- intermediateTypes: ['DevFirmwareInstallProgress'],
66
+ intermediateTypes: ['DeviceFirmwareUpdateStatus'],
59
67
  };
60
68
 
61
69
  export const PROTOCOL_V2_FIRMWARE_UPDATE_RESPONSE_TYPES: (
62
70
  | 'Success'
63
- | 'DevFirmwareUpdateStatus'
64
- )[] = ['Success', 'DevFirmwareUpdateStatus'];
71
+ | 'DeviceFirmwareUpdateStatus'
72
+ )[] = ['Success', 'DeviceFirmwareUpdateStatus'];
65
73
 
66
74
  export const getProtocolV2UnknownErrorText = (error: unknown) => {
67
75
  if (!error) {
@@ -120,40 +128,56 @@ export const isProtocolV2DeviceDisconnectedError = (error: unknown) => {
120
128
  );
121
129
  };
122
130
 
123
- export function normalizeRebootType(value: RebootTypeInput | undefined): DevRebootType {
131
+ export function normalizeRebootType(value: RebootTypeInput | undefined): DeviceRebootType {
124
132
  if (typeof value === 'number') return value;
125
133
  if (typeof value === 'string') {
126
134
  const numeric = Number(value);
127
135
  if (Number.isFinite(numeric)) return numeric;
128
- if (value in DEV_REBOOT_TYPES) return DEV_REBOOT_TYPES[value];
136
+ if (value in DEVICE_REBOOT_TYPES) return DEVICE_REBOOT_TYPES[value];
129
137
  }
130
- return DevRebootType.Normal;
138
+ return DeviceRebootType.Normal;
131
139
  }
132
140
 
133
- // 当前 firmware-pro2 子模块的 DevFirmwareTargetType 合法值。
134
- const VALID_FIRMWARE_TARGET_IDS = new Set<number>([0, 1, 2, 3, 4, 5, 6, 10]);
141
+ // firmware-pro2 proto_target_to_firmware_target 安装白名单保持一致。
142
+ const INSTALLABLE_FIRMWARE_TARGET_IDS = new Set<number>([
143
+ ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
144
+ ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER,
145
+ ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1,
146
+ ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2,
147
+ ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_COPROCESSOR,
148
+ ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE01,
149
+ ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE02,
150
+ ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03,
151
+ ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04,
152
+ ]);
153
+ const FIRMWARE_TARGET_ID_BY_NAME = new Map<string, DeviceFirmwareTargetType>(
154
+ Object.entries(ProtocolV2FirmwareTargetType).flatMap(([key, value]) =>
155
+ INSTALLABLE_FIRMWARE_TARGET_IDS.has(value) ? [[key, value as DeviceFirmwareTargetType]] : []
156
+ )
157
+ );
135
158
 
136
159
  function normalizeTargetId(
137
- value: DevFirmwareTargetType | string | number | undefined,
160
+ value: DeviceFirmwareTargetType | string | number | undefined,
138
161
  name: string
139
- ): DevFirmwareTargetType {
162
+ ): DeviceFirmwareTargetType {
140
163
  if (value === undefined || value === null) {
141
164
  throw invalidParameter(`Missing required parameter: ${name}`);
142
165
  }
143
- const numeric = typeof value === 'number' ? value : Number(value);
144
- // 校验值域:仅接受 DevFirmwareTargetType 中定义的 target id,
145
- // 不再放行任意非负整数。
146
- if (Number.isSafeInteger(numeric) && VALID_FIRMWARE_TARGET_IDS.has(numeric)) {
147
- return numeric as DevFirmwareTargetType;
166
+ const named = typeof value === 'string' ? FIRMWARE_TARGET_ID_BY_NAME.get(value) : undefined;
167
+ const numeric = named ?? (typeof value === 'number' ? value : Number(value));
168
+ if (Number.isSafeInteger(numeric) && INSTALLABLE_FIRMWARE_TARGET_IDS.has(numeric)) {
169
+ return numeric as DeviceFirmwareTargetType;
148
170
  }
149
171
  throw invalidParameter(
150
- `Parameter [${name}] must be a valid firmware target id (one of ${[
151
- ...VALID_FIRMWARE_TARGET_IDS,
172
+ `Parameter [${name}] must be an installable firmware target id (one of ${[
173
+ ...INSTALLABLE_FIRMWARE_TARGET_IDS,
152
174
  ].join(', ')}).`
153
175
  );
154
176
  }
155
177
 
156
- export function normalizeFirmwareTargets(params: DeviceFirmwareUpdateParams): DevFirmwareTarget[] {
178
+ export function normalizeFirmwareTargets(
179
+ params: DeviceFirmwareUpdateParams
180
+ ): DeviceFirmwareTarget[] {
157
181
  const targets =
158
182
  params.targets ??
159
183
  (params.path
@@ -51,11 +51,7 @@ export default class TonSignData extends BaseMethod<HardwareTonSignData> {
51
51
  }
52
52
 
53
53
  getVersionRange() {
54
- return {
55
- pro2: {
56
- min: '0.0.0',
57
- },
58
- };
54
+ return {};
59
55
  }
60
56
 
61
57
  async run() {
@@ -47,7 +47,6 @@ export default class TronSignMessage extends BaseMethod<HardwareTronSignMessage>
47
47
  return {
48
48
  pro2: {
49
49
  min: '0.0.0',
50
- unsupported: true,
51
50
  },
52
51
  model_mini: {
53
52
  min: '2.5.0',
@@ -150,7 +150,6 @@ export default class TronSignTransaction extends BaseMethod<TronSignTx> {
150
150
  return {
151
151
  pro2: {
152
152
  min: '0.0.0',
153
- unsupported: true,
154
153
  },
155
154
  model_mini: {
156
155
  min: '2.5.0',
@@ -14,6 +14,8 @@ export type RequestTask = {
14
14
  export default class RequestQueue {
15
15
  private requestQueue = new Map<number, RequestTask>();
16
16
 
17
+ private operationRequestIds = new Map<string, number>();
18
+
17
19
  private pendingCallbackTasks = new Map<string, Deferred<void>>();
18
20
 
19
21
  // 生成唯一请求ID
@@ -30,11 +32,21 @@ export default class RequestQueue {
30
32
  method.responseID = requestId;
31
33
  }
32
34
  const abortController = new AbortController();
35
+ method.abortSignal = abortController.signal;
33
36
  const task = { id: requestId, method, abortController };
34
37
  this.requestQueue.set(requestId, task);
38
+ const operationId = method.payload?.operationId;
39
+ if (typeof operationId === 'string' && operationId) {
40
+ this.operationRequestIds.set(operationId, requestId);
41
+ }
35
42
  return task;
36
43
  }
37
44
 
45
+ public abortOperation(operationId: string) {
46
+ const requestId = this.operationRequestIds.get(operationId);
47
+ return requestId === undefined ? false : this.abortRequest(requestId);
48
+ }
49
+
38
50
  public getTask(requestId: number): RequestTask | undefined {
39
51
  return this.requestQueue.get(requestId);
40
52
  }
@@ -105,6 +117,13 @@ export default class RequestQueue {
105
117
 
106
118
  // 删除请求
107
119
  public releaseTask(requestId: number) {
120
+ const operationId = this.requestQueue.get(requestId)?.method.payload?.operationId;
121
+ if (
122
+ typeof operationId === 'string' &&
123
+ this.operationRequestIds.get(operationId) === requestId
124
+ ) {
125
+ this.operationRequestIds.delete(operationId);
126
+ }
108
127
  this.requestQueue.delete(requestId);
109
128
  }
110
129
 
package/src/core/index.ts CHANGED
@@ -56,7 +56,7 @@ import TransportManager from '../data-manager/TransportManager';
56
56
  import DeviceConnector from '../device/DeviceConnector';
57
57
  import RequestQueue from './RequestQueue';
58
58
  import { getSynchronize } from '../utils/getSynchronize';
59
- import { setProtocolV2DeviceInfoMock } from '../protocols/protocol-v2/features';
59
+ import { runMethodWithUnlockRetry } from '../protocols/protocol-v2/unlockRetry';
60
60
 
61
61
  import type { ConnectSettings, Features, KnownDevice } from '../types';
62
62
  import type { CoreMessage, IFrameCallMessage, UiPromise, UiPromiseResponse } from '../events';
@@ -96,6 +96,7 @@ const parseInitOptions = (method?: BaseMethod): InitOptions => ({
96
96
  deviceId: method?.payload.deviceId,
97
97
  deriveCardano: method && hasDeriveCardano(method),
98
98
  connectProtocol: method?.payload.connectProtocol,
99
+ protocolV2DeviceInfoTimeoutMs: method?.payload.protocolV2DeviceInfoTimeoutMs,
99
100
  });
100
101
 
101
102
  let _core: Core;
@@ -223,9 +224,15 @@ const handlePreWarmSignal = async (
223
224
  message: CoreMessage,
224
225
  method: BaseMethod
225
226
  ): Promise<any> => {
227
+ const createAckResponse = () => {
228
+ completeMethodRequestContext(method);
229
+ method.dispose();
230
+ return createResponseMessage(method.responseID, true, true);
231
+ };
232
+
226
233
  // no connectId: can't target a device safely, skip pre-warm (ack only)
227
234
  if (!method.connectId) {
228
- return createResponseMessage(method.responseID, true, true);
235
+ return createAckResponse();
229
236
  }
230
237
 
231
238
  const key = method.getPreWarmKey();
@@ -238,12 +245,12 @@ const handlePreWarmSignal = async (
238
245
  } catch {
239
246
  // pre-warm is best-effort; ignore its failure for the coalesced caller
240
247
  }
241
- return createResponseMessage(method.responseID, true, true);
248
+ return createAckResponse();
242
249
  }
243
250
 
244
251
  const doneAt = preWarmDoneAt.get(key);
245
252
  if (typeof doneAt === 'number' && Date.now() - doneAt <= method.preWarmTtl) {
246
- return createResponseMessage(method.responseID, true, true);
253
+ return createAckResponse();
247
254
  }
248
255
 
249
256
  const run = onCallDevice(context, message, method);
@@ -610,7 +617,7 @@ const onCallDevice = async (
610
617
  method.device?.commands?.checkDisposed();
611
618
 
612
619
  try {
613
- const response: object = await method.run();
620
+ const response: object = await runMethodWithUnlockRetry(method, device);
614
621
  messageResponse = createResponseMessage(method.responseID, true, response);
615
622
  requestQueue.resolveRequest(method.responseID, messageResponse);
616
623
  completeMethodRequestContext(method);
@@ -732,6 +739,15 @@ function initDevice(method: BaseMethod) {
732
739
 
733
740
  if (method.connectId) {
734
741
  device = _deviceList.getDevice(method.connectId);
742
+ if (!device && method.name === 'firmwareUpdateV4' && allDevices.length === 1) {
743
+ const [singleDevice] = allDevices;
744
+ if (singleDevice.isBootloader()) {
745
+ Log.debug(
746
+ 'firmwareUpdateV4 uses the only bootloader device when connectId changed after reboot'
747
+ );
748
+ device = singleDevice;
749
+ }
750
+ }
735
751
  } else if (allDevices.length === 1) {
736
752
  [device] = allDevices;
737
753
  } else if (allDevices.length > 1) {
@@ -1326,6 +1342,10 @@ export default class Core extends EventEmitter {
1326
1342
  Log.debug(`[Core] Created SDK instance: ${this.sdkInstanceId}`);
1327
1343
  }
1328
1344
 
1345
+ cancelOperation(operationId: string) {
1346
+ this.requestQueue.abortOperation(operationId);
1347
+ }
1348
+
1329
1349
  private getCoreContext() {
1330
1350
  return {
1331
1351
  sdkInstanceId: this.sdkInstanceId,
@@ -1394,6 +1414,10 @@ export default class Core extends EventEmitter {
1394
1414
  cancel(this.getCoreContext(), message.payload.connectId);
1395
1415
  break;
1396
1416
  }
1417
+ case IFRAME.CANCEL_OPERATION: {
1418
+ this.cancelOperation(message.payload.operationId);
1419
+ break;
1420
+ }
1397
1421
  case IFRAME.CALLBACK: {
1398
1422
  Log.log('callback message: ', message);
1399
1423
  postMessage(message);
@@ -1439,7 +1463,6 @@ export const init = async (
1439
1463
  try {
1440
1464
  try {
1441
1465
  await DataManager.load(settings);
1442
- setProtocolV2DeviceInfoMock(settings.protocolV2DeviceInfoMockEnabled ?? false);
1443
1466
  initTransport(Transport, plugin);
1444
1467
  } catch {
1445
1468
  Log.error('DataManager.load error');