forked from jordanlambrecht/tracker-tracker
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscheduler-key-store.ts
More file actions
71 lines (64 loc) · 2.14 KB
/
Copy pathscheduler-key-store.ts
File metadata and controls
71 lines (64 loc) · 2.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// src/lib/scheduler-key-store.ts
import "server-only"
import { eq } from "drizzle-orm"
import { decrypt, deriveWrappingKey, encrypt } from "@/lib/crypto"
import { db } from "@/lib/db"
import { appSettings } from "@/lib/db/schema"
import { log } from "@/lib/logger"
/**
* Encrypt the scheduler key with the HKDF-derived wrapping key
* and store it in appSettings. Called after successful login.
*/
export async function persistSchedulerKey(key: Buffer, settingsId: number): Promise<void> {
try {
const wrappingKey = deriveWrappingKey()
const wrapped = encrypt(key.toString("hex"), wrappingKey)
await db
.update(appSettings)
.set({ encryptedSchedulerKey: wrapped })
.where(eq(appSettings.id, settingsId))
} catch (err) {
log.warn({ err }, "Failed to persist scheduler key — polling will not survive restart")
}
}
/**
* Read and decrypt the stored scheduler key. Returns null if:
* - No settings row exists
* - No key is stored (first boot or post-nuke/lockdown)
* - Decryption fails (SESSION_SECRET rotated or corrupt data)
*/
export async function loadSchedulerKey(): Promise<Buffer | null> {
try {
const [settings] = await db
.select({
encryptedSchedulerKey: appSettings.encryptedSchedulerKey,
})
.from(appSettings)
.limit(1)
if (!settings?.encryptedSchedulerKey) return null
const wrappingKey = deriveWrappingKey()
const keyHex = decrypt(settings.encryptedSchedulerKey, wrappingKey)
return Buffer.from(keyHex, "hex")
} catch (err) {
log.warn({ err }, "Could not unwrap scheduler key — will start after next login")
return null
}
}
/**
* Clear the stored key from the DB. Called on lockdown, nuke,
* password change, and restore. NOT called on logout — scheduler
* persists through logout.
*/
export async function clearSchedulerKey(settingsId: number): Promise<void> {
try {
await db
.update(appSettings)
.set({ encryptedSchedulerKey: null })
.where(eq(appSettings.id, settingsId))
} catch (err) {
log.error(
{ err, settingsId },
"SECURITY: Failed to clear scheduler key from DB. Old key may persist."
)
}
}