@trezor/connect 9.1.4 → 9.1.5

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 (54) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +1 -1
  3. package/lib/api/authenticateDevice.d.ts +7 -0
  4. package/lib/api/authenticateDevice.js +51 -0
  5. package/lib/api/checkFirmwareAuthenticity.js +7 -5
  6. package/lib/api/common/paramsValidator.js +45 -51
  7. package/lib/api/ethereum/ethereumDefinitions.js +3 -2
  8. package/lib/api/firmware/getBinary.js +1 -1
  9. package/lib/api/firmware/verifyAuthenticityProof.d.ts +14 -0
  10. package/lib/api/firmware/verifyAuthenticityProof.js +103 -0
  11. package/lib/api/firmware/x509certificate.d.ts +73 -0
  12. package/lib/api/firmware/x509certificate.js +203 -0
  13. package/lib/api/firmwareUpdate.js +2 -1
  14. package/lib/api/getAccountInfo.js +1 -5
  15. package/lib/api/getFirmwareHash.js +1 -4
  16. package/lib/api/index.d.ts +1 -0
  17. package/lib/api/index.js +4 -2
  18. package/lib/api/rebootToBootloader.js +1 -4
  19. package/lib/core/AbstractMethod.d.ts +1 -0
  20. package/lib/core/AbstractMethod.js +11 -10
  21. package/lib/core/index.d.ts +3 -2
  22. package/lib/core/index.js +11 -3
  23. package/lib/core/method.d.ts +1 -1
  24. package/lib/data/DataManager.d.ts +53 -7
  25. package/lib/data/DataManager.js +4 -2
  26. package/lib/data/config.d.ts +52 -6
  27. package/lib/data/config.js +35 -23
  28. package/lib/data/connectSettings.js +3 -0
  29. package/lib/data/deviceAuthenticityConfig.d.ts +15 -0
  30. package/lib/data/deviceAuthenticityConfig.js +26 -0
  31. package/lib/data/firmwareInfo.d.ts +3 -2
  32. package/lib/data/firmwareInfo.js +17 -8
  33. package/lib/data/models.d.ts +4 -1
  34. package/lib/data/models.js +6 -3
  35. package/lib/data/version.d.ts +1 -1
  36. package/lib/data/version.js +1 -1
  37. package/lib/device/Device.d.ts +1 -1
  38. package/lib/device/Device.js +11 -11
  39. package/lib/device/DeviceList.d.ts +1 -0
  40. package/lib/device/DeviceList.js +4 -3
  41. package/lib/events/iframe.d.ts +7 -1
  42. package/lib/events/iframe.js +1 -0
  43. package/lib/factory.js +1 -0
  44. package/lib/types/api/authenticateDevice.d.ts +21 -0
  45. package/lib/types/api/authenticateDevice.js +3 -0
  46. package/lib/types/api/index.d.ts +2 -0
  47. package/lib/types/coinInfo.d.ts +3 -2
  48. package/lib/types/firmware.d.ts +6 -2
  49. package/lib/types/index.d.ts +1 -0
  50. package/lib/utils/assetUtils.js +6 -4
  51. package/lib/utils/debug.d.ts +9 -3
  52. package/lib/utils/debug.js +50 -17
  53. package/lib/utils/deviceFeaturesUtils.js +3 -3
  54. package/package.json +13 -10
package/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ # 9.1.5
2
+
3
+ - feat(suite): T2B1 replace Model R name by official Trezor Safe 3 name (7460372ed1)
4
+ - feat(connect): add authenticateDevice method (45b99c0813, af907a296d, 249ddc358a)
5
+ - feat(connect): btg, dash, dgb, nmc, vrc no support for T2B1 (0819ff6fc1)
6
+ - feat(suite): support t2b1 firmware installation (9ef2bf627a)
7
+ - fix(connect): get firmware status and release after ensuring internal model (dca3333c2d)
8
+ - fix(connect-popup): webusb in popup if iframe is on same origin as host (e571971586)
9
+ - feat(connect-web): trust-issues query string param (b1b6e3f287)
10
+ - feat(connect-plugin-stellar): Update stellar-sdk and stellar-base (ee7e67db04)
11
+ - chore(connect): t1 emulator with pin (33c6ca58bf)
12
+ - fix(connect-popup): allow decimal custom fee entry (bf20f23f05, 8a8d93b5e8)
13
+ - feat(connect-explorer): add rebootToBootloader method (9996676358)
14
+ - fix(connect): wrong version format in discovery (19b13d1d4c)
15
+ - feat(connect-popup): logger in sharedworker collecting from all environments (732bc7d, 2521c7c, 6501dfa4fd)
16
+ - chore(connect): do not lowercase device color (7229b88c20)
17
+
1
18
  # 9.1.4
2
19
 
3
20
  - feat(connect-popup): add metamask extension id to known third party (f137b3e4d6)
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @trezor/connect
2
2
 
3
- API version 9.1.4
3
+ API version 9.1.5
4
4
 
5
5
  [![Build Status](https://github.com/trezor/trezor-suite/actions/workflows/connect-test.yml/badge.svg)](https://github.com/trezor/trezor-suite/actions/workflows/connect-test.yml)
6
6
  [![NPM](https://img.shields.io/npm/v/@trezor/connect.svg)](https://www.npmjs.org/package/@trezor/connect)
@@ -0,0 +1,7 @@
1
+ import { AbstractMethod } from '../core/AbstractMethod';
2
+ import { AuthenticateDeviceParams } from '../types/api/authenticateDevice';
3
+ export default class AuthenticateDevice extends AbstractMethod<'authenticateDevice', AuthenticateDeviceParams> {
4
+ init(): void;
5
+ run(): Promise<import("../types/api/authenticateDevice").AuthenticateDeviceResult>;
6
+ }
7
+ //# sourceMappingURL=authenticateDevice.d.ts.map
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const AbstractMethod_1 = require("../core/AbstractMethod");
4
+ const events_1 = require("../events");
5
+ const paramsValidator_1 = require("./common/paramsValidator");
6
+ const deviceAuthenticityConfig_1 = require("../data/deviceAuthenticityConfig");
7
+ const verifyAuthenticityProof_1 = require("./firmware/verifyAuthenticityProof");
8
+ class AuthenticateDevice extends AbstractMethod_1.AbstractMethod {
9
+ init() {
10
+ this.useEmptyPassphrase = true;
11
+ this.allowDeviceMode = [events_1.UI.INITIALIZE, events_1.UI.SEEDLESS];
12
+ this.requiredPermissions = ['management'];
13
+ this.useDeviceState = false;
14
+ this.firmwareRange = (0, paramsValidator_1.getFirmwareRange)(this.name, null, this.firmwareRange);
15
+ const { payload } = this;
16
+ (0, paramsValidator_1.validateParams)(payload, [
17
+ { name: 'config', type: 'object' },
18
+ { name: 'allowDebugKeys', type: 'boolean' },
19
+ ]);
20
+ if (payload.config) {
21
+ (0, paramsValidator_1.validateParams)(payload.config, [{ name: 'timestamp', type: 'string', required: true }]);
22
+ (0, paramsValidator_1.validateParams)(payload.config.T2B1, [
23
+ { name: 'rootPubKeys', type: 'array', required: true },
24
+ { name: 'caPubKeys', type: 'array', required: true },
25
+ ]);
26
+ }
27
+ this.params = {
28
+ config: payload.config,
29
+ allowDebugKeys: payload.allowDebugKeys,
30
+ };
31
+ }
32
+ async run() {
33
+ const challenge = (0, verifyAuthenticityProof_1.getRandomChallenge)();
34
+ const { message } = await this.device
35
+ .getCommands()
36
+ .typedCall('AuthenticateDevice', 'AuthenticityProof', {
37
+ challenge: challenge.toString('hex'),
38
+ });
39
+ const config = this.params.config || deviceAuthenticityConfig_1.deviceAuthenticityConfig;
40
+ const valid = await (0, verifyAuthenticityProof_1.verifyAuthenticityProof)({
41
+ ...message,
42
+ challenge,
43
+ config,
44
+ allowDebugKeys: this.params.allowDebugKeys,
45
+ deviceModel: this.device.features.internal_model,
46
+ });
47
+ return valid;
48
+ }
49
+ }
50
+ exports.default = AuthenticateDevice;
51
+ //# sourceMappingURL=authenticateDevice.js.map
@@ -14,15 +14,17 @@ class CheckFirmwareAuthenticity extends AbstractMethod_1.AbstractMethod {
14
14
  this.useDeviceState = false;
15
15
  }
16
16
  async run() {
17
+ var _a;
17
18
  const { device } = this;
18
- const deviceVersion = `${device.features.major_version}.${device.features.minor_version}.${device.features.patch_version}`;
19
- const releases = (0, firmwareInfo_1.getReleases)(device.features.major_version);
20
- const release = releases.find(release => release.version.join('.') === deviceVersion);
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);
21
22
  if (!release) {
22
23
  throw constants_1.ERRORS.TypedError('Runtime', 'checkFirmwareAuthenticity: No release found for device firmware');
23
24
  }
24
- const baseUrl = `https://data.trezor.io/firmware/${device.features.major_version}`;
25
- const fwUrl = `${baseUrl}/trezor-${deviceVersion}${device.firmwareType === types_1.FirmwareType.BitcoinOnly ? '-bitcoinonly.bin' : '.bin'}`;
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'}`;
26
28
  const fw = await (0, assets_1.httpRequest)(fwUrl, 'binary');
27
29
  if (!fw) {
28
30
  throw constants_1.ERRORS.TypedError('Runtime', 'checkFirmwareAuthenticity: firmware binary not found');
@@ -68,25 +68,22 @@ const validateCoinPath = (path, coinInfo) => {
68
68
  };
69
69
  exports.validateCoinPath = validateCoinPath;
70
70
  const getFirmwareRange = (method, coinInfo, currentRange) => {
71
- const current = JSON.parse(JSON.stringify(currentRange));
71
+ const range = JSON.parse(JSON.stringify(currentRange));
72
+ const models = Object.keys(range);
72
73
  if (coinInfo) {
73
- if (!coinInfo.support || typeof coinInfo.support.trezor1 !== 'string') {
74
- current['1'].min = '0';
75
- }
76
- else if (utils_1.versionUtils.isNewer(coinInfo.support.trezor1, current['1'].min)) {
77
- current['1'].min = coinInfo.support.trezor1;
78
- }
79
- if (!coinInfo.support || typeof coinInfo.support.trezor2 !== 'string') {
80
- current['2'].min = '0';
81
- }
82
- else if (utils_1.versionUtils.isNewer(coinInfo.support.trezor2, current['2'].min)) {
83
- current['2'].min = coinInfo.support.trezor2;
84
- }
74
+ models.forEach(model => {
75
+ if (!coinInfo.support || typeof coinInfo.support[model] !== 'string') {
76
+ range[model].min = '0';
77
+ }
78
+ else if (range[model].min !== '0' &&
79
+ utils_1.versionUtils.isNewer(coinInfo.support[model], range[model].min)) {
80
+ range[model].min = coinInfo.support[model];
81
+ }
82
+ });
85
83
  }
86
- const coinType = coinInfo ? coinInfo.type : null;
87
- const shortcut = coinInfo ? coinInfo.shortcut.toLowerCase() : null;
88
- const { supportedFirmware } = config_1.config;
89
- const ranges = supportedFirmware
84
+ const coinType = coinInfo === null || coinInfo === void 0 ? void 0 : coinInfo.type;
85
+ const shortcut = coinInfo === null || coinInfo === void 0 ? void 0 : coinInfo.shortcut.toLowerCase();
86
+ const configRules = config_1.config.supportedFirmware
90
87
  .filter(rule => {
91
88
  if (rule.methods) {
92
89
  return rule.methods.includes(method);
@@ -96,45 +93,42 @@ const getFirmwareRange = (method, coinInfo, currentRange) => {
96
93
  }
97
94
  return true;
98
95
  })
99
- .filter(c => {
100
- if (c.coinType) {
101
- return c.coinType === coinType;
96
+ .filter(rule => {
97
+ if (rule.coinType) {
98
+ return rule.coinType === coinType;
102
99
  }
103
- if (c.coin) {
104
- return (typeof c.coin === 'string' ? [c.coin] : c.coin).includes(shortcut);
100
+ if (rule.coin) {
101
+ return (typeof rule.coin === 'string' ? [rule.coin] : rule.coin).includes(shortcut);
105
102
  }
106
- return c.methods || c.capabilities;
103
+ return rule.methods || rule.capabilities;
107
104
  });
108
- ranges.forEach(range => {
109
- const { min, max } = range;
110
- if (min) {
111
- const [t1, t2] = min;
112
- if (t1 === '0' ||
113
- current['1'].min === '0' ||
114
- !utils_1.versionUtils.isNewerOrEqual(current['1'].min, t1)) {
115
- current['1'].min = t1;
116
- }
117
- if (t2 === '0' ||
118
- current['2'].min === '0' ||
119
- !utils_1.versionUtils.isNewerOrEqual(current['2'].min, t2)) {
120
- current['2'].min = t2;
121
- }
122
- }
123
- if (max) {
124
- const [t1, t2] = max;
125
- if (t1 === '0' ||
126
- current['1'].max === '0' ||
127
- !utils_1.versionUtils.isNewerOrEqual(current['1'].max, t1)) {
128
- current['1'].max = t1;
129
- }
130
- if (t2 === '0' ||
131
- current['2'].max === '0' ||
132
- !utils_1.versionUtils.isNewerOrEqual(current['2'].max, t2)) {
133
- current['2'].max = t2;
134
- }
105
+ configRules.forEach(rule => {
106
+ if (rule.min) {
107
+ models.forEach(model => {
108
+ const modelMin = rule.min[model];
109
+ if (modelMin) {
110
+ if (modelMin === '0' ||
111
+ range[model].min === '0' ||
112
+ !utils_1.versionUtils.isNewerOrEqual(range[model].min, modelMin)) {
113
+ range[model].min = modelMin;
114
+ }
115
+ }
116
+ });
117
+ }
118
+ if (rule.max) {
119
+ models.forEach(model => {
120
+ const modelMax = rule.max[model];
121
+ if (modelMax) {
122
+ if (modelMax === '0' ||
123
+ range[model].max === '0' ||
124
+ !utils_1.versionUtils.isNewerOrEqual(range[model].max, modelMax)) {
125
+ range[model].max = modelMax;
126
+ }
127
+ }
128
+ });
135
129
  }
136
130
  });
137
- return current;
131
+ return range;
138
132
  };
139
133
  exports.getFirmwareRange = getFirmwareRange;
140
134
  //# sourceMappingURL=paramsValidator.js.map
@@ -93,8 +93,9 @@ const ethereumNetworkInfoFromDefinition = (definition) => ({
93
93
  shortcut: definition.symbol,
94
94
  support: {
95
95
  connect: true,
96
- trezor1: '1.6.2',
97
- trezor2: '2.0.7',
96
+ T1B1: '1.6.2',
97
+ T2T1: '2.0.7',
98
+ T2B1: '2.6.1',
98
99
  },
99
100
  blockchainLink: undefined,
100
101
  });
@@ -10,7 +10,7 @@ const getBinary = ({ features, releases, baseUrl, version, btcOnly, intermediary
10
10
  throw new Error('Features of unexpected shape provided');
11
11
  }
12
12
  if (intermediaryVersion) {
13
- return (0, assets_1.httpRequest)(`${baseUrl}/firmware/1/trezor-inter-v${intermediaryVersion}.bin`, 'binary');
13
+ return (0, assets_1.httpRequest)(`${baseUrl}/firmware/t1b1/trezor-t1b1-inter-v${intermediaryVersion}.bin`, 'binary');
14
14
  }
15
15
  const infoByBootloader = (0, firmwareInfo_1.getInfo)({ features, releases });
16
16
  const releaseByFirmware = releases.find(r => version &&
@@ -0,0 +1,14 @@
1
+ /// <reference types="node" />
2
+ import { PROTO } from '../../constants';
3
+ import { DeviceAuthenticityConfig } from '../../data/deviceAuthenticityConfig';
4
+ import { AuthenticateDeviceResult } from '../../types/api/authenticateDevice';
5
+ interface AuthenticityProofData extends PROTO.AuthenticityProof {
6
+ challenge: Buffer;
7
+ config: DeviceAuthenticityConfig;
8
+ allowDebugKeys?: boolean;
9
+ deviceModel: keyof typeof PROTO.DeviceModelInternal;
10
+ }
11
+ export declare const getRandomChallenge: () => Buffer;
12
+ export declare const verifyAuthenticityProof: ({ certificates, signature, challenge, config, allowDebugKeys, deviceModel, }: AuthenticityProofData) => Promise<AuthenticateDeviceResult>;
13
+ export {};
14
+ //# sourceMappingURL=verifyAuthenticityProof.d.ts.map
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.verifyAuthenticityProof = exports.getRandomChallenge = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const crypto = tslib_1.__importStar(require("crypto"));
6
+ const utils_1 = require("@trezor/utils");
7
+ const x509certificate_1 = require("./x509certificate");
8
+ const verifySignature = async (rawKey, data, signature) => {
9
+ const signer = crypto.createVerify('sha256');
10
+ signer.update(Buffer.from(data));
11
+ const SubtleCrypto = typeof window !== 'undefined' ? window.crypto.subtle : crypto.subtle;
12
+ if (!SubtleCrypto) {
13
+ throw new Error('SubtleCrypto not supported');
14
+ }
15
+ const ecPubKey = await SubtleCrypto.importKey('raw', rawKey, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['verify']);
16
+ const spkiPubKey = await SubtleCrypto.exportKey('spki', ecPubKey);
17
+ const key = `-----BEGIN PUBLIC KEY-----\n${Buffer.from(spkiPubKey).toString('base64')}\n-----END PUBLIC KEY-----`;
18
+ return signer.verify({ key }, Buffer.from(signature));
19
+ };
20
+ const getRandomChallenge = () => crypto.randomBytes(32);
21
+ exports.getRandomChallenge = getRandomChallenge;
22
+ const verifyAuthenticityProof = async ({ certificates, signature, challenge, config, allowDebugKeys, deviceModel, }) => {
23
+ const modelConfig = config[deviceModel];
24
+ if (!modelConfig) {
25
+ throw new Error(`Pubkeys for ${deviceModel} not found in config`);
26
+ }
27
+ const { caPubKeys, debug } = modelConfig;
28
+ const caCert = (0, x509certificate_1.parseCertificate)(new Uint8Array(Buffer.from(certificates[1], 'hex')));
29
+ 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
+ const rootPubKeys = allowDebugKeys
32
+ ? modelConfig.rootPubKeys.concat((debug === null || debug === void 0 ? void 0 : debug.rootPubKeys) || [])
33
+ : modelConfig.rootPubKeys;
34
+ const isCertSignedByRootPubkey = await Promise.all(rootPubKeys.map(rootPubKey => verifySignature(Buffer.from(rootPubKey, 'hex'), caCert.tbsCertificate.asn1.raw, caCert.signatureValue.bits.bytes)));
35
+ const rootPubKeyIndex = isCertSignedByRootPubkey.findIndex(valid => !!valid);
36
+ const rootPubKey = rootPubKeys[rootPubKeyIndex];
37
+ const isDebugRootPubKey = debug === null || debug === void 0 ? void 0 : debug.rootPubKeys.includes(rootPubKey);
38
+ const caCertValidityFrom = caCert.tbsCertificate.validity.from.getTime();
39
+ if (caCertValidityFrom > new Date().getTime()) {
40
+ throw new Error(`CA validity from ${caCertValidityFrom} cant't be in the future!`);
41
+ }
42
+ if (!rootPubKey) {
43
+ const configExpired = new Date(config.timestamp).getTime() < caCertValidityFrom;
44
+ return {
45
+ valid: false,
46
+ configExpired,
47
+ caPubKey,
48
+ error: 'ROOT_PUBKEY_NOT_FOUND',
49
+ };
50
+ }
51
+ const [subject] = deviceCert.tbsCertificate.subject;
52
+ if (!subject.parameters || subject.algorithm !== '2.5.4.3') {
53
+ throw new Error('Missing certificate subject');
54
+ }
55
+ const subjectValue = Buffer.from(subject.parameters.asn1.contents.subarray(0, 4)).toString();
56
+ if (subjectValue !== deviceModel) {
57
+ return {
58
+ valid: false,
59
+ caPubKey,
60
+ error: 'INVALID_DEVICE_MODEL',
61
+ };
62
+ }
63
+ const isDeviceCertValid = await verifySignature(Buffer.from(caCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes), deviceCert.tbsCertificate.asn1.raw, deviceCert.signatureValue.bits.bytes);
64
+ const challengePrefix = Buffer.from('AuthenticateDevice:');
65
+ const prefixedChallenge = Buffer.concat([
66
+ utils_1.bufferUtils.getChunkSize(challengePrefix.length),
67
+ challengePrefix,
68
+ utils_1.bufferUtils.getChunkSize(challenge.length),
69
+ challenge,
70
+ ]);
71
+ const isSignatureValid = await verifySignature(Buffer.from(deviceCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes), prefixedChallenge, Buffer.from(signature, 'hex'));
72
+ if (rootPubKey && isDeviceCertValid && isSignatureValid) {
73
+ if ((!isDebugRootPubKey && !caPubKeys.includes(caPubKey)) ||
74
+ (isDebugRootPubKey && !(debug === null || debug === void 0 ? void 0 : debug.caPubKeys.includes(caPubKey)))) {
75
+ const configExpired = new Date(config.timestamp).getTime() < caCertValidityFrom;
76
+ return {
77
+ valid: false,
78
+ configExpired,
79
+ caPubKey,
80
+ error: 'CA_PUBKEY_NOT_FOUND',
81
+ };
82
+ }
83
+ return {
84
+ valid: true,
85
+ caPubKey,
86
+ debugKey: isDebugRootPubKey,
87
+ };
88
+ }
89
+ if (!isDeviceCertValid) {
90
+ return {
91
+ valid: false,
92
+ caPubKey,
93
+ error: 'INVALID_DEVICE_CERTIFICATE',
94
+ };
95
+ }
96
+ return {
97
+ valid: false,
98
+ caPubKey,
99
+ error: 'INVALID_DEVICE_SIGNATURE',
100
+ };
101
+ };
102
+ exports.verifyAuthenticityProof = verifyAuthenticityProof;
103
+ //# sourceMappingURL=verifyAuthenticityProof.js.map
@@ -0,0 +1,73 @@
1
+ interface Asn1 {
2
+ cls: number;
3
+ tag: number;
4
+ structured: boolean;
5
+ byteLength: number;
6
+ contents: Uint8Array;
7
+ raw: Uint8Array;
8
+ }
9
+ export declare const parseName: (asn1: Asn1) => {
10
+ asn1: Asn1;
11
+ algorithm: string;
12
+ parameters: {
13
+ asn1: Asn1;
14
+ } | null;
15
+ }[];
16
+ export declare const parseCertificate: (byteArray: Uint8Array) => {
17
+ asn1: Asn1;
18
+ tbsCertificate: {
19
+ asn1: Asn1;
20
+ version: Asn1;
21
+ serialNumber: Asn1;
22
+ signature: {
23
+ asn1: Asn1;
24
+ algorithm: string;
25
+ parameters: {
26
+ asn1: Asn1;
27
+ } | null;
28
+ };
29
+ issuer: Asn1;
30
+ validity: {
31
+ from: Date;
32
+ to: Date;
33
+ };
34
+ subject: {
35
+ asn1: Asn1;
36
+ algorithm: string;
37
+ parameters: {
38
+ asn1: Asn1;
39
+ } | null;
40
+ }[];
41
+ subjectPublicKeyInfo: {
42
+ asn1: Asn1;
43
+ algorithm: {
44
+ asn1: Asn1;
45
+ algorithm: string;
46
+ parameters: {
47
+ asn1: Asn1;
48
+ } | null;
49
+ };
50
+ bits: {
51
+ unusedBits: number;
52
+ bytes: Uint8Array;
53
+ };
54
+ };
55
+ extensions: Asn1;
56
+ };
57
+ signatureAlgorithm: {
58
+ asn1: Asn1;
59
+ algorithm: string;
60
+ parameters: {
61
+ asn1: Asn1;
62
+ } | null;
63
+ };
64
+ signatureValue: {
65
+ asn1: Asn1;
66
+ bits: {
67
+ unusedBits: number;
68
+ bytes: Uint8Array;
69
+ };
70
+ };
71
+ };
72
+ export {};
73
+ //# sourceMappingURL=x509certificate.d.ts.map
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseCertificate = exports.parseName = void 0;
4
+ const derToAsn1 = (byteArray) => {
5
+ let position = 0;
6
+ function getTag() {
7
+ let tag = byteArray[0] & 0x1f;
8
+ position += 1;
9
+ if (tag === 0x1f) {
10
+ tag = 0;
11
+ while (byteArray[position] >= 0x80) {
12
+ tag = tag * 128 + byteArray[position] - 0x80;
13
+ position += 1;
14
+ }
15
+ tag = tag * 128 + byteArray[position] - 0x80;
16
+ position += 1;
17
+ }
18
+ return tag;
19
+ }
20
+ function getLength() {
21
+ let length = 0;
22
+ if (byteArray[position] < 0x80) {
23
+ length = byteArray[position];
24
+ position += 1;
25
+ }
26
+ else {
27
+ const numberOfDigits = byteArray[position] & 0x7f;
28
+ position += 1;
29
+ length = 0;
30
+ for (let i = 0; i < numberOfDigits; i++) {
31
+ length = length * 256 + byteArray[position];
32
+ position += 1;
33
+ }
34
+ }
35
+ return length;
36
+ }
37
+ const cls = (byteArray[0] & 0xc0) / 64;
38
+ const structured = (byteArray[0] & 0x20) === 0x20;
39
+ const tag = getTag();
40
+ let length = getLength();
41
+ let byteLength;
42
+ 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
+ }
55
+ const raw = byteArray.subarray(0, byteLength);
56
+ return {
57
+ cls,
58
+ tag,
59
+ structured,
60
+ byteLength,
61
+ contents,
62
+ raw,
63
+ };
64
+ };
65
+ const derToAsn1List = (byteArray) => {
66
+ const result = [];
67
+ let nextPosition = 0;
68
+ while (nextPosition < byteArray.length) {
69
+ const nextPiece = derToAsn1(byteArray.subarray(nextPosition));
70
+ result.push(nextPiece);
71
+ nextPosition += nextPiece.byteLength;
72
+ }
73
+ return result;
74
+ };
75
+ const derBitStringValue = (byteArray) => ({
76
+ unusedBits: byteArray[0],
77
+ bytes: byteArray.subarray(1),
78
+ });
79
+ const parseSignatureValue = (asn1) => {
80
+ if (asn1.cls !== 0 || asn1.tag !== 3 || asn1.structured) {
81
+ throw new Error('Bad signature value. Not a BIT STRING.');
82
+ }
83
+ return {
84
+ asn1,
85
+ bits: derBitStringValue(asn1.contents),
86
+ };
87
+ };
88
+ const derObjectIdentifierValue = (byteArray) => {
89
+ let oid = `${Math.floor(byteArray[0] / 40)}.${byteArray[0] % 40}`;
90
+ let position = 1;
91
+ while (position < byteArray.length) {
92
+ let nextInteger = 0;
93
+ while (byteArray[position] >= 0x80) {
94
+ nextInteger = nextInteger * 0x80 + (byteArray[position] & 0x7f);
95
+ position += 1;
96
+ }
97
+ nextInteger = nextInteger * 0x80 + byteArray[position];
98
+ position += 1;
99
+ oid += `.${nextInteger}`;
100
+ }
101
+ return oid;
102
+ };
103
+ const parseAlgorithmIdentifier = (asn1) => {
104
+ if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
105
+ throw new Error('Bad algorithm identifier. Not a SEQUENCE.');
106
+ }
107
+ const pieces = derToAsn1List(asn1.contents);
108
+ if (pieces.length > 2) {
109
+ throw new Error('Bad algorithm identifier. Contains too many child objects.');
110
+ }
111
+ const encodedAlgorithm = pieces[0];
112
+ if (encodedAlgorithm.cls !== 0 || encodedAlgorithm.tag !== 6 || encodedAlgorithm.structured) {
113
+ throw new Error('Bad algorithm identifier. Does not begin with an OBJECT IDENTIFIER.');
114
+ }
115
+ const algorithm = derObjectIdentifierValue(encodedAlgorithm.contents);
116
+ return {
117
+ asn1,
118
+ algorithm,
119
+ parameters: pieces.length === 2 ? { asn1: pieces[1] } : null,
120
+ };
121
+ };
122
+ const parseName = (asn1) => derToAsn1List(asn1.contents).map(item => {
123
+ const attrSet = derToAsn1(item.contents);
124
+ return parseAlgorithmIdentifier(attrSet);
125
+ });
126
+ exports.parseName = parseName;
127
+ const parseSubjectPublicKeyInfo = (asn1) => {
128
+ if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
129
+ throw new Error('Bad SPKI. Not a SEQUENCE.');
130
+ }
131
+ const pieces = derToAsn1List(asn1.contents);
132
+ if (pieces.length !== 2) {
133
+ throw new Error('Bad SubjectPublicKeyInfo. Wrong number of child objects.');
134
+ }
135
+ return {
136
+ asn1,
137
+ algorithm: parseAlgorithmIdentifier(pieces[0]),
138
+ bits: derBitStringValue(pieces[1].contents),
139
+ };
140
+ };
141
+ const parseUtcTime = (time) => {
142
+ let offset = 4;
143
+ let yearOffset = 0;
144
+ if (time.tag === 23) {
145
+ offset = 2;
146
+ yearOffset = 2000;
147
+ }
148
+ const utc = Buffer.from(time.contents).toString();
149
+ const year = yearOffset + Number(utc.substring(0, offset));
150
+ const month = Number(utc.substring(offset, offset + 2)) - 1;
151
+ const day = Number(utc.substring(offset + 2, offset + 4));
152
+ const hour = Number(utc.substring(offset + 4, offset + 6));
153
+ const minute = Number(utc.substring(offset + 6, offset + 8));
154
+ const date = new Date();
155
+ date.setUTCFullYear(year, month, day);
156
+ date.setUTCHours(hour, minute, 0);
157
+ return date;
158
+ };
159
+ const parseValidity = (asn1) => {
160
+ const [from, to] = derToAsn1List(asn1.contents);
161
+ return {
162
+ from: parseUtcTime(from),
163
+ to: parseUtcTime(to),
164
+ };
165
+ };
166
+ const parseTBSCertificate = (asn1) => {
167
+ if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
168
+ throw new Error("This can't be a TBSCertificate. Wrong data type.");
169
+ }
170
+ const pieces = derToAsn1List(asn1.contents);
171
+ if (pieces.length < 7) {
172
+ throw new Error('Bad TBS Certificate. There are fewer than the seven required children.');
173
+ }
174
+ return {
175
+ asn1,
176
+ version: pieces[0],
177
+ serialNumber: pieces[1],
178
+ signature: parseAlgorithmIdentifier(pieces[2]),
179
+ issuer: pieces[3],
180
+ validity: parseValidity(pieces[4]),
181
+ subject: (0, exports.parseName)(pieces[5]),
182
+ subjectPublicKeyInfo: parseSubjectPublicKeyInfo(pieces[6]),
183
+ extensions: pieces[7],
184
+ };
185
+ };
186
+ const parseCertificate = (byteArray) => {
187
+ const asn1 = derToAsn1(byteArray);
188
+ if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
189
+ throw new Error("This can't be an X.509 certificate. Wrong data type.");
190
+ }
191
+ const pieces = derToAsn1List(asn1.contents);
192
+ if (pieces.length !== 3) {
193
+ throw new Error('Certificate contains more than the three specified children.');
194
+ }
195
+ return {
196
+ asn1,
197
+ tbsCertificate: parseTBSCertificate(pieces[0]),
198
+ signatureAlgorithm: parseAlgorithmIdentifier(pieces[1]),
199
+ signatureValue: parseSignatureValue(pieces[2]),
200
+ };
201
+ };
202
+ exports.parseCertificate = parseCertificate;
203
+ //# sourceMappingURL=x509certificate.js.map
@@ -53,6 +53,7 @@ class FirmwareUpdate extends AbstractMethod_1.AbstractMethod {
53
53
  return uiResp.payload;
54
54
  }
55
55
  async run() {
56
+ var _a;
56
57
  const { device, params } = this;
57
58
  let binary;
58
59
  try {
@@ -62,7 +63,7 @@ class FirmwareUpdate extends AbstractMethod_1.AbstractMethod {
62
63
  else {
63
64
  binary = await (0, firmware_1.getBinary)({
64
65
  features: device.features,
65
- releases: (0, firmwareInfo_1.getReleases)(device.features.major_version),
66
+ releases: (0, firmwareInfo_1.getReleases)((_a = device.features) === null || _a === void 0 ? void 0 : _a.internal_model),
66
67
  version: params.version,
67
68
  btcOnly: params.btcOnly,
68
69
  baseUrl: params.baseUrl,