191 lines
7.0 KiB
JavaScript
191 lines
7.0 KiB
JavaScript
// DashCaddy Shared Constants
|
|
// Centralizes configuration values used across the application.
|
|
// Edit values here instead of hunting through server.js.
|
|
|
|
// ── App Identity ──────────────────────────────────────────────
|
|
const APP = {
|
|
NAME: 'DashCaddy',
|
|
VERSION: '1.1',
|
|
PORT: 3001,
|
|
USER_AGENTS: {
|
|
PROBE: 'DashCaddy-Probe/1.0',
|
|
API: 'DashCaddy/1.0',
|
|
HEALTH: 'DashCaddy-HealthCheck/1.0',
|
|
},
|
|
DEVICE_IDS: {
|
|
SSO: 'dashcaddy-sso', // Backend auth gate (never invalidates browser token)
|
|
BROWSER: 'dashcaddy-browser', // Browser-side localStorage token
|
|
},
|
|
};
|
|
|
|
// ── Default Ports for Media/Arr Apps ──────────────────────────
|
|
const APP_PORTS = {
|
|
plex: 32400,
|
|
radarr: 7878,
|
|
sonarr: 8989,
|
|
seerr: 5055,
|
|
lidarr: 8686,
|
|
prowlarr: 9696,
|
|
};
|
|
|
|
// Arr service discovery config (used by /api/arr/* endpoints)
|
|
const ARR_SERVICES = {
|
|
plex: { names: ['plex'], port: APP_PORTS.plex, configPath: 'Plex' },
|
|
radarr: { names: ['radarr'], port: APP_PORTS.radarr, configPath: 'radarr' },
|
|
sonarr: { names: ['sonarr'], port: APP_PORTS.sonarr, configPath: 'sonarr' },
|
|
seerr: { names: ['seerr', 'requests'], port: APP_PORTS.seerr, configPath: 'seerr' },
|
|
lidarr: { names: ['lidarr'], port: APP_PORTS.lidarr, configPath: 'lidarr' },
|
|
prowlarr: { names: ['prowlarr'], port: APP_PORTS.prowlarr, configPath: 'prowlarr' },
|
|
};
|
|
|
|
// ── Timeouts (ms) ─────────────────────────────────────────────
|
|
const TIMEOUTS = {
|
|
HTTP_DEFAULT: 5000, // Standard fetch/http timeout
|
|
HTTP_LONG: 10000, // DNS ops, downloads, login requests
|
|
DEPLOY_SETTLE: 3000, // Wait after container start before health check
|
|
CADDY_PRE_RELOAD: 2000, // Pause before Caddy reload
|
|
RETRY_SHORT: 1000, // Short retry delay
|
|
RETRY_MEDIUM: 2000, // Medium retry delay
|
|
SHUTDOWN_GRACE: 5000, // Graceful shutdown window
|
|
SHUTDOWN_ERROR: 1000, // Error shutdown window
|
|
PORT_CHECK: 2000, // TCP port availability check
|
|
};
|
|
|
|
// ── Retry Configuration ───────────────────────────────────────
|
|
const RETRIES = {
|
|
CADDY_RELOAD: 3, // Max attempts to reload Caddy
|
|
};
|
|
|
|
// ── Session / Cache Expiry (ms) ───────────────────────────────
|
|
const SESSION_TTL = {
|
|
IP_SESSION: 30 * 60 * 1000, // 30 min — router IP-based sessions
|
|
COOKIE_SESSION: 30 * 60 * 1000, // 30 min — cookie-based login sessions
|
|
TOKEN_SESSION: 60 * 60 * 1000, // 60 min — JWT/access token sessions (Jellyfin, Plex, etc.)
|
|
FAILED_LOGIN: 5 * 60 * 1000, // 5 min — cooldown after failed login
|
|
DNS_TOKEN: 6 * 60 * 60 * 1000, // 6 hrs — DNS auto-refresh interval
|
|
};
|
|
|
|
// ── Rate Limiting ─────────────────────────────────────────────
|
|
const RATE_LIMITS = {
|
|
GENERAL: {
|
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
max: 100,
|
|
},
|
|
STRICT: {
|
|
windowMs: 15 * 60 * 1000,
|
|
max: 20,
|
|
},
|
|
TOTP: {
|
|
windowMs: 15 * 60 * 1000,
|
|
max: 10,
|
|
},
|
|
};
|
|
|
|
// ── Caddy ─────────────────────────────────────────────────────
|
|
const CADDY = {
|
|
CONTENT_TYPE: 'text/caddyfile',
|
|
DEFAULT_DNS_PORT: '5380',
|
|
DEFAULT_TTL: 300,
|
|
TTL_MIN: 60,
|
|
TTL_MAX: 86400,
|
|
};
|
|
|
|
// ── Validation Patterns ─────────────────────────────────────────
|
|
const REGEX = {
|
|
SUBDOMAIN: /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i,
|
|
DOMAIN: /^[a-z0-9]([a-z0-9.-]{0,251}[a-z0-9])?$/i,
|
|
};
|
|
|
|
// ── DNS ─────────────────────────────────────────────────────────
|
|
const DNS_RECORD_TYPES = ['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'NS', 'SRV', 'PTR', 'SOA'];
|
|
|
|
// ── Docker ──────────────────────────────────────────────────────
|
|
const DOCKER = {
|
|
CONTAINER_PREFIX: 'sami-',
|
|
TIMEOUT: 30000, // 30s — timeout for docker pull/create operations
|
|
LOG_CONFIG: {
|
|
Type: 'json-file',
|
|
Config: { 'max-size': '10m', 'max-file': '3' } // 30MB max per container
|
|
},
|
|
MAINTENANCE: {
|
|
INTERVAL: 24 * 60 * 60 * 1000, // 24 hours
|
|
DISK_WARN_GB: 20, // Warn when Docker uses more than 20GB
|
|
},
|
|
DIGEST: {
|
|
COLLECT_INTERVAL: 60 * 60 * 1000, // Hourly log collection
|
|
DIGEST_HOUR: 0, // Generate daily digest at midnight
|
|
MAX_HOURLY_ENTRIES: 24, // Keep 24 hours of hourly summaries
|
|
MAX_DIGEST_FILES: 30, // Keep 30 days of daily digests
|
|
LOG_TAIL: 500, // Lines to fetch per container per hour
|
|
},
|
|
};
|
|
|
|
// ── Emby/Jellyfin Auth Header Builder ─────────────────────────
|
|
function buildMediaAuth(deviceId) {
|
|
return `MediaBrowser Client="${APP.NAME}", Device="${APP.NAME}", DeviceId="${deviceId}", Version="${APP.VERSION}"`;
|
|
}
|
|
|
|
// ── Plex Auth Headers ─────────────────────────────────────────
|
|
const PLEX = {
|
|
AUTH_URL: 'https://plex.tv/users/sign_in.json',
|
|
};
|
|
|
|
// ── Tailscale API ────────────────────────────────────────────
|
|
const TAILSCALE = {
|
|
API_BASE: 'https://api.tailscale.com/api/v2',
|
|
OAUTH_TOKEN_URL: 'https://api.tailscale.com/api/v2/oauth/token',
|
|
};
|
|
|
|
// ── Error Log ─────────────────────────────────────────────────
|
|
const LIMITS = {
|
|
ERROR_LOG_SIZE: 5 * 1024 * 1024, // 5 MB
|
|
BODY_DEFAULT: '1mb',
|
|
BODY_UPLOAD: '10mb',
|
|
};
|
|
|
|
|
|
// HTTP Status Codes
|
|
const HTTP_STATUS = {
|
|
OK: 200,
|
|
CREATED: 201,
|
|
NO_CONTENT: 204,
|
|
BAD_REQUEST: 400,
|
|
UNAUTHORIZED: 401,
|
|
FORBIDDEN: 403,
|
|
NOT_FOUND: 404,
|
|
CONFLICT: 409,
|
|
INTERNAL_ERROR: 500,
|
|
SERVICE_UNAVAILABLE: 503,
|
|
};
|
|
|
|
// Network Constants
|
|
const NETWORK = {
|
|
LOCALHOST: '127.0.0.1',
|
|
PRIVATE_RANGES: ['192.168.', '10.', /^172\.(1[6-9]|2[0-9]|3[0-1])\./],
|
|
BUFFER_SIZE: 1024,
|
|
};
|
|
|
|
module.exports = {
|
|
APP,
|
|
TAILSCALE,
|
|
APP_PORTS,
|
|
ARR_SERVICES,
|
|
TIMEOUTS,
|
|
RETRIES,
|
|
SESSION_TTL,
|
|
RATE_LIMITS,
|
|
CADDY,
|
|
PLEX,
|
|
LIMITS,
|
|
REGEX,
|
|
DNS_RECORD_TYPES,
|
|
DOCKER,
|
|
buildMediaAuth,
|
|
HTTP_STATUS,
|
|
NETWORK,
|
|
HTTP_STATUS,
|
|
NETWORK,
|
|
};
|
|
|
|
|