OpenNIT-Vault-Extension/extension/options.html
Claude 19051bbacd 2FA-Restlaufzeit korrigiert, manuellen API-Token entfernt
Countdown des 2FA-Codes: Die Anzeige zaehlte blind im Sekundentakt
herunter und lief dadurch aus dem Takt. Am Ende eines Zeitfensters wurde
zwar ein neuer Code angefordert, der Zaehler aber nicht angehalten - bei
langsamer oder fehlschlagender Antwort lief er ins Negative und stiess
jede Sekunde eine weitere Anfrage an (inkl. Audit-Eintrag je Abruf),
waehrend die Anzeige auf dem alten Wert stehenblieb.

Die Restlaufzeit wird jetzt aus einem festen Ablaufzeitpunkt berechnet,
sodass gedrosselte oder ausgefallene Ticks sie nicht verschieben. Pro
Ablauf wird genau einmal nachgeladen; liefert der Server keinen Code
mehr (gesperrt/offline), stoppt der Timer und die Anzeige wird geleert.
Dieselbe Rechnung gilt fuer die Benachrichtigung im Seiteninhalt; die
Periode steckt dort wie im Popup in einer Konstanten statt als 30 im
Ausdruck.

Manueller API-Token: Eingabefeld, "Token speichern" und "Verbindung
testen" sind aus den Optionen entfernt; die Server-URL laesst sich
weiterhin separat speichern. getAccessToken() kennt nur noch den
SSO-Weg, und ein aus einer frueheren Version uebernommener Token wird
bei onInstalled aus chrome.storage.local geloescht. Doku und
Store-Listing entsprechend angepasst.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G12DRMpe4UjYDwuRU1sjy1
2026-07-31 15:55:37 +02:00

288 lines
No EOL
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>OpenNIT Vault &ndash; Einstellungen</title>
<style>
/* ── Reset & Base ──────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
body {
font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
font-size: 14px;
color: #212529;
background: #f4f6f9;
margin: 0; padding: 0;
min-height: 100vh;
}
/* ── Main navbar (AdminLTE style) ─────────────────────────────────────── */
.main-header {
background: #343a40;
border-bottom: 3px solid #007bff;
padding: 0 1.25rem;
height: 56px;
display: flex;
align-items: center;
gap: 1rem;
position: sticky;
top: 0;
z-index: 100;
box-shadow: 0 2px 6px rgba(0,0,0,.25);
}
.brand-logo {
width: 36px; height: 36px;
border-radius: 6px;
background: none;
display: flex; align-items: center; justify-content: center;
overflow: hidden; flex-shrink: 0;
}
.brand-logo img { width: 26px; height: 26px; object-fit: contain; }
.brand-text {
color: #fff;
font-size: 1rem;
font-weight: 700;
letter-spacing: .01em;
white-space: nowrap;
}
.brand-sep { color: rgba(255,255,255,.35); margin: 0 2px; font-weight: 300; }
.brand-sub { color: #adb5bd; font-weight: 400; font-size: .95rem; }
.header-user {
margin-left: auto;
display: flex;
align-items: center;
gap: .5rem;
color: #dee2e6;
font-size: .82rem;
}
.user-badge {
background: rgba(255,255,255,.1);
border: 1px solid rgba(255,255,255,.15);
border-radius: 20px;
padding: 3px 10px 3px 6px;
display: flex;
align-items: center;
gap: 5px;
font-size: .78rem;
}
.user-dot { width: 7px; height: 7px; background: #28a745; border-radius: 50%; }
/* ── Content wrapper ──────────────────────────────────────────────────── */
.content-wrapper { max-width: 680px; margin: 0 auto; padding: 1.5rem 1.25rem; }
/* ── Card (AdminLTE .card) ───────────────────────────────────────────── */
.card {
background: #fff;
border: none;
border-radius: .35rem;
box-shadow: 0 1px 3px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.06);
margin-bottom: 1.25rem;
}
.card-header {
background: #f8f9fa;
border-bottom: 1px solid #dee2e6;
padding: .75rem 1.25rem;
border-radius: .35rem .35rem 0 0;
display: flex;
align-items: center;
gap: .5rem;
}
.card-header h3 {
margin: 0;
font-size: .9rem;
font-weight: 600;
color: #343a40;
line-height: 1;
}
.card-header .card-tools { margin-left: auto; }
.card-body { padding: 1.25rem; }
/* ── Form controls ───────────────────────────────────────────────────── */
.form-group { margin-bottom: 1rem; }
.form-group:last-child { margin-bottom: 0; }
label.control-label {
display: block;
font-size: .78rem;
font-weight: 700;
color: #6c757d;
text-transform: uppercase;
letter-spacing: .04em;
margin-bottom: .35rem;
}
.form-control {
display: block;
width: 100%;
padding: .45rem .75rem;
font-size: .9rem;
color: #495057;
background: #fff;
border: 1px solid #ced4da;
border-radius: .25rem;
transition: border-color .15s, box-shadow .15s;
}
.form-control:focus {
outline: none;
border-color: #80bdff;
box-shadow: 0 0 0 .2rem rgba(0,123,255,.25);
}
.form-text { font-size: .78rem; color: #6c757d; margin-top: .25rem; line-height: 1.5; }
/* ── Buttons ─────────────────────────────────────────────────────────── */
.btn {
display: inline-flex;
align-items: center;
gap: .35rem;
padding: .4rem .85rem;
font-size: .875rem;
font-weight: 600;
border: 1px solid transparent;
border-radius: .25rem;
cursor: pointer;
transition: background .15s, border-color .15s, color .15s;
text-decoration: none;
}
.btn-primary { background: #007bff; border-color: #007bff; color: #fff; }
.btn-primary:hover { background: #0069d9; border-color: #0062cc; }
.btn-default { background: #fff; border-color: #ced4da; color: #212529; }
.btn-default:hover { background: #f8f9fa; border-color: #adb5bd; }
.btn-sm { padding: .28rem .65rem; font-size: .8rem; }
.btn-group { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-top: .75rem; }
/* ── Alerts ──────────────────────────────────────────────────────────── */
.alert { padding: .65rem 1rem; border-radius: .25rem; font-size: .85rem; margin-top: .75rem; border: 1px solid transparent; }
.alert-success { background: #d4edda; color: #155724; border-color: #c3e6cb; }
.alert-danger { background: #f8d7da; color: #721c24; border-color: #f5c6cb; }
.alert-info { background: #d1ecf1; color: #0c5460; border-color: #bee5eb; }
.save-ok { color: #28a745; font-size: .82rem; font-weight: 600; display: inline-flex; align-items: center; gap: 4px; }
/* ── Spinner ─────────────────────────────────────────────────────────── */
.fa-spin-sm {
display: inline-block;
width: 12px; height: 12px;
border: 2px solid #dee2e6;
border-top-color: #007bff;
border-radius: 50%;
animation: sp .7s linear infinite;
vertical-align: middle;
}
@keyframes sp { to { transform: rotate(360deg); } }
/* ── Steps list ──────────────────────────────────────────────────────── */
.steps-list { list-style: none; margin: 0; padding: 0; }
.steps-list li {
display: flex;
gap: .875rem;
align-items: flex-start;
padding: .5rem 0;
border-bottom: 1px solid #f1f3f5;
font-size: .875rem;
color: #495057;
line-height: 1.55;
}
.steps-list li:last-child { border-bottom: none; padding-bottom: 0; }
.step-badge {
min-width: 22px; height: 22px;
background: #007bff;
color: #fff;
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: .7rem;
font-weight: 700;
flex-shrink: 0;
margin-top: .15rem;
}
</style>
</head>
<body>
<!-- Main Header -->
<nav class="main-header">
<div class="brand-logo"><img src="icon128.png" alt=""></div>
<span class="brand-text" id="optTitle">OpenNIT Vault</span>
<div class="header-user" id="headerStatus" style="display:none;">
<span class="user-badge">
<span class="user-dot"></span>
<span id="headerUser"></span>
</span>
</div>
</nav>
<div class="content-wrapper">
<!-- Connection card -->
<div class="card">
<div class="card-header">
<h3>Server-Verbindung</h3>
</div>
<div class="card-body">
<div class="form-group">
<label class="control-label" for="serverUrl">Server-URL</label>
<input type="url" class="form-control" id="serverUrl"
placeholder="https://ihre-opennit.firma.de"
value="">
<span class="form-text">Adresse Ihrer OpenNIT-Instanz &ndash; ohne abschlie&szlig;enden Slash.</span>
</div>
<!-- SSO-Anmeldung (empfohlen) -->
<div class="btn-group">
<button class="btn btn-primary" id="btnSso">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:2px;"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" y1="12" x2="3" y2="12"/></svg>
Mit OpenNIT anmelden
</button>
<button class="btn btn-default" id="btnSave">URL speichern</button>
<button class="btn btn-default" id="btnLogout" style="display:none;">Abmelden</button>
<span id="ssoMsg"></span>
<span id="savedMsg"></span>
</div>
<span class="form-text">Die Anmeldung erfolgt wie an OpenNIT (lokal + 2FA / Microsoft 365 / Keycloak). Der Zugang wird automatisch erneuert und l&auml;sst sich jederzeit im Vault widerrufen.</span>
<div id="statusMsg"></div>
</div>
</div>
<!-- Security card -->
<div class="card">
<div class="card-header">
<h3>Sicherheit</h3>
</div>
<div class="card-body">
<div class="form-group">
<label class="control-label" for="lockDuration">PIN-Sperre: erneut fragen</label>
<select class="form-control" id="lockDuration">
<option value="5">Nach 5 Minuten</option>
<option value="15">Nach 15 Minuten</option>
<option value="60">Nach 1 Stunde</option>
<option value="session">Bis der Browser geschlossen wird</option>
</select>
<span class="form-text">Ist im Web-Tresor ein <strong>Tresor-PIN</strong> aktiv, verlangt die Erweiterung diesen PIN <strong>serverseitig erzwungen</strong>, damit ein gestohlener Token allein nichts nützt. Diese Einstellung legt nur fest, <em>wie lange</em> eine Entsperrung gilt. Ohne gesetzten Tresor-PIN entfällt die Sperre.</span>
</div>
<div class="form-group">
<label class="control-label"><input type="checkbox" id="clipClear" checked> Zwischenablage nach 30&nbsp;Sekunden leeren</label>
<span class="form-text">Kopierte Passwörter und 2FA-Codes werden nach kurzer Zeit automatisch aus der Zwischenablage entfernt.</span>
</div>
<div class="btn-group">
<button class="btn btn-primary btn-sm" id="btnSaveSec">Speichern</button>
<span id="savedSecMsg"></span>
</div>
</div>
</div>
<!-- Setup card -->
<div class="card">
<div class="card-header">
<h3>Einrichtungsschritte</h3>
</div>
<div class="card-body">
<ul class="steps-list">
<li><span class="step-badge">1</span><span>Tragen Sie oben die <strong>Server-URL</strong> Ihrer OpenNIT-Instanz ein (nur <strong>https://</strong>).</span></li>
<li><span class="step-badge">2</span><span>Klicken Sie auf <strong>&bdquo;Mit OpenNIT anmelden&ldquo;</strong> und melden Sie sich wie gewohnt an.</span></li>
<li><span class="step-badge">3</span><span>Best&auml;tigen Sie den Zugriff auf den <strong>Passwort-Vault</strong> &ndash; die Erweiterung ist damit verbunden.</span></li>
<li><span class="step-badge">4</span><span>Fokussieren Sie ein Login-Feld auf einer Website &ndash; Vault-Vorschl&auml;ge erscheinen automatisch.</span></li>
</ul>
</div>
</div>
</div><!-- /.content-wrapper -->
<script src="options.js"></script>
</body>
</html>