mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-11-01 08:05:23 +00:00
chore: lock the plugin boundary and remove 2.9.0 leftovers
This commit is contained in:
1 parent
6489b62ece
commit
2961297989
399 files changed
+3964
-5627
No files matched your search
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Moves the 2.8 ACME configuration into the acme-ssl plugin.
|
||||
*
|
||||
* 2.8 kept it as one JSON row, `acme_ssl_settings`, in core settings. Each
|
||||
* field becomes a plugin admin setting. "manual" was never ACME (it meant an
|
||||
* uploaded certificate, which core still handles), so it turns renewal off.
|
||||
* The Cloudflare token was plaintext and lands as an encrypted secret; it is
|
||||
* then removed from the old row. The rest of the row stays for one release.
|
||||
*
|
||||
* Idempotent: a field already set in plugin_settings is never overwritten.
|
||||
*/
|
||||
|
||||
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 = "acme-ssl";
|
||||
const LEGACY_KEY = "acme_ssl_settings";
|
||||
|
||||
export interface AcmeSslSettingsMigrationResult {
|
||||
moved: string[];
|
||||
}
|
||||
|
||||
interface LegacyAcmeSettings {
|
||||
enabled?: unknown;
|
||||
domain?: unknown;
|
||||
email?: unknown;
|
||||
challengeType?: unknown;
|
||||
cloudflareToken?: unknown;
|
||||
}
|
||||
|
||||
const text = (value: unknown) =>
|
||||
typeof value === "string" && value.trim() ? value.trim() : null;
|
||||
|
||||
export async function runAcmeSslSettingsMigration(): Promise<AcmeSslSettingsMigrationResult> {
|
||||
const result: AcmeSslSettingsMigrationResult = { moved: [] };
|
||||
|
||||
try {
|
||||
const plugin = await createCurrentPluginRepository().findById(PLUGIN_ID);
|
||||
if (!plugin) return result;
|
||||
|
||||
const settings = createCurrentSettingsRepository();
|
||||
const raw = await settings.get(LEGACY_KEY);
|
||||
if (!raw) return result;
|
||||
|
||||
let legacy: LegacyAcmeSettings;
|
||||
try {
|
||||
legacy = JSON.parse(raw) as LegacyAcmeSettings;
|
||||
} catch {
|
||||
return result;
|
||||
}
|
||||
if (!legacy || typeof legacy !== "object") return result;
|
||||
|
||||
const pluginSettings = createCurrentPluginSettingsRepository();
|
||||
const writeIfUnset = async (
|
||||
field: string,
|
||||
value: unknown,
|
||||
secret = false,
|
||||
) => {
|
||||
const existing = await pluginSettings.get(
|
||||
PLUGIN_ID,
|
||||
"admin",
|
||||
null,
|
||||
field,
|
||||
);
|
||||
if (existing && existing.value !== null) return;
|
||||
await pluginSettings.set(
|
||||
PLUGIN_ID,
|
||||
"admin",
|
||||
null,
|
||||
field,
|
||||
JSON.stringify(value),
|
||||
secret,
|
||||
);
|
||||
result.moved.push(field);
|
||||
};
|
||||
|
||||
const challenge = legacy.challengeType;
|
||||
const manual = challenge === "manual";
|
||||
|
||||
const domain = text(legacy.domain);
|
||||
if (domain) await writeIfUnset("domain", domain);
|
||||
const email = text(legacy.email);
|
||||
if (email) await writeIfUnset("email", email);
|
||||
if (challenge === "dns-cloudflare") {
|
||||
await writeIfUnset("challengeType", "dns-cloudflare");
|
||||
} else if (challenge === "http-webroot") {
|
||||
await writeIfUnset("challengeType", "http-01");
|
||||
}
|
||||
if (typeof legacy.enabled === "boolean") {
|
||||
await writeIfUnset("autoRenew", legacy.enabled && !manual);
|
||||
}
|
||||
|
||||
const token = text(legacy.cloudflareToken);
|
||||
if (token) {
|
||||
await writeIfUnset(
|
||||
"cloudflareToken",
|
||||
await encryptSystemSecret(token),
|
||||
true,
|
||||
);
|
||||
const { cloudflareToken: _dropped, ...rest } = legacy;
|
||||
await settings.set(LEGACY_KEY, JSON.stringify(rest));
|
||||
}
|
||||
|
||||
if (result.moved.length > 0) {
|
||||
databaseLogger.info(
|
||||
`Moved ${result.moved.length} ACME setting(s) into plugin settings`,
|
||||
{
|
||||
operation: "acme_ssl_settings_migration",
|
||||
moved: result.moved.join(", "),
|
||||
},
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// Must not stop the backend: the plugin then shows "not configured".
|
||||
databaseLogger.warn("ACME settings migration failed", {
|
||||
operation: "acme_ssl_settings_migration",
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Reference in new issue
Block a user