Public Access
Visitor sign in kiosk: multi-site, badge printing, WWCC expiry warnings, admin accounts with 2FA
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import 'dotenv/config';
|
||||
import path from 'node:path';
|
||||
import crypto from 'node:crypto';
|
||||
|
||||
function bool(value, fallback) {
|
||||
if (value === undefined || value === '') return fallback;
|
||||
return ['1', 'true', 'yes', 'on'].includes(String(value).toLowerCase());
|
||||
}
|
||||
|
||||
function int(value, fallback) {
|
||||
const n = Number.parseInt(value, 10);
|
||||
return Number.isFinite(n) ? n : fallback;
|
||||
}
|
||||
|
||||
const dataDir = process.env.DATA_DIR || '/data';
|
||||
|
||||
if (!process.env.APP_SECRET) {
|
||||
console.warn(
|
||||
'[config] APP_SECRET is not set. A random one is being generated for this process only.\n' +
|
||||
' Sessions will drop and stored visitor PINs will become unreadable on restart.\n' +
|
||||
' Set APP_SECRET in your .env before going live.'
|
||||
);
|
||||
}
|
||||
|
||||
export const config = {
|
||||
port: int(process.env.PORT, 3000),
|
||||
siteName: process.env.SITE_NAME || 'Visitor sign in',
|
||||
timezone: process.env.TZ || 'Australia/Melbourne',
|
||||
dataDir,
|
||||
dbPath: process.env.DB_PATH || path.join(dataDir, 'visitors.db'),
|
||||
photoDir: process.env.PHOTO_DIR || path.join(dataDir, 'photos'),
|
||||
|
||||
appSecret: process.env.APP_SECRET || crypto.randomBytes(32).toString('hex'),
|
||||
trustProxy: bool(process.env.TRUST_PROXY, false),
|
||||
secureCookies: bool(process.env.SECURE_COOKIES, false),
|
||||
|
||||
admin: {
|
||||
// Used once, to create the first account if the user table is empty.
|
||||
bootstrapEmail: (process.env.ADMIN_BOOTSTRAP_EMAIL || '').trim().toLowerCase(),
|
||||
bootstrapPassword: process.env.ADMIN_BOOTSTRAP_PASSWORD || process.env.ADMIN_PASSWORD || '',
|
||||
// Blank allows any address. Otherwise a comma separated list, e.g. "school.vic.edu.au".
|
||||
allowedDomains: (process.env.ADMIN_ALLOWED_DOMAINS || '')
|
||||
.split(',')
|
||||
.map((d) => d.trim().toLowerCase().replace(/^@/, ''))
|
||||
.filter(Boolean),
|
||||
require2fa: bool(process.env.ADMIN_REQUIRE_2FA, true),
|
||||
},
|
||||
|
||||
printing: {
|
||||
// brother_ql drives the label printer over the network. Overridable so a
|
||||
// wrapper or a different binary can be swapped in.
|
||||
command: process.env.PRINT_COMMAND || 'brother_ql',
|
||||
timeoutMs: int(process.env.PRINT_TIMEOUT_MS, 15000),
|
||||
// How long a sign in waits for the badge before falling back to the browser.
|
||||
signInWaitMs: int(process.env.PRINT_SIGNIN_WAIT_MS, 9000),
|
||||
},
|
||||
|
||||
// Admins are warned this many days before a WWCC or VIT expires.
|
||||
expiryWarningDays: int(process.env.EXPIRY_WARNING_DAYS, 28),
|
||||
|
||||
requirePhoto: bool(process.env.REQUIRE_PHOTO, true),
|
||||
photoRetentionDays: int(process.env.PHOTO_RETENTION_DAYS, 90),
|
||||
// Blank disables the nightly sweep. Format "HH:MM" in local time.
|
||||
autoSignOutTime: process.env.AUTO_SIGNOUT_TIME || '',
|
||||
|
||||
https: {
|
||||
enabled: bool(process.env.HTTPS_ENABLED, false),
|
||||
keyPath: process.env.HTTPS_KEY || path.join(dataDir, 'certs', 'server.key'),
|
||||
certPath: process.env.HTTPS_CERT || path.join(dataDir, 'certs', 'server.crt'),
|
||||
// Names and addresses staff will actually type. Baked into the certificate.
|
||||
hostnames: (process.env.HTTPS_HOSTNAMES || 'visitors.local')
|
||||
.split(',')
|
||||
.map((h) => h.trim())
|
||||
.filter(Boolean),
|
||||
// A plain http listener that serves the CA certificate and redirects
|
||||
// everything else to https. 0 turns it off.
|
||||
redirectPort: int(process.env.HTTP_REDIRECT_PORT, 3001),
|
||||
// The https port as published on the docker host, used when redirecting.
|
||||
publicPort: int(process.env.HTTPS_PUBLIC_PORT, 8443),
|
||||
},
|
||||
|
||||
sheets: {
|
||||
enabled: bool(process.env.SHEETS_ENABLED, false),
|
||||
spreadsheetId: process.env.SHEETS_SPREADSHEET_ID || '',
|
||||
// Append-only history of every sign in and sign out.
|
||||
logTab: process.env.SHEETS_LOG_TAB || process.env.SHEETS_TAB_NAME || 'Visitor log',
|
||||
// Rewritten on every change: just the people currently on site.
|
||||
onSiteTab: process.env.SHEETS_ONSITE_TAB || 'On site now',
|
||||
// Either a path to the service account JSON, or the JSON itself base64 encoded.
|
||||
credentialsPath: process.env.GOOGLE_CREDENTIALS_PATH || '',
|
||||
credentialsB64: process.env.GOOGLE_CREDENTIALS_B64 || '',
|
||||
retryIntervalMs: int(process.env.SHEETS_RETRY_INTERVAL_MS, 60000),
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
Reference in New Issue
Block a user