Vorschlaege weichen Seiten-Comboboxen, 2FA-Code bereitlegen
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
This commit is contained in:
parent
19051bbacd
commit
26c01a4fc3
8 changed files with 169 additions and 27 deletions
|
|
@ -100,11 +100,13 @@ async function setUnlockedLocal(dur) {
|
|||
}
|
||||
async function clearUnlocked() {
|
||||
await chrome.storage.session.remove('unlock');
|
||||
await chrome.storage.local.remove(['__armedTotp', '__pendingFill']);
|
||||
cachedEntries = null; cacheTime = 0; faviconCache.clear();
|
||||
try { await apiFetch('/api/vault/extension/lock', { method: 'POST' }); } catch (e) { /* ignore */ }
|
||||
}
|
||||
async function onServerLocked() {
|
||||
await chrome.storage.session.remove('unlock');
|
||||
await chrome.storage.local.remove(['__armedTotp', '__pendingFill']);
|
||||
cachedEntries = null; cacheTime = 0;
|
||||
}
|
||||
async function doUnlock(pin) {
|
||||
|
|
@ -242,19 +244,22 @@ async function scheduleClipClear(text) {
|
|||
pendingClip = text || '';
|
||||
chrome.alarms.create('clipClear', { delayInMinutes: 0.5 });
|
||||
}
|
||||
async function clearClipboard() {
|
||||
// Schreibt über das Offscreen-Dokument. Dieser Weg funktioniert auch dann, wenn
|
||||
// die Seite selbst keinen Zugriff bekommt – etwa ohne frische Nutzerinteraktion.
|
||||
async function writeClipboard(text) {
|
||||
try {
|
||||
if (!chrome.offscreen) return;
|
||||
const has = chrome.offscreen.hasDocument ? await chrome.offscreen.hasDocument() : false;
|
||||
if (!has) {
|
||||
await chrome.offscreen.createDocument({
|
||||
url: 'offscreen.html', reasons: ['CLIPBOARD'],
|
||||
justification: 'Zwischenablage nach dem Kopieren von Zugangsdaten leeren.',
|
||||
justification: 'Zugangsdaten in die Zwischenablage legen und nach kurzer Zeit wieder entfernen.',
|
||||
});
|
||||
}
|
||||
await chrome.runtime.sendMessage({ target: 'offscreen', type: 'CLIP_WRITE', text: '' });
|
||||
await chrome.runtime.sendMessage({ target: 'offscreen', type: 'CLIP_WRITE', text: text || '' });
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
async function clearClipboard() { await writeClipboard(''); }
|
||||
|
||||
// ── Status prüfen (Bearer) ──────────────────────────────────────────────────
|
||||
async function checkStatus() {
|
||||
|
|
@ -293,6 +298,7 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
|||
}
|
||||
if (msg.type === 'DO_UNLOCK') { doUnlock(msg.pin || '').then(sendResponse); return true; }
|
||||
if (msg.type === 'LOCK_NOW') { clearUnlocked().then(() => sendResponse({ ok: true })); return true; }
|
||||
if (msg.type === 'CLIP_WRITE') { writeClipboard(msg.text || '').then(() => sendResponse({ ok: true })); return true; }
|
||||
if (msg.type === 'SCHEDULE_CLIP_CLEAR') { scheduleClipClear(msg.text || ''); sendResponse({ ok: true }); return true; }
|
||||
if (msg.type === 'CHECK_STATUS') { checkStatus().then(sendResponse); return true; }
|
||||
if (msg.type === 'CLEAR_CACHE') { cachedEntries = null; cacheTime = 0; faviconCache.clear(); sendResponse({ ok: true }); return true; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue