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 = { 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, }, ]; };