2e450dc01d
P1-A: Fix CSP - add fonts.googleapis.com to style-src, fonts.gstatic.com to font-src
P1-B: CSRF token rotation - add rotateToken() to CsrfMiddleware; bootstrap.php rotates
after successful validation and stores in $GLOBALS['_new_csrf_token']; add
apiRespond() helper to append token to responses; lt.api interceptor in
layout_footer.php auto-updates window.CSRF_TOKEN from responses
P1-C: Styled 403/404 error views with TDS layout instead of raw text; index.php now
uses requireAdmin() helper eliminating 7 duplicated guard blocks (P3-D)
P2-A: Remove duplicate JS-generated keyboard help modal from keyboard-shortcuts.js;
'?' key now routes to static #lt-keys-help modal in footer
P2-B: Asset versioning driven by config ASSET_VERSION key; base.css and base.js get
?v= cache-busting in layout_header.php
P2-C: Add data-theme="dark" to <html> tag to prevent FOUC on light-mode users
P2-E: Escape status value in dashboard.js hover preview class attribute via lt.escHtml()
P2-F: Replace bespoke showLoadingOverlay() with lt-spinner / lt-loading-text from
base.css; add .lt-loading-overlay wrapper CSS to dashboard.css
P2-G: Add keyboard-shortcuts.js to all 7 admin views so J/K nav and ? help work
P3-A: APP_NAME, APP_SUBTITLE, APP_VERSION driven from config.php; layout header/footer
use config values instead of hardcoded strings
P3-G: Replace custom initTableSorting() with lt.sortTable.init() which manages aria-sort
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
119 lines
4.8 KiB
PHP
119 lines
4.8 KiB
PHP
<?php
|
|
// Load environment variables
|
|
$envFile = __DIR__ . '/../.env';
|
|
if (!file_exists($envFile)) {
|
|
die('Configuration error: .env file not found. Copy .env.example to .env and configure your database settings.');
|
|
}
|
|
$envVars = parse_ini_file($envFile, false, INI_SCANNER_TYPED);
|
|
|
|
// Strip quotes from values if present (parse_ini_file may include them)
|
|
if ($envVars) {
|
|
foreach ($envVars as $key => $value) {
|
|
if (is_string($value)) {
|
|
if ((substr($value, 0, 1) === '"' && substr($value, -1) === '"') ||
|
|
(substr($value, 0, 1) === "'" && substr($value, -1) === "'")) {
|
|
$envVars[$key] = substr($value, 1, -1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Global configuration
|
|
$GLOBALS['config'] = [
|
|
// Application identity
|
|
'APP_NAME' => $envVars['APP_NAME'] ?? 'TINKER TICKETS',
|
|
'APP_SUBTITLE' => $envVars['APP_SUBTITLE'] ?? 'LotusGuild Infrastructure',
|
|
'APP_VERSION' => $envVars['APP_VERSION'] ?? '1.2',
|
|
|
|
// Asset cache-busting version string (bump when CSS/JS changes)
|
|
'ASSET_VERSION' => $envVars['ASSET_VERSION'] ?? '20260329',
|
|
|
|
// Database settings
|
|
'DB_HOST' => $envVars['DB_HOST'] ?? 'localhost',
|
|
'DB_USER' => $envVars['DB_USER'] ?? 'root',
|
|
'DB_PASS' => $envVars['DB_PASS'] ?? '',
|
|
'DB_NAME' => $envVars['DB_NAME'] ?? 'tinkertickets',
|
|
|
|
// URL settings
|
|
'BASE_URL' => '', // Empty since we're serving from document root
|
|
'ASSETS_URL' => '/assets', // Assets URL
|
|
'API_URL' => '/api', // API URL
|
|
|
|
// Matrix webhook (hookshot generic webhook URL)
|
|
'MATRIX_WEBHOOK_URL' => $envVars['MATRIX_WEBHOOK_URL'] ?? null,
|
|
// Comma-separated Matrix user IDs to @mention on new tickets (e.g. @jared:matrix.lotusguild.org)
|
|
'MATRIX_NOTIFY_USERS' => $envVars['MATRIX_NOTIFY_USERS'] ?? '',
|
|
|
|
// Domain settings for external integrations (webhooks, links, etc.)
|
|
// Set APP_DOMAIN in .env to override
|
|
'APP_DOMAIN' => $envVars['APP_DOMAIN'] ?? null,
|
|
// Allowed hosts for HTTP_HOST validation (comma-separated in .env)
|
|
'ALLOWED_HOSTS' => array_filter(array_map('trim',
|
|
explode(',', $envVars['ALLOWED_HOSTS'] ?? 'localhost,127.0.0.1')
|
|
)),
|
|
|
|
// Session settings
|
|
'SESSION_TIMEOUT' => 18000, // 5 hours in seconds
|
|
'SESSION_REGENERATE_INTERVAL' => 300, // Regenerate session ID every 5 minutes
|
|
|
|
// CSRF settings
|
|
'CSRF_LIFETIME' => 3600, // 1 hour in seconds
|
|
|
|
// Pagination settings
|
|
'PAGINATION_DEFAULT' => 15, // Default items per page
|
|
'PAGINATION_MAX' => 100, // Maximum items per page
|
|
|
|
// File upload settings
|
|
'MAX_UPLOAD_SIZE' => 10485760, // 10MB in bytes
|
|
'ALLOWED_FILE_TYPES' => [
|
|
'image/jpeg',
|
|
'image/png',
|
|
'image/gif',
|
|
'image/webp',
|
|
'application/pdf',
|
|
'text/plain',
|
|
'text/csv',
|
|
'application/msword',
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
'application/vnd.ms-excel',
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
'application/zip',
|
|
'application/x-7z-compressed',
|
|
'application/x-tar',
|
|
'application/gzip'
|
|
],
|
|
'UPLOAD_DIR' => __DIR__ . '/../uploads',
|
|
|
|
// Rate limiting
|
|
'RATE_LIMIT_DEFAULT' => 100, // Requests per minute for general
|
|
'RATE_LIMIT_API' => 60, // Requests per minute for API
|
|
|
|
// Audit log settings
|
|
'AUDIT_LOG_RETENTION_DAYS' => 90,
|
|
|
|
// Timezone settings
|
|
// Default: America/New_York (EST/EDT)
|
|
// Common options: America/Chicago (CST), America/Denver (MST), America/Los_Angeles (PST), UTC
|
|
'TIMEZONE' => $envVars['TIMEZONE'] ?? 'America/New_York',
|
|
'TIMEZONE_OFFSET' => null, // Will be calculated below
|
|
|
|
// LDAP / lldap settings (for user avatar lookups)
|
|
'LDAP_HOST' => $envVars['LDAP_HOST'] ?? '10.10.10.39',
|
|
'LDAP_PORT' => (int)($envVars['LDAP_PORT'] ?? 3890),
|
|
'LDAP_BIND_DN' => $envVars['LDAP_BIND_DN'] ?? 'uid=tinker-tickets,ou=people,dc=example,dc=com',
|
|
'LDAP_BIND_PW' => $envVars['LDAP_BIND_PW'] ?? '',
|
|
'LDAP_BASE_DN' => $envVars['LDAP_BASE_DN'] ?? 'dc=example,dc=com',
|
|
'LDAP_USER_BASE' => $envVars['LDAP_USER_BASE'] ?? 'ou=people,dc=example,dc=com',
|
|
'LDAP_ENABLED' => filter_var($envVars['LDAP_ENABLED'] ?? 'true', FILTER_VALIDATE_BOOLEAN),
|
|
'AVATAR_CACHE_DIR' => __DIR__ . '/../uploads/avatars',
|
|
'AVATAR_CACHE_TTL' => (int)($envVars['AVATAR_CACHE_TTL'] ?? 3600), // seconds
|
|
];
|
|
|
|
// Set PHP default timezone
|
|
date_default_timezone_set($GLOBALS['config']['TIMEZONE']);
|
|
|
|
// Calculate UTC offset for JavaScript (in minutes, negative for west of UTC)
|
|
$now = new DateTime('now', new DateTimeZone($GLOBALS['config']['TIMEZONE']));
|
|
$GLOBALS['config']['TIMEZONE_OFFSET'] = $now->getOffset() / 60; // Convert seconds to minutes
|
|
$GLOBALS['config']['TIMEZONE_ABBREV'] = $now->format('T'); // e.g., "EST", "EDT"
|
|
?>
|