spb/drive Public
SPB Drive — self-hosted personal cloud drive (files, previews, sharing) on the MacLustr cluster.
JavaScript 82.7%
CSS 10.6%
Nunjucks 3.6%
Shell 1.8%
SQL 1.3%
1/**2 * ─────────────────────────────────────────────3 * SPB Drive — Personal Cloud Drive4 * ─────────────────────────────────────────────5 * Author : Simon-Pierre Boucher6 * Contact : contact@spboucher.ai7 * File : src/config.mjs8 * Purpose : zod-validated environment configuration + data-dir layout9 * License : MIT © Simon-Pierre Boucher10 * ─────────────────────────────────────────────11 */1213import { mkdirSync } from 'node:fs';14import path from 'node:path';15import { z } from 'zod';1617const schema = z.object({18 SPBDRIVE_DATA_DIR: z.string().default('/srv/drive'),19 SPBDRIVE_PORT: z.coerce.number().int().min(1).max(65535).default(7430),20 SPBDRIVE_HOST: z.string().default('127.0.0.1'),21 SPBDRIVE_PUBLIC_URL: z.string().url().default('https://drive.spboucher.ai'),22 SPBDRIVE_LOG_LEVEL: z.enum(['silent', 'fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),23 SPBDRIVE_TRUST_PROXY: z24 .string()25 .default('true')26 .transform((v) => v === 'true' || v === '1'),27 /** Read once at first boot to seed the login password; ignored afterwards. */28 SPBDRIVE_BOOTSTRAP_PASSWORD: z.string().optional(),29});3031const env = schema.parse(process.env);32const dataDir = path.resolve(env.SPBDRIVE_DATA_DIR);3334/** Resolved, validated application configuration (frozen). */35export const config = Object.freeze({36 port: env.SPBDRIVE_PORT,37 host: env.SPBDRIVE_HOST,38 publicUrl: env.SPBDRIVE_PUBLIC_URL.replace(/\/$/, ''),39 logLevel: env.SPBDRIVE_LOG_LEVEL,40 trustProxy: env.SPBDRIVE_TRUST_PROXY,41 bootstrapPassword: env.SPBDRIVE_BOOTSTRAP_PASSWORD ?? null,4243 dataDir,44 filesDir: path.join(dataDir, 'files'),45 dbDir: path.join(dataDir, 'db'),46 cacheDir: path.join(dataDir, 'cache'),47 uploadsDir: path.join(dataDir, 'cache', 'uploads'),48 logsDir: path.join(dataDir, 'logs'),49 dbFile: path.join(dataDir, 'db', 'drive.sqlite'),50 authFile: path.join(dataDir, 'auth.json'),51 keysFile: path.join(dataDir, 'keys.json'),5253 chunkSize: 8 * 1024 * 1024,54 sessionTtlMs: 24 * 60 * 60 * 1000,55 rememberTtlMs: 30 * 24 * 60 * 60 * 1000,56 trashRetentionDays: 30,57 loginMaxFailures: 5,58 loginLockoutMs: 15 * 60 * 1000,59});6061/** Create every runtime directory (idempotent, restrictive perms). */62export function ensureDataDirs() {63 for (const dir of [64 config.dataDir, config.filesDir, config.dbDir, config.cacheDir,65 config.uploadsDir, config.logsDir,66 path.join(config.cacheDir, 'thumbs'),67 path.join(config.cacheDir, 'transcode'),68 path.join(config.cacheDir, 'office'),69 path.join(config.cacheDir, 'peaks'),70 path.join(config.cacheDir, 'text'),71 path.join(config.cacheDir, 'tmp'),72 ]) {73 mkdirSync(dir, { recursive: true, mode: 0o700 });74 }75}76