@trezor/connect 9.3.0 → 9.3.1-beta.1
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.
- package/CHANGELOG.md +63 -8
- package/README.md +1 -1
- package/lib/api/checkFirmwareAuthenticity.d.ts +2 -1
- package/lib/api/checkFirmwareAuthenticity.js +34 -26
- package/lib/api/ethereum/api/ethereumSignTypedData.d.ts +1 -0
- package/lib/api/ethereum/ethereumDefinitions.js +1 -0
- package/lib/api/firmware/getBinary.d.ts +4 -4
- package/lib/api/firmware/getBinary.js +4 -15
- package/lib/api/firmware/getBinaryForFirmwareUpgrade.d.ts +11 -0
- package/lib/api/firmware/getBinaryForFirmwareUpgrade.js +32 -0
- package/lib/api/firmware/index.d.ts +1 -0
- package/lib/api/firmware/index.js +3 -1
- package/lib/api/firmware/verifyAuthenticityProof.d.ts +1 -1
- package/lib/api/firmware/verifyAuthenticityProof.js +37 -2
- package/lib/api/firmware/x509certificate.d.ts +20 -6
- package/lib/api/firmware/x509certificate.js +82 -13
- package/lib/api/getCoinInfo.d.ts +3 -0
- package/lib/api/getFeatures.d.ts +1 -0
- package/lib/backend/Blockchain.js +10 -1
- package/lib/core/AbstractMethod.js +1 -0
- package/lib/core/index.d.ts +3 -3
- package/lib/core/index.js +23 -6
- package/lib/core/onCallFirmwareUpdate.js +25 -14
- package/lib/data/DataManager.d.ts +11 -0
- package/lib/data/DataManager.js +1 -1
- package/lib/data/coinInfo.d.ts +14 -0
- package/lib/data/config.d.ts +11 -0
- package/lib/data/config.js +17 -1
- package/lib/data/connectSettings.js +3 -2
- package/lib/data/deviceAuthenticityConfig.d.ts +1 -28
- package/lib/data/deviceAuthenticityConfig.js +25 -24
- package/lib/data/deviceAuthenticityConfigTypes.d.ts +38 -0
- package/lib/data/deviceAuthenticityConfigTypes.js +28 -0
- package/lib/data/models.d.ts +10 -0
- package/lib/data/models.js +12 -10
- package/lib/data/version.d.ts +1 -1
- package/lib/data/version.js +1 -1
- package/lib/device/Device.d.ts +1 -3
- package/lib/device/Device.js +7 -21
- package/lib/device/DeviceCommands.js +1 -26
- package/lib/events/core.d.ts +2 -2
- package/lib/events/transport.d.ts +5 -0
- package/lib/index.js +20 -20
- package/lib/types/api/authenticateDevice.d.ts +9 -0
- package/lib/types/api/authenticateDevice.js +2 -2
- package/lib/types/api/checkFirmwareAuthenticity.d.ts +4 -1
- package/lib/types/api/init.d.ts +2 -2
- package/lib/types/coinInfo.d.ts +7 -0
- package/lib/types/firmware.d.ts +2 -2
- package/lib/types/settings.d.ts +7 -3
- package/lib/utils/assetUtils.js +1 -0
- package/package.json +9 -10
- package/lib/core/coreManager.d.ts +0 -16
- package/lib/core/coreManager.js +0 -55
package/CHANGELOG.md
CHANGED
|
@@ -1,15 +1,70 @@
|
|
|
1
|
-
| Package | Stable |
|
|
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.1 |
|
|
4
|
+
| npm @trezor/connect-web | 9.3.0 | 9.3.1-beta.1 |
|
|
5
|
+
| npm @trezor/connect-webextension | 9.3.0 | 9.3.1-beta.1 |
|
|
6
6
|
|
|
7
|
-
| Deployment | Stable |
|
|
8
|
-
| :----------------: | :----: |
|
|
9
|
-
| connect.trezor.io/ | 9.3.0 |
|
|
7
|
+
| Deployment | Stable | Canary |
|
|
8
|
+
| :----------------: | :----: | :----------: |
|
|
9
|
+
| connect.trezor.io/ | 9.3.0 | 9.3.1-beta.1 |
|
|
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.1
|
|
14
|
+
|
|
15
|
+
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/).
|
|
16
|
+
|
|
17
|
+
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)
|
|
18
|
+
|
|
19
|
+
AuthenticateDevice verify CA cert extensions (4ba4445)
|
|
20
|
+
|
|
21
|
+
Add support for T3B1 (f7f1705)
|
|
22
|
+
|
|
23
|
+
- chore(connect): Add Ambire Browser Extension to knownHosts (cbe81ab)
|
|
24
|
+
- chore(connect): remove ethereum-cryptography (18851d1)
|
|
25
|
+
- chore(connect): split public and internal settings type (3aab4ea)
|
|
26
|
+
- chore(connect): remove useCoreInPopup from explorer and tests (fee60c1)
|
|
27
|
+
- chore(connect): add new CA pubkeys and update timestamp (48ec951)
|
|
28
|
+
- chore(connect): refactoring of the CheckFirmwareAuthenticity to support local binary (and wont download it from web, when its available in the suite) (82ab513)
|
|
29
|
+
- docs(connect): describe coreMode (a5238d6)
|
|
30
|
+
- fix(connect): disallow interaction-less fw update when switching fw type (4936939)
|
|
31
|
+
- fix(connect): validate x509 asn1 component (bc13fe2)
|
|
32
|
+
- fix(connect): handle missing language binary (954dbb9)
|
|
33
|
+
- fix(connect): proceed with fw install even when language data fails to download (b40d1b7)
|
|
34
|
+
- test(connect): x509 extensions parser (163c82c)
|
|
35
|
+
- test(connect): update to min version fw 1.0.9 and 2.3.0 (544c311)
|
|
36
|
+
|
|
37
|
+
## connect-ui
|
|
38
|
+
|
|
39
|
+
- remove bridge references, deeplink to suite desktop (98e98a4)
|
|
40
|
+
|
|
41
|
+
## connect-plugin-stellar
|
|
42
|
+
|
|
43
|
+
- update stellar sdk (89cf20e)
|
|
44
|
+
- update trends libs (70b9c11)
|
|
45
|
+
|
|
46
|
+
## connect-web
|
|
47
|
+
|
|
48
|
+
- default coreMode to auto (e45d47e)
|
|
49
|
+
- automatic fallback to core in popup (e4e1fcc)
|
|
50
|
+
|
|
51
|
+
## connect-webextension
|
|
52
|
+
|
|
53
|
+
- link changelog to the one in connect (a02ec72)
|
|
54
|
+
|
|
55
|
+
## connect-explorer
|
|
56
|
+
|
|
57
|
+
- applySettings optional values (0bcd83a)
|
|
58
|
+
- hide extra headings from toc in homepage (14f89c4)
|
|
59
|
+
- show success message in settings (0ca7c0c)
|
|
60
|
+
- remove MTT for firmwareUpdate (ebbe96c)
|
|
61
|
+
- bad styled-components prop (e2b7fc7)
|
|
62
|
+
|
|
63
|
+
## connect-common
|
|
64
|
+
|
|
65
|
+
- add new fw 2.8.0 (314052b)
|
|
66
|
+
- fw version 1.9.0 and 2.3.0 required (ee623e4)
|
|
67
|
+
|
|
13
68
|
# 9.3.0
|
|
14
69
|
|
|
15
70
|
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.
|
|
3
|
+
API version 9.3.1-beta.1
|
|
4
4
|
|
|
5
5
|
[](https://github.com/trezor/trezor-suite/actions/workflows/test-connect.yml)
|
|
6
6
|
[](https://www.npmjs.org/package/@trezor/connect)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AbstractMethod } from '../core/AbstractMethod';
|
|
2
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
}>;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
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: ({
|
|
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
|
|
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 (
|
|
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
|
-
|
|
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,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 = (
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
70
|
+
extensions: Extension[];
|
|
57
71
|
};
|
|
58
72
|
signatureAlgorithm: {
|
|
59
73
|
asn1: Asn1;
|
|
60
|
-
algorithm:
|
|
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
|
-
|
|
44
|
-
|
|
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) => {
|
package/lib/api/getCoinInfo.d.ts
CHANGED
|
@@ -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
|
};
|
package/lib/api/getFeatures.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export default class GetFeatures extends AbstractMethod<'getFeatures'> {
|
|
|
15
15
|
language_version_matches?: boolean | undefined;
|
|
16
16
|
unit_packaging?: number | undefined;
|
|
17
17
|
recovery_type?: "NormalRecovery" | "DryRun" | "UnlockRepeatedBackup" | undefined;
|
|
18
|
+
optiga_sec?: number | undefined;
|
|
18
19
|
flags: number | null;
|
|
19
20
|
language: string | null;
|
|
20
21
|
label: string | null;
|
|
@@ -22,6 +22,15 @@ const getWorker = (type) => {
|
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
|
+
const getNormalizedShortcut = (shortcut) => {
|
|
26
|
+
if (shortcut === 'tXRP') {
|
|
27
|
+
return 'XRP';
|
|
28
|
+
}
|
|
29
|
+
if (shortcut.toLowerCase() === 'bsc') {
|
|
30
|
+
return 'bnb';
|
|
31
|
+
}
|
|
32
|
+
return shortcut;
|
|
33
|
+
};
|
|
25
34
|
class Blockchain {
|
|
26
35
|
constructor(options) {
|
|
27
36
|
this.feeForBlock = [];
|
|
@@ -72,7 +81,7 @@ class Blockchain {
|
|
|
72
81
|
throw constants_1.ERRORS.TypedError('Backend_Error', error.message);
|
|
73
82
|
}
|
|
74
83
|
this.serverInfo = info;
|
|
75
|
-
const shortcut = this.coinInfo.shortcut
|
|
84
|
+
const shortcut = getNormalizedShortcut(this.coinInfo.shortcut);
|
|
76
85
|
if (info.shortcut.toLowerCase() !== shortcut.toLowerCase()) {
|
|
77
86
|
throw constants_1.ERRORS.TypedError('Backend_Invalid');
|
|
78
87
|
}
|
package/lib/core/index.d.ts
CHANGED
|
@@ -14,9 +14,9 @@ export declare class Core extends EventEmitter {
|
|
|
14
14
|
init(settings: ConnectSettings, onCoreEvent: (message: CoreEventMessage) => void, logWriterFactory?: () => LogWriter | undefined): Promise<void>;
|
|
15
15
|
}
|
|
16
16
|
export declare const initCoreState: () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
get: () => Core | undefined;
|
|
18
|
+
getPending: () => Promise<Core> | undefined;
|
|
19
|
+
getOrInit: (settings: ConnectSettings, onCoreEvent: (message: CoreEventMessage) => void, logWriterFactory?: (() => LogWriter) | undefined) => Promise<Core>;
|
|
20
20
|
dispose: () => void;
|
|
21
21
|
};
|
|
22
22
|
//# sourceMappingURL=index.d.ts.map
|