Bounded test succeeded; native RandomX miner accepted one block
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
import { lstat, readFile } from 'node:fs/promises';
|
||||
import { constants } from 'node:fs';
|
||||
import { open } from 'node:fs/promises';
|
||||
import { X509Certificate } from 'node:crypto';
|
||||
import type { PoolConfig } from 'pg';
|
||||
|
||||
export function custodyStorage(env: NodeJS.ProcessEnv = process.env): 'sqlite' | 'postgres' {
|
||||
@@ -13,6 +16,60 @@ async function secretFile(path: string | undefined): Promise<string> {
|
||||
if (process.platform !== 'win32' && (info.mode & 0o077) !== 0) throw new Error('PostgreSQL secret file permissions are too broad');
|
||||
return (await readFile(path, 'utf8')).trim();
|
||||
}
|
||||
function derLength(bytes: Buffer, offset: number): { length: number; next: number } {
|
||||
if (offset >= bytes.length) throw new Error('Invalid certificate DER length');
|
||||
const first = bytes[offset];
|
||||
if (first < 0x80) return { length: first, next: offset + 1 };
|
||||
const count = first & 0x7f;
|
||||
if (count === 0 || count > 4 || offset + count >= bytes.length) throw new Error('Invalid certificate DER length');
|
||||
let length = 0;
|
||||
for (let i = 1; i <= count; i++) length = length * 256 + bytes[offset + i];
|
||||
return { length, next: offset + count + 1 };
|
||||
}
|
||||
function derElement(bytes: Buffer, offset: number): { tag: number; start: number; end: number; next: number } {
|
||||
if (offset >= bytes.length) throw new Error('Invalid certificate DER');
|
||||
const tag = bytes[offset], size = derLength(bytes, offset + 1), end = size.next + size.length;
|
||||
if (end > bytes.length) throw new Error('Invalid certificate DER');
|
||||
return { tag, start: size.next, end, next: end };
|
||||
}
|
||||
function validateCaCertificate(pem: Buffer): string {
|
||||
const certificate = new X509Certificate(pem);
|
||||
const now = Date.now();
|
||||
if (!Number.isFinite(Date.parse(certificate.validFrom)) || !Number.isFinite(Date.parse(certificate.validTo)) ||
|
||||
now < Date.parse(certificate.validFrom) || now > Date.parse(certificate.validTo)) {
|
||||
throw new Error('PostgreSQL CA certificate is not currently valid');
|
||||
}
|
||||
if (certificate.subject !== certificate.issuer || !certificate.verify(certificate.publicKey)) {
|
||||
throw new Error('PostgreSQL CA certificate must be a valid self-signed trust anchor');
|
||||
}
|
||||
const key = certificate.publicKey;
|
||||
if (key.asymmetricKeyType !== 'rsa' || (key.asymmetricKeyDetails?.modulusLength ?? 0) < 2048) {
|
||||
throw new Error('PostgreSQL CA certificate key must be RSA-2048 or stronger');
|
||||
}
|
||||
const der = certificate.raw;
|
||||
const outer = derElement(der, 0);
|
||||
if (outer.tag !== 0x30) throw new Error('Invalid PostgreSQL CA certificate DER');
|
||||
const tbs = derElement(der, outer.start);
|
||||
const signatureAlgorithm = derElement(der, tbs.next);
|
||||
if (signatureAlgorithm.tag !== 0x30) throw new Error('Invalid PostgreSQL CA signature algorithm');
|
||||
const oid = derElement(der, signatureAlgorithm.start);
|
||||
if (oid.tag !== 0x06) throw new Error('Invalid PostgreSQL CA signature algorithm');
|
||||
const signatureOid = der.subarray(oid.start, oid.end).toString('hex');
|
||||
const weakSignatureOids = new Set(['2a864886f70d010104', '2b0e03021a', '2b0e03021b']);
|
||||
if (weakSignatureOids.has(signatureOid)) throw new Error('PostgreSQL CA certificate uses a weak signature algorithm');
|
||||
return pem.toString('utf8');
|
||||
}
|
||||
async function publicCaFile(path: string | undefined): Promise<string | undefined> {
|
||||
if (!path) return undefined;
|
||||
const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
||||
try {
|
||||
const info = await file.stat();
|
||||
if (!info.isFile() || info.size < 1 || info.size > 64 * 1024) throw new Error('Invalid PostgreSQL CA file');
|
||||
// A CA certificate is public trust material; mode 0644 is expected. It is not a database credential.
|
||||
const bytes = await file.readFile();
|
||||
return validateCaCertificate(bytes);
|
||||
} finally { await file.close(); }
|
||||
}
|
||||
/** No URL logging, no TLS options in a connection string overriding verified transport. */
|
||||
export async function postgresConfig(env: NodeJS.ProcessEnv = process.env): Promise<PoolConfig> {
|
||||
try {
|
||||
@@ -33,7 +90,7 @@ export async function postgresConfig(env: NodeJS.ProcessEnv = process.env): Prom
|
||||
if (insecure && !['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname)) throw new Error('Non-TLS test connections must be loopback');
|
||||
if (!insecure && (!url.username || !url.password)) throw new Error('PostgreSQL credentials required');
|
||||
if (url.port && (!/^\d+$/.test(url.port) || Number(url.port) < 1 || Number(url.port) > 65535)) throw new Error('Invalid PostgreSQL port');
|
||||
const ca = env.WIKIDECK_CUSTODY_PG_CA_FILE ? await secretFile(env.WIKIDECK_CUSTODY_PG_CA_FILE) : undefined;
|
||||
const ca = await publicCaFile(env.WIKIDECK_CUSTODY_PG_CA_FILE);
|
||||
return { host: url.hostname.replace(/^\[|\]$/g, ''), port: url.port ? Number(url.port) : 5432,
|
||||
database: url.pathname.slice(1), user: decodeURIComponent(url.username), password: decodeURIComponent(url.password),
|
||||
// Infrastructure mode is explicit plaintext on the driver's hop. It does NOT configure or
|
||||
|
||||
Reference in New Issue
Block a user