From e5a2602fe8c958735a576b525f3586b32d533fdc Mon Sep 17 00:00:00 2001 From: notquitenothing Date: Wed, 28 Jan 2026 19:59:41 -0600 Subject: [PATCH] Add DB_SSL and DB_SSL_VERIFICATION environment variables --- docs/Getting-Started.md | 4 ++++ server/cli/migrateDB.ts | 2 ++ server/db/connection.ts | 53 +++++++++++++++-------------------------- server/db/db.ts | 2 ++ server/db/user.ts | 3 ++- server/util/config.ts | 8 +++++++ server/util/util.ts | 12 +++------- 7 files changed, 40 insertions(+), 44 deletions(-) diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index 8291efc..27ceb37 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -129,6 +129,8 @@ When using the `sqlite` database adapter type, no additional database connection | DB_PORT | `5432` | Port of the database. Not used if using SQLite database. | | | | DB_USER | `postgres` | Username used to sign into the database by the app. Not used if using SQLite database. | | | | DB_NAME | `postgres` | Database name used to connect to the database by the app. Not used if using SQLite database. | | | +| DB_SSL | `false` | Enables SSL connection to the database. | | | +| DB_SSL_VERIFICATION | `true` | If DB_SSL is enabled, whether to verify the SSL certificate. | | | #### Database Migration Settings Use the following environment variables to configure a database migration. These variables *exactly* mirror the `DB_*` environment variables and describe the connection to be made to the new database. See details on how to migrate an existing database to a new one on the [Database Migration](DB-Migration.md) page. @@ -141,6 +143,8 @@ Use the following environment variables to configure a database migration. These | MIGRATE_TO_DB_PORT | `5432` | Port of the database. Not used if migrating to SQLite database. | | | | MIGRATE_TO_DB_USER | `postgres` | Username used to sign into the database by the app. Not used if migrating to SQLite database. | | | | MIGRATE_TO_DB_NAME | `postgres` | Database name used to connect to the database by the app. Not used if migrating to SQLite database. | | | +| MIGRATE_TO_DB_SSL | `false` | Enables SSL connection to the database. | | | +| MIGRATE_TO_DB_SSL_VERIFICATION | `true` | If MIGRATE_TO_DB_SSL is enabled, whether to verify the SSL certificate. | | | #### SMTP Settings All of these settings are ✅ recommended to be set to the correct values for your email provider. diff --git a/server/cli/migrateDB.ts b/server/cli/migrateDB.ts index 3027509..20088a7 100644 --- a/server/cli/migrateDB.ts +++ b/server/cli/migrateDB.ts @@ -26,6 +26,8 @@ export async function migrate() { DB_USER: appConfig.MIGRATE_TO_DB_USER, DB_NAME: appConfig.MIGRATE_TO_DB_NAME, DB_PASSWORD: appConfig.MIGRATE_TO_DB_PASSWORD, + DB_SSL: appConfig.MIGRATE_TO_DB_SSL, + DB_SSL_VERIFICATION: appConfig.MIGRATE_TO_DB_SSL_VERIFICATION, isMigration: true, }) diff --git a/server/db/connection.ts b/server/db/connection.ts index b8177fa..b130d82 100644 --- a/server/db/connection.ts +++ b/server/db/connection.ts @@ -4,6 +4,18 @@ import knex from 'knex' import fs from 'node:fs' import { logger } from '../util/logger' +export type DBConnectionOptions = { + DB_ADAPTER: string + DB_PASSWORD?: string + DB_HOST?: string + DB_PORT?: number + DB_NAME?: string + DB_USER?: string + DB_SSL?: boolean + DB_SSL_VERIFICATION?: boolean + isMigration?: boolean +} + async function runSchemaUpdates(connectionOptions: Knex.Config) { if (connectionOptions.client === 'sqlite3' || connectionOptions.client === 'better-sqlite') { const { pool, ...rest } = connectionOptions @@ -20,15 +32,7 @@ async function runSchemaUpdates(connectionOptions: Knex.Config) { return migrations } -export async function createDB(options: { - DB_ADAPTER: string - DB_PASSWORD?: string - DB_HOST?: string - DB_PORT?: number - DB_NAME?: string - DB_USER?: string - isMigration?: boolean -}) { +export async function createDB(options: DBConnectionOptions) { const connOptions = getConnectionOptions(options) const migrations = await runSchemaUpdates(connOptions) if (migrations.length) { @@ -37,23 +41,9 @@ export async function createDB(options: { return knex(connOptions) } -function getConnectionOptions(options: { - DB_ADAPTER: string - DB_PASSWORD?: string - DB_HOST?: string - DB_PORT?: number - DB_NAME?: string - DB_USER?: string - isMigration?: boolean -}): knex.Knex.Config { +function getConnectionOptions(options: DBConnectionOptions): knex.Knex.Config { if (options.DB_ADAPTER === 'postgres') { - return connectionPg({ - DB_HOST: options.DB_HOST, - DB_PORT: options.DB_PORT, - DB_USER: options.DB_USER, - DB_NAME: options.DB_NAME, - DB_PASSWORD: options.DB_PASSWORD, - }, options.isMigration) + return connectionPg(options) } else if (options.DB_ADAPTER === 'sqlite') { return connectionSQLite() } else { @@ -61,22 +51,16 @@ function getConnectionOptions(options: { } } -function connectionPg(options: { - DB_PASSWORD?: string - DB_HOST?: string - DB_PORT?: number - DB_NAME?: string - DB_USER?: string -}, isMigration: boolean = false) { +function connectionPg(options: DBConnectionOptions): Knex.Config { // check that DB_PASSWORD is set if (!options.DB_PASSWORD?.length) { - throw new Error(`${isMigration ? 'MIGRATE_TO_' : ''}DB_PASSWORD must be set. If you don't already have one, use something long and random like: + throw new Error(`${options.isMigration ? 'MIGRATE_TO_' : ''}DB_PASSWORD must be set. If you don't already have one, use something long and random like: ${generate({ length: 32, numbers: true })}`) } // check that DB_HOST is set if (!options.DB_HOST?.length) { - throw new Error(`${isMigration ? 'MIGRATE_TO_' : ''}DB_HOST must be set.`) + throw new Error(`${options.isMigration ? 'MIGRATE_TO_' : ''}DB_HOST must be set.`) } return { @@ -88,6 +72,7 @@ function connectionPg(options: { user: options.DB_USER ?? 'postgres', database: options.DB_NAME ?? 'postgres', password: options.DB_PASSWORD, + ssl: options.DB_SSL ? { rejectUnauthorized: !!options.DB_SSL_VERIFICATION } : false, }, } } diff --git a/server/db/db.ts b/server/db/db.ts index 2be07da..b2fae3b 100644 --- a/server/db/db.ts +++ b/server/db/db.ts @@ -30,6 +30,8 @@ const _db = await createDB({ DB_USER: appConfig.DB_USER, DB_NAME: appConfig.DB_NAME, DB_PASSWORD: appConfig.DB_PASSWORD, + DB_SSL: appConfig.DB_SSL, + DB_SSL_VERIFICATION: appConfig.DB_SSL_VERIFICATION, }) logger.info(`Connected to ${appConfig.DB_ADAPTER} database.`) diff --git a/server/db/user.ts b/server/db/user.ts index 4cb89e1..91c6084 100644 --- a/server/db/user.ts +++ b/server/db/user.ts @@ -12,6 +12,7 @@ import type { OIDCPayload } from '@shared/db/OIDCPayload' import { hasTOTP } from './totp' import { getUserPasskeys } from './passkey' import { argon2 } from '../util/argon2id' +import zod from 'zod' export async function getUsers(searchTerm?: string): Promise { return (await db().table(TABLES.USER).select<(User & { isAdmin: number })[]>('user.*', db().raw(` @@ -124,7 +125,7 @@ export async function findAccount(_: KoaContextWithOIDC | null, id: string): Pro export async function createInitialAdmin() { // Check if admin user and group have ever been created. const adminCreated = await db().table(TABLES.FLAG).select().where({ name: 'ADMIN_CREATED' }).first() - if (adminCreated?.value?.toLowerCase() !== 'true') { + if (!zod.stringbool().safeParse(adminCreated?.value).data) { const password = generate({ length: 32, numbers: true, diff --git a/server/util/config.ts b/server/util/config.ts index f583a2d..0303e0f 100644 --- a/server/util/config.ts +++ b/server/util/config.ts @@ -27,6 +27,8 @@ class Config { DB_PORT?: number DB_USER?: string DB_NAME?: string + DB_SSL: boolean = false + DB_SSL_VERIFICATION: boolean = true // Database migration config MIGRATE_TO_DB_ADAPTER = 'postgres' @@ -35,6 +37,8 @@ class Config { MIGRATE_TO_DB_PORT?: number MIGRATE_TO_DB_USER?: string MIGRATE_TO_DB_NAME?: string + MIGRATE_TO_DB_SSL: boolean = false + MIGRATE_TO_DB_SSL_VERIFICATION: boolean = true // required and checked for validity STORAGE_KEY: string = '' @@ -82,6 +86,10 @@ function assignConfigValue(key: keyof Config, value: string | undefined) { case 'SIGNUP': case 'SIGNUP_REQUIRES_APPROVAL': case 'MFA_REQUIRED': + case 'DB_SSL': + case 'DB_SSL_VERIFICATION': + case 'MIGRATE_TO_DB_SSL': + case 'MIGRATE_TO_DB_SSL_VERIFICATION': appConfig[key] = booleanString(value) ?? appConfig[key] break diff --git a/server/util/util.ts b/server/util/util.ts index a2eeae3..f44b247 100644 --- a/server/util/util.ts +++ b/server/util/util.ts @@ -1,17 +1,11 @@ // No imports from project +import zod from 'zod' + export function booleanString(value: unknown): boolean | null { if (typeof value === 'boolean') { return value } - if (typeof value === 'string') { - if (value.toLowerCase() === 'true') { - return true - } else if (value.toLowerCase() === 'false') { - return false - } - } - - return null + return zod.stringbool().safeParse(value).data ?? null }