Some checks failed
Build & Release / build (push) Failing after 35s
- app_settings table with encrypted field support (AES-256-GCM, key from ENCRYPTION_KEY env) - SettingsService for transparent encrypt/decrypt on get/set - EmailService factory with Resend and SendGrid providers (SMTP stub) — provider config lives in app_settings - Seeds initial admin user and email settings from env vars on first startup if not already present - Migration 0039_app_settings.sql Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
42 lines
1.3 KiB
TypeScript
42 lines
1.3 KiB
TypeScript
import { eq } from 'drizzle-orm'
|
|
import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'
|
|
import { appSettings } from '../db/schema/settings.js'
|
|
import { encrypt, decrypt } from '../utils/encryption.js'
|
|
|
|
export const SettingsService = {
|
|
async get(db: PostgresJsDatabase<any>, key: string): Promise<string | null> {
|
|
const [row] = await db
|
|
.select()
|
|
.from(appSettings)
|
|
.where(eq(appSettings.key, key))
|
|
.limit(1)
|
|
|
|
if (!row || row.value === null) return null
|
|
if (row.isEncrypted && row.iv) return decrypt(row.value, row.iv)
|
|
return row.value
|
|
},
|
|
|
|
async set(db: PostgresJsDatabase<any>, key: string, value: string, encrypted = false): Promise<void> {
|
|
let storedValue = value
|
|
let iv: string | null = null
|
|
|
|
if (encrypted) {
|
|
const result = encrypt(value)
|
|
storedValue = result.ciphertext
|
|
iv = result.iv
|
|
}
|
|
|
|
await db
|
|
.insert(appSettings)
|
|
.values({ key, value: storedValue, isEncrypted: encrypted, iv, updatedAt: new Date() })
|
|
.onConflictDoUpdate({
|
|
target: appSettings.key,
|
|
set: { value: storedValue, isEncrypted: encrypted, iv, updatedAt: new Date() },
|
|
})
|
|
},
|
|
|
|
async delete(db: PostgresJsDatabase<any>, key: string): Promise<void> {
|
|
await db.delete(appSettings).where(eq(appSettings.key, key))
|
|
},
|
|
}
|