22 lines
3.6 KiB
JavaScript
22 lines
3.6 KiB
JavaScript
async function copyTokenValue(value){
|
|
if(!value)throw Error('empty');
|
|
try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(value);return;}}catch{}
|
|
const active=document.activeElement,selection=window.getSelection(),ranges=[];
|
|
if(selection)for(let i=0;i<selection.rangeCount;i++)ranges.push(selection.getRangeAt(i).cloneRange());
|
|
const area=document.createElement('textarea');area.value=value;area.readOnly=true;
|
|
area.style.cssText='position:fixed;left:-9999px;top:0;opacity:0';document.body.append(area);
|
|
try{area.focus();area.select();if(!document.execCommand('copy'))throw Error('clipboard');}
|
|
finally{area.value='';area.remove();active?.focus();if(selection){selection.removeAllRanges();for(const range of ranges)selection.addRange(range);}}
|
|
}
|
|
let firstSetup=false;
|
|
const form=document.querySelector('#login'),message=document.querySelector('#error');
|
|
function freshToken(){const bytes=crypto.getRandomValues(new Uint8Array(32));return 'ad_'+Array.from(bytes,b=>b.toString(16).padStart(2,'0')).join('');}
|
|
async function load(){try{const r=await fetch('/api/v1/auth/status'),s=await r.json();firstSetup=!s.initialized;document.querySelector('#title').textContent=firstSetup?'Dein Zugang zu Athena.':'Willkommen zurück.';document.querySelector('#intro').textContent=firstSetup?'Lege das Kennwort für diese Oberfläche und einen separaten Token für API-Clients fest.':'Melde dich mit deinem Oberflächenkennwort an.';document.querySelector('#setup-fields').hidden=!firstSetup;document.querySelector('#password').autocomplete=firstSetup?'new-password':'current-password';document.querySelector('#submit').textContent=firstSetup?'Zugang einrichten':'Anmelden';form.hidden=false;}catch(e){message.textContent='Zugangsstatus nicht erreichbar.'}}
|
|
const syncSetupCopy=()=>document.querySelector('#copy').disabled=!document.querySelector('#api-token').value;
|
|
document.querySelector('#api-token').addEventListener('input',syncSetupCopy);syncSetupCopy();
|
|
document.querySelector('#generate').onclick=()=>{document.querySelector('#api-token').value=freshToken();syncSetupCopy();message.textContent='Token erzeugt. Vor dem Einrichten kopieren und sicher speichern.';};
|
|
document.querySelector('#show-token').onclick=()=>{const input=document.querySelector('#api-token');input.type=input.type==='password'?'text':'password';document.querySelector('#show-token').textContent=input.type==='password'?'Token anzeigen':'Token verbergen';};
|
|
document.querySelector('#copy').onclick=async()=>{try{const token=document.querySelector('#api-token').value;if(!token)throw Error();await copyTokenValue(token);message.textContent='Token kopiert. Bitte sicher speichern.';}catch{message.textContent='Der Browser hat das Kopieren nicht erlaubt. Bitte „Token anzeigen“ wählen und manuell kopieren.'}};
|
|
form.addEventListener('submit',async event=>{event.preventDefault();const input=document.querySelector('#password'),button=document.querySelector('#submit');button.disabled=true;try{let data={password:input.value},path='login';if(firstSetup){if(input.value!==document.querySelector('#repeat').value)throw Error('Die Kennwörter stimmen nicht überein.');data.api_token=document.querySelector('#api-token').value;path='auth/setup';}const r=await fetch('/api/v1/'+path,{method:'POST',headers:{'Content-Type':'application/json','X-Athena-Deck':'1'},body:JSON.stringify(data)});const value=await r.json();if(!r.ok)throw Error(value.error);form.reset();syncSetupCopy();if(firstSetup){await load();message.textContent='Zugang eingerichtet. Bitte jetzt anmelden.';}else location.reload();}catch(e){message.textContent=e.message}finally{button.disabled=false}});
|
|
load();
|