mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-29 22:55:24 +00:00
81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
/**
|
|
* Reseals 2.8 Termix ID certificate authority keys for the termix-identity
|
|
* plugin.
|
|
*
|
|
* Core encrypted termix_identity_ca.private_key with the owner's data key.
|
|
* The plugin adopts that table as p_termix_identity_ca and reads the key with
|
|
* ctx.secrets.unseal, which only opens installation-key encryption. Each row
|
|
* still under a data key is decrypted and written back with
|
|
* encryptSystemSecret, what ctx.secrets.seal writes.
|
|
*
|
|
* Does nothing until the plugin's table exists. A row whose owner's data key
|
|
* cannot be opened is skipped and tried again next time. Idempotent.
|
|
*/
|
|
|
|
import { sql } from "drizzle-orm";
|
|
import { databaseLogger } from "../utils/logger.js";
|
|
import { DataCrypto } from "../utils/data-crypto.js";
|
|
import { LazyFieldEncryption } from "../utils/lazy-field-encryption.js";
|
|
import {
|
|
encryptSystemSecret,
|
|
isSystemEncrypted,
|
|
} from "../utils/system-secret-crypto.js";
|
|
import {
|
|
runStatement,
|
|
selectRows,
|
|
} from "../utils/crypto-migration/raw-rows.js";
|
|
|
|
const CA_TABLE = "p_termix_identity_ca";
|
|
|
|
interface CaRow {
|
|
id: number;
|
|
user_id: string;
|
|
private_key: string | null;
|
|
}
|
|
|
|
export async function runTermixIdentityCaMigration(): Promise<number> {
|
|
let rows: CaRow[];
|
|
try {
|
|
rows = await selectRows<CaRow>(
|
|
sql`SELECT id, user_id, private_key FROM ${sql.identifier(CA_TABLE)}`,
|
|
);
|
|
} catch {
|
|
// The plugin has not adopted the table yet.
|
|
return 0;
|
|
}
|
|
|
|
let resealed = 0;
|
|
for (const row of rows) {
|
|
if (!row.private_key || isSystemEncrypted(row.private_key)) continue;
|
|
try {
|
|
const dek = DataCrypto.getUserDataKey(row.user_id);
|
|
if (!dek) continue;
|
|
const plain = LazyFieldEncryption.safeGetFieldValue(
|
|
row.private_key,
|
|
dek,
|
|
String(row.id),
|
|
"privateKey",
|
|
);
|
|
if (!plain) continue;
|
|
await runStatement(
|
|
sql`UPDATE ${sql.identifier(CA_TABLE)} SET private_key = ${await encryptSystemSecret(plain)} WHERE id = ${row.id}`,
|
|
);
|
|
resealed++;
|
|
} catch (error) {
|
|
databaseLogger.warn("Termix ID CA reseal failed for a row", {
|
|
operation: "termix_identity_ca_migration",
|
|
caId: row.id,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
});
|
|
}
|
|
}
|
|
|
|
if (resealed > 0) {
|
|
databaseLogger.info("Resealed Termix ID CA keys for the plugin", {
|
|
operation: "termix_identity_ca_migration",
|
|
resealed,
|
|
});
|
|
}
|
|
return resealed;
|
|
}
|