@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
112 lines • 4.95 kB
JavaScript
import { HttpManagerApiRepository } from "@ledgerhq/device-core";
import { getEnv } from "@ledgerhq/live-env";
import { DeviceModelId } from "@ledgerhq/devices";
import { Device as CryptoWallet } from "./enum/Device";
import { sanitizeError } from "./index";
import * as fs from "fs";
import * as path from "path";
const liveCommonVersion = "34.64.0"; // live-common version isn't really necessary here, so we can hardcode it
export function getSpeculosModel() {
const speculosDevice = process.env.SPECULOS_DEVICE;
switch (speculosDevice) {
case CryptoWallet.LNS.name:
return DeviceModelId.nanoS;
case CryptoWallet.LNX.name:
return DeviceModelId.nanoX;
case CryptoWallet.STAX.name:
return DeviceModelId.stax;
case CryptoWallet.FLEX.name:
case DeviceModelId.europa:
return DeviceModelId.europa;
case CryptoWallet.NANO_GEN_5.name:
return DeviceModelId.apex;
case CryptoWallet.LNSP.name:
default:
return DeviceModelId.nanoSP;
}
}
export function isTouchDevice() {
const model = getSpeculosModel();
return (model === DeviceModelId.stax || model === DeviceModelId.europa || model === DeviceModelId.apex);
}
function getDeviceTargetId(device) {
const modelToTargetIdMap = {
[DeviceModelId.nanoS]: CryptoWallet.LNS.targetId,
[DeviceModelId.nanoX]: CryptoWallet.LNX.targetId,
[DeviceModelId.nanoSP]: CryptoWallet.LNSP.targetId,
[DeviceModelId.stax]: CryptoWallet.STAX.targetId,
[DeviceModelId.europa]: CryptoWallet.FLEX.targetId,
[DeviceModelId.apex]: CryptoWallet.NANO_GEN_5.targetId,
};
return modelToTargetIdMap[device];
}
export async function getNanoAppCatalog(device, deviceFirmware) {
const repository = new HttpManagerApiRepository(getEnv("MANAGER_API_BASE"), liveCommonVersion);
const targetId = getDeviceTargetId(device);
return await repository.catalogForDevice({
provider: 1,
targetId: targetId,
firmwareVersion: deviceFirmware,
});
}
const firmwareVersionCache = new Map();
export async function getDeviceFirmwareVersion(device) {
const cached = firmwareVersionCache.get(device);
if (cached)
return cached;
const providerId = 1;
const repository = new HttpManagerApiRepository(getEnv("MANAGER_API_BASE"), liveCommonVersion);
const deviceVersion = await repository.getDeviceVersion({
targetId: getDeviceTargetId(device),
providerId,
});
const firmwareIds = deviceVersion.se_firmware_final_versions;
if (!Array.isArray(firmwareIds) || firmwareIds.length === 0) {
throw new Error(`No firmware versions found for device ${device}`);
}
const firmwares = await Promise.all(firmwareIds.map(id => repository.getFinalFirmwareById(id)));
// Only firmwares matching providerId
const providerFirmwares = firmwares.filter(fw => Array.isArray(fw.providers) && fw.providers.includes(providerId));
if (providerFirmwares.length === 0) {
throw new Error(`No firmware versions found for device version ${deviceVersion.id} for device ${device}`);
}
// Latest is chosen by highest numeric ID
const latestFirmware = providerFirmwares.reduce((latest, current) => current.id > latest.id ? current : latest);
firmwareVersionCache.set(device, latestFirmware.version);
process.env.SPECULOS_FIRMWARE_VERSION = latestFirmware.version;
return latestFirmware.version;
}
export async function createNanoAppJsonFile(nanoAppFilePath) {
const jsonFilePath = path.resolve(process.cwd(), nanoAppFilePath);
try {
if (fs.existsSync(jsonFilePath)) {
return; // File already exists
}
fs.mkdirSync(path.dirname(jsonFilePath), { recursive: true });
const device = getSpeculosModel();
const firmware = await getDeviceFirmwareVersion(device);
const appCatalog = await getNanoAppCatalog(device, firmware);
fs.writeFileSync(jsonFilePath, JSON.stringify(appCatalog, null, 2), "utf8");
}
catch (error) {
console.error("Unable to create app version file:", sanitizeError(error));
}
}
export async function getAppVersionFromCatalog(currency, nanoAppFilePath) {
const jsonFilePath = path.resolve(process.cwd(), nanoAppFilePath);
try {
await createNanoAppJsonFile(nanoAppFilePath);
if (!fs.existsSync(jsonFilePath)) {
console.error(`Catalog file not found: ${jsonFilePath}`);
return;
}
const raw = fs.readFileSync(jsonFilePath, "utf8");
const catalog = JSON.parse(raw);
const app = catalog.find(entry => entry.versionDisplayName === currency);
return app?.version ?? "";
}
catch (error) {
console.error(`Unable to get app version for ${currency} from catalog:`, error);
}
}
//# sourceMappingURL=speculosAppVersion.js.map