fix: harden terminal action endpoints
This commit is contained in:
@@ -415,6 +415,7 @@ let terminalOutput = 'Ready. Live data is loaded from /api/data in server mode.'
|
||||
let terminalBusy = false;
|
||||
let currentRegion = 'world';
|
||||
let flatSvg, flatProjection, flatPath, flatG, flatZoom, flatW, flatH;
|
||||
const terminalActionTokenKey = 'crucix_sweep_token';
|
||||
|
||||
const layerTypeMap = {
|
||||
air: ['air'],
|
||||
@@ -615,6 +616,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>
|
||||
@@ -627,12 +629,26 @@ 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'?'▲ '+t('dashboard.riskOff','RISK-OFF'):D.delta.summary.direction==='risk-on'?'▼ '+t('dashboard.riskOn','RISK-ON'):'◆ '+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="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) || localStorage.getItem('crucix_terminal_action_token') || '';
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// === LEFT RAIL ===
|
||||
function layerMode(key){ return layerModes[key] || 'normal'; }
|
||||
function layerModeLabel(key){ return layerMode(key) === 'focus' ? 'focused' : layerMode(key) === 'hidden' ? 'hidden' : 'normal'; }
|
||||
@@ -1575,6 +1591,12 @@ function renderLower(){
|
||||
|
||||
async function runTerminalAction(action){
|
||||
if(terminalBusy) return;
|
||||
let token = getTerminalActionToken();
|
||||
if(!token && location.hostname !== 'localhost' && location.hostname !== '127.0.0.1'){
|
||||
configureTerminalActionToken();
|
||||
token = getTerminalActionToken();
|
||||
if(!token) return;
|
||||
}
|
||||
terminalBusy = true;
|
||||
terminalOutput = `> ${action}\nRunning...`;
|
||||
renderRight();
|
||||
@@ -1583,7 +1605,7 @@ async function runTerminalAction(action){
|
||||
method:'POST',
|
||||
headers:{
|
||||
'Content-Type':'application/json',
|
||||
...(localStorage.getItem('crucix_sweep_token') ? {'x-crucix-token': localStorage.getItem('crucix_sweep_token')} : {})
|
||||
...(token ? {'x-crucix-token': token} : {})
|
||||
},
|
||||
body:JSON.stringify({action})
|
||||
});
|
||||
@@ -1661,6 +1683,7 @@ function renderRight(){
|
||||
<button class="action-btn" ${terminalBusy?'disabled':''} onclick="runTerminalAction('sweep')">Sweep</button>
|
||||
<button class="action-btn" ${terminalBusy?'disabled':''} onclick="runTerminalAction('brief')">Brief</button>
|
||||
</div>
|
||||
<button class="mini-btn" style="margin-bottom:8px" onclick="configureTerminalActionToken()">Configure token</button>
|
||||
<div class="terminal-output">${terminalOutput.replace(/[&<>]/g,c=>({'&':'&','<':'<','>':'>'}[c])).replace(/\n/g,'<br>')}</div>
|
||||
</div>
|
||||
<div class="g-panel right-signals">
|
||||
|
||||
Reference in New Issue
Block a user