import { settings as settingsTable } from '../db/schema.ts' import { generateSigningCertificates } from './apiKeys.ts' import crypto from 'node:crypto' import type { SystemIds } from './types.ts' /** * Settings model */ class Settings { /** * Fetch settings from DB * @returns Settings, or `false` when the table is empty */ async getConfig(): Promise | false> { const settings = await WIKI.db.select().from(settingsTable) if (settings.length > 0) { return settings.reduce((res: Record, val: any) => { res[val.key] = 'v' in val.value ? val.value.v : val.value return res }, {}) } else { return false } } /** * Apply settings to DB * @param key Setting key * @param value Setting value object */ async updateConfig(key: string, value: Record): Promise { await WIKI.db .insert(settingsTable) .values({ key, value }) .onConflictDoUpdate({ target: settingsTable.key, set: { value } }) } /** * Initialize settings table * @param ids Generated IDs */ async init(ids: SystemIds): Promise { WIKI.logger.info('Generating certificates...') const certs = generateSigningCertificates() WIKI.logger.info('Inserting default settings...') await WIKI.db.insert(settingsTable).values([ { key: 'api', value: { isEnabled: false } }, { key: 'audit', value: { retentionDays: 90 } }, { key: 'auth', value: { // -> The installation keypair, carrying its own passphrase. Its one job is signing API // keys (`models/apiKeys.ts`). certs, // -> What @fastify/session signs its cookies with, and nothing else. Separate from the // keypair's passphrase so that either can be rotated without disturbing the other — // the two utilities that do so are `POST /system/certificates` and // `POST /system/sessions/invalidate`. secret: crypto.randomBytes(32).toString('hex'), rootAdminGroupId: ids.groupAdminId, rootAdminUserId: ids.userAdminId, guestUserId: ids.userGuestId } }, { key: 'flags', value: { experimental: false, authDebug: false, sqlLog: false } }, { key: 'icons', value: { fa: { isActive: true, config: { version: 6, license: 'free', token: '' } }, la: { isActive: true } } }, { key: 'mail', value: { senderName: '', senderEmail: '', defaultBaseURL: '', host: '', port: 465, name: '', secure: true, verifySSL: true, user: '', pass: '', useDKIM: false, dkimDomainName: '', dkimKeySelector: '', dkimPrivateKey: '' } }, { key: 'metrics', value: { isEnabled: false, path: '/metrics', allowAnonymousLocal: true, allowAnonymousPrivate: true, allowAnonymousExternal: false, includeRuntime: true, includeWiki: false } }, { key: 'search', value: { termHighlighting: true, dictOverrides: {} } }, { key: 'security', value: { corsConfig: '', corsMode: 'OFF', cspDirectives: '', disallowIframe: true, disallowOpenRedirect: true, enforceCsp: false, enforceHsts: false, enforceSameOriginReferrerPolicy: true, forceAssetDownload: true, hstsDuration: 0, trustProxy: false, uploadMaxFileSize: 10485760, uploadMaxFiles: 20, uploadScanSVG: true } }, { key: 'update', value: { lastCheckedAt: null, version: WIKI.version, versionDate: WIKI.releaseDate } }, { key: 'userDefaults', value: { timezone: 'America/New_York', dateFormat: 'YYYY-MM-DD', timeFormat: '12h' } } ]) } } export const settings = new Settings()