security: fix 3 critical vulnerabilities
1. Remove raw API key from get_settings response
- getServerSettings() no longer returns gemini_key in plain text
- Only gemini_key_set (boolean) and settings_token_set (boolean)
- JS updated to only check gemini_key_set (removes stale gemini_key fallback)
2. Protect save_settings with SETTINGS_TOKEN
- If SETTINGS_TOKEN is set in .env, all save_settings calls must
include matching X-Settings-Token header (uses hash_equals)
- Empty token = no protection (backwards-compatible default)
- Settings UI (Security tab) has a token input field
- Wrong/missing token returns HTTP 403 with error 'unauthorized'
- JS shows '🔒 Token non valido o mancante' on 403
3. DEMO_MODE native blocking in PHP
- DEMO_MODE=false added to .env (default off)
- When DEMO_MODE=true, all write actions return HTTP 403 before routing
- Blocked: save_settings, product_save/delete/merge, inventory_add/use/update/remove,
dismiss_anomaly, bring_add/remove/sync
- demo_mode flag exposed via get_settings so JS can adapt UI
This commit is contained in:
+27
-1
@@ -191,6 +191,20 @@ $action = $_GET['action'] ?? '';
|
||||
|
||||
if (!defined('CRON_MODE')):
|
||||
try {
|
||||
// DEMO_MODE guard
|
||||
if (env('DEMO_MODE') === 'true') {
|
||||
$demoBlocked = [
|
||||
'save_settings', 'product_save', 'product_delete', 'product_merge',
|
||||
'inventory_add', 'inventory_use', 'inventory_update', 'inventory_remove',
|
||||
'dismiss_anomaly', 'bring_add', 'bring_remove', 'bring_sync',
|
||||
];
|
||||
if (in_array($action, $demoBlocked, true)) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['success' => false, 'error' => 'demo_mode']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
// ===== PRODUCTS =====
|
||||
case 'search_barcode':
|
||||
@@ -2037,9 +2051,10 @@ function getServerSettings(): void {
|
||||
$bringEmail = env('BRING_EMAIL');
|
||||
|
||||
echo json_encode([
|
||||
'gemini_key' => $geminiKey,
|
||||
'gemini_key_set' => !empty($geminiKey),
|
||||
'bring_email' => $bringEmail,
|
||||
'settings_token_set' => !empty(env('SETTINGS_TOKEN')),
|
||||
'demo_mode' => env('DEMO_MODE') === 'true',
|
||||
'bring_password_set' => !empty(env('BRING_PASSWORD')),
|
||||
'tts_url' => env('TTS_URL'),
|
||||
'tts_token' => env('TTS_TOKEN'),
|
||||
@@ -2066,6 +2081,17 @@ function getServerSettings(): void {
|
||||
}
|
||||
|
||||
function saveSettings(): void {
|
||||
// Require SETTINGS_TOKEN if configured
|
||||
$requiredToken = env('SETTINGS_TOKEN');
|
||||
if (!empty($requiredToken)) {
|
||||
$provided = $_SERVER['HTTP_X_SETTINGS_TOKEN'] ?? '';
|
||||
if (!hash_equals($requiredToken, $provided)) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['success' => false, 'error' => 'unauthorized']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$envFile = __DIR__ . '/../.env';
|
||||
$envVars = loadEnv();
|
||||
|
||||
Reference in New Issue
Block a user