diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts index e489963e7..008d8b34f 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts +++ b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts @@ -19,4 +19,6 @@ export const integrationSecretIcons = { tokenId: IconGrid3x3, personalAccessToken: IconPasswordUser, topic: IconMessage, + opnsenseApiKey: IconKey, + opnsenseApiSecret: IconPassword, } satisfies Record; diff --git a/packages/db/migrations/custom/0001_opnsense_credentials.ts b/packages/db/migrations/custom/0001_opnsense_credentials.ts new file mode 100644 index 000000000..9e62b92d3 --- /dev/null +++ b/packages/db/migrations/custom/0001_opnsense_credentials.ts @@ -0,0 +1,52 @@ +import type { Database } from "../.."; +import { and, eq } from "../.."; +import { integrationSecrets } from "../../schema"; + +/** + * Previously the credentials for OPNsense were stored as username and password. + * However it should have been the api key and secret. + * For more information see: + * https://docs.opnsense.org/development/how-tos/api.html#creating-keys + */ +export async function migrateOpnsenseCredentialsAsync(db: Database) { + const existingIntegrations = await db.query.integrations.findMany({ + where: (table, { eq }) => eq(table.kind, "opnsense"), + with: { + secrets: true, + }, + }); + + await Promise.all( + existingIntegrations.map(async (integration) => { + const username = integration.secrets.find((secret) => secret.kind === "username"); + if (!username) return; + await db + .update(integrationSecrets) + .set({ + kind: "opnsenseApiKey", + }) + .where( + and(eq(integrationSecrets.integrationId, username.integrationId), eq(integrationSecrets.kind, "username")), + ); + }), + ); + + await Promise.all( + existingIntegrations.map(async (integration) => { + const password = integration.secrets.find((secret) => secret.kind === "password"); + if (!password) return; + await db + .update(integrationSecrets) + .set({ + kind: "opnsenseApiSecret", + }) + .where( + and(eq(integrationSecrets.integrationId, password.integrationId), eq(integrationSecrets.kind, "password")), + ); + }), + ); + + if (existingIntegrations.length > 0) { + console.log(`Migrated OPNsense credentials count="${existingIntegrations.length}"`); + } +} diff --git a/packages/db/migrations/custom/index.ts b/packages/db/migrations/custom/index.ts index e60a52c5e..03a48cbbd 100644 --- a/packages/db/migrations/custom/index.ts +++ b/packages/db/migrations/custom/index.ts @@ -1,6 +1,8 @@ import type { Database } from "../.."; import { migrateReleaseWidgetProviderToOptionsAsync } from "./0000_release_widget_provider_to_options"; +import { migrateOpnsenseCredentialsAsync } from "./0001_opnsense_credentials"; export const applyCustomMigrationsAsync = async (db: Database) => { await migrateReleaseWidgetProviderToOptionsAsync(db); + await migrateOpnsenseCredentialsAsync(db); }; diff --git a/packages/definitions/src/integration.ts b/packages/definitions/src/integration.ts index 4bf7adada..27480b4ac 100644 --- a/packages/definitions/src/integration.ts +++ b/packages/definitions/src/integration.ts @@ -9,6 +9,8 @@ export const integrationSecretKindObject = { realm: { isPublic: true }, personalAccessToken: { isPublic: false }, topic: { isPublic: true }, + opnsenseApiKey: { isPublic: false }, + opnsenseApiSecret: { isPublic: false }, } satisfies Record; export const integrationSecretKinds = objectKeys(integrationSecretKindObject); @@ -174,7 +176,7 @@ export const integrationDefs = { }, opnsense: { name: "OPNsense", - secretKinds: [["username", "password"]], + secretKinds: [["opnsenseApiKey", "opnsenseApiSecret"]], iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/opnsense.svg", category: ["firewall"], }, diff --git a/packages/integrations/src/opnsense/opnsense-integration.ts b/packages/integrations/src/opnsense/opnsense-integration.ts index d8f84c723..2f11dfcc4 100644 --- a/packages/integrations/src/opnsense/opnsense-integration.ts +++ b/packages/integrations/src/opnsense/opnsense-integration.ts @@ -37,9 +37,9 @@ export class OPNsenseIntegration extends Integration implements FirewallSummaryI } private getAuthHeaders() { - const username = super.getSecretValue("username"); - const password = super.getSecretValue("password"); - return `Basic ${btoa(`${username}:${password}`)}`; + const key = super.getSecretValue("opnsenseApiKey"); + const secret = super.getSecretValue("opnsenseApiSecret"); + return `Basic ${btoa(`${key}:${secret}`)}`; } public async getFirewallVersionAsync(): Promise { diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index 0a472c3da..03590099d 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -944,6 +944,14 @@ "topic": { "label": "Topic", "newLabel": "New topic" + }, + "opnsenseApiKey": { + "label": "API Key (Key)", + "newLabel": "New API Key (Key)" + }, + "opnsenseApiSecret": { + "label": "API Key (Secret)", + "newLabel": "New API Key (Secret)" } } },