@onekeyfe/hd-core 0.3.16 → 0.3.19
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/dist/api/evm/EVMGetAddress.d.ts +4 -3
- package/dist/api/evm/EVMGetAddress.d.ts.map +1 -1
- package/dist/api/evm/EVMGetPublicKey.d.ts +4 -3
- package/dist/api/evm/EVMGetPublicKey.d.ts.map +1 -1
- package/dist/api/evm/EVMSignMessage.d.ts +2 -2
- package/dist/api/evm/EVMSignMessage.d.ts.map +1 -1
- package/dist/api/evm/EVMSignTransaction.d.ts +2 -6
- package/dist/api/evm/EVMSignTransaction.d.ts.map +1 -1
- package/dist/api/evm/EVMSignTypedData.d.ts +19 -1
- package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
- package/dist/api/evm/EVMVerifyMessage.d.ts +2 -2
- package/dist/api/evm/EVMVerifyMessage.d.ts.map +1 -1
- package/dist/api/evm/latest/getAddress.d.ts +6 -0
- package/dist/api/evm/latest/getAddress.d.ts.map +1 -0
- package/dist/api/evm/latest/getPublicKey.d.ts +6 -0
- package/dist/api/evm/latest/getPublicKey.d.ts.map +1 -0
- package/dist/api/evm/latest/signMessage.d.ts +6 -0
- package/dist/api/evm/latest/signMessage.d.ts.map +1 -0
- package/dist/api/evm/latest/signTransaction.d.ts +16 -0
- package/dist/api/evm/latest/signTransaction.d.ts.map +1 -0
- package/dist/api/evm/latest/signTypedData.d.ts +10 -0
- package/dist/api/evm/latest/signTypedData.d.ts.map +1 -0
- package/dist/api/evm/latest/signTypedHash.d.ts +11 -0
- package/dist/api/evm/latest/signTypedHash.d.ts.map +1 -0
- package/dist/api/evm/latest/verifyMessage.d.ts +6 -0
- package/dist/api/evm/latest/verifyMessage.d.ts.map +1 -0
- package/dist/api/evm/legacyV1/getAddress.d.ts +6 -0
- package/dist/api/evm/legacyV1/getAddress.d.ts.map +1 -0
- package/dist/api/evm/legacyV1/getPublicKey.d.ts +6 -0
- package/dist/api/evm/legacyV1/getPublicKey.d.ts.map +1 -0
- package/dist/api/evm/legacyV1/signMessage.d.ts +6 -0
- package/dist/api/evm/legacyV1/signMessage.d.ts.map +1 -0
- package/dist/api/evm/legacyV1/signTransaction.d.ts +9 -0
- package/dist/api/evm/legacyV1/signTransaction.d.ts.map +1 -0
- package/dist/api/evm/legacyV1/signTypedData.d.ts +10 -0
- package/dist/api/evm/legacyV1/signTypedData.d.ts.map +1 -0
- package/dist/api/evm/legacyV1/signTypedHash.d.ts +11 -0
- package/dist/api/evm/legacyV1/signTypedHash.d.ts.map +1 -0
- package/dist/api/evm/legacyV1/verifyMessage.d.ts +6 -0
- package/dist/api/evm/legacyV1/verifyMessage.d.ts.map +1 -0
- package/dist/api/helpers/pathUtils.d.ts +1 -0
- package/dist/api/helpers/pathUtils.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data/messages-config/index.d.ts +11 -0
- package/dist/data/messages-config/index.d.ts.map +1 -0
- package/dist/data-manager/DataManager.d.ts +4 -3
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/TransportManager.d.ts +5 -1
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/device/Device.d.ts +1 -1
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/index.d.ts +48 -38
- package/dist/index.js +11680 -334
- package/dist/types/api/nexaGetAddress.d.ts +3 -2
- package/dist/types/api/nexaGetAddress.d.ts.map +1 -1
- package/dist/types/device.d.ts +6 -0
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/settings.d.ts +1 -0
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts +7 -2
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +1 -1
- package/src/api/evm/EVMGetAddress.ts +25 -6
- package/src/api/evm/EVMGetPublicKey.ts +21 -10
- package/src/api/evm/EVMSignMessage.ts +15 -10
- package/src/api/evm/EVMSignTransaction.ts +22 -136
- package/src/api/evm/EVMSignTypedData.ts +197 -83
- package/src/api/evm/EVMVerifyMessage.ts +15 -6
- package/src/api/evm/latest/getAddress.ts +13 -0
- package/src/api/evm/latest/getPublicKey.ts +13 -0
- package/src/api/evm/latest/signMessage.ts +19 -0
- package/src/api/evm/latest/signTransaction.ts +196 -0
- package/src/api/evm/latest/signTypedData.ts +33 -0
- package/src/api/evm/latest/signTypedHash.ts +44 -0
- package/src/api/evm/latest/verifyMessage.ts +15 -0
- package/src/api/evm/legacyV1/getAddress.ts +16 -0
- package/src/api/evm/legacyV1/getPublicKey.ts +16 -0
- package/src/api/evm/legacyV1/signMessage.ts +22 -0
- package/src/api/evm/legacyV1/signTransaction.ts +99 -0
- package/src/api/evm/legacyV1/signTypedData.ts +36 -0
- package/src/api/evm/legacyV1/signTypedHash.ts +48 -0
- package/src/api/evm/legacyV1/verifyMessage.ts +19 -0
- package/src/api/helpers/pathUtils.ts +1 -0
- package/src/core/index.ts +5 -4
- package/src/data/messages/messages.json +577 -21
- package/src/data/messages/messages_legacy_v1.json +10270 -0
- package/src/data/messages-config/index.ts +20 -0
- package/src/data-manager/DataManager.ts +15 -11
- package/src/data-manager/TransportManager.ts +19 -5
- package/src/device/Device.ts +8 -5
- package/src/types/api/nexaGetAddress.ts +3 -2
- package/src/types/device.ts +12 -0
- package/src/types/settings.ts +1 -0
- package/src/utils/deviceFeaturesUtils.ts +45 -5
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IDeviceModel, IDeviceType } from '../../types';
|
|
2
|
+
import { MessageVersion } from '../../data-manager/DataManager';
|
|
3
|
+
|
|
4
|
+
type DeviceVersionConfig = {
|
|
5
|
+
[deviceType in IDeviceType | IDeviceModel]?: {
|
|
6
|
+
minVersion: string;
|
|
7
|
+
messageVersion: MessageVersion;
|
|
8
|
+
}[];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const PROTOBUF_MESSAGE_CONFIG: DeviceVersionConfig = {
|
|
12
|
+
model_mini: [
|
|
13
|
+
{ minVersion: '3.2.0', messageVersion: 'latest' },
|
|
14
|
+
{ minVersion: '0.0.0', messageVersion: 'v1' },
|
|
15
|
+
],
|
|
16
|
+
model_touch: [
|
|
17
|
+
{ minVersion: '4.4.0', messageVersion: 'latest' },
|
|
18
|
+
{ minVersion: '0.0.0', messageVersion: 'v1' },
|
|
19
|
+
],
|
|
20
|
+
};
|
|
@@ -1,28 +1,31 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import semver from 'semver';
|
|
3
3
|
import MessagesJSON from '../data/messages/messages.json';
|
|
4
|
+
import MessagesLegacyV1JSON from '../data/messages/messages_legacy_v1.json';
|
|
4
5
|
import { getTimeStamp } from '../utils';
|
|
5
6
|
import {
|
|
6
|
-
getDeviceType,
|
|
7
|
-
getDeviceFirmwareVersion,
|
|
8
7
|
getDeviceBLEFirmwareVersion,
|
|
8
|
+
getDeviceFirmwareVersion,
|
|
9
|
+
getDeviceType,
|
|
9
10
|
getFirmwareUpdateField,
|
|
10
11
|
} from '../utils/deviceFeaturesUtils';
|
|
11
12
|
|
|
12
13
|
import type {
|
|
14
|
+
AssetsMap,
|
|
13
15
|
ConnectSettings,
|
|
14
16
|
DeviceTypeMap,
|
|
15
|
-
AssetsMap,
|
|
16
|
-
RemoteConfigResponse,
|
|
17
17
|
Features,
|
|
18
|
-
IDeviceFirmwareStatus,
|
|
19
18
|
IDeviceBLEFirmwareStatus,
|
|
19
|
+
IDeviceFirmwareStatus,
|
|
20
20
|
ITransportStatus,
|
|
21
21
|
IVersionArray,
|
|
22
|
+
RemoteConfigResponse,
|
|
22
23
|
} from '../types';
|
|
23
|
-
import { getReleaseChangelog, getReleaseStatus
|
|
24
|
+
import { findLatestRelease, getReleaseChangelog, getReleaseStatus } from '../utils/release';
|
|
25
|
+
|
|
26
|
+
type FirmwareField = 'firmware' | 'firmware-v2' | 'firmware-v3' | 'firmware-v4';
|
|
24
27
|
|
|
25
|
-
type
|
|
28
|
+
export type MessageVersion = 'latest' | 'v1';
|
|
26
29
|
|
|
27
30
|
export default class DataManager {
|
|
28
31
|
static deviceMap: DeviceTypeMap = {
|
|
@@ -48,8 +51,9 @@ export default class DataManager {
|
|
|
48
51
|
|
|
49
52
|
static settings: ConnectSettings;
|
|
50
53
|
|
|
51
|
-
static messages: {
|
|
52
|
-
|
|
54
|
+
static messages: { [version in MessageVersion]: JSON } = {
|
|
55
|
+
latest: MessagesJSON as unknown as JSON,
|
|
56
|
+
v1: MessagesLegacyV1JSON as unknown as JSON,
|
|
53
57
|
};
|
|
54
58
|
|
|
55
59
|
static lastCheckTimestamp = 0;
|
|
@@ -254,8 +258,8 @@ export default class DataManager {
|
|
|
254
258
|
}
|
|
255
259
|
}
|
|
256
260
|
|
|
257
|
-
static getProtobufMessages() {
|
|
258
|
-
return this.messages
|
|
261
|
+
static getProtobufMessages(messageVersion: MessageVersion = 'latest'): JSON {
|
|
262
|
+
return this.messages[messageVersion];
|
|
259
263
|
}
|
|
260
264
|
|
|
261
265
|
static getSettings(key?: undefined): ConnectSettings;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { Transport } from '@onekeyfe/hd-transport';
|
|
2
2
|
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
3
|
-
import DataManager from './DataManager';
|
|
3
|
+
import DataManager, { MessageVersion } from './DataManager';
|
|
4
4
|
import { getLogger, LoggerNames } from '../utils';
|
|
5
5
|
// eslint-disable-next-line import/no-cycle
|
|
6
6
|
import { DevicePool } from '../device/DevicePool';
|
|
7
|
+
import { getSupportMessageVersion } from '../utils/deviceFeaturesUtils';
|
|
8
|
+
import { Features } from '../types';
|
|
7
9
|
|
|
8
10
|
const Log = getLogger(LoggerNames.Transport);
|
|
9
11
|
const BleLogger = getLogger(LoggerNames.HdBleTransport);
|
|
10
12
|
const HttpLogger = getLogger(LoggerNames.HdTransportHttp);
|
|
13
|
+
|
|
11
14
|
/**
|
|
12
15
|
* transport 在同一个环境中只会存在一个
|
|
13
16
|
* 这里设计成单例获取
|
|
@@ -22,10 +25,13 @@ export default class TransportManager {
|
|
|
22
25
|
|
|
23
26
|
static reactNativeInit = false;
|
|
24
27
|
|
|
28
|
+
static messageVersion: MessageVersion = 'latest';
|
|
29
|
+
|
|
25
30
|
static load() {
|
|
26
31
|
Log.debug('transport manager load');
|
|
27
32
|
this.defaultMessages = DataManager.getProtobufMessages();
|
|
28
33
|
this.currentMessages = this.defaultMessages;
|
|
34
|
+
this.messageVersion = 'latest';
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
static async configure() {
|
|
@@ -53,16 +59,20 @@ export default class TransportManager {
|
|
|
53
59
|
}
|
|
54
60
|
}
|
|
55
61
|
|
|
56
|
-
static async reconfigure(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
static async reconfigure(features?: Features | undefined) {
|
|
63
|
+
Log.debug(`Begin reconfiguring transports`);
|
|
64
|
+
const { messageVersion, messages } = getSupportMessageVersion(features);
|
|
65
|
+
|
|
60
66
|
if (this.currentMessages === messages || !messages) {
|
|
61
67
|
return;
|
|
62
68
|
}
|
|
69
|
+
|
|
70
|
+
Log.debug(`Reconfiguring transports version:${messageVersion}`);
|
|
71
|
+
|
|
63
72
|
try {
|
|
64
73
|
await this.transport.configure(JSON.stringify(messages));
|
|
65
74
|
this.currentMessages = messages;
|
|
75
|
+
this.messageVersion = messageVersion;
|
|
66
76
|
} catch (error) {
|
|
67
77
|
throw ERRORS.TypedError(
|
|
68
78
|
HardwareErrorCode.TransportInvalidProtobuf,
|
|
@@ -94,4 +104,8 @@ export default class TransportManager {
|
|
|
94
104
|
static getCurrentMessages() {
|
|
95
105
|
return this.currentMessages;
|
|
96
106
|
}
|
|
107
|
+
|
|
108
|
+
static getMessageVersion() {
|
|
109
|
+
return this.messageVersion;
|
|
110
|
+
}
|
|
97
111
|
}
|
package/src/device/Device.ts
CHANGED
|
@@ -3,17 +3,17 @@ import { OneKeyDeviceInfo as DeviceDescriptor } from '@onekeyfe/hd-transport';
|
|
|
3
3
|
import {
|
|
4
4
|
createDeferred,
|
|
5
5
|
Deferred,
|
|
6
|
-
HardwareErrorCode,
|
|
7
6
|
ERRORS,
|
|
8
7
|
HardwareError,
|
|
8
|
+
HardwareErrorCode,
|
|
9
9
|
} from '@onekeyfe/hd-shared';
|
|
10
10
|
import {
|
|
11
|
+
getDeviceBLEFirmwareVersion,
|
|
11
12
|
getDeviceFirmwareVersion,
|
|
12
13
|
getDeviceLabel,
|
|
13
14
|
getDeviceType,
|
|
14
|
-
getDeviceUUID,
|
|
15
|
-
getDeviceBLEFirmwareVersion,
|
|
16
15
|
getDeviceTypeOnBootloader,
|
|
16
|
+
getDeviceUUID,
|
|
17
17
|
getPassphraseState,
|
|
18
18
|
} from '../utils/deviceFeaturesUtils';
|
|
19
19
|
|
|
@@ -21,12 +21,13 @@ import type DeviceConnector from './DeviceConnector';
|
|
|
21
21
|
// eslint-disable-next-line import/no-cycle
|
|
22
22
|
import { DeviceCommands, PassphrasePromptResponse } from './DeviceCommands';
|
|
23
23
|
|
|
24
|
-
import type {
|
|
24
|
+
import type { Device as DeviceTyped, Features, UnavailableCapabilities } from '../types';
|
|
25
25
|
import { DEVICE, DeviceButtonRequestPayload, DeviceFeaturesPayload } from '../events';
|
|
26
26
|
import { UI_REQUEST } from '../constants/ui-request';
|
|
27
27
|
import { PROTO } from '../constants';
|
|
28
28
|
import { getLogger, LoggerNames } from '../utils';
|
|
29
29
|
import { DataManager } from '../data-manager';
|
|
30
|
+
import TransportManager from '../data-manager/TransportManager';
|
|
30
31
|
|
|
31
32
|
export type InitOptions = {
|
|
32
33
|
initSession?: boolean;
|
|
@@ -355,6 +356,8 @@ export class Device extends EventEmitter {
|
|
|
355
356
|
|
|
356
357
|
const { message } = await this.commands.typedCall('Initialize', 'Features', payload);
|
|
357
358
|
this._updateFeatures(message, options?.initSession);
|
|
359
|
+
|
|
360
|
+
await TransportManager.reconfigure(message);
|
|
358
361
|
}
|
|
359
362
|
|
|
360
363
|
async getFeatures() {
|
|
@@ -370,7 +373,7 @@ export class Device extends EventEmitter {
|
|
|
370
373
|
if (this.features && this.features.device_id && feat.session_id) {
|
|
371
374
|
this.setInternalState(feat.session_id, initSession);
|
|
372
375
|
}
|
|
373
|
-
feat.unlocked = feat.unlocked
|
|
376
|
+
feat.unlocked = feat.unlocked ?? true;
|
|
374
377
|
|
|
375
378
|
this.features = feat;
|
|
376
379
|
this.featuresNeedsReload = false;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { NexaAddress as HardwareNexaAddress } from '@onekeyfe/hd-transport';
|
|
2
1
|
import type { CommonParams, Response } from '../params';
|
|
3
2
|
|
|
4
3
|
export type NexaAddress = {
|
|
5
4
|
path: string;
|
|
6
|
-
|
|
5
|
+
pub: string;
|
|
6
|
+
address: string;
|
|
7
|
+
};
|
|
7
8
|
|
|
8
9
|
export type NexaGetAddressParams = {
|
|
9
10
|
path: string | number[];
|
package/src/types/device.ts
CHANGED
|
@@ -77,6 +77,18 @@ export type IDeviceType = 'classic' | 'mini' | 'touch' | 'pro';
|
|
|
77
77
|
// model_touch: 'touch' | 'pro'
|
|
78
78
|
export type IDeviceModel = 'model_mini' | 'model_touch';
|
|
79
79
|
|
|
80
|
+
export const DeviceModelToTypes: { [deviceModel in IDeviceModel]: IDeviceType[] } = {
|
|
81
|
+
model_mini: ['classic', 'mini'],
|
|
82
|
+
model_touch: ['touch', 'pro'],
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const DeviceTypeToModels: { [deviceType in IDeviceType]: IDeviceModel[] } = {
|
|
86
|
+
classic: ['model_mini'],
|
|
87
|
+
mini: ['model_mini'],
|
|
88
|
+
touch: ['model_touch'],
|
|
89
|
+
pro: ['model_touch'],
|
|
90
|
+
};
|
|
91
|
+
|
|
80
92
|
export type IDeviceFirmwareStatus = 'valid' | 'outdated' | 'required' | 'unknown' | 'none';
|
|
81
93
|
|
|
82
94
|
export type IDeviceBLEFirmwareStatus = 'valid' | 'outdated' | 'required' | 'unknown' | 'none';
|
package/src/types/settings.ts
CHANGED
|
@@ -4,11 +4,14 @@ import { toHardened } from '../api/helpers/pathUtils';
|
|
|
4
4
|
import { DeviceCommands } from '../device/DeviceCommands';
|
|
5
5
|
import type {
|
|
6
6
|
Features,
|
|
7
|
-
IVersionArray,
|
|
8
|
-
IDeviceType,
|
|
9
7
|
IDeviceModel,
|
|
8
|
+
IDeviceType,
|
|
9
|
+
IVersionArray,
|
|
10
10
|
SupportFeatureType,
|
|
11
11
|
} from '../types';
|
|
12
|
+
import { DeviceTypeToModels } from '../types';
|
|
13
|
+
import DataManager, { MessageVersion } from '../data-manager/DataManager';
|
|
14
|
+
import { PROTOBUF_MESSAGE_CONFIG } from '../data/messages-config';
|
|
12
15
|
|
|
13
16
|
export const getDeviceModel = (features?: Features): IDeviceModel => {
|
|
14
17
|
if (!features || typeof features !== 'object') {
|
|
@@ -113,6 +116,43 @@ export const getDeviceBootloaderVersion = (features: Features): IVersionArray =>
|
|
|
113
116
|
return [0, 0, 0];
|
|
114
117
|
};
|
|
115
118
|
|
|
119
|
+
export const getSupportMessageVersion = (
|
|
120
|
+
features: Features | undefined
|
|
121
|
+
): { messages: JSON; messageVersion: MessageVersion } => {
|
|
122
|
+
if (!features)
|
|
123
|
+
return {
|
|
124
|
+
messages: DataManager.messages.latest,
|
|
125
|
+
messageVersion: 'latest',
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const currentDeviceVersion = getDeviceFirmwareVersion(features).join('.');
|
|
129
|
+
const deviceType = getDeviceType(features);
|
|
130
|
+
|
|
131
|
+
const deviceVersionConfigs =
|
|
132
|
+
PROTOBUF_MESSAGE_CONFIG[deviceType] ||
|
|
133
|
+
(DeviceTypeToModels[deviceType] &&
|
|
134
|
+
DeviceTypeToModels[deviceType]
|
|
135
|
+
.map(model => PROTOBUF_MESSAGE_CONFIG[model])
|
|
136
|
+
.find(range => range !== undefined));
|
|
137
|
+
|
|
138
|
+
const sortedDeviceVersionConfigs =
|
|
139
|
+
deviceVersionConfigs?.sort((a, b) => semver.compare(b.minVersion, a.minVersion)) ?? [];
|
|
140
|
+
|
|
141
|
+
for (const { minVersion, messageVersion } of sortedDeviceVersionConfigs) {
|
|
142
|
+
if (semver.gte(currentDeviceVersion, minVersion)) {
|
|
143
|
+
return {
|
|
144
|
+
messages: DataManager.messages[messageVersion],
|
|
145
|
+
messageVersion,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
messages: DataManager.messages.latest,
|
|
152
|
+
messageVersion: 'latest',
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
|
|
116
156
|
export const supportInputPinOnSoftware = (features: Features): SupportFeatureType => {
|
|
117
157
|
if (!features) return { support: false };
|
|
118
158
|
|
|
@@ -185,7 +225,7 @@ export const supportModifyHomescreen = (features?: Features): SupportFeatureType
|
|
|
185
225
|
export const getFirmwareUpdateField = (
|
|
186
226
|
features: Features,
|
|
187
227
|
updateType: 'firmware' | 'ble'
|
|
188
|
-
): 'firmware' | 'ble' | 'firmware-
|
|
228
|
+
): 'firmware' | 'ble' | 'firmware-v4' => {
|
|
189
229
|
const deviceType = getDeviceType(features);
|
|
190
230
|
const deviceFirmwareVersion = getDeviceFirmwareVersion(features);
|
|
191
231
|
if (updateType === 'ble') {
|
|
@@ -193,12 +233,12 @@ export const getFirmwareUpdateField = (
|
|
|
193
233
|
}
|
|
194
234
|
|
|
195
235
|
if (deviceType === 'classic' || deviceType === 'mini') {
|
|
196
|
-
return 'firmware-
|
|
236
|
+
return 'firmware-v4';
|
|
197
237
|
}
|
|
198
238
|
|
|
199
239
|
if (deviceType === 'touch') {
|
|
200
240
|
if (semver.lt(deviceFirmwareVersion.join('.'), '3.4.0')) return 'firmware';
|
|
201
|
-
return 'firmware-
|
|
241
|
+
return 'firmware-v4';
|
|
202
242
|
}
|
|
203
243
|
return 'firmware';
|
|
204
244
|
};
|