Skip to content

Commit

Permalink
OK-34140: Improve hardware device verification process (#6323)
Browse files Browse the repository at this point in the history
* Update Verification.tsx

* Update ConnectYourDevice.tsx

* Update Verification.tsx

* Update FirmwareVerifyDialog.tsx

* Update FirmwareVerifyDialog.tsx

* Update FirmwareVerifyDialog.tsx

* Update FirmwareVerifyDialog.tsx

* Update FirmwareVerifyDialog.tsx

* remove features

* feat: verify firmware

* feat: compare version

* refactor: Remove deplicate component

* feat: memoizee version info

* fix: memoizee

* fix: Catch validate failed

* fix: compare field

* fix: code review issue

* i18n

* feat: Add verify log

* feat: Link to release url

* chore: lint

* fix: adapter classic1s

---------

Co-authored-by: huhuanming <[email protected]>
Co-authored-by: Franco <[email protected]>
  • Loading branch information
3 people authored Dec 11, 2024
1 parent 752fcb8 commit c761359
Show file tree
Hide file tree
Showing 30 changed files with 955 additions and 41 deletions.
198 changes: 197 additions & 1 deletion packages/kit-bg/src/services/ServiceHardware/HardwareVerifyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,18 @@ import {
EAppEventBusNames,
appEventBus,
} from '@onekeyhq/shared/src/eventBus/appEventBus';
import platformEnv from '@onekeyhq/shared/src/platformEnv';
import { defaultLogger } from '@onekeyhq/shared/src/logger/logger';
import bufferUtils from '@onekeyhq/shared/src/utils/bufferUtils';
import { memoizee } from '@onekeyhq/shared/src/utils/cacheUtils';
import deviceUtils from '@onekeyhq/shared/src/utils/deviceUtils';
import stringUtils from '@onekeyhq/shared/src/utils/stringUtils';
import timerUtils from '@onekeyhq/shared/src/utils/timerUtils';
import type {
IDeviceVerifyVersionCompareResult,
IFetchFirmwareVerifyHashParams,
IFirmwareVerifyInfo,
IOneKeyDeviceFeatures,
} from '@onekeyhq/shared/types/device';
import { EServiceEndpointEnum } from '@onekeyhq/shared/types/endpoint';

import localDb from '../../dbs/local/localDb';
Expand All @@ -25,6 +34,7 @@ import type {
import type {
DeviceVerifySignature,
IDeviceType,
OnekeyFeatures,
SearchDevice,
} from '@onekeyfe/hd-core';

Expand Down Expand Up @@ -189,4 +199,190 @@ export class HardwareVerifyManager extends ServiceHardwareManagerBase {
},
);
}

@backgroundMethod()
async shouldAuthenticateFirmwareByHash({
features,
}: {
features: IOneKeyDeviceFeatures | undefined;
}) {
// onekey_firmware_version
// onekey_firmware_hash
// onekey_ble_version
// onekey_ble_hash
// onekey_boot_version
// onekey_boot_hash
if (!features) {
return false;
}
const verifyVersions =
await deviceUtils.getDeviceVerifyVersionsFromFeatures({
features,
});
if (!verifyVersions) {
return false;
}
const result = await this.fetchFirmwareVerifyHash(verifyVersions);
// server should return 3 firmware config
if (!result || !Array.isArray(result) || result.length !== 3) {
return false;
}
const isValid = result.every((firmware) => {
if (
firmware.type === 'system' &&
firmware.version !== verifyVersions.firmwareVersion
) {
console.log('System version mismatch:', {
expected: verifyVersions.firmwareVersion,
actual: firmware.version,
});
return false;
}
if (
firmware.type === 'bluetooth' &&
firmware.version !== verifyVersions.bluetoothVersion
) {
console.log('Bluetooth version mismatch:', {
expected: verifyVersions.bluetoothVersion,
actual: firmware.version,
});
return false;
}
if (
firmware.type === 'bootloader' &&
firmware.version !== verifyVersions.bootloaderVersion
) {
console.log('Bootloader version mismatch:', {
expected: verifyVersions.bootloaderVersion,
actual: firmware.version,
});
return false;
}
return true;
});

console.log('shouldAuthenticateFirmwareByHash isValid: ', isValid);
return isValid;
}

@backgroundMethod()
async fetchFirmwareVerifyHash(
params: IFetchFirmwareVerifyHashParams,
): Promise<IFirmwareVerifyInfo[]> {
try {
return await this.fetchFirmwareVerifyHashWithCache(params);
} catch {
return [];
}
}

fetchFirmwareVerifyHashWithCache = memoizee(
async (params: IFetchFirmwareVerifyHashParams) => {
const client = await this.serviceHardware.getClient(
EServiceEndpointEnum.Utility,
);
const resp = await client.get<{
data: {
firmwares: IFirmwareVerifyInfo[];
};
}>('/utility/v1/firmware/detail', {
params: {
deviceType: params.deviceType,
system: params.firmwareVersion,
bluetooth: params.bluetoothVersion,
bootloader: params.bootloaderVersion,
},
});
return resp.data.data.firmwares;
},
{
promise: true,
maxAge: timerUtils.getTimeDurationMs({ minute: 2 }),
},
);

@backgroundMethod()
async verifyFirmwareHash({
deviceType,
onekeyFeatures,
}: {
deviceType: IDeviceType;
onekeyFeatures: OnekeyFeatures | undefined;
}): Promise<IDeviceVerifyVersionCompareResult> {
const defaultResult = {
certificate: {
isMatch: true,
format: onekeyFeatures?.onekey_serial_no ?? '',
},
firmware: { isMatch: false, format: '' },
bluetooth: { isMatch: false, format: '' },
bootloader: { isMatch: false, format: '' },
};

if (!onekeyFeatures) {
return defaultResult;
}

const verifyVersions =
await deviceUtils.getDeviceVerifyVersionsFromFeatures({
features: onekeyFeatures,
deviceType,
});
if (!verifyVersions) {
return defaultResult;
}

const result = await this.fetchFirmwareVerifyHash(verifyVersions);
if (!result || !Array.isArray(result)) {
return defaultResult;
}
const serverVerifyInfos = deviceUtils.parseServerVersionInfos({
serverVerifyInfos: result,
});
const localVerifyInfos = deviceUtils.parseLocalDeviceVersions({
onekeyFeatures,
});

const firmwareMatch = deviceUtils.compareDeviceVersions({
local: localVerifyInfos.firmware.raw,
remote: serverVerifyInfos.firmware.raw,
});
const bluetoothMatch = deviceUtils.compareDeviceVersions({
local: localVerifyInfos.bluetooth.raw,
remote: serverVerifyInfos.bluetooth.raw,
});
const bootloaderMatch = deviceUtils.compareDeviceVersions({
local: localVerifyInfos.bootloader.raw,
remote: serverVerifyInfos.bootloader.raw,
});

if (!firmwareMatch || !bluetoothMatch || !bootloaderMatch) {
defaultLogger.hardware.verify.verifyFailed({
local: localVerifyInfos,
server: serverVerifyInfos,
});
}

return {
certificate: {
isMatch: true,
format: onekeyFeatures?.onekey_serial_no ?? '',
},
firmware: {
isMatch: firmwareMatch,
format: serverVerifyInfos.firmware.formatted,
releaseUrl: serverVerifyInfos.firmware.releaseUrl,
},
bluetooth: {
isMatch: bluetoothMatch,
format: serverVerifyInfos.bluetooth.formatted,
releaseUrl: serverVerifyInfos.bluetooth.releaseUrl,
},
bootloader: {
isMatch: bootloaderMatch,
format: serverVerifyInfos.bootloader.formatted,
releaseUrl: serverVerifyInfos.bootloader.releaseUrl,
},
};
}
}
45 changes: 45 additions & 0 deletions packages/kit-bg/src/services/ServiceHardware/ServiceHardware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import deviceUtils from '@onekeyhq/shared/src/utils/deviceUtils';
import timerUtils from '@onekeyhq/shared/src/utils/timerUtils';
import type {
IBleFirmwareReleasePayload,
IDeviceResponseResult,
IDeviceVerifyVersionCompareResult,
IFirmwareReleasePayload,
IOneKeyDeviceFeatures,
} from '@onekeyhq/shared/types/device';
Expand Down Expand Up @@ -75,6 +77,8 @@ import type {
Features,
IDeviceType,
KnownDevice,
OnekeyFeatures,
Response,
SearchDevice,
UiEvent,
} from '@onekeyfe/hd-core';
Expand Down Expand Up @@ -891,6 +895,27 @@ class ServiceHardware extends ServiceBase {
return this.hardwareVerifyManager.firmwareAuthenticate(p);
}

@backgroundMethod()
async shouldAuthenticateFirmwareByHash(params: {
features: IOneKeyDeviceFeatures | undefined;
}) {
return this.hardwareVerifyManager.shouldAuthenticateFirmwareByHash(params);
}

@backgroundMethod()
async verifyFirmwareHash({
deviceType,
onekeyFeatures,
}: {
deviceType: IDeviceType;
onekeyFeatures: OnekeyFeatures | undefined;
}): Promise<IDeviceVerifyVersionCompareResult> {
return this.hardwareVerifyManager.verifyFirmwareHash({
deviceType,
onekeyFeatures,
});
}

@backgroundMethod()
async uploadResource(connectId: string, params: DeviceUploadResourceParams) {
const hardwareSDK = await this.getSDKInstance();
Expand All @@ -911,6 +936,26 @@ class ServiceHardware extends ServiceBase {
}
return logs;
}

@backgroundMethod()
async getOneKeyFeatures({
connectId,
deviceType,
}: {
connectId: string;
deviceType: IDeviceType;
}): Promise<OnekeyFeatures> {
const hardwareSDK = await this.getSDKInstance();
return convertDeviceResponse(() => {
// classic1s does not support getOnekeyFeatures method
if (deviceType === 'classic1s') {
return hardwareSDK?.getFeatures(
connectId,
) as unknown as Response<OnekeyFeatures>;
}
return hardwareSDK?.getOnekeyFeatures(connectId);
});
}
}

export default ServiceHardware;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useIntl } from 'react-intl';

import type { IIconProps, IKeyOfIcons } from '@onekeyhq/components';
import { type IIconProps, type IKeyOfIcons } from '@onekeyhq/components';
import { useFirmwareVerifyDialog } from '@onekeyhq/kit/src/views/Onboarding/pages/ConnectHardwareWallet/FirmwareVerifyDialog';
import type { IDBDevice } from '@onekeyhq/kit-bg/src/dbs/local/types';
import { ETranslations } from '@onekeyhq/shared/src/locale';
Expand All @@ -9,21 +9,6 @@ import { WalletOptionItem } from './WalletOptionItem';

export function Verification({ device }: { device?: IDBDevice | undefined }) {
const intl = useIntl();
// const returnVerified = () => {
// setVerified(true);
// Toast.success({
// title: 'Verified',
// message: 'You are good to go',
// });
// };

// const returnUnofficial = () => {
// setUnofficial(true);
// Toast.error({
// title: 'Unofficial',
// message: 'Please contact support',
// });
// };

const getIconNameAndIconColor = (): {
iconName: IKeyOfIcons;
Expand Down Expand Up @@ -69,6 +54,7 @@ export function Verification({ device }: { device?: IDBDevice | undefined }) {
}
await showFirmwareVerifyDialog({
device,
features: device.featuresInfo,
onContinue: async ({ checked }) => {
console.log(checked);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ function ConnectByUSBOrBLE({
) {
await showFirmwareVerifyDialog({
device,
features,
onContinue: async ({ checked }) => {
if (deviceMode === EOneKeyDeviceMode.notInitialized) {
handleNotActivatedDevicePress({ deviceType });
Expand Down
Loading

0 comments on commit c761359

Please sign in to comment.