SPB Git

Repository Public

config.ts 3.0 KB 58 lines typescript

1import { mkdirSync, readFileSync } from 'node:fs';2import { homedir } from 'node:os';3import { join } from 'node:path';45const env = (k: string, d?: string) => { const v = process.env[k] ?? d; if (v === undefined || v === '') throw new Error(`missing env ${k}`); return v; };6const num = (k: string, d: number) => { const v = Number(process.env[k] ?? d); if (!Number.isFinite(v)) throw new Error(`bad env ${k}`); return v; };7const GIB = 1024 ** 3, MIB = 1024 ** 2;89const dataDir = env('SPD_DATA_DIR', join(homedir(), 'sp-drive-data'));10export const config = {11  origin: env('SPD_ORIGIN'),12  rpId: env('SPD_RP_ID'),13  port: num('PORT', 8660),14  host: env('HOST', '127.0.0.1'),15  databaseUrl: env('DATABASE_URL'),16  trustProxy: (process.env.SPD_TRUST_PROXY ?? '127.0.0.1').split(',').map((x) => x.trim()),17  webDir: process.env.SPD_WEB_DIR ?? '',18  dataDir,19  blobDir: join(dataDir, 'blobs'),20  tmpDir: join(dataDir, 'tmp'),21  quarantineDir: join(dataDir, 'quarantine'),22  workDir: join(dataDir, 'work'),23  /** where the code lives (readable by sandboxed helpers; holds no secret) */24  appDir: env('SPD_APP_DIR', process.cwd()),25  masterKeyFile: env('SPD_MASTER_KEY_FILE', join(homedir(), '.config/sp-drive/master.key')),26  /** default quota of a new account */27  defaultQuotaBytes: num('SPD_DEFAULT_QUOTA_GB', 100) * GIB,28  maxFileBytes: num('SPD_MAX_FILE_GB', 50) * GIB,29  /** clamd Unix socket; empty = no antivirus available */30  clamdSocket: process.env.SPD_CLAMD_SOCKET ?? '',31  /** 'required': portal deposits stay in quarantine when the scanner is unavailable; 'optional': dev/test only */32  avMode: env('SPD_AV_MODE', 'required') as 'required' | 'optional',33  soffice: process.env.SPD_SOFFICE ?? '/Applications/LibreOffice.app/Contents/MacOS/soffice',34  /** preview limits */35  officeMaxBytes: num('SPD_OFFICE_MAX_MB', 100) * MIB,36  sheetMaxBytes: num('SPD_SHEET_MAX_MB', 30) * MIB,37  convertTimeoutMs: num('SPD_CONVERT_TIMEOUT_S', 90) * 1000,38  /** test hook: run the job loop inside the API process */39  inlineWorker: process.env.SPD_INLINE_WORKER === 'on',40  commit: process.env.SPD_COMMIT ?? '',41};42export const secureCookies = config.origin.startsWith('https://');43for (const d of [config.blobDir, config.tmpDir, config.quarantineDir, config.workDir]) mkdirSync(d, { recursive: true, mode: 0o700 });4445/** 32-byte master key, hex or base64 in a file outside the repository. */46export function loadMasterKey(): Buffer {47  const raw = readFileSync(config.masterKeyFile, 'utf8').trim();48  const key = /^[0-9a-f]{64}$/i.test(raw) ? Buffer.from(raw, 'hex') : Buffer.from(raw, 'base64');49  if (key.length !== 32) throw new Error('master key must be 32 bytes');50  return key;51}5253/** An error whose message is safe to show to the caller. `code` is stable and drives the UI translation. */54export class UserError extends Error {55  constructor(public code: string, message: string, public status = 400, public extra: Record<string, unknown> = {}) { super(message); }56}57export const notFound = (what = 'not found') => new UserError('not_found', what, 404);58
Files main
Menu

Theme