@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
324 lines • 13.3 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable camelcase */
const errors_1 = require("@ledgerhq/errors");
const cache_1 = require("@ledgerhq/live-network/cache");
const network_1 = __importDefault(require("@ledgerhq/live-network/network"));
const logs_1 = require("@ledgerhq/logs");
const invariant_1 = __importDefault(require("invariant"));
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const semver_1 = __importDefault(require("semver"));
const url_1 = __importDefault(require("url"));
const package_json_1 = require("../../package.json");
const live_env_1 = require("@ledgerhq/live-env");
const socket_1 = require("../socket");
const socket_mock_1 = require("../socket/socket.mock");
const provider_1 = require("./provider");
const fetchMcusUseCase_1 = require("../device/use-cases/fetchMcusUseCase");
const remapSocketError = (context) => (0, operators_1.catchError)((e) => {
if (!e || !e.message)
return (0, rxjs_1.throwError)(() => e);
if (e.message.startsWith("invalid literal")) {
// hack to detect the case you're not in good condition (not in dashboard)
return (0, rxjs_1.throwError)(() => new errors_1.DeviceOnDashboardExpected());
}
const status = e instanceof errors_1.TransportStatusError
? e.statusCode.toString(16)
: e.message.slice(e.message.length - 4);
// TODO use StatusCode instead of this.
switch (status) {
case "6a80":
case "6a81":
case "6a8e":
case "6a8f":
return (0, rxjs_1.throwError)(() => new errors_1.ManagerAppAlreadyInstalledError());
case "6982":
case "5303":
return (0, rxjs_1.throwError)(() => new errors_1.ManagerDeviceLockedError());
case "6a84":
case "5103":
if (context === "firmware" || context === "mcu") {
return (0, rxjs_1.throwError)(() => new errors_1.ManagerFirmwareNotEnoughSpaceError());
}
return (0, rxjs_1.throwError)(() => new errors_1.ManagerNotEnoughSpaceError());
case "6a85":
case "5102":
if (context === "firmware" || context === "mcu") {
return (0, rxjs_1.throwError)(() => new errors_1.UserRefusedFirmwareUpdate());
}
return (0, rxjs_1.throwError)(() => new errors_1.ManagerNotEnoughSpaceError());
case "6985":
case "5501":
if (context === "firmware" || context === "mcu") {
return (0, rxjs_1.throwError)(() => new errors_1.UserRefusedFirmwareUpdate());
}
return (0, rxjs_1.throwError)(() => new errors_1.ManagerNotEnoughSpaceError());
default:
return (0, rxjs_1.throwError)(() => e);
}
});
/** @deprecated use getAppsCatalogForDevice (from ledger-live-common/src/device/use-cases) instead */
const listApps = (0, cache_1.makeLRUCache)(async () => {
const { data } = await (0, network_1.default)({
method: "GET",
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}/applications`,
query: {
livecommonversion: package_json_1.version,
},
}),
});
if (!data || !Array.isArray(data)) {
throw new errors_1.NetworkDown("");
}
return data;
}, () => (0, live_env_1.getEnv)("MANAGER_API_BASE"));
const listCategories = async () => {
const r = await (0, network_1.default)({
method: "GET",
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}/categories`,
query: {
livecommonversion: package_json_1.version,
},
}),
});
return r.data;
};
const compatibleMCUForDeviceInfo = (mcus, deviceInfo, provider) => mcus.filter(m => (deviceInfo.majMin === m.from_bootloader_version ||
deviceInfo.version === m.from_bootloader_version) &&
m.providers.includes(provider));
const findBestMCU = (compatibleMCU) => {
let best = compatibleMCU[0];
for (let i = 1; i < compatibleMCU.length; i++) {
if (semver_1.default.gt(semver_1.default.coerce(compatibleMCU[i].name) || "", semver_1.default.coerce(best.name) || "")) {
best = compatibleMCU[i];
}
}
return best;
};
const getLanguagePackagesForDevice = async (deviceInfo) => {
const deviceVersion = await getDeviceVersion(deviceInfo.targetId, (0, provider_1.getProviderId)(deviceInfo));
const seFirmwareVersion = await getCurrentFirmware({
version: deviceInfo.version,
deviceId: deviceVersion.id,
provider: (0, provider_1.getProviderId)(deviceInfo),
});
const { data } = await (0, network_1.default)({
method: "GET",
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}/language-package`,
query: {
livecommonversion: package_json_1.version,
},
}),
});
const allPackages = data.reduce((acc, response) => [
...acc,
...response.language_package_version.map(p => ({
...p,
language: response.language,
})),
], []);
const packages = allPackages.filter(pack => pack.device_versions.includes(deviceVersion.id) &&
pack.se_firmware_final_versions.includes(seFirmwareVersion.id));
return packages;
};
const getCurrentOSU = (0, cache_1.makeLRUCache)(async (input) => {
const { data } = await (0, network_1.default)({
method: "GET",
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}/get_osu_version`,
query: {
livecommonversion: package_json_1.version,
device_version: input.deviceId,
version_name: `${input.version}-osu`,
provider: input.provider,
},
}),
});
return data;
}, a => `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}_${a.version}_${a.deviceId}_${a.provider}`);
const getCurrentFirmware = (0, cache_1.makeLRUCache)(async (input) => {
const { data, } = await (0, network_1.default)({
method: "GET",
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}/get_firmware_version`,
query: {
livecommonversion: package_json_1.version,
device_version: input.deviceId,
version_name: input.version,
provider: input.provider,
},
}),
}).catch(error => {
const status = error?.status || error?.response?.status;
if (status === 404)
throw new errors_1.FirmwareNotRecognized();
throw error;
});
return data;
}, a => `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}_${a.version}_${a.deviceId}_${a.provider}`);
const getFinalFirmwareById = (0, cache_1.makeLRUCache)(async (id) => {
const { data, } = await (0, network_1.default)({
method: "GET",
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}/firmware_final_versions/${id}`,
query: {
livecommonversion: package_json_1.version,
},
}),
});
return data;
}, id => `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}}_${String(id)}`);
const getDeviceVersion = (0, cache_1.makeLRUCache)(async (targetId, provider) => {
const { data, } = await (0, network_1.default)({
method: "GET",
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}/get_device_version`,
query: {
livecommonversion: package_json_1.version,
provider,
target_id: targetId,
},
}),
}).catch(error => {
const status = error?.status || error?.response?.status;
if (status === 404)
throw new errors_1.FirmwareNotRecognized("manager api did not recognize targetId=" + targetId, {
targetId,
});
throw error;
});
return data;
}, (targetId, provider) => `${(0, live_env_1.getEnv)("MANAGER_API_BASE")}_${targetId}_${provider}`);
const install = (transport, context, params, unresponsiveExpectedDuringBulk) => {
if ((0, live_env_1.getEnv)("MOCK")) {
return (0, socket_mock_1.createMockSocket)((0, socket_mock_1.secureChannelMock)(true), (0, socket_mock_1.bulkSocketMock)(3000));
}
(0, logs_1.log)("manager", "install " + context, params);
return (0, socket_1.createDeviceSocket)(transport, {
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("BASE_SOCKET_URL")}/install`,
query: { ...params, livecommonversion: package_json_1.version },
}),
unresponsiveExpectedDuringBulk,
}).pipe(remapSocketError(context));
};
const genuineCheck = (transport, { targetId, perso, }) => {
if ((0, live_env_1.getEnv)("MOCK")) {
return (0, socket_mock_1.createMockSocket)((0, socket_mock_1.secureChannelMock)(false), (0, socket_mock_1.resultMock)("0000"));
}
(0, logs_1.log)("manager", "genuineCheck", {
targetId,
perso,
});
return (0, socket_1.createDeviceSocket)(transport, {
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("BASE_SOCKET_URL")}/genuine`,
query: {
targetId,
perso,
livecommonversion: package_json_1.version,
},
}),
}).pipe((0, operators_1.map)(e => {
if (e.type === "result") {
return {
type: "result",
payload: String(e.payload || ""),
};
}
return e;
}));
};
const listInstalledApps = (transport, { targetId, perso, }) => {
if ((0, live_env_1.getEnv)("MOCK")) {
const result = global._listInstalledApps_mock_result;
(0, invariant_1.default)(result, "using MOCK, global._listInstalledApps_mock_result must be set");
return (0, socket_mock_1.createMockSocket)((0, socket_mock_1.secureChannelMock)(false), (0, socket_mock_1.resultMock)(result));
}
(0, logs_1.log)("manager", "listInstalledApps", {
targetId,
perso,
});
return (0, socket_1.createDeviceSocket)(transport, {
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("BASE_SOCKET_URL")}/apps/list`,
query: {
targetId,
perso,
livecommonversion: package_json_1.version,
},
}),
}).pipe(remapSocketError("listInstalledApps"), (0, operators_1.map)(o => {
if (o.type === "result") {
return {
type: "result",
payload: [...o.payload].map(a => {
(0, invariant_1.default)(typeof a === "object" && a, "payload array item are objects");
const { hash, name, hash_code_data } = a;
(0, invariant_1.default)(typeof hash === "string", "hash is defined");
(0, invariant_1.default)(typeof name === "string", "name is defined");
return {
hash,
name,
hash_code_data,
};
}),
};
}
return o;
}));
};
const installMcu = (transport, context, { targetId, version, }) => {
if ((0, live_env_1.getEnv)("MOCK")) {
return (0, socket_mock_1.createMockSocket)((0, socket_mock_1.secureChannelMock)(false), (0, socket_mock_1.bulkSocketMock)(5000));
}
(0, logs_1.log)("manager", "installMCU " + context, {
targetId,
version,
});
return (0, socket_1.createDeviceSocket)(transport, {
url: url_1.default.format({
pathname: `${(0, live_env_1.getEnv)("BASE_SOCKET_URL")}/mcu`,
query: {
targetId,
version,
livecommonversion: package_json_1.version,
},
}),
unresponsiveExpectedDuringBulk: true,
}).pipe(remapSocketError(context));
};
async function retrieveMcuVersion({ mcu_versions, }) {
const mcus = await (0, fetchMcusUseCase_1.fetchMcusUseCase)();
const provider = (0, provider_1.getProviderId)(undefined);
const availableMcus = mcus.filter(({ id, providers, from_bootloader_version }) => providers.includes(provider) &&
from_bootloader_version !== "none" &&
mcu_versions.includes(id));
return findBestMCU(availableMcus);
}
const API = {
/** @deprecated use getAppsCatalogForDevice (from ledger-live-common/src/device/use-cases) instead */
listApps,
listInstalledApps,
listCategories,
getLanguagePackagesForDevice,
getCurrentOSU,
compatibleMCUForDeviceInfo,
findBestMCU,
getCurrentFirmware,
getFinalFirmwareById,
getDeviceVersion,
install,
genuineCheck,
installMcu,
retrieveMcuVersion,
};
exports.default = API;
//# sourceMappingURL=api.js.map