fix(opnsense): switch secrets to api-key key and secret for easier understanding (#3744)
This commit is contained in:
@@ -19,4 +19,6 @@ export const integrationSecretIcons = {
|
|||||||
tokenId: IconGrid3x3,
|
tokenId: IconGrid3x3,
|
||||||
personalAccessToken: IconPasswordUser,
|
personalAccessToken: IconPasswordUser,
|
||||||
topic: IconMessage,
|
topic: IconMessage,
|
||||||
|
opnsenseApiKey: IconKey,
|
||||||
|
opnsenseApiSecret: IconPassword,
|
||||||
} satisfies Record<IntegrationSecretKind, TablerIcon>;
|
} satisfies Record<IntegrationSecretKind, TablerIcon>;
|
||||||
|
|||||||
52
packages/db/migrations/custom/0001_opnsense_credentials.ts
Normal file
52
packages/db/migrations/custom/0001_opnsense_credentials.ts
Normal file
@@ -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}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import type { Database } from "../..";
|
import type { Database } from "../..";
|
||||||
import { migrateReleaseWidgetProviderToOptionsAsync } from "./0000_release_widget_provider_to_options";
|
import { migrateReleaseWidgetProviderToOptionsAsync } from "./0000_release_widget_provider_to_options";
|
||||||
|
import { migrateOpnsenseCredentialsAsync } from "./0001_opnsense_credentials";
|
||||||
|
|
||||||
export const applyCustomMigrationsAsync = async (db: Database) => {
|
export const applyCustomMigrationsAsync = async (db: Database) => {
|
||||||
await migrateReleaseWidgetProviderToOptionsAsync(db);
|
await migrateReleaseWidgetProviderToOptionsAsync(db);
|
||||||
|
await migrateOpnsenseCredentialsAsync(db);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ export const integrationSecretKindObject = {
|
|||||||
realm: { isPublic: true },
|
realm: { isPublic: true },
|
||||||
personalAccessToken: { isPublic: false },
|
personalAccessToken: { isPublic: false },
|
||||||
topic: { isPublic: true },
|
topic: { isPublic: true },
|
||||||
|
opnsenseApiKey: { isPublic: false },
|
||||||
|
opnsenseApiSecret: { isPublic: false },
|
||||||
} satisfies Record<string, { isPublic: boolean }>;
|
} satisfies Record<string, { isPublic: boolean }>;
|
||||||
|
|
||||||
export const integrationSecretKinds = objectKeys(integrationSecretKindObject);
|
export const integrationSecretKinds = objectKeys(integrationSecretKindObject);
|
||||||
@@ -174,7 +176,7 @@ export const integrationDefs = {
|
|||||||
},
|
},
|
||||||
opnsense: {
|
opnsense: {
|
||||||
name: "OPNsense",
|
name: "OPNsense",
|
||||||
secretKinds: [["username", "password"]],
|
secretKinds: [["opnsenseApiKey", "opnsenseApiSecret"]],
|
||||||
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/opnsense.svg",
|
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/opnsense.svg",
|
||||||
category: ["firewall"],
|
category: ["firewall"],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ export class OPNsenseIntegration extends Integration implements FirewallSummaryI
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getAuthHeaders() {
|
private getAuthHeaders() {
|
||||||
const username = super.getSecretValue("username");
|
const key = super.getSecretValue("opnsenseApiKey");
|
||||||
const password = super.getSecretValue("password");
|
const secret = super.getSecretValue("opnsenseApiSecret");
|
||||||
return `Basic ${btoa(`${username}:${password}`)}`;
|
return `Basic ${btoa(`${key}:${secret}`)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getFirewallVersionAsync(): Promise<FirewallVersionSummary> {
|
public async getFirewallVersionAsync(): Promise<FirewallVersionSummary> {
|
||||||
|
|||||||
@@ -944,6 +944,14 @@
|
|||||||
"topic": {
|
"topic": {
|
||||||
"label": "Topic",
|
"label": "Topic",
|
||||||
"newLabel": "New topic"
|
"newLabel": "New topic"
|
||||||
|
},
|
||||||
|
"opnsenseApiKey": {
|
||||||
|
"label": "API Key (Key)",
|
||||||
|
"newLabel": "New API Key (Key)"
|
||||||
|
},
|
||||||
|
"opnsenseApiSecret": {
|
||||||
|
"label": "API Key (Secret)",
|
||||||
|
"newLabel": "New API Key (Secret)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user