fix: disable PostgreSQL TLS for refusing RDS endpoint

This commit is contained in:
2026-08-16 23:26:03 +08:00
parent acf368b6fe
commit ed978142eb
17 changed files with 340 additions and 180 deletions

View File

@@ -1,6 +1,5 @@
import "server-only";
import { readFileSync } from "node:fs";
import { Pool, type PoolClient, type PoolConfig, type QueryResult, type QueryResultRow } from "pg";
export type DataBackend = "local" | "postgres";
@@ -97,33 +96,30 @@ function getPool(): Pool {
const connectionString = process.env.DATABASE_URL?.trim();
if (!connectionString) throw new Error("DATABASE_URL is required when ZHINIAN_DATA_BACKEND=postgres");
const parsed = assertConnectionStringContract(connectionString);
const config: PoolConfig = {
connectionString,
...buildPlaintextPoolConfig(connectionString),
max: positiveInteger("DATABASE_POOL_MAX", 10),
idleTimeoutMillis: nonNegativeInteger("DATABASE_IDLE_TIMEOUT_MS", 30_000),
connectionTimeoutMillis: positiveInteger("DATABASE_CONNECTION_TIMEOUT_MS", 10_000),
statement_timeout: positiveInteger("DATABASE_STATEMENT_TIMEOUT_MS", 30_000),
application_name: process.env.DATABASE_APPLICATION_NAME?.trim() || "zhinian-web"
};
const sslMode = parsed.searchParams.get("sslmode")?.trim().toLowerCase() || "verify-full";
if (sslMode === "verify-full") {
const caPath = parsed.searchParams.get("sslrootcert")?.trim();
config.ssl = {
...(caPath ? { ca: readFileSync(caPath, "utf8") } : {}),
rejectUnauthorized: true
};
} else if (sslMode !== "disable") {
throw new Error("DATABASE_URL sslmode must be 'disable' or 'verify-full'");
}
parsed.searchParams.delete("sslmode");
parsed.searchParams.delete("sslrootcert");
config.connectionString = parsed.toString();
pool = new Pool(config);
pool.on("error", (error) => console.error("Unexpected PostgreSQL pool error", error));
return pool;
}
export function buildPlaintextPoolConfig(
connectionString: string
): Pick<PoolConfig, "connectionString" | "ssl"> {
const parsed = assertConnectionStringContract(connectionString);
for (const key of [...parsed.searchParams.keys()]) {
if (["sslmode", "sslrootcert"].includes(key.toLowerCase())) parsed.searchParams.delete(key);
}
parsed.searchParams.set("sslmode", "disable");
return { connectionString: parsed.toString(), ssl: false };
}
function assertConnectionStringContract(connectionString: string): URL {
let parsed: URL;
try {
@@ -138,7 +134,7 @@ function assertConnectionStringContract(connectionString: string): URL {
const unsupportedSSLParameters = sslParameters.filter((key) => !["sslmode", "sslrootcert"].includes(key.toLowerCase()));
if (unsupportedSSLParameters.length > 0) {
throw new Error(
`DATABASE_URL contains unsupported SSL query parameters (${unsupportedSSLParameters.join(", ")}); use sslmode and optional sslrootcert`
`DATABASE_URL contains unsupported SSL query parameters (${unsupportedSSLParameters.join(", ")}); PostgreSQL transport is forced to sslmode=disable`
);
}
const sslMode = parsed.searchParams.get("sslmode")?.trim().toLowerCase();