fix: harden terminal action endpoints
All checks were successful
Build / test-and-image (pull_request) Successful in 49s
Codex Template Compliance / template-compliance (pull_request) Successful in 5s

This commit is contained in:
MrSphay
2026-05-17 14:14:45 +02:00
parent c2d572e6f5
commit 79f897f8ac
6 changed files with 223 additions and 8 deletions

View File

@@ -406,6 +406,7 @@ let layerModes = JSON.parse(localStorage.getItem('crucix_layer_modes') || '{}');
let spaceDisplayMode = localStorage.getItem('crucix_space_display') || 'icons';
let currentRegion = 'world';
let flatSvg, flatProjection, flatPath, flatG, flatZoom, flatW, flatH;
const terminalActionTokenKey = 'crucix_terminal_action_token';
const layerTypeMap = {
air: ['air'],
@@ -606,6 +607,7 @@ function renderTopbar(){
const ts = new Date(D.meta.timestamp);
const d = ts.toLocaleDateString('en-US',{month:'short',day:'numeric',year:'numeric'}).toUpperCase();
const timeStr = ts.toLocaleTimeString('en-US',{hour:'2-digit',minute:'2-digit',hour12:true});
const hasActionToken = !!getTerminalActionToken();
document.getElementById('topbar').innerHTML=`
<div class="top-left">
<span class="brand">CRUCIX MONITOR</span>
@@ -618,12 +620,56 @@ function renderTopbar(){
<span class="meta-pill">${d} <span class="v">${timeStr}</span></span>
<span class="meta-pill">${t('dashboard.sources','SOURCES')} <span class="v">${D.meta.sourcesOk}/${D.meta.sourcesQueried}</span></span>
${D.delta?.summary ? `<span class="meta-pill">${t('dashboard.delta','DELTA')} <span class="v">${D.delta.summary.direction==='risk-off'?'&#x25B2; '+t('dashboard.riskOff','RISK-OFF'):D.delta.summary.direction==='risk-on'?'&#x25BC; '+t('dashboard.riskOn','RISK-ON'):'&#x25C6; '+t('dashboard.mixed','MIXED')}</span></span>` : ''}
<button class="guide-btn" onclick="configureTerminalActionToken()" title="Configure SWEEP_TOKEN for protected terminal actions">${hasActionToken?'TOKEN SET':'SET TOKEN'}</button>
<button class="guide-btn" onclick="runTerminalAction('status')" title="Check protected terminal action access">STATUS</button>
<button class="guide-btn" onclick="runTerminalAction('sweep')" title="Trigger a protected intelligence sweep">SWEEP</button>
<button class="guide-btn" onclick="openGlossary()">${t('dashboard.guideBtn','What Signals Mean')}</button>
<span class="alert-badge">${t('dashboard.highAlert','HIGH ALERT')}</span>
</div>`;
renderRegionControls();
}
function getTerminalActionToken(){
return localStorage.getItem(terminalActionTokenKey) || '';
}
function configureTerminalActionToken(){
const next = window.prompt('Terminal action token (SWEEP_TOKEN). Leave empty to clear.', getTerminalActionToken());
if(next === null) return;
const clean = next.trim();
if(clean) localStorage.setItem(terminalActionTokenKey, clean);
else localStorage.removeItem(terminalActionTokenKey);
renderTopbar();
}
async function runTerminalAction(action){
let token = getTerminalActionToken();
if(!token && location.hostname !== 'localhost' && location.hostname !== '127.0.0.1'){
configureTerminalActionToken();
token = getTerminalActionToken();
if(!token) return;
}
const headers = {'Content-Type':'application/json'};
if(token) headers['x-crucix-token'] = token;
try{
const response = await fetch('/api/action', {
method:'POST',
headers,
body:JSON.stringify({action})
});
const payload = await response.json().catch(() => ({}));
if(!response.ok) throw new Error(payload.error || `Action failed (${response.status})`);
if(action === 'status'){
window.alert(`Terminal actions OK. Health: ${payload.health?.status || 'unknown'}`);
} else if(action === 'sweep'){
window.alert(payload.status === 'accepted' ? 'Sweep accepted.' : `Sweep status: ${payload.status || 'unknown'}`);
}
}catch(err){
window.alert(`Terminal action failed: ${err.message}`);
}
}
// === LEFT RAIL ===
function layerMode(key){ return layerModes[key] || 'normal'; }
function layerModeLabel(key){ return layerMode(key) === 'focus' ? 'focused' : layerMode(key) === 'hidden' ? 'hidden' : 'normal'; }