One last step Linux users need to do one last step to get started. You can:
4 |
7 |
8 | Go to TREZOR Wallet and follow instructions there
9 | Alternatively, you can do the following:
10 |
11 | Disconnect your TREZOR device.
12 | Create new file /etc/udev/rules.d/51-trezor.rules in your favourite text editor (root privileges are necessary).
13 | Copy the following two lines, paste them into the file and save it.
14 |
15 |
16 |
17 |
SUBSYSTEM=="usb", ATTR{idVendor}=="534c", ATTR{idProduct}=="0001", MODE="0666", GROUP="dialout", SYMLINK+="trezor%n"
18 | KERNEL=="hidraw*", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", MODE="0666", GROUP="dialout"
19 |
20 |
21 | Reconnect your device.
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/management/app/views/main.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
6 |
This app is intended for a simple device management.
7 |
8 |
9 |
10 |
Connect your TREZOR to start.
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/management/app/views/modal/button.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
9 |
Fee is over threshold.
10 | Please confirm the action on your device.
11 |
12 |
13 |
15 |
Please write down the recovery seed from your device.
16 |
17 |
18 |
20 |
Check address on TREZOR display
21 |
If the address matches your TREZOR display,
22 | you can be sure it is genuine.
23 |
24 |
25 | /{{address.path[address.path.length-1]}}
27 | {{address.address}}
29 |
30 |
31 |
32 |
37 |
38 |
39 |
40 |
43 |
44 |
Confirm passphrase encryption
45 |
46 | If you forget your passphrase, you will lose your coins.
47 |
48 |
49 |
50 |
54 |
Please confirm the action on your device.
55 |
56 |
57 |
58 |
59 |
61 |
62 |
All data on your device will be deleted.
63 |
This action cannot be undone. Please confirm on your
64 | device .
65 |
Never do this action with TREZOR holding coins unless you have your
66 | recovery seed at hand.
67 |
68 |
69 |
70 |
Please confirm the action on your device.
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/management/app/views/modal/disconnect.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 | {{customText}}
13 |
14 |
19 |
--------------------------------------------------------------------------------
/management/app/views/modal/disconnect.wipe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
Your Trezor was successfully wiped.
8 |
Please disconnect it now.
9 |
10 |
--------------------------------------------------------------------------------
/management/app/views/modal/firmware.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
Our team is constantly working on adding new features to TREZOR.
14 | To enjoy full functionality and security of your device, we
15 | strongly recommend you to update.
16 |
17 |
To update the firmware, please disconnect your device and then plug it
18 | in while holding both device buttons pressed .
19 |
20 |
21 |
22 | For more information
23 | see the user manual .
25 |
26 |
27 |
28 |
Firmware info
29 |
30 | Current firmware:
31 | {{version[0]}}.{{version[1]}}.{{version[2]}}
32 | Available firmware:
33 | {{firmware.version[0]}}.{{firmware.version[1]}}.{{firmware.version[2]}}
34 |
35 |
36 |
37 |
Changelog
38 |
{{firmware.changelog}}
39 |
40 |
41 |
42 | Read the full release notes
44 |
45 |
46 |
47 |
Support needed?
49 |
50 |
55 |
56 |
57 |
58 |
59 |
64 |
65 |
Now plug your device in with both device buttons pressed .
66 |
67 |
68 | For more information
69 | see the user manual.
71 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
85 | You have plugged in a device in a bootloader mode. That is a special mode intended for updating the firmware. If you don't want to change the firmware, just unplug the device and plug it in again.
86 |
87 |
88 |
89 |
Caution!
90 |
If your TREZOR is already initialized always have your Recovery seed with you before updating the firmware!
91 |
In very rare cases, a firmware update might result in the need to recover the wallet
92 | from Recovery seed.
93 |
For more information,
94 | visit the user manual.
97 |
98 |
99 |
100 |
Firmware info
101 |
102 | Current firmware:
103 | {{version[0]}}.{{version[1]}}.{{version[2]}}
104 | (Current firmware version can't be determined in bootloader mode)
105 | Available firmware:
106 | {{firmware.version[0]}}.{{firmware.version[1]}}.{{firmware.version[2]}}
107 |
108 |
109 |
110 |
Changelog
111 |
{{firmware.changelog}}
112 |
113 |
114 |
115 | Read the full release notes
117 |
118 |
119 |
120 |
121 |
130 |
131 |
132 |
133 |
134 |
139 |
140 |
141 |
142 |
Your TREZOR is not in the firmware update mode.
143 |
Please reconnect it while pressing both buttons simultaneously.
144 |
145 |
146 |
151 |
152 |
153 |
154 |
155 |
156 |
Downloading firmware...
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
Uploading firmware...
165 |
If asked, please confirm the update on your device.
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
Please confirm the firmware fingerprint.
175 |
Make sure the same fingerprint is displayed on the device screen.
176 |
177 |
178 |
180 | {{firmware.fingerprint.substr(0, 16)}}
181 | {{firmware.fingerprint.substr(16, 16)}}
182 | {{firmware.fingerprint.substr(32, 16)}}
183 | {{firmware.fingerprint.substr(48, 16)}}
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
Update was successful
195 |
Please unplug the device now.
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
Update failed
204 |
{{error}}
205 |
206 |
207 |
208 |
209 |
210 |
--------------------------------------------------------------------------------
/management/app/views/modal/forget.disconnected.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/management/app/views/modal/forget.requested.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
Do you want to forget your device?
8 |
Forgetting only removes the device from the list
9 | on the left, your bitcoins are still safe and you can access them by
10 | reconnecting your Trezor again.
11 |
12 |
13 |
17 |
--------------------------------------------------------------------------------
/management/app/views/modal/forget.wipe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
Your Trezor was successfully wiped.
9 |
10 |
13 |
--------------------------------------------------------------------------------
/management/app/views/modal/label.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
21 |
--------------------------------------------------------------------------------
/management/app/views/modal/passphrase.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
59 |
64 |
--------------------------------------------------------------------------------
/management/app/views/modal/pin.html:
--------------------------------------------------------------------------------
1 |
2 |
106 |
--------------------------------------------------------------------------------
/management/app/views/modal/setup.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
7 |
8 |
10 |
We will now show you {{recoveryWords}} words that will allow
11 | you to recover your accounts in case you lose your
12 | device. Please write down all these words
13 | carefully.
14 |
15 |
Please write down the {{recoveryCurrentWord | ordinal}} word of your
16 | recovery seed.
17 |
18 |
19 |
21 |
Please write down the {{recoveryCurrentWord | ordinal}} word of your
22 | recovery seed.
23 |
24 |
25 |
27 |
We will now show you the {{recoveryWords}} words
28 | again. Please check carefully that you wrote them down
29 | correctly.
30 |
31 |
Please check the {{recoveryCurrentWord | ordinal}} word of your recovery
32 | seed.
33 |
34 |
35 |
37 |
Please check the {{recoveryCurrentWord | ordinal}} word of your recovery
38 | seed.
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/management/app/views/modal/upperheader.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
--------------------------------------------------------------------------------
/management/app/views/topBars.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 | New TREZOR firmware is available.
7 | Upgrade for the newest features and bug fixes.
8 | Show details
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/management/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webwallet",
3 | "version": "1.0.0",
4 | "dependencies": {
5 | "lodash": "~2.4.1",
6 | "jquery": "~2.1.0",
7 | "angular": "~1.3.0",
8 | "angular-route": "~1.3.0",
9 | "angular-sanitize": "~1.3.0",
10 | "angular-bootstrap": "~0.12.0",
11 | "angular-qr": "~0.2.0",
12 | "bootstrap": "~3.2.0",
13 | "bootstrap-slider": "seiyria/bootstrap-slider#~1.9.0",
14 | "trezor.js": "trezor/trezor.js#4.1.3"
15 | },
16 | "devDependencies": {},
17 | "resolutions": {
18 | "angular": "~1.3.0"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/management/firmware_copy.py:
--------------------------------------------------------------------------------
1 | import json
2 | import shutil
3 | import os
4 |
5 | if not os.path.exists('../extension/data'):
6 | os.makedirs('../extension/data')
7 |
8 | with open('data/firmware/releases.json') as data_file:
9 | data = json.load(data_file)
10 |
11 | top = data[0]
12 |
13 |
14 | url = top["url"]
15 | filename = url[url.rfind("/")+1 : ]
16 |
17 | shutil.copy('data/firmware/' + filename, '../extension/data/firmware.bin.hex')
18 |
19 | shutil.copy('data/config_signed.bin', '../extension/data/config_signed.bin');
20 |
21 | top["url"] = '/data/firmware.bin.hex';
22 |
23 | with open('../extension/data/releases.json', 'w') as outfile:
24 | json.dump([ top ], outfile, indent=4)
25 |
26 |
27 |
--------------------------------------------------------------------------------
/management/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webwallet",
3 | "version": "0.0.0",
4 | "devDependencies": {
5 | "grunt": "~0.4.5",
6 | "grunt-angular-templates": "~0.5.7",
7 | "grunt-autoprefixer": "~1.0.1",
8 | "grunt-concurrent": "^1.0.0",
9 | "grunt-contrib-clean": "~0.6.0",
10 | "grunt-contrib-compass": "~1.0.1",
11 | "grunt-contrib-concat": "~0.5.0",
12 | "grunt-contrib-connect": "~0.8.0",
13 | "grunt-contrib-copy": "^0.7.0",
14 | "grunt-contrib-cssmin": "~0.10.0",
15 | "grunt-contrib-htmlmin": "~0.3.0",
16 | "grunt-contrib-jshint": "~0.10.0",
17 | "grunt-contrib-uglify": "~0.6.0",
18 | "grunt-contrib-watch": "~0.6.1",
19 | "grunt-filerev": "~2.1.2",
20 | "grunt-google-cdn": "~0.4.3",
21 | "grunt-ng-annotate": "^0.10.0",
22 | "grunt-rev": "~0.1.0",
23 | "grunt-svgmin": "~1.0.0",
24 | "grunt-usemin": "~2.4.0",
25 | "jshint-stylish": "~1.0.0",
26 | "load-grunt-tasks": "~0.6.0",
27 | "time-grunt": "~1.0.0",
28 | "grunt-cli": "~0.1.13",
29 | "bower": "~1.4.1"
30 | },
31 | "engines": {
32 | "node": ">=0.8.0"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/manifest_no_matches.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "TREZOR Chrome Extension",
3 | "description": "Chrome extension for TREZOR",
4 | "version": "1.2.7",
5 | "author": "SatoshiLabs",
6 | "short_name": "TREZOR Extension",
7 |
8 | "manifest_version": 2,
9 | "minimum_chrome_version": "38.0.2125.7",
10 | "icons": {
11 | "16": "icon16.png",
12 | "48": "icon48.png",
13 | "128": "icon128.png"
14 | },
15 |
16 | "sockets": {
17 | "udp": {
18 | "bind": [
19 | "127.0.0.1:21327", "127.0.0.1:21328","127.0.0.1:21329",
20 | "127.0.0.1:21330", "127.0.0.1:21331","127.0.0.1:21332"
21 | ],
22 | "send": ["127.0.0.1:21324", "127.0.0.1:21325","127.0.0.1:21326"]
23 | }
24 | },
25 | "app": {
26 | "background": {
27 | "scripts": ["index.js"]
28 | }
29 | },
30 | "externally_connectable": "WILL BE CHANGED BY SCRIPT",
31 | "permissions": [
32 | "hid", {
33 | "usbDevices": [{
34 | "vendorId": 21324,
35 | "productId": 1
36 | },
37 | {
38 | "vendorId": 4617,
39 | "productId": 21441
40 | },
41 | {
42 | "vendorId": 4617,
43 | "productId": 21440
44 | }
45 | ]
46 | },
47 | "storage"
48 | ],
49 | "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlBLI7C8hybngCmlKgfLytKQiqrTQYHQpz6E0DcWYeqC047J5hFtxbODYsPIn9sCJePv/LCW9jOc3G3B/aUGK1Lks+DrbnNlDgI/Ja4MzYEEaYyLFquHJlQe7B2doMTLS9JQfkWsXe/IQW8vfYq5Jo4JmiucXUbr37Xlsl0U/ScwSz0hDnzHQfpCpuLuUQP6kQrqbJ8Rd3NDlh5qAB0BfewDoDmlgGBlV+za80I8KYRSwgAvfEndevcsXQzV6myKptdqpffEbGhjwZ63ehofbnlr4c5i25OkMirI5bfcmP+6g/wYt4zOBnCep8MK8eG92NvocSBsu530XDywuCiY+2QIDAQAB"
50 | }
51 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "trezor-chrome-extension",
3 | "version": "1.2.4",
4 | "description": "Chrome extension for communication with Trezor",
5 | "main": "index.js",
6 | "keywords": [
7 | "chrome",
8 | "trezor",
9 | "bitcoin"
10 | ],
11 | "contributors": [
12 | {
13 | "name": "Mike Tsao",
14 | "mail": "mike@sowbug.com"
15 | },
16 | {
17 | "name": "Liz Fong-Jones",
18 | "mail": "lizf@google.com"
19 | },
20 | {
21 | "name": "William Wolf",
22 | "mail": "throughnothing@gmail.com"
23 | },
24 | {
25 | "name": "Karel Bílek",
26 | "mail": "kb@karelbilek.com"
27 | }
28 | ],
29 | "license": "GPL-3.0",
30 | "homepage": "https://github.com/trezor/trezor-chrome-extension",
31 | "repository": {
32 | "type": "git",
33 | "url": "git://github.com/trezor/trezor-chrome-extension.git"
34 | },
35 | "dependencies": {
36 | "trezor-link-browser-extension": "0.2.85"
37 | },
38 | "devDependencies": {
39 | "babel-plugin-add-module-exports": "^0.1.2",
40 | "babel-plugin-transform-class-properties": "^6.6.0",
41 | "babel-plugin-transform-flow-strip-types": "^6.7.0",
42 | "babel-plugin-transform-object-rest-spread": "^6.8.0",
43 | "babel-preset-chrome-49": "^1.0.0",
44 | "babelify": "^7.2.0",
45 | "browserify": "^13.1.0",
46 | "envify": "^3.4.0",
47 | "fast-async": "^6.0.31"
48 | },
49 | "browserify": {
50 | "transform": [
51 | [
52 | "babelify",
53 | {
54 | "presets": [
55 | "chrome-49"
56 | ],
57 | "plugins": [
58 | "transform-flow-strip-types",
59 | "transform-class-properties",
60 | "transform-object-rest-spread",
61 | "add-module-exports",
62 | "fast-async"
63 | ]
64 | }
65 | ],
66 | [
67 | "envify"
68 | ]
69 | ]
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/.eslintignore:
--------------------------------------------------------------------------------
1 | config_proto_compiled.js
2 |
--------------------------------------------------------------------------------
/src/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | .*/node_modules/protobufjs/src/.*
3 | .*/node_modules/bitcoinjs-lib-zcash/.*
4 | .*/node_modules/bigi/.*
5 |
6 | [include]
7 | ../node_modules/trezor-link-browser-extension/
8 | ../node_modules/json-stable-stringify/*
9 | ../node_modules/protobufjs/*
10 | ../node_modules/object.values/*
11 | ../node_modules/semver-compare/*
12 |
13 | [libs]
14 | ../flowtype_definitions/chrome.js
15 | ../node_modules/trezor-link-browser-extension/flowtype/bitcoinjs-lib.js
16 | ../node_modules/trezor-link-browser-extension/flowtype/chrome.js
17 | ../node_modules/trezor-link-browser-extension/flowtype/webusb.js
18 | ../node_modules/trezor-link-browser-extension/flowtype/node-hid.js
19 |
20 | [options]
21 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue
22 | esproposal.class_instance_fields=enable
23 | esproposal.decorators=ignore
24 |
--------------------------------------------------------------------------------
/src/chrome/platformInfo.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 | /**
3 | * This file is part of the TREZOR project.
4 | *
5 | * Copyright (C) 2015 SatoshiLabs
6 | *
7 | * This library is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This library is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with this library. If not, see .
19 | */
20 |
21 | "use strict";
22 |
23 | export function manifest(): Promise {
24 | return new Promise((resolve, reject) => {
25 | try {
26 | resolve(chrome.runtime.getManifest());
27 | } catch (e) {
28 | reject(e);
29 | }
30 | });
31 | }
32 |
--------------------------------------------------------------------------------
/src/chrome/storage.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 | /**
3 | * This file is part of the TREZOR project.
4 | *
5 | * Copyright (C) 2015 SatoshiLabs
6 | *
7 | * This library is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This library is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with this library. If not, see .
19 | */
20 |
21 | // Chrome's extension storage is actually more complicated
22 | // than LocalStorage, because it uses callbacks =>
23 | // I am converting them to (IMO) more manageable Promises
24 |
25 | "use strict";
26 |
27 | // Get from storage
28 | export function get(key: string): Promise {
29 | return new Promise((resolve, reject) => {
30 | try {
31 | chrome.storage.local.get(key, (items) => {
32 | if (chrome.runtime.lastError) {
33 | reject(chrome.runtime.lastError);
34 | } else {
35 | if (items[key] === null || items[key] === undefined) {
36 | resolve(null);
37 | } else {
38 | resolve(items[key]);
39 | }
40 | resolve(items);
41 | }
42 | });
43 | } catch (e) {
44 | reject(e);
45 | }
46 | });
47 | }
48 |
49 | // Set to storage
50 | export function set(key:string, value:any): Promise {
51 | return new Promise((resolve, reject) => {
52 | try {
53 | const obj: {} = {};
54 | obj[key] = value;
55 | chrome.storage.local.set(obj, () => {
56 | if (chrome.runtime.lastError) {
57 | reject(chrome.runtime.lastError);
58 | } else {
59 | resolve(undefined);
60 | }
61 | });
62 | } catch (e) {
63 | reject(e);
64 | }
65 | });
66 | }
67 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | "use strict";
4 |
5 | import type {AcquireInput, TrezorDeviceInfoWithSession as LinkDevice} from "trezor-link-browser-extension";
6 |
7 | import Link from "trezor-link-browser-extension";
8 | import * as storage from "./chrome/storage";
9 | import {manifest} from "./chrome/platformInfo";
10 |
11 | type MessageFromTrezor = {type: string, message: Object};
12 | type StatusInfo = {version: string, configured: boolean}
13 |
14 | type TrezorDeviceInfo = {
15 | path: string;
16 | vendor: number;
17 | product: number;
18 | serialNumber: number; // always 0
19 | session: ?string; // might be null/undefined
20 | }
21 |
22 | const TREZOR_VENDOR_ID: number = 0x534c;
23 | const TREZOR_PRODUCT_ID: number = 0x0001;
24 |
25 | const ParallelTransport = Link.Parallel;
26 | const LowlevelTransport = Link.Lowlevel;
27 | const ChromeHidPlugin = Link.ChromeHid;
28 | const ChromeUdpPlugin = Link.ChromeUdp;
29 | // const FallbackTransport = Link.Fallback;
30 | // const BridgeTransport = Link.Bridge;
31 | /* const link = new FallbackTransport(
32 | [
33 | new BridgeTransport(),
34 | new LowlevelTransport(new ChromeHidPlugin()),
35 | ]
36 | );*/
37 |
38 | const udpPlugin = new ChromeUdpPlugin();
39 | const link = new ParallelTransport(
40 | {
41 | "udp": new LowlevelTransport(udpPlugin),
42 | "hid": new LowlevelTransport(new ChromeHidPlugin()),
43 | }
44 | );
45 |
46 | link.init(process.env.NODE_ENV === "debug").catch((err) => console.error("Cannot init", err));
47 |
48 | // when we try to read messages and it's null, we look into storage
49 | // if it's not saved. If it is saved, we try to configure again
50 | async function messagesReload(): Promise {
51 | const hasMessages = link.configured;
52 | if (hasMessages) {
53 | return;
54 | }
55 | let savedConfigure: string = "";
56 | try {
57 | savedConfigure = await storage.get("savedConfigure");
58 | } catch (e) {
59 | throw new Error("No protocol definition, call configure.");
60 | }
61 | await configure(savedConfigure);
62 | }
63 |
64 | async function ping() {
65 | return "pong";
66 | }
67 |
68 | function convertDevices(devices: Array): Array {
69 | return devices.map(device => {
70 | return {
71 | ...device,
72 | vendor: TREZOR_VENDOR_ID,
73 | product: TREZOR_PRODUCT_ID,
74 | serialNumber: 0,
75 | };
76 | });
77 | }
78 |
79 | async function enumerate(): Promise> {
80 | return convertDevices(await link.enumerate());
81 | }
82 |
83 | async function listen(previous: mixed): Promise> {
84 | let convertedPrevious: ?Array = null;
85 | if (previous != null) {
86 | if (typeof previous === "object") {
87 | if (previous instanceof Array) {
88 | convertedPrevious = previous.map((d: mixed): LinkDevice => {
89 | if (typeof d !== "object" || d == null) {
90 | throw new Error("Device is not an object");
91 | }
92 | if (typeof d.path !== "string" && typeof d.path !== "number") {
93 | throw new Error("Device path is strange");
94 | }
95 | const path: string = d.path.toString();
96 | let session: ?string = null;
97 | if (d.session != null) {
98 | if (typeof d.session !== "string" && typeof d.session !== "number") {
99 | throw new Error("Device session is strange");
100 | }
101 | session = d.session.toString();
102 | }
103 | const r: LinkDevice = {path, session};
104 | return r;
105 | });
106 | }
107 | }
108 | }
109 | return convertDevices(await link.listen(convertedPrevious));
110 | }
111 |
112 | function parseAcquireInput(input: mixed): AcquireInput {
113 | if (typeof input === "string") {
114 | return {path: input, previous: null, checkPrevious: false};
115 | } else if (typeof input === "object" && input != null) {
116 | if (typeof input.path !== "string" && typeof input.path !== "number") {
117 | throw new Error("Device path is strange.");
118 | }
119 | const path: string = input.path.toString();
120 | let previous: ?string = null;
121 | if (input.previous != null) {
122 | if (typeof input.previous !== "string" && typeof input.previous !== "number") {
123 | throw new Error("Device session is strange.");
124 | }
125 | previous = input.previous.toString();
126 | }
127 |
128 | return {path, previous, checkPrevious: true};
129 | }
130 | throw new Error("Acquire input is strange.");
131 | }
132 |
133 | async function acquire(input: mixed): Promise<{session: string}> {
134 | const session = await link.acquire(parseAcquireInput(input));
135 | return {session};
136 | }
137 |
138 | async function release(input: mixed): Promise {
139 | if (typeof input !== "string" && typeof input !== "number") {
140 | throw new Error("Device session is strange.");
141 | }
142 | await link.release(input.toString());
143 | return "Success";
144 | }
145 |
146 | async function udevStatus(): Promise {
147 | // const hasError: boolean = await hidTransport.showUdevError();
148 | // return hasError ? "display" : "hide";
149 | return "hide";
150 | }
151 |
152 | async function call(input: mixed): Promise {
153 | if (typeof input !== "object" || input == null) {
154 | throw new Error("Input is not an object");
155 | }
156 | if (typeof input.id !== "string" && typeof input.id !== "number") {
157 | throw new Error("Session is strange.");
158 | }
159 | if (typeof input.type !== "string") {
160 | throw new Error("Type is not a string.");
161 | }
162 | const type: string = input.type;
163 | if (typeof input.message !== "object" || input.message == null) {
164 | throw new Error("Message is not an object.");
165 | }
166 | const message: Object = input.message;
167 | const id: string = input.id.toString();
168 | await messagesReload();
169 | return await link.call(id, type, message);
170 | }
171 |
172 | async function configure(input: mixed): Promise {
173 | if (typeof input !== "string") {
174 | throw new Error("Configure input is strange.");
175 | }
176 | const body: string = input;
177 | await storage.set(body);
178 | await link.configure(body);
179 | return "Success";
180 | }
181 |
182 | async function _version(): Promise {
183 | const version = (await manifest()).version;
184 | if (version == null) {
185 | throw new Error("Manifest doesn't have a version!");
186 | }
187 | return version;
188 | }
189 |
190 | async function _configured(): Promise {
191 | try {
192 | await messagesReload();
193 | return true;
194 | } catch (e) {
195 | return false;
196 | }
197 | }
198 |
199 | async function info(): Promise {
200 | return {
201 | version: await _version(),
202 | configured: await _configured(),
203 | };
204 | }
205 |
206 | const responseFunctions = {
207 | ping,
208 | enumerate,
209 | listen,
210 | acquire,
211 | release,
212 | udevStatus,
213 | call,
214 | configure,
215 | info,
216 | };
217 |
218 | const setUdp = function (ports: Array) {
219 | storage.set("udp", JSON.stringify(ports));
220 | udpPlugin.setPorts(ports);
221 | console.log("Ports added", ports);
222 | };
223 |
224 | window.setUdp = setUdp;
225 |
226 | const startingPromise = storage.get("udp").then((udpSerialized) => {
227 | const udpStorage = JSON.parse(udpSerialized);
228 | if (udpStorage instanceof Array) {
229 | setUdp(udpStorage);
230 | }
231 | return;
232 | });
233 |
234 | function handleMessage(request: Object, sender: ChromeMessageSender, sendResponse: (response: Object) => void): boolean {
235 | if (process.env.NODE_ENV === "debug") {
236 | console.log("Message arrived: ", request);
237 | }
238 |
239 | const responseFunction = (responseFunctions[request.type])
240 | ? responseFunctions[request.type]
241 | : () => {
242 | throw new Error("No function defined for " + request.type);
243 | };
244 |
245 | const nonThrowingResponse = (body) => {
246 | try {
247 | return startingPromise.then(() => responseFunction(body));
248 | } catch (e) {
249 | return Promise.reject(e);
250 | }
251 | };
252 |
253 | nonThrowingResponse(request.body).then((responseBody) => {
254 | if (process.env.NODE_ENV === "debug") {
255 | console.log("Response sent: ", JSON.parse(JSON.stringify(responseBody)), JSON.parse(JSON.stringify(request)));
256 | }
257 |
258 | sendResponse({
259 | type: "response",
260 | body: responseBody,
261 | });
262 | }).catch((error) => {
263 | if (process.env.NODE_ENV === "debug") {
264 | console.log("Error sent: ", error, JSON.parse(JSON.stringify(request)));
265 | }
266 |
267 | sendResponse({
268 | type: "error",
269 | message: error.message || error,
270 | });
271 | });
272 |
273 | // "return true" is necessary for asynchronous message passing,
274 | // don't remove it!
275 | return true;
276 | }
277 |
278 | chrome.runtime.onMessage.addListener(handleMessage);
279 | chrome.runtime.onMessageExternal.addListener(handleMessage);
280 | let windowOpen: boolean = false;
281 |
282 | chrome.app.runtime.onLaunched.addListener(() => {
283 | if (!windowOpen) {
284 | chrome.app.window.create("management/index.html", {
285 | "innerBounds": {
286 | "width": 774,
287 | "height": 774,
288 | },
289 | }, (newWindow) => {
290 | windowOpen = true;
291 | newWindow.onClosed.addListener(() => {
292 | windowOpen = false;
293 | });
294 | });
295 | }
296 | });
297 |
298 | storage.get("udp").then((udpSerialized) => {
299 | const udpStorage = JSON.parse(udpSerialized);
300 | if (udpStorage instanceof Array) {
301 | udpPlugin.setPorts(udpStorage);
302 | }
303 | });
304 |
--------------------------------------------------------------------------------