@onekeyfe/hd-transport 1.2.0-alpha.11 → 1.2.0-alpha.13

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.
@@ -5,14 +5,10 @@ set -euxo pipefail
5
5
  echo $#
6
6
 
7
7
  PARENT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
8
- PACKAGE_ROOT="$PARENT_PATH/.."
9
8
 
10
9
  SRC="../../submodules/firmware/common/protob"
11
10
  DIST="."
12
11
  LANG="typescript"
13
- # Absolute paths — resolved relative to this script's directory
14
- REPO_ROOT="$PARENT_PATH/../../.."
15
- CORE_MESSAGES_DIR="$REPO_ROOT/packages/core/src/data/messages"
16
12
 
17
13
  if [[ $# -ne 0 && $# -ne 3 ]]
18
14
  then
@@ -33,238 +29,30 @@ if [[ "$LANG" != "typescript" && "$LANG" != "flow" ]];
33
29
  exit 1
34
30
  fi
35
31
 
36
- if [[ "$SRC" = /* ]]; then
37
- SRC_PATH="$SRC"
38
- else
39
- SRC_PATH="$PACKAGE_ROOT/$SRC"
40
- fi
41
-
42
- if [[ "$DIST" = /* ]]; then
43
- DIST_PATH="$DIST"
44
- else
45
- DIST_PATH="$PACKAGE_ROOT/$DIST"
46
- fi
47
-
48
- # Remove temp proto files on any exit, including failure paths
49
- trap 'rm -f "$DIST_PATH/messages-tmp.proto" "$PARENT_PATH/messages-protocol-v2-tmp.proto"' EXIT
50
-
51
-
52
- # ============================================================
53
- # BUILD Pro1 messages.json (requires firmware submodule)
54
- # ============================================================
55
- # Combines all messages*.proto files from firmware submodule into
56
- # messages.json, then copies to core package.
57
- if [ -d "$SRC_PATH" ] && ls "$SRC_PATH"/messages*.proto 1>/dev/null 2>&1; then
58
- echo "=== Building Pro1 (legacy) protobuf messages ==="
59
- TMP_PROTO="$DIST_PATH/messages-tmp.proto"
60
- echo 'syntax = "proto2";' > "$TMP_PROTO"
61
- echo 'import "google/protobuf/descriptor.proto";' >> "$TMP_PROTO"
62
- echo "Build proto file from $SRC_PATH"
63
- grep -hv -e '^import ' -e '^syntax' -e '^package' -e 'option java_' "$SRC_PATH"/messages*.proto \
64
- | sed 's/ hw\.trezor\.messages\.common\./ /' \
65
- | sed 's/ common\./ /' \
66
- | sed 's/ ethereum_definitions\./ /' \
67
- | sed 's/ management\./ /' \
68
- | sed 's/^option /\/\/ option /' \
69
- | grep -v ' reserved '>> "$TMP_PROTO"
70
-
71
- npx pbjs -t json -p "$DIST_PATH" -o "$DIST_PATH/messages.json" --keep-case "$TMP_PROTO"
72
- rm "$TMP_PROTO"
73
32
 
74
- # Copy to core package
75
- cp "$DIST_PATH/messages.json" "$CORE_MESSAGES_DIR/messages.json"
76
- echo "Pro1 messages.json copied to core"
33
+ # BUILD combined messages.proto file from protobuf files
34
+ # this code was copied from ./submodules/firmware/protob Makekile
35
+ # clear protobuf syntax and remove unknown values to be able to work with proto2js
36
+ echo 'syntax = "proto2";' > $DIST/messages.proto
37
+ echo 'import "google/protobuf/descriptor.proto";' >> $DIST/messages.proto
38
+ echo "Build proto file from $SRC"
39
+ grep -hv -e '^import ' -e '^syntax' -e '^package' -e 'option java_' $SRC/messages*.proto \
40
+ | sed 's/ hw\.trezor\.messages\.common\./ /' \
41
+ | sed 's/ common\./ /' \
42
+ | sed 's/ ethereum_definitions\./ /' \
43
+ | sed 's/ management\./ /' \
44
+ | sed 's/^option /\/\/ option /' \
45
+ | grep -v ' reserved '>> $DIST/messages.proto
77
46
 
78
- yarn --cwd "$PACKAGE_ROOT" prettier --write "$DIST_PATH/messages.json"
79
- yarn --cwd "$PACKAGE_ROOT" prettier --write "$CORE_MESSAGES_DIR/messages.json"
80
- # Type generation (protobuf-types.js) runs once at the end of the Protocol V2
81
- # section below, after both schemas are available.
82
- else
83
- # Intentional asymmetry with the Protocol V2 section below: the legacy firmware
84
- # submodule is optional (the committed messages.json stays in use when it is
85
- # absent), while firmware-pro2 is the only source of the Protocol V2 schema,
86
- # so its absence is a hard error (exit 1).
87
- echo "⚠️ firmware submodule not found at $SRC_PATH"
88
- echo " Skipping Pro1 protobuf build. To enable:"
89
- echo " git submodule update --init submodules/firmware"
90
- fi
47
+ # BUILD messages.json from message.proto
48
+ npx pbjs -t json -p $DIST -o $DIST/messages.json --keep-case messages.proto
49
+ rm $DIST/messages.proto
91
50
 
51
+ echo "generating type definitions for: $LANG"
92
52
 
93
- # ============================================================
94
- # BUILD Protocol V2 messages-protocol-v2.json
95
- # ============================================================
96
- # Source of truth: submodules/firmware-pro2/sys/protobuf/onekey_protocol/.
97
- # Protocol V2 keeps chain/app protocols under legacy/ and system protocols under latest/.
98
- # The SDK flattens them into one protobuf schema for transport runtime, but it must keep
99
- # firmware message names and enum values intact. SDK-facing aliases belong in core/API code,
100
- # not in the protobuf schema.
101
- # ============================================================
102
53
  cd "$PARENT_PATH"
103
54
 
104
- SRC_PRO2_LEGACY="$REPO_ROOT/submodules/firmware-pro2/sys/protobuf/onekey_protocol/legacy"
105
- SRC_PRO2_LATEST="$REPO_ROOT/submodules/firmware-pro2/sys/protobuf/onekey_protocol/latest"
106
-
107
- if [ -d "$SRC_PRO2_LATEST" ] && ls "$SRC_PRO2_LATEST"/messages*.proto 1>/dev/null 2>&1; then
108
- echo "=== Building Protocol V2 messages from firmware-pro2 legacy + latest protobuf schema ==="
109
- TMP_PROTO="$PARENT_PATH/messages-protocol-v2-tmp.proto"
110
-
111
- {
112
- echo 'syntax = "proto2";'
113
- echo 'import "google/protobuf/descriptor.proto";'
114
- echo ''
115
-
116
- # Pro2 firmware keeps chain/app protocols under legacy/, and Protocol V2
117
- # device/filesystem/firmware protocols under latest/. Build one flat
118
- # schema so Protocol V2 framing can also encode legacy public-chain calls.
119
- grep -hv \
120
- -e '^import ' -e '^syntax' -e '^package' -e 'option java_' \
121
- "$SRC_PRO2_LEGACY"/messages*.proto \
122
- | sed 's/ hw\.onekey\.messages\.[a-zA-Z_]*\./ /g' \
123
- | sed 's/ crypto\./ /g' \
124
- | sed 's/ ethereum_definitions\./ /g' \
125
- | sed 's/ management\./ /g' \
126
- | sed 's/^option /\/\/ option /' \
127
- | grep -v ' reserved '
128
-
129
- echo ''
130
- echo '// --- Protocol V2 system messages ---'
131
- grep -hv \
132
- -e '^import ' -e '^syntax' -e '^package' -e 'option java_' \
133
- -e '^option ' \
134
- "$SRC_PRO2_LATEST"/messages*.proto \
135
- | grep -v ' reserved '
136
-
137
- } > "$TMP_PROTO"
138
-
139
- node - "$TMP_PROTO" <<'NODE'
140
- const fs = require('fs');
55
+ node ./protobuf-types.js $LANG
141
56
 
142
- const protoPath = process.argv[2];
143
- let proto = fs.readFileSync(protoPath, 'utf8');
144
-
145
- const removeTopLevelMessage = (source, name) => {
146
- const pattern = new RegExp(`(^|\\n)message\\s+${name}\\s*\\{`, 'm');
147
- const match = pattern.exec(source);
148
- if (!match) return source;
149
-
150
- const start = match.index + (match[1] ? match[1].length : 0);
151
- let index = start;
152
- let depth = 0;
153
- while (index < source.length) {
154
- const char = source[index];
155
- if (char === '{') {
156
- depth += 1;
157
- } else if (char === '}') {
158
- depth -= 1;
159
- if (depth === 0) {
160
- index += 1;
161
- while (index < source.length && /\s/.test(source[index])) index += 1;
162
- return `${source.slice(0, start)}${source.slice(index)}`;
163
- }
164
- }
165
- index += 1;
166
- }
167
- throw new Error(`Unterminated message block: ${name}`);
168
- };
169
-
170
- [
171
- 'Initialize',
172
- 'GetFeatures',
173
- 'OnekeyGetFeatures',
174
- 'Features',
175
- ].forEach(name => {
176
- proto = removeTopLevelMessage(proto, name);
177
- });
178
-
179
- fs.writeFileSync(protoPath, proto);
180
-
181
- const messageNames = new Set(
182
- Array.from(proto.matchAll(/^\s*message\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{/gm)).map(
183
- match => match[1]
184
- )
185
- );
186
- const messageTypeNames = new Set(
187
- Array.from(proto.matchAll(/^\s*MessageType_([A-Za-z_][A-Za-z0-9_]*)\s*=/gm)).map(
188
- match => match[1]
189
- )
190
- );
191
- const requiredMessages = [
192
- 'DeviceFactoryInfoSet',
193
- 'DeviceFactoryInfoGet',
194
- 'DeviceFactoryInfo',
195
- 'ProtocolInfoRequest',
196
- 'ProtocolInfo',
197
- 'Ping',
198
- 'Success',
199
- 'Failure',
200
- 'DeviceReboot',
201
- 'DeviceInfoGet',
202
- 'DeviceInfo',
203
- 'DeviceStatusGet',
204
- 'DeviceStatus',
205
- 'DevGetOnboardingStatus',
206
- 'DevOnboardingStatus',
207
- 'DeviceSessionGet',
208
- 'DeviceSession',
209
- 'DeviceSessionAskPin',
210
- 'DeviceSessionPinResult',
211
- 'DeviceFirmwareUpdateRequest',
212
- 'DeviceFirmwareUpdateStatusGet',
213
- 'DeviceFirmwareUpdateStatus',
214
- 'FilesystemPermissionFix',
215
- 'FilesystemPathInfo',
216
- 'FilesystemPathInfoQuery',
217
- 'FilesystemFile',
218
- 'FilesystemFileRead',
219
- 'FilesystemFileWrite',
220
- 'FilesystemFileDelete',
221
- 'FilesystemDir',
222
- 'FilesystemDirList',
223
- 'FilesystemDirMake',
224
- 'FilesystemDirRemove',
225
- 'FilesystemFormat',
226
- 'PortfolioUpdate',
227
- ];
228
- const missingMessages = requiredMessages.filter(name => !messageNames.has(name));
229
- const missingMessageTypes = requiredMessages.filter(name => !messageTypeNames.has(name));
230
-
231
- if (missingMessages.length > 0 || missingMessageTypes.length > 0) {
232
- throw new Error(
233
- `Protocol V2 schema missing required entries: messages=[${missingMessages.join(
234
- ', '
235
- )}], messageTypes=[${missingMessageTypes.join(
236
- ', '
237
- )}]. Make sure submodules/firmware-pro2 is checked out on branch dev ` +
238
- '(origin/dev), which contains the latest Protocol V2 Device*/Filesystem* messages.'
239
- );
240
- }
241
-
242
- NODE
243
-
244
- npx pbjs -t json \
245
- -p "$PARENT_PATH" \
246
- -o "$PARENT_PATH/../messages-protocol-v2.json" \
247
- --keep-case \
248
- "$(basename "$TMP_PROTO")"
249
-
250
- rm -f "$TMP_PROTO"
251
-
252
- cp "$PARENT_PATH/../messages-protocol-v2.json" "$CORE_MESSAGES_DIR/messages-protocol-v2.json"
253
- echo "Protocol V2 messages-protocol-v2.json generated from firmware-pro2 legacy + latest schema and copied to core"
254
-
255
- yarn --cwd "$PACKAGE_ROOT" prettier --write "$PARENT_PATH/../messages-protocol-v2.json"
256
- yarn --cwd "$PACKAGE_ROOT" prettier --write "$CORE_MESSAGES_DIR/messages-protocol-v2.json"
257
-
258
- echo "generating type definitions for: $LANG"
259
- node ./protobuf-types.js $LANG
260
- yarn --cwd "$PACKAGE_ROOT" prettier --write "$PACKAGE_ROOT/src/types/messages.ts"
261
- echo "=== Protocol V2 messages build complete ==="
262
- else
263
- # Unlike the optional Pro1 (legacy) section above, the firmware-pro2 submodule is
264
- # the only source of the Protocol V2 schema, so a missing checkout is a hard error.
265
- echo "firmware-pro2 latest protobuf schema not found at $SRC_PRO2_LATEST"
266
- echo "The Protocol V2 schema requires firmware-pro2 on branch dev."
267
- echo "Run: git submodule update --init submodules/firmware-pro2"
268
- echo "Then: git -C submodules/firmware-pro2 fetch origin dev && git -C submodules/firmware-pro2 checkout origin/dev"
269
- exit 1
270
- fi
57
+ yarn prettier --write messages.json
58
+ yarn prettier --write **/messages.ts
@@ -19,6 +19,10 @@ const optionalJsonFiles = ['../messages-protocol-v2.json'];
19
19
  const OPTIONAL_DUPLICATE_TYPE_ALIASES = {
20
20
  DeviceInfo: 'ProtocolV2DeviceInfo',
21
21
  };
22
+ const OPTIONAL_NESTED_TYPE_ALIASES = [
23
+ { parent: 'Failure', name: 'FailureType', alias: 'ProtocolV2FailureType' },
24
+ { parent: 'Features', name: 'Capability', alias: 'ProtocolV2Capability' },
25
+ ];
22
26
  const messageTypeAliases = {};
23
27
  const skipMessageTypeKeys = new Set(Object.values(OPTIONAL_DUPLICATE_TYPE_ALIASES));
24
28
 
@@ -59,6 +63,7 @@ const ENUM_KEYS = [
59
63
  'ButtonRequestType',
60
64
  'PinMatrixRequestType',
61
65
  'WordRequestType',
66
+ 'ProtocolV2Capability',
62
67
  ];
63
68
 
64
69
  const parseEnumTypescript = (itemName, item) => {
@@ -317,6 +322,10 @@ optionalJsonFiles.forEach(jsonFile => {
317
322
  const jsonPath = path.join(__dirname, jsonFile);
318
323
  if (!fs.existsSync(jsonPath)) return;
319
324
  const optionalJson = readJson(jsonPath);
325
+ OPTIONAL_NESTED_TYPE_ALIASES.forEach(({ parent, name, alias }) => {
326
+ const definition = optionalJson.nested[parent]?.nested?.[name];
327
+ if (definition) optionalJson.nested[alias] = definition;
328
+ });
320
329
  optionalJsons.push(optionalJson);
321
330
  Object.keys(optionalJson.nested).forEach(e => {
322
331
  if (!json.nested[e]) return; // V2-only type, parsed after the V1 pass below
@@ -9,7 +9,6 @@ import { decode as decodeProtobuf } from '../serialization/protobuf/decode';
9
9
  import { decodeFrame as decodeV2Frame, encodeProtobufFrame, isAckFrame } from './v2';
10
10
 
11
11
  import type { Root } from 'protobufjs/light';
12
- import type { ProtocolV2DebugLogger } from './v2';
13
12
 
14
13
  export const PROTOCOL_V2_SYS_MESSAGE_THRESHOLD = 60000;
15
14
 
@@ -23,9 +22,6 @@ type ProtocolV2FrameOptions = {
23
22
  router?: number;
24
23
  /** Sequence number (1-255). Managed per-session by ProtocolV2Session. */
25
24
  seq?: number;
26
- logger?: ProtocolV2DebugLogger;
27
- logPrefix?: string;
28
- context?: string;
29
25
  };
30
26
 
31
27
  const resolveProtocolV2EncodeSchema = (name: string, schemas: ProtocolV2Schemas) => {
@@ -76,6 +72,18 @@ export const ProtocolV1 = {
76
72
  export const ProtocolV2 = {
77
73
  isAckFrame,
78
74
 
75
+ inspectFrame(schemas: ProtocolV2Schemas, frame: Uint8Array) {
76
+ const { messageTypeId, pbPayload, seq } = decodeV2Frame(frame);
77
+ const { messageName } = createProtocolV2MessageFromType(messageTypeId, schemas);
78
+ return {
79
+ messageName,
80
+ messageTypeId,
81
+ pbPayload,
82
+ seq,
83
+ type: messageName,
84
+ };
85
+ },
86
+
79
87
  encodeFrame(
80
88
  schemas: ProtocolV2Schemas,
81
89
  name: string,
@@ -89,52 +97,21 @@ export const ProtocolV2 = {
89
97
  const rawPbBuffer = pbBuffer.toBuffer() as unknown as ArrayBuffer;
90
98
  const pbBytes = new Uint8Array(rawPbBuffer);
91
99
 
92
- options.logger?.debug?.(`[${options.logPrefix ?? 'ProtocolV2'}] encode protobuf`, {
93
- context: options.context ?? `encode:${name}`,
94
- messageName: name,
95
- messageTypeId,
96
- pbPayloadLength: pbBytes.length,
97
- packetSrc: options.packetSrc ?? 0,
98
- router: options.router ?? 0,
99
- });
100
-
101
100
  return encodeProtobufFrame(
102
101
  messageTypeId,
103
102
  pbBytes,
104
103
  options.packetSrc,
105
104
  options.router,
106
- {
107
- logger: options.logger,
108
- logPrefix: options.logPrefix,
109
- context: options.context ?? `encode:${name}`,
110
- messageName: name,
111
- },
112
105
  options.seq
113
106
  );
114
107
  },
115
108
 
116
- decodeFrame(
117
- schemas: ProtocolV2Schemas,
118
- frame: Uint8Array,
119
- options: Pick<ProtocolV2FrameOptions, 'logger' | 'logPrefix' | 'context'> = {}
120
- ) {
121
- const { messageTypeId, pbPayload, seq } = decodeV2Frame(frame, {
122
- logger: options.logger,
123
- logPrefix: options.logPrefix,
124
- context: options.context ?? 'decode',
125
- });
126
- const { Message, messageName } = createProtocolV2MessageFromType(messageTypeId, schemas);
109
+ decodeFrame(schemas: ProtocolV2Schemas, frame: Uint8Array) {
110
+ const { messageTypeId, pbPayload, seq, messageName } = this.inspectFrame(schemas, frame);
111
+ const { Message } = createProtocolV2MessageFromType(messageTypeId, schemas);
127
112
  const rxByteBuffer = ByteBuffer.wrap(Buffer.from(pbPayload) as unknown as ArrayBuffer);
128
113
  const message = decodeProtobuf(Message, rxByteBuffer);
129
114
 
130
- options.logger?.debug?.(`[${options.logPrefix ?? 'ProtocolV2'}] decode protobuf`, {
131
- context: options.context ?? `decode:${messageName}`,
132
- messageName,
133
- messageTypeId,
134
- pbPayloadLength: pbPayload.length,
135
- seq,
136
- });
137
-
138
115
  return {
139
116
  message,
140
117
  messageName,
@@ -1,8 +1,5 @@
1
1
  import { PROTO_DATA_TYPE_ACK, PROTO_HEAD_CRC_SIZE, PROTO_HEAD_SOF } from './constants';
2
2
  import { crc8 } from './crc8';
3
- import { logProtocolV2Debug } from './debug';
4
-
5
- import type { ProtocolV2FrameDebugOptions } from './debug';
6
3
 
7
4
  export interface ProtoV2Frame {
8
5
  /** Little-endian message type ID */
@@ -74,13 +71,8 @@ export function isAckFrame(data: Uint8Array): boolean {
74
71
  *
75
72
  * Returns the decoded messageTypeId, raw protobuf payload, and sequence number.
76
73
  */
77
- export function decodeFrame(
78
- data: Uint8Array,
79
- debugOptions?: ProtocolV2FrameDebugOptions
80
- ): ProtoV2Frame {
74
+ export function decodeFrame(data: Uint8Array): ProtoV2Frame {
81
75
  const frameLen = validateFrame(data);
82
- const expectedHeaderCrc = data[3];
83
- const expectedFrameCrc = data[frameLen - 1];
84
76
 
85
77
  const seq = data[6];
86
78
  // Payload spans bytes 7 to frameLen-2 (inclusive), excluding final CRC byte
@@ -93,19 +85,5 @@ export function decodeFrame(
93
85
  const messageTypeId = payloadData[0] + payloadData[1] * 256;
94
86
  const pbPayload = payloadData.slice(2);
95
87
 
96
- logProtocolV2Debug(debugOptions, 'decode raw frame', {
97
- frameLen,
98
- dataLength: data.length,
99
- router: data[4],
100
- attr: data[5],
101
- seq,
102
- headerCrc: data[3],
103
- expectedHeaderCrc,
104
- frameCrc: data[frameLen - 1],
105
- expectedFrameCrc,
106
- messageTypeId,
107
- pbPayloadLength: pbPayload.length,
108
- });
109
-
110
88
  return { messageTypeId, pbPayload, seq };
111
89
  }
@@ -1,10 +1,7 @@
1
1
  import { PROTO_DATA_TYPE_PACKET, PROTO_HEAD_CRC_SIZE, PROTO_HEAD_SOF } from './constants';
2
2
  import { crc8 } from './crc8';
3
- import { logProtocolV2Debug } from './debug';
4
3
  import { PROTOCOL_V2_FRAME_MAX_BYTES } from '../../constants';
5
4
 
6
- import type { ProtocolV2FrameDebugOptions } from './debug';
7
-
8
5
  // Default sequence number when callers do not manage one themselves.
9
6
  // Stateful per-session sequencing lives in ProtocolV2Session (session.ts),
10
7
  // which advances the counter via nextProtoSeq() and passes it in explicitly.
@@ -35,7 +32,6 @@ export function encodeFrame(
35
32
  payload: Uint8Array | null,
36
33
  packetSrc?: number,
37
34
  router?: number,
38
- debugOptions?: ProtocolV2FrameDebugOptions,
39
35
  seq?: number
40
36
  ): Uint8Array {
41
37
  const resolvedPacketSrc = packetSrc ?? 0;
@@ -69,17 +65,6 @@ export function encodeFrame(
69
65
  // CRC8 over entire frame except last byte
70
66
  frame[frameLen - 1] = crc8(frame, frameLen - 1);
71
67
 
72
- logProtocolV2Debug(debugOptions, 'encode raw frame', {
73
- frameLen,
74
- payloadLen,
75
- packetSrc: resolvedPacketSrc,
76
- router: frame[4],
77
- attr: frame[5],
78
- seq: frame[6],
79
- headerCrc: frame[3],
80
- frameCrc: frame[frameLen - 1],
81
- });
82
-
83
68
  return frame;
84
69
  }
85
70
 
@@ -95,22 +80,11 @@ export function encodeProtobufFrame(
95
80
  pbPayload: Uint8Array,
96
81
  packetSrc?: number,
97
82
  router?: number,
98
- debugOptions?: ProtocolV2FrameDebugOptions,
99
83
  seq?: number
100
84
  ): Uint8Array {
101
85
  const payload = new Uint8Array(2 + pbPayload.length);
102
86
  payload[0] = messageTypeId % 256;
103
87
  payload[1] = Math.floor(messageTypeId / 256) % 256;
104
88
  payload.set(pbPayload, 2);
105
- return encodeFrame(
106
- payload,
107
- packetSrc,
108
- router,
109
- {
110
- ...debugOptions,
111
- messageTypeId,
112
- pbPayloadLength: pbPayload.length,
113
- },
114
- seq
115
- );
89
+ return encodeFrame(payload, packetSrc, router, seq);
116
90
  }
@@ -1,6 +1,5 @@
1
1
  export * from './constants';
2
2
  export * from './crc8';
3
- export * from './debug';
4
3
  export * from './encode';
5
4
  export * from './decode';
6
5
  export * from './frame-assembler';