mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 07:05:24 +00:00
feat: move desktop, status, import, audit and branding features into plugins
This commit is contained in:
1 parent
9d93fb0893
commit
1cdbfc674c
166 files changed
+21298
-12041
No files matched your search
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Moves the audit forwarding collector URL and token out of the core settings
|
||||
* table into the audit-tools plugin's admin settings. The token is stored
|
||||
* encrypted with the installation key, like any plugin secret setting, and the
|
||||
* core copies are removed once the plugin has its own.
|
||||
*
|
||||
* Idempotent: a value the plugin already has is kept, and a core value is only
|
||||
* removed after the plugin holds a copy. Does nothing until the plugin row
|
||||
* exists (plugin_settings has a foreign key to plugins).
|
||||
*/
|
||||
|
||||
import { databaseLogger } from "../utils/logger.js";
|
||||
import {
|
||||
createCurrentPluginRepository,
|
||||
createCurrentPluginSettingsRepository,
|
||||
createCurrentSettingsRepository,
|
||||
} from "../database/repositories/factory.js";
|
||||
import { encryptSystemSecret } from "../utils/system-secret-crypto.js";
|
||||
|
||||
const PLUGIN_ID = "audit-tools";
|
||||
const URL_SETTING = "audit_log_forward_url";
|
||||
const TOKEN_SETTING = "audit_log_forward_token";
|
||||
|
||||
export interface AuditForwardingMigrationResult {
|
||||
url: boolean;
|
||||
token: boolean;
|
||||
}
|
||||
|
||||
export async function runAuditForwardingMigration(): Promise<AuditForwardingMigrationResult> {
|
||||
const result: AuditForwardingMigrationResult = { url: false, token: false };
|
||||
|
||||
try {
|
||||
if (!(await createCurrentPluginRepository().findById(PLUGIN_ID))) {
|
||||
return result;
|
||||
}
|
||||
} catch {
|
||||
return result;
|
||||
}
|
||||
|
||||
const core = createCurrentSettingsRepository();
|
||||
const plugin = createCurrentPluginSettingsRepository();
|
||||
const legacyUrl = (await core.get(URL_SETTING))?.trim();
|
||||
const legacyToken = (await core.get(TOKEN_SETTING))?.trim();
|
||||
|
||||
const has = async (key: string) => {
|
||||
const row = await plugin.get(PLUGIN_ID, "admin", null, key);
|
||||
return !!row && row.value !== null && row.value !== '""';
|
||||
};
|
||||
|
||||
if (legacyUrl) {
|
||||
if (!(await has("url"))) {
|
||||
await plugin.set(
|
||||
PLUGIN_ID,
|
||||
"admin",
|
||||
null,
|
||||
"url",
|
||||
JSON.stringify(legacyUrl),
|
||||
);
|
||||
result.url = true;
|
||||
}
|
||||
if (legacyToken && !(await has("token"))) {
|
||||
await plugin.set(
|
||||
PLUGIN_ID,
|
||||
"admin",
|
||||
null,
|
||||
"token",
|
||||
JSON.stringify(await encryptSystemSecret(legacyToken)),
|
||||
true,
|
||||
);
|
||||
result.token = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Safe to drop now: the plugin holds the values, or never had a collector.
|
||||
if (legacyUrl ? await has("url") : true) {
|
||||
if (legacyUrl) await core.delete(URL_SETTING);
|
||||
if (legacyToken && (await has("token"))) await core.delete(TOKEN_SETTING);
|
||||
else if (!legacyUrl && legacyToken) await core.delete(TOKEN_SETTING);
|
||||
}
|
||||
|
||||
if (result.url || result.token) {
|
||||
databaseLogger.info("Moved audit forwarding settings into audit-tools", {
|
||||
operation: "audit_forwarding_migration",
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Moves the global status check interval into the host-status plugin, before
|
||||
* it activates, so its first checks use the interval an admin chose instead of
|
||||
* the plugin's 30 second default.
|
||||
*
|
||||
* Idempotent: a value the plugin already has is kept.
|
||||
*/
|
||||
|
||||
import { databaseLogger } from "../utils/logger.js";
|
||||
import {
|
||||
createCurrentPluginRepository,
|
||||
createCurrentPluginSettingsRepository,
|
||||
createCurrentSettingsRepository,
|
||||
} from "../database/repositories/factory.js";
|
||||
|
||||
const PLUGIN_ID = "host-status";
|
||||
const LEGACY_KEY = "global_status_check_interval";
|
||||
|
||||
function seconds(value: unknown): number | null {
|
||||
const parsed = Number(value);
|
||||
return Number.isInteger(parsed) && parsed >= 5 && parsed <= 3600
|
||||
? parsed
|
||||
: null;
|
||||
}
|
||||
|
||||
export async function runHostStatusSettingsMigration(): Promise<number | null> {
|
||||
try {
|
||||
const plugin = await createCurrentPluginRepository().findById(PLUGIN_ID);
|
||||
if (!plugin) return null;
|
||||
|
||||
const settings = createCurrentPluginSettingsRepository();
|
||||
const existing = await settings.get(
|
||||
PLUGIN_ID,
|
||||
"admin",
|
||||
null,
|
||||
"intervalSeconds",
|
||||
);
|
||||
if (existing && existing.value !== null) return null;
|
||||
|
||||
const legacy = seconds(
|
||||
await createCurrentSettingsRepository().get(LEGACY_KEY),
|
||||
);
|
||||
if (legacy === null) return null;
|
||||
|
||||
await settings.set(
|
||||
PLUGIN_ID,
|
||||
"admin",
|
||||
null,
|
||||
"intervalSeconds",
|
||||
JSON.stringify(legacy),
|
||||
);
|
||||
databaseLogger.info("Moved the status check interval into the plugin", {
|
||||
operation: "host_status_settings_migration",
|
||||
intervalSeconds: legacy,
|
||||
});
|
||||
return legacy;
|
||||
} catch (error) {
|
||||
databaseLogger.warn("Host status settings migration failed", {
|
||||
operation: "host_status_settings_migration",
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import { runOpksshConfigMigration } from "./opkssh-config-migration.js";
|
||||
import { runTermixIdentityCaMigration } from "./termix-identity-ca-migration.js";
|
||||
import { runSessionRecordingDataMigration } from "./session-recording-data-migration.js";
|
||||
import { runNotificationChannelMigration } from "./notification-channel-migration.js";
|
||||
import { runHostStatusSettingsMigration } from "./host-status-settings-migration.js";
|
||||
import { runAuditForwardingMigration } from "./audit-forwarding-migration.js";
|
||||
|
||||
export async function runPluginDataMoves(): Promise<void> {
|
||||
await runLdapProviderMigration();
|
||||
@@ -19,4 +21,8 @@ export async function runPluginDataMoves(): Promise<void> {
|
||||
await runSessionRecordingDataMigration();
|
||||
// Automations name channels by id, so they are in place before it starts.
|
||||
await runNotificationChannelMigration();
|
||||
// The plugin forwards from its own settings, so they are in place first.
|
||||
await runAuditForwardingMigration();
|
||||
// Sets the check interval, which the plugin reads when it activates.
|
||||
await runHostStatusSettingsMigration();
|
||||
}
|
||||
Reference in new issue
Block a user