chore(protocol): rename getChunkHeader to getHeaders and return [header, chunkHeader]

This commit is contained in:
Szymon Lesisz
2025-06-02 17:28:28 +02:00
committed by Szymon Lesisz
parent 4b8dbc051e
commit b893516894
10 changed files with 51 additions and 43 deletions

View File

@@ -1,13 +1,13 @@
import { HEADER_SIZE } from './constants';
import { TransportProtocolEncode } from '../types';
import { TransportProtocol } from '../types';
// for type compatibility, bridge doesn't send chunks
export const getChunkHeader = (_data: Buffer) => Buffer.alloc(0);
// just for type compatibility, bridge doesn't send headers
export const getHeaders: TransportProtocol['getHeaders'] = () => [Buffer.alloc(0), Buffer.alloc(0)];
// this file is basically combination of "trezor v1 protocol" and "bridge protocol"
// there is actually no officially described bridge protocol, but in fact there is one
// it is because bridge does some parts of the protocol itself (like chunking)
export const encode: TransportProtocolEncode = (data, options) => {
export const encode: TransportProtocol['encode'] = (data, options) => {
const { messageType } = options;
if (typeof messageType === 'string') {
throw new Error(`Unsupported message type ${messageType}`);

View File

@@ -1,14 +1,22 @@
import { HEADER_SIZE, MESSAGE_HEADER_BYTE, MESSAGE_MAGIC_HEADER_BYTE } from './constants';
import { TransportProtocolEncode } from '../types';
import { TransportProtocol } from '../types';
export const getChunkHeader = (_data: Buffer) => {
const header = Buffer.alloc(1);
header.writeUInt8(MESSAGE_MAGIC_HEADER_BYTE);
// header: 3f2323 `?##` and chunkHeader: 3f `?`
export const getHeaders: TransportProtocol['getHeaders'] = () => {
const header = Buffer.alloc(3);
// 1 byte
header.writeUInt8(MESSAGE_MAGIC_HEADER_BYTE, 0);
// 2*1 byte
header.writeUInt8(MESSAGE_HEADER_BYTE, 1);
header.writeUInt8(MESSAGE_HEADER_BYTE, 2);
return header;
const chunkHeader = Buffer.alloc(1);
chunkHeader.writeUInt8(MESSAGE_MAGIC_HEADER_BYTE);
return [header, chunkHeader];
};
export const encode: TransportProtocolEncode = (data, options) => {
export const encode: TransportProtocol['encode'] = (data, options) => {
const { messageType } = options;
if (typeof messageType === 'string') {
throw new Error(`Unsupported message type ${messageType}`);
@@ -17,12 +25,8 @@ export const encode: TransportProtocolEncode = (data, options) => {
const fullSize = HEADER_SIZE + data.length;
const encodedBuffer = Buffer.alloc(fullSize);
// 1 byte
encodedBuffer.writeUInt8(MESSAGE_MAGIC_HEADER_BYTE, 0);
// 2*1 byte
encodedBuffer.writeUInt8(MESSAGE_HEADER_BYTE, 1);
encodedBuffer.writeUInt8(MESSAGE_HEADER_BYTE, 2);
const [header] = getHeaders(data);
header.copy(encodedBuffer);
// 2 bytes
encodedBuffer.writeUInt16BE(messageType, 3);

View File

@@ -1,6 +1,6 @@
import * as ERRORS from '../errors';
import { HEADER_SIZE, MESSAGE_LEN_SIZE, MESSAGE_TYPE } from './constants';
import { getChunkHeader } from './encode';
import { getHeaders } from './encode';
import { TransportProtocolDecode } from '../types';
// Parses raw input from Trezor and returns some information about the whole message
@@ -12,9 +12,11 @@ export const decode: TransportProtocolDecode = bytes => {
throw new Error(ERRORS.PROTOCOL_MALFORMED);
}
const [header, chunkHeader] = getHeaders(buffer);
return {
header: buffer.subarray(0, HEADER_SIZE),
chunkHeader: getChunkHeader(buffer),
header,
chunkHeader,
length: buffer.readUint16BE(HEADER_SIZE),
messageType: MESSAGE_TYPE, // will be decoded by `protocol-thp`
payload: buffer.subarray(HEADER_SIZE + MESSAGE_LEN_SIZE),

View File

@@ -1,8 +1,8 @@
import * as ERRORS from '../errors';
import { HEADER_SIZE, MESSAGE_LEN_SIZE, MESSAGE_TYPE } from './constants';
import { TransportProtocolEncode } from '../types';
import { TransportProtocol } from '../types';
export const getChunkHeader = (data: Buffer) => {
const getChunkHeader = (data: Buffer) => {
// data should have at least 1 control_byte + 2 bytes channel
if (data.byteLength < HEADER_SIZE) {
throw new Error(ERRORS.PROTOCOL_MALFORMED);
@@ -14,8 +14,14 @@ export const getChunkHeader = (data: Buffer) => {
return header;
};
export const getHeaders: TransportProtocol['getHeaders'] = data => {
const chunkHeader = getChunkHeader(data);
return [data.subarray(0, HEADER_SIZE), chunkHeader];
};
// encode `protocol-thp` message
export const encode: TransportProtocolEncode = (data, options) => {
export const encode: TransportProtocol['encode'] = (data, options) => {
if (options.messageType === MESSAGE_TYPE) {
if (!options.header || options.header.byteLength !== HEADER_SIZE) {
throw new Error(

View File

@@ -26,5 +26,5 @@ export interface TransportProtocol {
name: 'bridge' | 'v1' | 'v2';
encode: TransportProtocolEncode;
decode: TransportProtocolDecode;
getChunkHeader: (data: Buffer) => Buffer;
getHeaders: (data: Buffer) => [header: Buffer, chunkHeader: Buffer];
}

View File

@@ -1,4 +1,4 @@
import { decode, encode, getChunkHeader } from '../src/protocol-v2';
import { decode, encode, getHeaders } from '../src/protocol-v2';
describe('protocol-v2', () => {
it('encode/decode TrezorHostProtocolMessage', () => {
@@ -43,11 +43,12 @@ describe('protocol-v2', () => {
expect(() => decode(Buffer.alloc(0))).toThrow('Malformed protocol format');
});
it('getChunkHeader', () => {
expect(getChunkHeader(Buffer.from('0412380000', 'hex'))).toEqual(
it('getHeaders', () => {
expect(getHeaders(Buffer.from('0412380000', 'hex'))).toEqual([
Buffer.from('041238', 'hex'),
Buffer.from('801238', 'hex'),
);
]);
// with error
expect(() => getChunkHeader(Buffer.alloc(0))).toThrow('Malformed protocol format');
expect(() => getHeaders(Buffer.alloc(0))).toThrow('Malformed protocol format');
});
});

View File

@@ -67,10 +67,10 @@ export const createCore = (apiArg: 'usb' | 'udp' | AbstractApi, logger?: Log) =>
if (protocol.name === 'bridge') {
const { messageType, payload } = protocolBridge.decode(buffer);
encodedMessage = protocolV1.encode(payload, { messageType });
chunkHeader = protocolV1.getChunkHeader(encodedMessage);
[, chunkHeader] = protocolV1.getHeaders(encodedMessage);
} else {
encodedMessage = buffer;
chunkHeader = protocol.getChunkHeader(encodedMessage);
[, chunkHeader] = protocol.getHeaders(encodedMessage);
}
const chunks = createChunks(encodedMessage, chunkHeader, api.chunkSize);

View File

@@ -201,11 +201,8 @@ export abstract class AbstractApiTransport extends AbstractTransport {
data,
protocol,
});
const chunks = createChunks(
bytes,
protocol.getChunkHeader(bytes),
this.api.chunkSize,
);
const [, chunkHeader] = protocol.getHeaders(bytes);
const chunks = createChunks(bytes, chunkHeader, this.api.chunkSize);
const apiWrite = (chunk: Buffer) => this.api.write(path, chunk, signal);
const sendResult = await sendChunks(chunks, apiWrite);
@@ -257,11 +254,9 @@ export abstract class AbstractApiTransport extends AbstractTransport {
data,
protocol,
});
const chunks = createChunks(
bytes,
protocol.getChunkHeader(bytes),
this.api.chunkSize,
);
const [_, chunkHeader] = protocol.getHeaders(bytes);
const chunks = createChunks(bytes, chunkHeader, this.api.chunkSize);
const apiWrite = (chunk: Buffer) => this.api.write(path, chunk, signal);
const sendResult = await sendChunks(chunks, apiWrite);

View File

@@ -15,7 +15,7 @@ export async function receive<T extends () => ReturnType<AbstractApi['read']>>(
const data = readResult.payload;
const { length, messageType, payload } = protocol.decode(data);
const result = Buffer.alloc(length);
const chunkHeader = protocol.getChunkHeader(Buffer.from(data));
const [, chunkHeader] = protocol.getHeaders(Buffer.from(data));
payload.copy(result);
let offset = payload.length;

View File

@@ -130,8 +130,8 @@ describe('encoding json -> protobuf -> json', () => {
data: f.in,
protocol: v1Protocol,
});
const chunks = createChunks(result, v1Protocol.getChunkHeader(result), 64);
const [, chunkHeader] = v1Protocol.getHeaders(result);
const chunks = createChunks(result, chunkHeader, 64);
// each protocol chunks are equal 64 bytes
chunks.forEach(chunk => {
expect(chunk.length).toEqual(64);