Vorschlagsliste: Bisher galt jedes E-Mail-Feld als Anmeldefeld (isUsernameField gibt bei type=email bedingungslos true zurueck), und das Dropdown liegt mit maximalem z-index direkt unter dem Feld. Auf Seiten mit eigener Auswahlliste - etwa einem Benutzer-Picker - verdeckte es deren Treffer, die dadurch nicht mehr anklickbar waren. Zwei Regeln davor: Felder mit eigener Vorschlagsliste (ARIA-Combobox mit aria-autocomplete/aria-controls/aria-expanded oder <input list>) bekommen keine Vault-Vorschlaege mehr, sofern autocomplete sie nicht ausdruecklich als Anmeldefeld ausweist. Und sobald der Nutzer selbst tippt, blendet sich die Liste aus und bleibt es, bis das Feld wieder leer ist. 2FA-Code bereitlegen: Nach dem Ausfuellen eines Eintrags mit 2FA bleibt dieser fuenf Minuten vorgemerkt. Taucht danach ein 2FA-Feld auf oder wird es fokussiert - auch auf einer Folgeseite -, wird ein frischer Code geholt und in die Zwischenablage gelegt, statt wie bisher nur einmal zum Fuellzeitpunkt (wo er bis zum 2FA-Schritt laengst rotiert waere). Automatisch wird ausschliesslich kopiert; ins Feld geschrieben wird ein Code weiterhin nur bei ausdruecklicher Auswahl. Geschrieben wird zuerst ueber die Seite und, falls diese keinen Zugriff bekommt, ueber das Offscreen-Dokument des Hintergrunds. Abschaltbar in den Einstellungen. Beim Sperren des Tresors werden Vormerkung und ausstehender Fuellauftrag verworfen. Der Seiten-Scan des MutationObservers laeuft jetzt gedrosselt statt bei jeder einzelnen Mutation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G12DRMpe4UjYDwuRU1sjy1
292 lines
No EOL
12 KiB
HTML
292 lines
No EOL
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>OpenNIT Vault – 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 – ohne abschließ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ä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 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="form-group">
|
||
<label class="control-label"><input type="checkbox" id="totpAutoCopy" checked> 2FA-Code beim Anmelden bereitlegen</label>
|
||
<span class="form-text">Nach dem Ausfüllen eines Eintrags mit 2FA wird beim nächsten 2FA-Feld – auch auf einer Folgeseite – automatisch ein frischer Code in die Zwischenablage gelegt. Einfügen genügt dann mit <strong>Strg + V</strong>.</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>„Mit OpenNIT anmelden“</strong> und melden Sie sich wie gewohnt an.</span></li>
|
||
<li><span class="step-badge">3</span><span>Bestätigen Sie den Zugriff auf den <strong>Passwort-Vault</strong> – die Erweiterung ist damit verbunden.</span></li>
|
||
<li><span class="step-badge">4</span><span>Fokussieren Sie ein Login-Feld auf einer Website – Vault-Vorschläge erscheinen automatisch.</span></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.content-wrapper -->
|
||
|
||
<script src="options.js"></script>
|
||
</body>
|
||
</html> |