mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 22:32:04 +00:00
Merge remote-tracking branch 'origin/main' into feat/v140-fixes
# Conflicts: # docs/api/openapi.yaml
This commit is contained in:
commit
cd3c0b7de2
74 files changed
+4140
-508
No files matched your search
@@ -0,0 +1,20 @@
|
||||
-- The encryption key backup step and the boot check that the configured key
|
||||
-- opens this database.
|
||||
--
|
||||
-- Four nullable columns on the instance settings row record which key the
|
||||
-- operator confirmed a backup of (id and fingerprint, never the key). The
|
||||
-- canary table holds one known plaintext per key id, sealed under that key; a
|
||||
-- process whose key cannot open it refuses to serve. Both are written at
|
||||
-- runtime, so the migration only creates the shapes.
|
||||
ALTER TABLE "app_settings" ADD COLUMN IF NOT EXISTS "encryption_key_backup_confirmed_at" TIMESTAMP(3);
|
||||
ALTER TABLE "app_settings" ADD COLUMN IF NOT EXISTS "encryption_key_backup_confirmed_key_id" TEXT;
|
||||
ALTER TABLE "app_settings" ADD COLUMN IF NOT EXISTS "encryption_key_backup_confirmed_fingerprint" TEXT;
|
||||
ALTER TABLE "app_settings" ADD COLUMN IF NOT EXISTS "encryption_key_backup_confirmed_by_user_id" TEXT;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "encryption_key_canaries" (
|
||||
"key_id" TEXT NOT NULL,
|
||||
"ciphertext" TEXT NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "encryption_key_canaries_pkey" PRIMARY KEY ("key_id")
|
||||
);
|
||||
@@ -4880,9 +4880,40 @@ model AppSettings {
|
||||
documentMaxFileBytes Int @default(26214400) @map("document_max_file_bytes")
|
||||
documentQuotaBytes BigInt @default(1073741824) @map("document_quota_bytes")
|
||||
|
||||
// The operator's confirmation that the encryption key is backed up, bound to
|
||||
// the key it was given for: the active key id and its fingerprint (the first
|
||||
// twelve hex characters of SHA-256 over the raw key bytes). A rotation or a
|
||||
// re-keyed install changes either one, and the step is due again. Never the
|
||||
// key itself. Written by `POST /api/admin/encryption/key-backup/confirm`;
|
||||
// consumer: `readKeyBackupStatus` (the admin step, the overview tile and the
|
||||
// dashboard banner for admins).
|
||||
encryptionKeyBackupConfirmedAt DateTime? @map("encryption_key_backup_confirmed_at")
|
||||
encryptionKeyBackupConfirmedKeyId String? @map("encryption_key_backup_confirmed_key_id")
|
||||
encryptionKeyBackupConfirmedFingerprint String? @map("encryption_key_backup_confirmed_fingerprint")
|
||||
/// Plain id, not a relation: the instance row must not become user-scoped,
|
||||
/// and a deleted admin leaves the confirmation standing. Consumer: the admin
|
||||
/// step names who confirmed when the account still exists.
|
||||
encryptionKeyBackupConfirmedByUserId String? @map("encryption_key_backup_confirmed_by_user_id")
|
||||
|
||||
@@map("app_settings")
|
||||
}
|
||||
|
||||
/// One known plaintext per configured encryption key id, sealed under that
|
||||
/// key. At boot every configured id is checked against its row: a row that no
|
||||
/// longer opens means the key in the environment is not the key this database
|
||||
/// was written with, and the process refuses to serve instead of answering
|
||||
/// with random errors. A missing row is written (`ON CONFLICT DO NOTHING`).
|
||||
/// Deliberately outside key rotation: a canary belongs to its key id, and
|
||||
/// re-sealing it under the active key would make every id's check test the
|
||||
/// active key. Written and read only by `src/lib/crypto/canary.ts`.
|
||||
model EncryptionKeyCanary {
|
||||
keyId String @id @map("key_id")
|
||||
ciphertext String
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
@@map("encryption_key_canaries")
|
||||
}
|
||||
|
||||
// ─── Audit Log ─────────────────────────────────────────────
|
||||
|
||||
model AuditLog {
|
||||
|
||||
Reference in new issue
Block a user