Files
homarr/packages/old-import/src/mappers/map-integration.ts

119 lines
3.0 KiB
TypeScript

import { createId } from "@homarr/common";
import { decryptSecretWithKey } from "@homarr/common/server";
import type { IntegrationKind } from "@homarr/definitions";
import type { OldmarrIntegrationType } from "@homarr/old-schema";
import type { PreparedIntegration } from "../prepare/prepare-integrations";
export const mapIntegrationType = (type: OldmarrIntegrationType) => {
const kind = mapping[type];
if (!kind) {
throw new Error(`Integration type ${type} is not supported yet`);
}
return kind;
};
const mapping: Record<OldmarrIntegrationType, IntegrationKind | null> = {
adGuardHome: "adGuardHome",
deluge: "deluge",
homeAssistant: "homeAssistant",
jellyfin: "jellyfin",
jellyseerr: "jellyseerr",
lidarr: "lidarr",
nzbGet: "nzbGet",
openmediavault: "openmediavault",
overseerr: "overseerr",
pihole: "piHole",
prowlarr: "prowlarr",
proxmox: "proxmox",
qBittorrent: "qBittorrent",
radarr: "radarr",
readarr: "readarr",
sabnzbd: "sabNzbd",
sonarr: "sonarr",
tdarr: "tdarr",
transmission: "transmission",
plex: "plex",
};
export const mapAndDecryptIntegrations = (
preparedIntegrations: PreparedIntegration[],
encryptionToken: string | null,
) => {
if (encryptionToken === null) {
return [];
}
return preparedIntegrations.map(({ type, name, url, properties }) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const kind = mapIntegrationType(type!);
return {
id: createId(),
name,
url,
kind,
secrets: mapSecrets(properties, encryptionToken, kind),
};
});
};
const mapSecrets = (properties: PreparedIntegration["properties"], encryptionToken: string, kind: IntegrationKind) => {
const key = Buffer.from(encryptionToken, "hex");
const decryptedProperties = properties.map((property) => ({
...property,
value: property.value ? decryptSecretWithKey(property.value as `${string}.${string}`, key) : null,
}));
return kind === "proxmox" ? mapProxmoxSecrets(decryptedProperties) : decryptedProperties;
};
/**
* Proxmox secrets have bee split up from format `user@realm!tokenId=secret` to separate fields
*/
const mapProxmoxSecrets = (decryptedProperties: PreparedIntegration["properties"]) => {
const apiToken = decryptedProperties.find((property) => property.field === "apiKey");
if (!apiToken?.value) return [];
let splitValues = apiToken.value.split("@");
if (splitValues.length <= 1) return [];
const [user, ...rest] = splitValues;
splitValues = rest.join("@").split("!");
if (splitValues.length <= 1) return [];
const [realm, ...rest2] = splitValues;
splitValues = rest2.join("!").split("=");
if (splitValues.length <= 1) return [];
const [tokenId, ...rest3] = splitValues;
const secret = rest3.join("=");
return [
{
field: "username" as const,
value: user,
},
{
field: "realm" as const,
value: realm,
},
{
field: "tokenId" as const,
value: tokenId,
},
{
field: "apiKey" as const,
value: secret,
},
];
};