@trezor/connect 9.3.0 → 9.3.1-beta.2

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.
Files changed (60) hide show
  1. package/CHANGELOG.md +121 -8
  2. package/README.md +1 -1
  3. package/lib/api/checkFirmwareAuthenticity.d.ts +2 -1
  4. package/lib/api/checkFirmwareAuthenticity.js +34 -26
  5. package/lib/api/ethereum/api/ethereumSignTypedData.d.ts +1 -0
  6. package/lib/api/ethereum/api/ethereumSignTypedData.js +3 -1
  7. package/lib/api/ethereum/ethereumDefinitions.js +1 -0
  8. package/lib/api/firmware/getBinary.d.ts +4 -4
  9. package/lib/api/firmware/getBinary.js +4 -15
  10. package/lib/api/firmware/getBinaryForFirmwareUpgrade.d.ts +11 -0
  11. package/lib/api/firmware/getBinaryForFirmwareUpgrade.js +32 -0
  12. package/lib/api/firmware/index.d.ts +1 -0
  13. package/lib/api/firmware/index.js +3 -1
  14. package/lib/api/firmware/verifyAuthenticityProof.d.ts +1 -1
  15. package/lib/api/firmware/verifyAuthenticityProof.js +37 -2
  16. package/lib/api/firmware/x509certificate.d.ts +20 -6
  17. package/lib/api/firmware/x509certificate.js +82 -13
  18. package/lib/api/getCoinInfo.d.ts +3 -0
  19. package/lib/api/getFeatures.d.ts +1 -0
  20. package/lib/backend/Blockchain.js +10 -1
  21. package/lib/core/AbstractMethod.js +1 -0
  22. package/lib/core/index.d.ts +3 -3
  23. package/lib/core/index.js +93 -111
  24. package/lib/core/onCallFirmwareUpdate.js +25 -14
  25. package/lib/data/DataManager.d.ts +11 -0
  26. package/lib/data/DataManager.js +1 -1
  27. package/lib/data/coinInfo.d.ts +14 -0
  28. package/lib/data/config.d.ts +11 -0
  29. package/lib/data/config.js +17 -1
  30. package/lib/data/connectSettings.js +3 -2
  31. package/lib/data/deviceAuthenticityConfig.d.ts +1 -28
  32. package/lib/data/deviceAuthenticityConfig.js +25 -24
  33. package/lib/data/deviceAuthenticityConfigTypes.d.ts +38 -0
  34. package/lib/data/deviceAuthenticityConfigTypes.js +28 -0
  35. package/lib/data/models.d.ts +10 -0
  36. package/lib/data/models.js +12 -10
  37. package/lib/data/version.d.ts +2 -1
  38. package/lib/data/version.js +3 -2
  39. package/lib/device/Device.d.ts +2 -3
  40. package/lib/device/Device.js +15 -24
  41. package/lib/device/DeviceCommands.js +2 -27
  42. package/lib/device/DeviceList.d.ts +42 -27
  43. package/lib/device/DeviceList.js +249 -233
  44. package/lib/events/core.d.ts +2 -2
  45. package/lib/events/popup.d.ts +1 -0
  46. package/lib/events/transport.d.ts +5 -0
  47. package/lib/index.js +20 -20
  48. package/lib/types/api/authenticateDevice.d.ts +9 -0
  49. package/lib/types/api/authenticateDevice.js +2 -2
  50. package/lib/types/api/checkFirmwareAuthenticity.d.ts +4 -1
  51. package/lib/types/api/init.d.ts +2 -2
  52. package/lib/types/coinInfo.d.ts +7 -0
  53. package/lib/types/firmware.d.ts +2 -2
  54. package/lib/types/settings.d.ts +7 -3
  55. package/lib/utils/assetUtils.js +1 -0
  56. package/lib/utils/promiseUtils.d.ts +3 -3
  57. package/lib/utils/promiseUtils.js +7 -5
  58. package/package.json +16 -17
  59. package/lib/core/coreManager.d.ts +0 -16
  60. package/lib/core/coreManager.js +0 -55
package/CHANGELOG.md CHANGED
@@ -1,15 +1,128 @@
1
- | Package | Stable | Canary |
2
- | :------------------------------: | :----: | :----: |
3
- | npm @trezor/connect | 9.3.0 | - |
4
- | npm @trezor/connect-web | 9.3.0 | - |
5
- | npm @trezor/connect-webextension | 9.3.0 | - |
1
+ | Package | Stable | Canary |
2
+ | :------------------------------: | :----: | :----------: |
3
+ | npm @trezor/connect | 9.3.0 | 9.3.1-beta.2 |
4
+ | npm @trezor/connect-web | 9.3.0 | 9.3.1-beta.2 |
5
+ | npm @trezor/connect-webextension | 9.3.0 | 9.3.1-beta.2 |
6
6
 
7
- | Deployment | Stable | Canary |
8
- | :----------------: | :----: | :----: |
9
- | connect.trezor.io/ | 9.3.0 | - |
7
+ | Deployment | Stable | Canary |
8
+ | :----------------: | :----: | :----------: |
9
+ | connect.trezor.io/ | 9.3.0 | 9.3.1-beta.2 |
10
10
 
11
11
  Use the persistent link [connect.trezor.io/9](https://connect.trezor.io/9/) to access the latest stable version of Connect Explorer.
12
12
 
13
+ # 9.3.1-beta.2
14
+
15
+ - refactor(connect): removed initDeviceList, move transportReconnect inside DeviceList, make DeviceList reusable, device list constructor not throwing, singleton-like DeviceList, separate onTransportUpdate, pendingTransportEvent improved, improve DeviceList init flow (f4b3694, 02215de, b53259b, e8c6c25, e395dc8, 6509e5c, 3e30d64, d173966, 50cbbea, 1a81d89, 4780c51, 75bfe75, 83c0cb3, 73261c8, f2167bf, bb7dfee)
16
+ - fix(connect): correctly wait for device selection in case of overriding (0c7a3bd)
17
+ - fix(connect): Fork old PassphraseTypeCard to connect (155afda)
18
+ - fix(connect): longer timeout for getFeatures due to suite-native performance issue (0910ab7)
19
+ - fix(connect): handle malformed EIP-712 data (d111006)
20
+ - fix(connect): remove superfluous space from error message (81be584)
21
+ - fix(connect): correctly await transport.receive (31c8519)
22
+ - fix(connect): proper pendingTransportEvent waiting (baa4144)
23
+ - chore(connect): add a comment to legacy code (a23a365)
24
+
25
+ ## connect-web
26
+
27
+ - don't fallback to core in popup with no webusb (7120e83)
28
+ - clean up in popupmanager when useUi=false (9bc2ea9)
29
+
30
+ ## connect-popup
31
+
32
+ - add missing device icons (9fdd1d7)
33
+
34
+ ## connect-webextension
35
+
36
+ - Allow multiple content script extension conflicts (348b32a)
37
+
38
+ ## connect-explorer
39
+
40
+ - wrong default coreMode in settings (3a81f14)
41
+ - don't validate connectSrc in webextension (8737d47)
42
+ - add link to new webextension example (86a13b1)
43
+
44
+ ## Dependencies update
45
+
46
+ - bump react-intl from 6.6.2 to 6.6.8
47
+ - bump @types/chrome from 0.0.260 to 0.0.269
48
+ - bump playwright from 1.41.2 to 1.45.3
49
+ - bump webpack-merge from 5.10.0 to 6.0.1
50
+ - bump webpack-dev-server from 4.15.1 to 5.0.4
51
+ - bump @babel/preset-typescript from 7.23.3 to 7.24.7
52
+ - bump @babel/preset-react from 7.23.3 to 7.24.7
53
+ - bump webpack from 5.90.1 to 5.93.0
54
+ - bump rimraf from 5.0.5 to 6.0.1
55
+ - bump txs from 4.7.0 to 4.16.2
56
+
57
+ - npm-prerelease: @trezor/blockchain-link 2.2.1-beta.2
58
+ - npm-prerelease: @trezor/blockchain-link-utils 1.1.1-beta.2
59
+ - npm-prerelease: @trezor/blockchain-link-types 1.1.1-beta.2
60
+ - npm-prerelease: @trezor/analytics 1.1.1-beta.1
61
+ - npm-prerelease: @trezor/connect-common 0.1.1-beta.2
62
+ - npm-prerelease: @trezor/env-utils 1.1.1-beta.1
63
+ - npm-prerelease: @trezor/transport 1.2.1-beta.2
64
+ - npm-prerelease: @trezor/protobuf 1.1.1-beta.2
65
+ - npm-prerelease: @trezor/schema-utils 1.1.1-beta.1
66
+ - npm-prerelease: @trezor/protocol 1.1.1-beta.1
67
+ - npm-prerelease: @trezor/utxo-lib 2.1.1-beta.1
68
+ - npm-prerelease: @trezor/utils 9.1.1-beta.2
69
+ - npm-release: @trezor/connect 9.3.1-beta.2
70
+
71
+ # 9.3.1-beta.1
72
+
73
+ We introduce a new init option `coreMode`, which allows websites to interact either using the existing `iframe` mode or the new `popup` mode. The `popup` mode is allows to use WebUSB even on third-party websites, which is not possible with the `iframe` mode. By default, the `coreMode` is set to `auto`, which means that the library will automatically choose the best mode based on the environment. More information can be found in [init method documentation](https://connect.trezor.io/9.3.1-beta.1/methods/other/init/).
74
+
75
+ Remove support for legacy passphrase, users with Firmware version smaller than 1.0.9 and 2.3.0 will be requested to update in order to use @trezor/connect (7bb57cf)
76
+
77
+ AuthenticateDevice verify CA cert extensions (4ba4445)
78
+
79
+ Add support for T3B1 (f7f1705)
80
+
81
+ - chore(connect): Add Ambire Browser Extension to knownHosts (cbe81ab)
82
+ - chore(connect): remove ethereum-cryptography (18851d1)
83
+ - chore(connect): split public and internal settings type (3aab4ea)
84
+ - chore(connect): remove useCoreInPopup from explorer and tests (fee60c1)
85
+ - chore(connect): add new CA pubkeys and update timestamp (48ec951)
86
+ - chore(connect): refactoring of the CheckFirmwareAuthenticity to support local binary (and wont download it from web, when its available in the suite) (82ab513)
87
+ - docs(connect): describe coreMode (a5238d6)
88
+ - fix(connect): disallow interaction-less fw update when switching fw type (4936939)
89
+ - fix(connect): validate x509 asn1 component (bc13fe2)
90
+ - fix(connect): handle missing language binary (954dbb9)
91
+ - fix(connect): proceed with fw install even when language data fails to download (b40d1b7)
92
+ - test(connect): x509 extensions parser (163c82c)
93
+ - test(connect): update to min version fw 1.0.9 and 2.3.0 (544c311)
94
+
95
+ ## connect-ui
96
+
97
+ - remove bridge references, deeplink to suite desktop (98e98a4)
98
+
99
+ ## connect-plugin-stellar
100
+
101
+ - update stellar sdk (89cf20e)
102
+ - update trends libs (70b9c11)
103
+
104
+ ## connect-web
105
+
106
+ - default coreMode to auto (e45d47e)
107
+ - automatic fallback to core in popup (e4e1fcc)
108
+
109
+ ## connect-webextension
110
+
111
+ - link changelog to the one in connect (a02ec72)
112
+
113
+ ## connect-explorer
114
+
115
+ - applySettings optional values (0bcd83a)
116
+ - hide extra headings from toc in homepage (14f89c4)
117
+ - show success message in settings (0ca7c0c)
118
+ - remove MTT for firmwareUpdate (ebbe96c)
119
+ - bad styled-components prop (e2b7fc7)
120
+
121
+ ## connect-common
122
+
123
+ - add new fw 2.8.0 (314052b)
124
+ - fw version 1.9.0 and 2.3.0 required (ee623e4)
125
+
13
126
  # 9.3.0
14
127
 
15
128
  Improved reliability of popup handshake mechanism.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @trezor/connect
2
2
 
3
- API version 9.3.0
3
+ API version 9.3.1-beta.2
4
4
 
5
5
  [![Build Status](https://github.com/trezor/trezor-suite/actions/workflows/test-connect.yml/badge.svg)](https://github.com/trezor/trezor-suite/actions/workflows/test-connect.yml)
6
6
  [![NPM](https://img.shields.io/npm/v/@trezor/connect.svg)](https://www.npmjs.org/package/@trezor/connect)
@@ -1,5 +1,6 @@
1
1
  import { AbstractMethod } from '../core/AbstractMethod';
2
- export default class CheckFirmwareAuthenticity extends AbstractMethod<'checkFirmwareAuthenticity'> {
2
+ import { CheckFirmwareAuthenticityParams } from '../types/api/checkFirmwareAuthenticity';
3
+ export default class CheckFirmwareAuthenticity extends AbstractMethod<'checkFirmwareAuthenticity', CheckFirmwareAuthenticityParams> {
3
4
  init(): void;
4
5
  run(): Promise<{
5
6
  expectedFirmwareHash: string;
@@ -5,43 +5,51 @@ const AbstractMethod_1 = require("../core/AbstractMethod");
5
5
  const firmware_1 = require("./firmware");
6
6
  const firmwareInfo_1 = require("../data/firmwareInfo");
7
7
  const constants_1 = require("../constants");
8
- const assets_1 = require("../utils/assets");
9
8
  const types_1 = require("../types");
9
+ const paramsValidator_1 = require("./common/paramsValidator");
10
10
  class CheckFirmwareAuthenticity extends AbstractMethod_1.AbstractMethod {
11
11
  init() {
12
12
  this.useEmptyPassphrase = true;
13
13
  this.requiredPermissions = ['management'];
14
14
  this.useDeviceState = false;
15
+ const { payload } = this;
16
+ (0, paramsValidator_1.validateParams)(payload, [{ name: 'baseUrl', type: 'string' }]);
17
+ this.params = { baseUrl: payload.baseUrl };
15
18
  }
16
19
  async run() {
17
- var _a;
20
+ var _a, _b;
18
21
  const { device } = this;
19
- const firmwareVersion = `${device.features.major_version}.${device.features.minor_version}.${device.features.patch_version}`;
20
- const releases = (0, firmwareInfo_1.getReleases)((_a = device.features) === null || _a === void 0 ? void 0 : _a.internal_model);
21
- const release = releases.find(release => release.version.join('.') === firmwareVersion);
22
- if (!release) {
23
- throw constants_1.ERRORS.TypedError('Runtime', 'checkFirmwareAuthenticity: No release found for device firmware');
22
+ if (!device.firmwareRelease) {
23
+ throw constants_1.ERRORS.TypedError('Runtime', 'device.firmwareRelease is not set');
24
24
  }
25
- const deviceModelPath = `${device.features.internal_model}`.toLowerCase();
26
- const baseUrl = `https://data.trezor.io/firmware/${deviceModelPath}`;
27
- const fwUrl = `${baseUrl}/trezor-${deviceModelPath}-${firmwareVersion}${device.firmwareType === types_1.FirmwareType.BitcoinOnly ? '-bitcoinonly.bin' : '.bin'}`;
28
- const fw = await (0, assets_1.httpRequest)(fwUrl, 'binary');
29
- if (!fw) {
30
- throw constants_1.ERRORS.TypedError('Runtime', 'checkFirmwareAuthenticity: firmware binary not found');
25
+ const btcOnly = device.firmwareType === types_1.FirmwareType.BitcoinOnly;
26
+ try {
27
+ const fw = await (0, firmware_1.getBinary)({
28
+ releases: (0, firmwareInfo_1.getReleases)((_a = device.features) === null || _a === void 0 ? void 0 : _a.internal_model),
29
+ baseUrl: (_b = this.params.baseUrl) !== null && _b !== void 0 ? _b : 'https://data.trezor.io',
30
+ version: device.getVersion(),
31
+ btcOnly,
32
+ });
33
+ if (!fw) {
34
+ throw constants_1.ERRORS.TypedError('Runtime', 'checkFirmwareAuthenticity: firmware binary not found');
35
+ }
36
+ const { hash: expectedFirmwareHash, challenge } = (0, firmware_1.calculateFirmwareHash)(device.features.major_version, (0, firmware_1.stripFwHeaders)(fw), (0, crypto_1.randomBytes)(32));
37
+ const result = await this.device
38
+ .getCommands()
39
+ .typedCall('GetFirmwareHash', 'FirmwareHash', {
40
+ challenge,
41
+ });
42
+ const { message } = result;
43
+ const { hash: actualFirmwareHash } = message;
44
+ return {
45
+ expectedFirmwareHash,
46
+ actualFirmwareHash,
47
+ valid: actualFirmwareHash === expectedFirmwareHash,
48
+ };
49
+ }
50
+ catch (e) {
51
+ throw constants_1.ERRORS.TypedError('Runtime', `${e}`);
31
52
  }
32
- const { hash: expectedFirmwareHash, challenge } = (0, firmware_1.calculateFirmwareHash)(device.features.major_version, (0, firmware_1.stripFwHeaders)(fw), (0, crypto_1.randomBytes)(32));
33
- const result = await this.device
34
- .getCommands()
35
- .typedCall('GetFirmwareHash', 'FirmwareHash', {
36
- challenge,
37
- });
38
- const { message } = result;
39
- const { hash: actualFirmwareHash } = message;
40
- return {
41
- expectedFirmwareHash,
42
- actualFirmwareHash,
43
- valid: actualFirmwareHash === expectedFirmwareHash,
44
- };
45
53
  }
46
54
  }
47
55
  exports.default = CheckFirmwareAuthenticity;
@@ -60,6 +60,7 @@ declare const Params: import("@sinclair/typebox").TIntersect<[import("@sinclair/
60
60
  T1B1: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TLiteral<false>]>;
61
61
  T2T1: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TLiteral<false>]>;
62
62
  T2B1: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TLiteral<false>]>;
63
+ T3B1: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TLiteral<false>]>;
63
64
  T3T1: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TLiteral<false>]>;
64
65
  connect: import("@sinclair/typebox").TBoolean;
65
66
  }>;
@@ -150,7 +150,9 @@ class EthereumSignTypedData extends AbstractMethod_1.AbstractMethod {
150
150
  memberTypeName = memberTypeDefinition.type;
151
151
  memberData = memberData[memberTypeDefinition.name];
152
152
  }
153
- else {
153
+ if (memberData === null || memberData === undefined) {
154
+ cmd.typedCall('Cancel', 'Success');
155
+ throw constants_1.ERRORS.TypedError('Runtime', `Value from member path ${member_path} is missing in the data object`);
154
156
  }
155
157
  }
156
158
  let encodedData;
@@ -102,6 +102,7 @@ const ethereumNetworkInfoFromDefinition = (definition) => ({
102
102
  T1B1: '1.6.2',
103
103
  T2T1: '2.0.7',
104
104
  T2B1: '2.6.1',
105
+ T3B1: '2.8.1',
105
106
  T3T1: '2.7.1',
106
107
  },
107
108
  blockchainLink: undefined,
@@ -1,11 +1,11 @@
1
- import { GetInfoProps } from '../../data/firmwareInfo';
2
- import { IntermediaryVersion } from '../../types';
3
- interface GetBinaryProps extends GetInfoProps {
1
+ import { FirmwareRelease, IntermediaryVersion } from '../../types';
2
+ interface GetBinaryProps {
4
3
  baseUrl: string;
5
4
  btcOnly?: boolean;
6
5
  version?: number[];
7
6
  intermediaryVersion?: IntermediaryVersion;
7
+ releases: FirmwareRelease[];
8
8
  }
9
- export declare const getBinary: ({ features, releases, baseUrl, version, btcOnly, intermediaryVersion, }: GetBinaryProps) => Promise<ArrayBuffer>;
9
+ export declare const getBinary: ({ releases, baseUrl, version, btcOnly, intermediaryVersion, }: GetBinaryProps) => Promise<ArrayBuffer>;
10
10
  export {};
11
11
  //# sourceMappingURL=getBinary.d.ts.map
@@ -3,30 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getBinary = void 0;
4
4
  const utils_1 = require("@trezor/utils");
5
5
  const assets_1 = require("../../utils/assets");
6
- const firmwareUtils_1 = require("../../utils/firmwareUtils");
7
- const firmwareInfo_1 = require("../../data/firmwareInfo");
8
- const getBinary = ({ features, releases, baseUrl, version, btcOnly, intermediaryVersion, }) => {
9
- if (!(0, firmwareUtils_1.isStrictFeatures)(features)) {
10
- throw new Error('Features of unexpected shape provided');
11
- }
6
+ const getBinary = ({ releases, baseUrl, version, btcOnly, intermediaryVersion, }) => {
12
7
  if (intermediaryVersion) {
13
8
  return (0, assets_1.httpRequest)(`${baseUrl}/firmware/t1b1/trezor-t1b1-inter-v${intermediaryVersion}.bin`, 'binary');
14
9
  }
15
- const infoByBootloader = (0, firmwareInfo_1.getInfo)({ features, releases });
16
10
  const releaseByFirmware = releases.find(r => version &&
17
11
  utils_1.versionUtils.isVersionArray(version) &&
18
12
  utils_1.versionUtils.isEqual(r.version, version));
19
- if (!infoByBootloader || !releaseByFirmware) {
13
+ if (releaseByFirmware === undefined) {
20
14
  throw new Error('no firmware found for this device');
21
15
  }
22
- if (btcOnly && !releaseByFirmware.url_bitcoinonly) {
23
- throw new Error(`firmware version ${version} does not exist in btc only variant`);
24
- }
25
- if (!utils_1.versionUtils.isEqual(releaseByFirmware.version, infoByBootloader.release.version)) {
26
- throw new Error('version provided as param does not match firmware version found by features in bootloader');
27
- }
28
16
  const fwUrl = releaseByFirmware[btcOnly ? 'url_bitcoinonly' : 'url'];
29
- return (0, assets_1.httpRequest)(`${baseUrl}/${fwUrl}`, 'binary');
17
+ const url = `${baseUrl}/${fwUrl}`;
18
+ return (0, assets_1.httpRequest)(url, 'binary');
30
19
  };
31
20
  exports.getBinary = getBinary;
32
21
  //# sourceMappingURL=getBinary.js.map
@@ -0,0 +1,11 @@
1
+ import { GetInfoProps } from '../../data/firmwareInfo';
2
+ import { IntermediaryVersion } from '../../types';
3
+ interface GetBinaryForFirmwareUpgradeProps extends GetInfoProps {
4
+ baseUrl: string;
5
+ btcOnly?: boolean;
6
+ version?: number[];
7
+ intermediaryVersion?: IntermediaryVersion;
8
+ }
9
+ export declare const getBinaryForFirmwareUpgrade: ({ features, releases, baseUrl, version, btcOnly, intermediaryVersion, }: GetBinaryForFirmwareUpgradeProps) => Promise<ArrayBuffer>;
10
+ export {};
11
+ //# sourceMappingURL=getBinaryForFirmwareUpgrade.d.ts.map
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getBinaryForFirmwareUpgrade = void 0;
4
+ const utils_1 = require("@trezor/utils");
5
+ const assets_1 = require("../../utils/assets");
6
+ const firmwareUtils_1 = require("../../utils/firmwareUtils");
7
+ const firmwareInfo_1 = require("../../data/firmwareInfo");
8
+ const getBinary_1 = require("./getBinary");
9
+ const getBinaryForFirmwareUpgrade = ({ features, releases, baseUrl, version, btcOnly, intermediaryVersion, }) => {
10
+ if (!(0, firmwareUtils_1.isStrictFeatures)(features)) {
11
+ throw new Error('Features of unexpected shape provided');
12
+ }
13
+ if (intermediaryVersion) {
14
+ return (0, assets_1.httpRequest)(`${baseUrl}/firmware/t1b1/trezor-t1b1-inter-v${intermediaryVersion}.bin`, 'binary');
15
+ }
16
+ const infoByBootloader = (0, firmwareInfo_1.getInfo)({ features, releases });
17
+ const releaseByFirmware = releases.find(r => version &&
18
+ utils_1.versionUtils.isVersionArray(version) &&
19
+ utils_1.versionUtils.isEqual(r.version, version));
20
+ if (!infoByBootloader || !releaseByFirmware) {
21
+ throw new Error('no firmware found for this device');
22
+ }
23
+ if (btcOnly && !releaseByFirmware.url_bitcoinonly) {
24
+ throw new Error(`firmware version ${version} does not exist in btc only variant`);
25
+ }
26
+ if (!utils_1.versionUtils.isEqual(releaseByFirmware.version, infoByBootloader.release.version)) {
27
+ throw new Error(`version provided as param (${releaseByFirmware.version}) does not match firmware version found by features in bootloader (${infoByBootloader.release.version})`);
28
+ }
29
+ return (0, getBinary_1.getBinary)({ releases, baseUrl, version, btcOnly, intermediaryVersion });
30
+ };
31
+ exports.getBinaryForFirmwareUpgrade = getBinaryForFirmwareUpgrade;
32
+ //# sourceMappingURL=getBinaryForFirmwareUpgrade.js.map
@@ -1,3 +1,4 @@
1
+ export { getBinaryForFirmwareUpgrade } from './getBinaryForFirmwareUpgrade';
1
2
  export { getBinary } from './getBinary';
2
3
  export { getLanguage } from '../../data/getLanguage';
3
4
  export { shouldStripFwHeaders, stripFwHeaders } from './modifyFirmware';
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseFirmwareHeaders = exports.calculateFirmwareHash = exports.uploadFirmware = exports.stripFwHeaders = exports.shouldStripFwHeaders = exports.getLanguage = exports.getBinary = void 0;
3
+ exports.parseFirmwareHeaders = exports.calculateFirmwareHash = exports.uploadFirmware = exports.stripFwHeaders = exports.shouldStripFwHeaders = exports.getLanguage = exports.getBinary = exports.getBinaryForFirmwareUpgrade = void 0;
4
+ var getBinaryForFirmwareUpgrade_1 = require("./getBinaryForFirmwareUpgrade");
5
+ Object.defineProperty(exports, "getBinaryForFirmwareUpgrade", { enumerable: true, get: function () { return getBinaryForFirmwareUpgrade_1.getBinaryForFirmwareUpgrade; } });
4
6
  var getBinary_1 = require("./getBinary");
5
7
  Object.defineProperty(exports, "getBinary", { enumerable: true, get: function () { return getBinary_1.getBinary; } });
6
8
  var getLanguage_1 = require("../../data/getLanguage");
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { PROTO } from '../../constants';
3
- import { DeviceAuthenticityConfig } from '../../data/deviceAuthenticityConfig';
4
3
  import { AuthenticateDeviceResult } from '../../types/api/authenticateDevice';
4
+ import { DeviceAuthenticityConfig } from '../../data/deviceAuthenticityConfigTypes';
5
5
  interface AuthenticityProofData extends PROTO.AuthenticityProof {
6
6
  challenge: Buffer;
7
7
  config: DeviceAuthenticityConfig;
@@ -19,15 +19,50 @@ const verifySignature = async (rawKey, data, signature) => {
19
19
  };
20
20
  const getRandomChallenge = () => crypto.randomBytes(32);
21
21
  exports.getRandomChallenge = getRandomChallenge;
22
+ const validateCaCertExtensions = (cert, pathLen) => {
23
+ let hasKeyUsage, hasBasicConstraints = false;
24
+ cert.tbsCertificate.extensions.forEach(ext => {
25
+ if (ext.key === 'keyUsage') {
26
+ if (ext.keyCertSign !== '1') {
27
+ throw new Error(`CA keyCertSign not set`);
28
+ }
29
+ hasKeyUsage = true;
30
+ }
31
+ else if (ext.key === 'basicConstraints') {
32
+ if (!ext.cA) {
33
+ throw new Error(`CA basicConstraints.cA not set`);
34
+ }
35
+ if (typeof ext.pathLenConstraint != 'number') {
36
+ throw new Error('CA basicConstraints.pathLenConstraint not set');
37
+ }
38
+ if (ext.pathLenConstraint < pathLen) {
39
+ throw new Error('Issuer was not permitted to issue certificate');
40
+ }
41
+ hasBasicConstraints = true;
42
+ }
43
+ else if (ext.critical) {
44
+ throw new Error(`Unknown critical extension ${ext.key} in CA certificate`);
45
+ }
46
+ });
47
+ if (!hasKeyUsage || !hasBasicConstraints) {
48
+ throw new Error(`CA missing extensions keyUsage: ${hasKeyUsage}, basicConstraints: ${hasBasicConstraints}`);
49
+ }
50
+ };
22
51
  const verifyAuthenticityProof = async ({ certificates, signature, challenge, config, allowDebugKeys, deviceModel, }) => {
23
52
  const modelConfig = config[deviceModel];
24
53
  if (!modelConfig) {
25
54
  throw new Error(`Pubkeys for ${deviceModel} not found in config`);
26
55
  }
27
56
  const { caPubKeys, debug } = modelConfig;
28
- const caCert = (0, x509certificate_1.parseCertificate)(new Uint8Array(Buffer.from(certificates[1], 'hex')));
57
+ const [deviceCert, caCert] = certificates.map((c, i) => {
58
+ const cert = (0, x509certificate_1.parseCertificate)(new Uint8Array(Buffer.from(c, 'hex')));
59
+ if (i === 0) {
60
+ return cert;
61
+ }
62
+ validateCaCertExtensions(cert, i - 1);
63
+ return cert;
64
+ });
29
65
  const caPubKey = Buffer.from(caCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes).toString('hex');
30
- const deviceCert = (0, x509certificate_1.parseCertificate)(new Uint8Array(Buffer.from(certificates[0], 'hex')));
31
66
  const rootPubKeys = allowDebugKeys
32
67
  ? modelConfig.rootPubKeys.concat((debug === null || debug === void 0 ? void 0 : debug.rootPubKeys) || [])
33
68
  : modelConfig.rootPubKeys;
@@ -6,10 +6,24 @@ interface Asn1 {
6
6
  contents: Uint8Array;
7
7
  raw: Uint8Array;
8
8
  }
9
+ type Oid = `${number}.${number}.${number}.${number}`;
10
+ type Extension = {
11
+ key: 'keyUsage';
12
+ critical?: boolean;
13
+ keyCertSign: '0' | '1';
14
+ } | {
15
+ key: 'basicConstraints';
16
+ critical?: boolean;
17
+ cA: boolean;
18
+ pathLenConstraint?: number;
19
+ } | (Asn1 & {
20
+ key: Oid;
21
+ critical?: boolean;
22
+ });
9
23
  export declare const fixSignature: (byteArray: Uint8Array) => Uint8Array;
10
24
  export declare const parseName: (asn1: Asn1) => {
11
25
  asn1: Asn1;
12
- algorithm: string;
26
+ algorithm: `${number}.${number}.${number}.${number}`;
13
27
  parameters: {
14
28
  asn1: Asn1;
15
29
  } | null;
@@ -22,7 +36,7 @@ export declare const parseCertificate: (byteArray: Uint8Array) => {
22
36
  serialNumber: Asn1;
23
37
  signature: {
24
38
  asn1: Asn1;
25
- algorithm: string;
39
+ algorithm: `${number}.${number}.${number}.${number}`;
26
40
  parameters: {
27
41
  asn1: Asn1;
28
42
  } | null;
@@ -34,7 +48,7 @@ export declare const parseCertificate: (byteArray: Uint8Array) => {
34
48
  };
35
49
  subject: {
36
50
  asn1: Asn1;
37
- algorithm: string;
51
+ algorithm: `${number}.${number}.${number}.${number}`;
38
52
  parameters: {
39
53
  asn1: Asn1;
40
54
  } | null;
@@ -43,7 +57,7 @@ export declare const parseCertificate: (byteArray: Uint8Array) => {
43
57
  asn1: Asn1;
44
58
  algorithm: {
45
59
  asn1: Asn1;
46
- algorithm: string;
60
+ algorithm: `${number}.${number}.${number}.${number}`;
47
61
  parameters: {
48
62
  asn1: Asn1;
49
63
  } | null;
@@ -53,11 +67,11 @@ export declare const parseCertificate: (byteArray: Uint8Array) => {
53
67
  bytes: Uint8Array;
54
68
  };
55
69
  };
56
- extensions: Asn1;
70
+ extensions: Extension[];
57
71
  };
58
72
  signatureAlgorithm: {
59
73
  asn1: Asn1;
60
- algorithm: string;
74
+ algorithm: `${number}.${number}.${number}.${number}`;
61
75
  parameters: {
62
76
  asn1: Asn1;
63
77
  } | null;
@@ -37,21 +37,14 @@ const derToAsn1 = (byteArray) => {
37
37
  const cls = (byteArray[0] & 0xc0) / 64;
38
38
  const structured = (byteArray[0] & 0x20) === 0x20;
39
39
  const tag = getTag();
40
+ if (byteArray[position] === 0x80) {
41
+ throw new Error('Unsupported length encoding');
42
+ }
40
43
  let length = getLength();
41
44
  let byteLength;
42
45
  let contents;
43
- if (length === 0x80) {
44
- length = 0;
45
- while (byteArray[position + length] !== 0 || byteArray[position + length + 1] !== 0) {
46
- length += 1;
47
- }
48
- byteLength = position + length + 2;
49
- contents = byteArray.subarray(position, position + length);
50
- }
51
- else {
52
- byteLength = position + length;
53
- contents = byteArray.subarray(position, byteLength);
54
- }
46
+ byteLength = position + length;
47
+ contents = byteArray.subarray(position, byteLength);
55
48
  const raw = byteArray.subarray(0, byteLength);
56
49
  return {
57
50
  cls,
@@ -195,6 +188,82 @@ const parseValidity = (asn1) => {
195
188
  to: parseUtcTime(to),
196
189
  };
197
190
  };
191
+ const parseExtensions = (data) => {
192
+ const asn1 = derToAsn1(data.contents);
193
+ if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
194
+ throw new Error("This can't be a Extension. Wrong data type.");
195
+ }
196
+ const readBoolean = (value) => {
197
+ if (!value)
198
+ return false;
199
+ if (value.cls !== 0 || value.tag !== 1 || value.contents.length !== 1 || value.structured) {
200
+ throw new Error("This can't be a boolean. Wrong data type.");
201
+ }
202
+ if (![0x00, 0xff].includes(value.contents[0])) {
203
+ throw new Error('Invalid boolean value.');
204
+ }
205
+ return value.contents[0] === 0xff;
206
+ };
207
+ const readBitString = (uint8Array) => {
208
+ const buffer = Buffer.from(uint8Array);
209
+ const tag = buffer.readUInt8(0);
210
+ if (tag !== 3) {
211
+ throw new Error("This can't be a bit string. Wrong data type.");
212
+ }
213
+ const length = buffer.readUInt8(1);
214
+ const unusedBits = buffer.readUInt8(2);
215
+ const bitStringBytes = buffer.subarray(3, 3 + length - 1);
216
+ const bitString = bitStringBytes.reduce((str, byte) => str + byte.toString(2).padStart(8, '0'), '');
217
+ return bitString.slice(0, bitString.length - unusedBits);
218
+ };
219
+ const readInteger = (value) => {
220
+ if (!value)
221
+ return undefined;
222
+ if (value.cls !== 0 || value.tag !== 2 || value.contents.length !== 1 || value.structured) {
223
+ throw new Error("This can't be a integer. Wrong data type.");
224
+ }
225
+ return Buffer.from(value.contents).readInt8();
226
+ };
227
+ const extensions = [];
228
+ derToAsn1List(asn1.contents).forEach(item => {
229
+ const [id, ...pieces] = derToAsn1List(item.contents);
230
+ if (id.cls !== 0 || id.tag !== 6 || id.structured) {
231
+ throw new Error('Bad extension. Does not begin with an OBJECT IDENTIFIER.');
232
+ }
233
+ const algorithm = derObjectIdentifierValue(id.contents);
234
+ const critical = pieces.length > 1 ? readBoolean(pieces[0]) : false;
235
+ const extnValue = pieces.length > 1 ? pieces[1] : pieces[0];
236
+ if (extnValue.cls !== 0 || extnValue.tag !== 4 || extnValue.structured) {
237
+ throw new Error("This can't be a octet string. Wrong data type.");
238
+ }
239
+ if (algorithm === '2.5.29.15') {
240
+ extensions.push({
241
+ key: 'keyUsage',
242
+ critical,
243
+ keyCertSign: readBitString(extnValue.contents)[5],
244
+ });
245
+ }
246
+ else if (algorithm === '2.5.29.19') {
247
+ const fields = derToAsn1List(derToAsn1(extnValue.contents).contents);
248
+ const ca = fields.length > 0 && fields[0].tag === 1 ? fields[0] : undefined;
249
+ const len = fields.length > 0 && fields[0].tag === 2 ? fields[0] : fields[1];
250
+ extensions.push({
251
+ key: 'basicConstraints',
252
+ critical,
253
+ cA: readBoolean(ca),
254
+ pathLenConstraint: readInteger(len),
255
+ });
256
+ }
257
+ else {
258
+ extensions.push({
259
+ key: algorithm,
260
+ critical,
261
+ ...item,
262
+ });
263
+ }
264
+ });
265
+ return extensions;
266
+ };
198
267
  const parseTBSCertificate = (asn1) => {
199
268
  if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
200
269
  throw new Error("This can't be a TBSCertificate. Wrong data type.");
@@ -212,7 +281,7 @@ const parseTBSCertificate = (asn1) => {
212
281
  validity: parseValidity(pieces[4]),
213
282
  subject: (0, exports.parseName)(pieces[5]),
214
283
  subjectPublicKeyInfo: parseSubjectPublicKeyInfo(pieces[6]),
215
- extensions: pieces[7],
284
+ extensions: parseExtensions(pieces[7]),
216
285
  };
217
286
  };
218
287
  const parseCertificate = (byteArray) => {
@@ -21,6 +21,7 @@ export default class GetCoinInfo extends AbstractMethod<'getCoinInfo', Params> {
21
21
  T1B1: string | false;
22
22
  T2T1: string | false;
23
23
  T2B1: string | false;
24
+ T3B1: string | false;
24
25
  T3T1: string | false;
25
26
  connect: boolean;
26
27
  };
@@ -77,6 +78,7 @@ export default class GetCoinInfo extends AbstractMethod<'getCoinInfo', Params> {
77
78
  T1B1: string | false;
78
79
  T2T1: string | false;
79
80
  T2B1: string | false;
81
+ T3B1: string | false;
80
82
  T3T1: string | false;
81
83
  connect: boolean;
82
84
  };
@@ -108,6 +110,7 @@ export default class GetCoinInfo extends AbstractMethod<'getCoinInfo', Params> {
108
110
  T1B1: string | false;
109
111
  T2T1: string | false;
110
112
  T2B1: string | false;
113
+ T3B1: string | false;
111
114
  T3T1: string | false;
112
115
  connect: boolean;
113
116
  };