Restore from Gitea ZIP snapshot (12.08.2026) after full instance reinstall
Git history was lost when the previous Gitea instance was wiped and reinstalled due to an unresolved corruption bug — this commit is the last known-good file content, exported before the reinstall. Prior commit history is not recoverable through this path.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Rotates the AES-256-GCM master key used to encrypt stored mailbox
|
||||
* credentials. Decrypts every stored IMAP/SMTP/CalDAV password under the
|
||||
* old key and re-encrypts under a newly generated one, in a single
|
||||
* transaction, then prints the new key so it can be written into
|
||||
* /etc/ai-chief-of-staff/secrets.env.
|
||||
*
|
||||
* Usage: OLD_KEY=<base64> npx tsx scripts/rotate-credential-key.ts
|
||||
* (reads the current key from CREDENTIALS_ENCRYPTION_KEY if OLD_KEY is unset)
|
||||
*/
|
||||
import crypto from "node:crypto";
|
||||
import Database from "better-sqlite3";
|
||||
import path from "node:path";
|
||||
import { rotateCredential } from "../src/lib/crypto/credentials";
|
||||
|
||||
const dataDir = process.env.DATA_DIR ?? path.join(process.cwd(), "data");
|
||||
const oldKeyB64 = process.env.OLD_KEY ?? process.env.CREDENTIALS_ENCRYPTION_KEY;
|
||||
|
||||
if (!oldKeyB64) {
|
||||
console.error("Set OLD_KEY (or CREDENTIALS_ENCRYPTION_KEY) to the current base64-encoded key before running.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const oldKey = Buffer.from(oldKeyB64, "base64");
|
||||
if (oldKey.length !== 32) {
|
||||
console.error("OLD_KEY must decode to exactly 32 bytes.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const newKey = crypto.randomBytes(32);
|
||||
|
||||
const sqlite = new Database(path.join(dataDir, "db.sqlite"));
|
||||
|
||||
const rows = sqlite
|
||||
.prepare(
|
||||
"SELECT id, imap_password_enc, smtp_password_enc, caldav_password_enc FROM mailbox_credentials",
|
||||
)
|
||||
.all() as Array<{
|
||||
id: string;
|
||||
imap_password_enc: string | null;
|
||||
smtp_password_enc: string | null;
|
||||
caldav_password_enc: string | null;
|
||||
}>;
|
||||
|
||||
const update = sqlite.prepare(
|
||||
"UPDATE mailbox_credentials SET imap_password_enc = ?, smtp_password_enc = ?, caldav_password_enc = ? WHERE id = ?",
|
||||
);
|
||||
|
||||
const rotateAll = sqlite.transaction(() => {
|
||||
for (const row of rows) {
|
||||
const imap = row.imap_password_enc ? rotateCredential(row.imap_password_enc, oldKey, newKey) : null;
|
||||
const smtp = row.smtp_password_enc ? rotateCredential(row.smtp_password_enc, oldKey, newKey) : null;
|
||||
const caldav = row.caldav_password_enc ? rotateCredential(row.caldav_password_enc, oldKey, newKey) : null;
|
||||
update.run(imap, smtp, caldav, row.id);
|
||||
}
|
||||
});
|
||||
|
||||
rotateAll();
|
||||
|
||||
console.log(`Rotated ${rows.length} mailbox_credentials row(s).`);
|
||||
console.log("\nNew key (update CREDENTIALS_ENCRYPTION_KEY in /etc/ai-chief-of-staff/secrets.env, then restart the service):\n");
|
||||
console.log(newKey.toString("base64"));
|
||||
Reference in New Issue
Block a user