UNPKG

4.14 kBJavaScriptView Raw
1/* @flow */
2
3'use strict';
4
5import * as messages from './messages';
6import type {AcquireInput, TrezorDeviceInfoWithSession, MessageFromTrezor} from '../transport';
7import * as check from '../highlevel-checks';
8
9import {debugInOut} from '../debug-decorator';
10
11const EXTENSION_ID: string = `jcjjhjgimijdkoamemaghajlhegmoclj`;
12
13function maybeParseInt(input: ?string): ?(string | number) {
14 if (input == null) {
15 return null;
16 }
17 if (isNaN(input)) {
18 return input;
19 } else {
20 const parsed = parseInt(input);
21 if (isNaN(parsed)) {
22 return input;
23 }
24 return parsed;
25 }
26}
27
28export default class ChromeExtensionTransport {
29 name: string = `ChromeExtensionTransport`;
30 version: string = ``;
31 configured: boolean = false;
32
33 id: string;
34 showUdevError: boolean = false;
35
36 debug: boolean = false;
37
38 constructor(id?: ?string) {
39 this.id = id == null ? EXTENSION_ID : id;
40 }
41
42 async _send(message: messages.ChromeMessage): Promise<mixed> {
43 const res = await messages.send(this.id, message);
44 const udev = await messages.send(this.id, {type: `udevStatus`});
45 this.showUdevError = (udev === `display`);
46 return res;
47 }
48
49 async ping(): Promise<void> {
50 const res = await this._send({type: `ping`});
51 if (res !== `pong`) {
52 throw new Error(`Response to "ping" should be "pong".`);
53 }
54 }
55
56 async info(): Promise<{version: string, configured: boolean}> {
57 const infoS = await this._send({type: `info`});
58 return check.info(infoS);
59 }
60
61 @debugInOut
62 async init(debug: ?boolean): Promise<void> {
63 this.debug = !!debug;
64 await this._silentInit();
65 }
66
67 async _silentInit(): Promise<void> {
68 await messages.exists();
69 await this.ping();
70 const info = await this.info();
71 this.version = info.version;
72 this.configured = info.configured;
73 }
74
75 @debugInOut
76 async configure(config: string): Promise<void> {
77 await this._send({
78 type: `configure`,
79 body: config,
80 });
81 // we should reload configured after configure
82 await this._silentInit();
83 }
84
85 @debugInOut
86 async listen(old: ?Array<TrezorDeviceInfoWithSession>): Promise<Array<TrezorDeviceInfoWithSession>> {
87 const devicesS: mixed = await (
88 this._send({
89 type: `listen`,
90 body: old == null ? null : old.map(device => {
91 // hack for old extension
92 const session = maybeParseInt(device.session);
93 const path = maybeParseInt(device.path);
94 let res = {
95 path,
96 // hack for old extension
97 product: 1,
98 vendor: 21324,
99 serialNumber: 0,
100 };
101 // hack for old extension
102 if (session != null) {
103 res = { session, ...res };
104 }
105 return res;
106 }),
107 })
108 );
109 const devices = check.devices(devicesS);
110 return devices;
111 }
112
113 @debugInOut
114 async enumerate(): Promise<Array<TrezorDeviceInfoWithSession>> {
115 const devicesS: mixed = await this._send({type: `enumerate`});
116 const devices = check.devices(devicesS);
117 return devices;
118 }
119
120 async _acquireMixed(input: AcquireInput): Promise<mixed> {
121 const checkPrevious = input.checkPrevious;
122 if (checkPrevious) {
123 return this._send({
124 type: `acquire`,
125 body: {
126 path: maybeParseInt(input.path),
127 previous: maybeParseInt(input.previous),
128 },
129 });
130 } else {
131 return this._send({
132 type: `acquire`,
133 body: maybeParseInt(input.path),
134 });
135 }
136 }
137
138 @debugInOut
139 async acquire(input: AcquireInput): Promise<string> {
140 const acquireS = await this._acquireMixed(input);
141 return check.acquire(acquireS);
142 }
143
144 @debugInOut
145 async release(session: string): Promise<void> {
146 await this._send({
147 type: `release`,
148 body: maybeParseInt(session),
149 });
150 }
151
152 @debugInOut
153 async call(session: string, name: string, data: Object): Promise<MessageFromTrezor> {
154 const res = await this._send({
155 type: `call`,
156 body: {
157 id: maybeParseInt(session),
158 type: name,
159 message: data,
160 },
161 });
162 return check.call(res);
163 }
164}