@onekeyfe/hd-transport 1.2.0-alpha.101 → 1.2.0-alpha.102
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__/protocol-v2.test.js +116 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +86 -0
- package/dist/protocols/index.d.ts +12 -0
- package/dist/protocols/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/protocols/index.ts +91 -0
|
@@ -233,6 +233,32 @@ const schemas = {
|
|
|
233
233
|
};
|
|
234
234
|
const productionProtocolV2Messages = parseConfigure(require('../messages-protocol-v2.json'));
|
|
235
235
|
|
|
236
|
+
const legacyProtocolInfoMessage = parseConfigure({
|
|
237
|
+
nested: {
|
|
238
|
+
ProtocolInfo: {
|
|
239
|
+
fields: {
|
|
240
|
+
version: {
|
|
241
|
+
type: 'uint32',
|
|
242
|
+
id: 1,
|
|
243
|
+
rule: 'required',
|
|
244
|
+
},
|
|
245
|
+
supported_messages: {
|
|
246
|
+
type: 'uint32',
|
|
247
|
+
id: 2,
|
|
248
|
+
rule: 'repeated',
|
|
249
|
+
options: {
|
|
250
|
+
packed: false,
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
protobuf_definition: {
|
|
254
|
+
type: 'string',
|
|
255
|
+
id: 3,
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
}).lookupType('ProtocolInfo');
|
|
261
|
+
|
|
236
262
|
const rewriteSeq = (frame, seq) => {
|
|
237
263
|
const copy = new Uint8Array(frame);
|
|
238
264
|
copy[4] = 1;
|
|
@@ -267,6 +293,64 @@ describe('Protocol V2 framing and session', () => {
|
|
|
267
293
|
});
|
|
268
294
|
});
|
|
269
295
|
|
|
296
|
+
test('decodes a two-byte legacy ProtocolInfo at the generic frame boundary', () => {
|
|
297
|
+
const frame = protocolV2.encodeProtobufFrame(60201, new Uint8Array([0x08, 0x01]));
|
|
298
|
+
const productionSchemas = {
|
|
299
|
+
protocolV1: protocolV1Messages,
|
|
300
|
+
protocolV2: productionProtocolV2Messages,
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
expect(ProtocolV2.decodeFrame(productionSchemas, frame)).toMatchObject({
|
|
304
|
+
type: 'ProtocolInfo',
|
|
305
|
+
message: {
|
|
306
|
+
version: 1,
|
|
307
|
+
build_fingerprint: '',
|
|
308
|
+
supported_messages: [],
|
|
309
|
+
protobuf_definition: null,
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test('does not reinterpret a malformed current ProtocolInfo as the legacy layout', () => {
|
|
315
|
+
const frame = protocolV2.encodeProtobufFrame(60201, new Uint8Array([0x08, 0x01, 0x18, 0x01]));
|
|
316
|
+
|
|
317
|
+
expect(() =>
|
|
318
|
+
ProtocolV2.decodeFrame(
|
|
319
|
+
{
|
|
320
|
+
protocolV1: protocolV1Messages,
|
|
321
|
+
protocolV2: productionProtocolV2Messages,
|
|
322
|
+
},
|
|
323
|
+
frame
|
|
324
|
+
)
|
|
325
|
+
).toThrow('Protocol V2 protobuf decode failed for "ProtocolInfo"');
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test('preserves legacy ProtocolInfo capabilities when using the old field numbers', () => {
|
|
329
|
+
const payload = legacyProtocolInfoMessage
|
|
330
|
+
.encode({
|
|
331
|
+
version: 1,
|
|
332
|
+
supported_messages: [60602],
|
|
333
|
+
protobuf_definition: 'legacy',
|
|
334
|
+
})
|
|
335
|
+
.finish();
|
|
336
|
+
const frame = protocolV2.encodeProtobufFrame(60201, payload);
|
|
337
|
+
|
|
338
|
+
const decoded = ProtocolV2.decodeFrame(
|
|
339
|
+
{
|
|
340
|
+
protocolV1: protocolV1Messages,
|
|
341
|
+
protocolV2: productionProtocolV2Messages,
|
|
342
|
+
},
|
|
343
|
+
frame
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
expect(decoded.message).toEqual({
|
|
347
|
+
version: 1,
|
|
348
|
+
build_fingerprint: '',
|
|
349
|
+
supported_messages: [60602],
|
|
350
|
+
protobuf_definition: null,
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
|
|
270
354
|
test('does not encode V1-only messages into Protocol V2 frames', () => {
|
|
271
355
|
expect(() => ProtocolV2.encodeFrame(schemas, 'Ping', { message: 'ok' })).not.toThrow();
|
|
272
356
|
expect(() => ProtocolV2.encodeFrame(schemas, 'OnekeyGetFeatures', {})).toThrow(
|
|
@@ -446,6 +530,38 @@ describe('Protocol V2 framing and session', () => {
|
|
|
446
530
|
});
|
|
447
531
|
});
|
|
448
532
|
|
|
533
|
+
test('session decodes legacy ProtocolInfo through the generic frame boundary', async () => {
|
|
534
|
+
const productionSchemas = {
|
|
535
|
+
protocolV1: protocolV1Messages,
|
|
536
|
+
protocolV2: productionProtocolV2Messages,
|
|
537
|
+
};
|
|
538
|
+
const response = protocolV2.encodeProtobufFrame(60201, new Uint8Array([0x08, 0x01]));
|
|
539
|
+
const session = new ProtocolV2Session({
|
|
540
|
+
schemas: productionSchemas,
|
|
541
|
+
router: 1,
|
|
542
|
+
writeFrame: () => Promise.resolve(),
|
|
543
|
+
readFrame: () => Promise.resolve(rewriteSeq(response, 1)),
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
await expect(
|
|
547
|
+
session.call(
|
|
548
|
+
'ProtocolInfoRequest',
|
|
549
|
+
{ eventless_wallet_session: true },
|
|
550
|
+
{
|
|
551
|
+
expectedTypes: ['ProtocolInfo'],
|
|
552
|
+
}
|
|
553
|
+
)
|
|
554
|
+
).resolves.toEqual({
|
|
555
|
+
type: 'ProtocolInfo',
|
|
556
|
+
message: {
|
|
557
|
+
version: 1,
|
|
558
|
+
build_fingerprint: '',
|
|
559
|
+
supported_messages: [],
|
|
560
|
+
protobuf_definition: null,
|
|
561
|
+
},
|
|
562
|
+
});
|
|
563
|
+
});
|
|
564
|
+
|
|
449
565
|
test('session does not log Protocol V2 TX and RX frames', async () => {
|
|
450
566
|
const written = [];
|
|
451
567
|
const logger = { debug: jest.fn() };
|
package/dist/index.d.ts
CHANGED
|
@@ -263,6 +263,18 @@ declare const ProtocolV2: {
|
|
|
263
263
|
};
|
|
264
264
|
encodeFrame(schemas: ProtocolV2Schemas$1, name: string, data: Record<string, unknown>, options?: ProtocolV2FrameOptions): Uint8Array;
|
|
265
265
|
decodeFrame(schemas: ProtocolV2Schemas$1, frame: Uint8Array): {
|
|
266
|
+
message: {
|
|
267
|
+
version: any;
|
|
268
|
+
build_fingerprint: string;
|
|
269
|
+
supported_messages: any;
|
|
270
|
+
protobuf_definition: null;
|
|
271
|
+
};
|
|
272
|
+
messageName: string;
|
|
273
|
+
messageTypeId: number;
|
|
274
|
+
pbPayload: Uint8Array;
|
|
275
|
+
seq: number;
|
|
276
|
+
type: string;
|
|
277
|
+
} | {
|
|
266
278
|
message: {
|
|
267
279
|
[key: string]: any;
|
|
268
280
|
};
|
|
@@ -6858,6 +6870,18 @@ declare const _default: {
|
|
|
6858
6870
|
protocolV1: protobuf.Root;
|
|
6859
6871
|
protocolV2: protobuf.Root;
|
|
6860
6872
|
}, frame: Uint8Array): {
|
|
6873
|
+
message: {
|
|
6874
|
+
version: any;
|
|
6875
|
+
build_fingerprint: string;
|
|
6876
|
+
supported_messages: any;
|
|
6877
|
+
protobuf_definition: null;
|
|
6878
|
+
};
|
|
6879
|
+
messageName: string;
|
|
6880
|
+
messageTypeId: number;
|
|
6881
|
+
pbPayload: Uint8Array;
|
|
6882
|
+
seq: number;
|
|
6883
|
+
type: string;
|
|
6884
|
+
} | {
|
|
6861
6885
|
message: {
|
|
6862
6886
|
[key: string]: any;
|
|
6863
6887
|
};
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAKL,cAAc,EACf,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,eAAe,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAEL,wBAAwB,EACxB,iBAAiB,EACjB,UAAU,EAEV,eAAe,EACf,UAAU,EACV,eAAe,EACf,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,KAAK,MAAM,0BAA0B,CAAC;AAKlD,YAAY,EACV,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,sBAAsB,EACtB,2BAA2B,EAC3B,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,6BAA6B,EAC7B,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,YAAY,EACZ,8BAA8B,GAC/B,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACpD,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AAErC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,OAAO,KAAK,UAAU,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,UAAU,MAAM,gBAAgB,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,mCAAmC,CAAC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAKL,cAAc,EACf,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,eAAe,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAEL,wBAAwB,EACxB,iBAAiB,EACjB,UAAU,EAEV,eAAe,EACf,UAAU,EACV,eAAe,EACf,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,KAAK,MAAM,0BAA0B,CAAC;AAKlD,YAAY,EACV,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,sBAAsB,EACtB,2BAA2B,EAC3B,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,6BAA6B,EAC7B,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,YAAY,EACZ,8BAA8B,GAC/B,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACpD,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AAErC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,OAAO,KAAK,UAAU,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,UAAU,MAAM,gBAAgB,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,mCAAmC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAElD,wBAsBE"}
|
package/dist/index.js
CHANGED
|
@@ -667,6 +667,81 @@ var protocolV2Codec = /*#__PURE__*/Object.freeze({
|
|
|
667
667
|
});
|
|
668
668
|
|
|
669
669
|
const PROTOCOL_V2_SYS_MESSAGE_THRESHOLD = 60000;
|
|
670
|
+
const LEGACY_PROTOCOL_V2_PROTOCOL_INFO = protobuf.Type.fromJSON('LegacyProtocolInfo', {
|
|
671
|
+
fields: {
|
|
672
|
+
version: {
|
|
673
|
+
rule: 'required',
|
|
674
|
+
type: 'uint32',
|
|
675
|
+
id: 1,
|
|
676
|
+
},
|
|
677
|
+
supported_messages: {
|
|
678
|
+
rule: 'repeated',
|
|
679
|
+
type: 'uint32',
|
|
680
|
+
id: 2,
|
|
681
|
+
options: {
|
|
682
|
+
packed: false,
|
|
683
|
+
},
|
|
684
|
+
},
|
|
685
|
+
protobuf_definition: {
|
|
686
|
+
type: 'string',
|
|
687
|
+
id: 3,
|
|
688
|
+
},
|
|
689
|
+
},
|
|
690
|
+
});
|
|
691
|
+
const decodeLegacyProtocolV2ProtocolInfo = (pbPayload) => {
|
|
692
|
+
var _a;
|
|
693
|
+
const byteBuffer = ByteBuffer__default["default"].wrap(Buffer.from(pbPayload));
|
|
694
|
+
const legacy = decode(LEGACY_PROTOCOL_V2_PROTOCOL_INFO, byteBuffer);
|
|
695
|
+
return {
|
|
696
|
+
version: legacy.version,
|
|
697
|
+
build_fingerprint: '',
|
|
698
|
+
supported_messages: (_a = legacy.supported_messages) !== null && _a !== void 0 ? _a : [],
|
|
699
|
+
protobuf_definition: null,
|
|
700
|
+
};
|
|
701
|
+
};
|
|
702
|
+
const isLegacyProtocolV2ProtocolInfoWireLayout = (pbPayload) => {
|
|
703
|
+
const reader = protobuf.Reader.create(pbPayload);
|
|
704
|
+
let hasVersion = false;
|
|
705
|
+
try {
|
|
706
|
+
while (reader.pos < reader.len) {
|
|
707
|
+
const tag = reader.uint32();
|
|
708
|
+
const fieldNumber = tag >>> 3;
|
|
709
|
+
const wireType = tag & 0x07;
|
|
710
|
+
if (fieldNumber === 1) {
|
|
711
|
+
if (wireType !== 0)
|
|
712
|
+
return false;
|
|
713
|
+
hasVersion = true;
|
|
714
|
+
}
|
|
715
|
+
else if (fieldNumber === 2) {
|
|
716
|
+
if (wireType !== 0)
|
|
717
|
+
return false;
|
|
718
|
+
}
|
|
719
|
+
else if (fieldNumber === 3) {
|
|
720
|
+
if (wireType !== 2)
|
|
721
|
+
return false;
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
return false;
|
|
725
|
+
}
|
|
726
|
+
reader.skipType(wireType);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
catch (_a) {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
return hasVersion;
|
|
733
|
+
};
|
|
734
|
+
const tryDecodeLegacyProtocolV2ProtocolInfo = (messageName, pbPayload) => {
|
|
735
|
+
if (messageName !== 'ProtocolInfo' || !isLegacyProtocolV2ProtocolInfoWireLayout(pbPayload)) {
|
|
736
|
+
return undefined;
|
|
737
|
+
}
|
|
738
|
+
try {
|
|
739
|
+
return decodeLegacyProtocolV2ProtocolInfo(pbPayload);
|
|
740
|
+
}
|
|
741
|
+
catch (_a) {
|
|
742
|
+
return undefined;
|
|
743
|
+
}
|
|
744
|
+
};
|
|
670
745
|
const resolveProtocolV2EncodeSchema = (name, schemas) => {
|
|
671
746
|
try {
|
|
672
747
|
schemas.protocolV2.lookupType(name);
|
|
@@ -745,6 +820,17 @@ const ProtocolV2 = {
|
|
|
745
820
|
message = decode(Message, rxByteBuffer);
|
|
746
821
|
}
|
|
747
822
|
catch (cause) {
|
|
823
|
+
const legacyProtocolInfo = tryDecodeLegacyProtocolV2ProtocolInfo(messageName, pbPayload);
|
|
824
|
+
if (legacyProtocolInfo) {
|
|
825
|
+
return {
|
|
826
|
+
message: legacyProtocolInfo,
|
|
827
|
+
messageName,
|
|
828
|
+
messageTypeId,
|
|
829
|
+
pbPayload,
|
|
830
|
+
seq,
|
|
831
|
+
type: messageName,
|
|
832
|
+
};
|
|
833
|
+
}
|
|
748
834
|
const error = new Error(`Protocol V2 protobuf decode failed for "${messageName}" ` +
|
|
749
835
|
`(${messageTypeId}, ${pbPayload.length}-byte payload); ` +
|
|
750
836
|
'the payload is malformed or incompatible with the active SDK schema.');
|
|
@@ -40,6 +40,18 @@ export declare const ProtocolV2: {
|
|
|
40
40
|
};
|
|
41
41
|
encodeFrame(schemas: ProtocolV2Schemas, name: string, data: Record<string, unknown>, options?: ProtocolV2FrameOptions): Uint8Array;
|
|
42
42
|
decodeFrame(schemas: ProtocolV2Schemas, frame: Uint8Array): {
|
|
43
|
+
message: {
|
|
44
|
+
version: any;
|
|
45
|
+
build_fingerprint: string;
|
|
46
|
+
supported_messages: any;
|
|
47
|
+
protobuf_definition: null;
|
|
48
|
+
};
|
|
49
|
+
messageName: string;
|
|
50
|
+
messageTypeId: number;
|
|
51
|
+
pbPayload: Uint8Array;
|
|
52
|
+
seq: number;
|
|
53
|
+
type: string;
|
|
54
|
+
} | {
|
|
43
55
|
message: {
|
|
44
56
|
[key: string]: any;
|
|
45
57
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/protocols/index.ts"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/protocols/index.ts"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AAGpC,OAAO,EAAE,qBAAqB,EAA+C,MAAM,cAAc,CAAC;AAElG,OAAO,EAAE,aAAa,IAAI,eAAe,EAAE,MAAM,cAAc,CAAC;AAIhE,OAAO,EAGL,kBAAkB,EAClB,UAAU,EACX,MAAM,MAAM,CAAC;AAEd,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,eAAO,MAAM,iCAAiC,QAAQ,CAAC;AAEvD,KAAK,iBAAiB,GAAG;IACvB,UAAU,EAAE,IAAI,CAAC;IACjB,UAAU,EAAE,IAAI,CAAC;CAClB,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAqHF,eAAO,MAAM,UAAU;;;;;;;;;;CAOtB,CAAC;AAEF,eAAO,MAAM,UAAU;;;0BAIC,iBAAiB,SAAS,UAAU;;;;;;;;;;yBAgB/C,iBAAiB,QACpB,MAAM,QACN,OAAO,MAAM,EAAE,OAAO,CAAC,YACpB,sBAAsB;yBAkBZ,iBAAiB,SAAS,UAAU;;;;;;;;;;;;;;;;;;;;;;CAqC1D,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.102",
|
|
4
4
|
"description": "Transport layer abstractions and utilities for OneKey hardware SDK.",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
@@ -28,5 +28,5 @@
|
|
|
28
28
|
"long": "^4.0.0",
|
|
29
29
|
"protobufjs": "^6.11.2"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "49f939a3fa496be9bd6763737a98b3ade81a2a45"
|
|
32
32
|
}
|
package/src/protocols/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ByteBuffer from 'bytebuffer';
|
|
2
|
+
import { Reader, Type } from 'protobufjs/light';
|
|
2
3
|
|
|
3
4
|
import { encodeEnvelopeMessage, encodeMessageChunks, encodeTransportPackets } from './v1/packets';
|
|
4
5
|
import { decodeFirstChunk } from './v1/decode';
|
|
@@ -29,6 +30,85 @@ type ProtocolV2FrameOptions = {
|
|
|
29
30
|
seq?: number;
|
|
30
31
|
};
|
|
31
32
|
|
|
33
|
+
const LEGACY_PROTOCOL_V2_PROTOCOL_INFO = Type.fromJSON('LegacyProtocolInfo', {
|
|
34
|
+
fields: {
|
|
35
|
+
version: {
|
|
36
|
+
rule: 'required',
|
|
37
|
+
type: 'uint32',
|
|
38
|
+
id: 1,
|
|
39
|
+
},
|
|
40
|
+
supported_messages: {
|
|
41
|
+
rule: 'repeated',
|
|
42
|
+
type: 'uint32',
|
|
43
|
+
id: 2,
|
|
44
|
+
options: {
|
|
45
|
+
packed: false,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
protobuf_definition: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
id: 3,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const decodeLegacyProtocolV2ProtocolInfo = (pbPayload: Uint8Array) => {
|
|
56
|
+
const byteBuffer = ByteBuffer.wrap(Buffer.from(pbPayload) as unknown as ArrayBuffer);
|
|
57
|
+
const legacy = decodeProtobuf(LEGACY_PROTOCOL_V2_PROTOCOL_INFO, byteBuffer);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
version: legacy.version,
|
|
61
|
+
build_fingerprint: '',
|
|
62
|
+
supported_messages: legacy.supported_messages ?? [],
|
|
63
|
+
// Presence of this legacy field lets Core keep the fallback recovery-only.
|
|
64
|
+
protobuf_definition: null,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const isLegacyProtocolV2ProtocolInfoWireLayout = (pbPayload: Uint8Array) => {
|
|
69
|
+
const reader = Reader.create(pbPayload);
|
|
70
|
+
let hasVersion = false;
|
|
71
|
+
try {
|
|
72
|
+
while (reader.pos < reader.len) {
|
|
73
|
+
const tag = reader.uint32();
|
|
74
|
+
// eslint-disable-next-line no-bitwise
|
|
75
|
+
const fieldNumber = tag >>> 3;
|
|
76
|
+
// eslint-disable-next-line no-bitwise
|
|
77
|
+
const wireType = tag & 0x07;
|
|
78
|
+
if (fieldNumber === 1) {
|
|
79
|
+
if (wireType !== 0) return false;
|
|
80
|
+
hasVersion = true;
|
|
81
|
+
} else if (fieldNumber === 2) {
|
|
82
|
+
// Legacy field 2 is repeated uint32; current field 2 is a string.
|
|
83
|
+
if (wireType !== 0) return false;
|
|
84
|
+
} else if (fieldNumber === 3) {
|
|
85
|
+
// Legacy field 3 is protobuf_definition; current field 3 is uint32.
|
|
86
|
+
if (wireType !== 2) return false;
|
|
87
|
+
} else {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
reader.skipType(wireType);
|
|
91
|
+
}
|
|
92
|
+
} catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return hasVersion;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const tryDecodeLegacyProtocolV2ProtocolInfo = (messageName: string, pbPayload: Uint8Array) => {
|
|
99
|
+
// TEMPORARY COMPATIBILITY: Remove this fallback after all supported Pro2 and Neo
|
|
100
|
+
// firmware versions return ProtocolInfo with the current build_fingerprint layout.
|
|
101
|
+
if (messageName !== 'ProtocolInfo' || !isLegacyProtocolV2ProtocolInfoWireLayout(pbPayload)) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
return decodeLegacyProtocolV2ProtocolInfo(pbPayload);
|
|
107
|
+
} catch {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
32
112
|
const resolveProtocolV2EncodeSchema = (name: string, schemas: ProtocolV2Schemas) => {
|
|
33
113
|
try {
|
|
34
114
|
schemas.protocolV2.lookupType(name);
|
|
@@ -123,6 +203,17 @@ export const ProtocolV2 = {
|
|
|
123
203
|
try {
|
|
124
204
|
message = decodeProtobuf(Message, rxByteBuffer);
|
|
125
205
|
} catch (cause) {
|
|
206
|
+
const legacyProtocolInfo = tryDecodeLegacyProtocolV2ProtocolInfo(messageName, pbPayload);
|
|
207
|
+
if (legacyProtocolInfo) {
|
|
208
|
+
return {
|
|
209
|
+
message: legacyProtocolInfo,
|
|
210
|
+
messageName,
|
|
211
|
+
messageTypeId,
|
|
212
|
+
pbPayload,
|
|
213
|
+
seq,
|
|
214
|
+
type: messageName,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
126
217
|
const error = new Error(
|
|
127
218
|
`Protocol V2 protobuf decode failed for "${messageName}" ` +
|
|
128
219
|
`(${messageTypeId}, ${pbPayload.length}-byte payload); ` +
|