trezor-link
Version:
Trezor Link for browser
108 lines (92 loc) • 3 kB
Flow
/* @flow */
;
// Helper module for converting Trezor's raw input to
// ProtoBuf's message and from there to regular JSON to trezor.js
import * as ProtoBuf from "protobufjs-old-fixed-webpack";
const ByteBuffer = ProtoBuf.ByteBuffer;
const Long = ProtoBuf.Long;
import {Messages} from "./messages.js";
export class MessageDecoder {
// Builders, generated by reading config
messages: Messages;
// message type number
type: number;
// raw data to push to Trezor
data: ArrayBuffer;
constructor(messages: Messages, type: number, data: ArrayBuffer) {
this.type = type;
this.data = data;
this.messages = messages;
}
// Returns an info about this message,
// which includes the constructor object and a name
_messageInfo() : MessageInfo {
const r = this.messages.messagesByType[this.type];
if (r == null) {
throw new Error(`Method type not found - ${this.type}`);
}
return new MessageInfo(r.constructor, r.name);
}
// Returns the name of the message
messageName() : string {
return this._messageInfo().name;
}
// Returns the actual decoded message, as a ProtoBuf.js object
_decodedMessage() : ProtoBuf.Builder.Message {
const constructor = this._messageInfo().messageConstructor;
return constructor.decode(this.data);
}
// Returns the message decoded to JSON, that could be handed back
// to trezor.js
decodedJSON() : Object {
const decoded = this._decodedMessage();
const converted = messageToJSON(decoded);
return JSON.parse(JSON.stringify(converted));
}
}
class MessageInfo {
messageConstructor: ProtoBuf.Builder.Message;
name: string;
constructor(messageConstructor: ProtoBuf.Builder.Message, name: string) {
this.messageConstructor = messageConstructor;
this.name = name;
}
}
// Converts any ProtoBuf message to JSON in Trezor.js-friendly format
function messageToJSON(message: ProtoBuf.Builder.Message) : Object {
const res = {};
const meta = message.$type;
for (const key in message) {
const value = message[key];
if (typeof value === `function`) {
// ignoring
} else if (value instanceof ByteBuffer) {
const hex = value.toHex();
res[key] = hex;
} else if (value instanceof Long) {
const num = value.toNumber();
res[key] = num;
} else if (Array.isArray(value)) {
const decodedArr = value.map((i) => {
if (typeof i === `object`) {
return messageToJSON(i);
} else {
return i;
}
});
res[key] = decodedArr;
} else if (value instanceof ProtoBuf.Builder.Message) {
res[key] = messageToJSON(value);
} else if (meta._fieldsByName[key].type.name === `enum`) {
if (value == null) {
res[key] = null;
} else {
const enumValues = meta._fieldsByName[key].resolvedType.getChildren();
res[key] = enumValues.find(e => e.id === value).name;
}
} else {
res[key] = value;
}
}
return res;
}