musealpha / src-tauri /resources /scripts /autofill_suppress.js
asdf98's picture
Upload 112 files
3d7d9b5 verified
/**
* Muse Autofill Suppression
*
* Disables native browser autofill (WebView2/WKWebView/WebKitGTK) so that
* the Muse password vault is the only credential source for form fields.
*
* Why: System WebView engines may show their own password save/autofill UIs
* which conflict with our Stronghold-backed vault. We suppress them by:
* 1. Setting autocomplete="off" on all form/input elements
* 2. Using autocomplete="new-password" on password fields (tells browsers not to autofill)
* 3. Adding data-* attributes that third-party password managers check
* 4. Intercepting dynamically created inputs via MutationObserver
*
* Platform notes:
* - Windows WebView2: general_autofill_enabled(false) is also set via Rust builder.
* Password save is already off by default (IsPasswordAutosaveEnabled=false).
* - macOS WKWebView: No public API exists. This JS approach + the Rust
* .general_autofill_enabled(false) builder call (noop on mac but future-proof).
* - Linux WebKitGTK: No built-in password manager UI — this is purely defensive.
*/
(function() {
if (window.__museAutofillSuppressed) return;
window.__museAutofillSuppressed = true;
function suppress(el) {
if (!el || !el.setAttribute) return;
var tag = el.tagName;
if (tag === 'FORM') {
el.setAttribute('autocomplete', 'off');
} else if (tag === 'INPUT') {
var type = (el.type || '').toLowerCase();
if (type === 'password') {
// "new-password" tells browsers: don't autofill existing passwords
el.setAttribute('autocomplete', 'new-password');
} else if (type === 'email' || type === 'text' || type === 'tel') {
el.setAttribute('autocomplete', 'off');
}
// Suppress third-party password managers too
el.setAttribute('data-lpignore', 'true'); // LastPass
el.setAttribute('data-form-type', 'other'); // Dashlane
el.setAttribute('data-1p-ignore', 'true'); // 1Password
}
}
function suppressAll() {
document.querySelectorAll('form, input').forEach(suppress);
}
// Initial pass
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', suppressAll);
} else {
suppressAll();
}
// Watch for dynamically added forms/inputs (SPAs)
var observer = new MutationObserver(function(mutations) {
for (var i = 0; i < mutations.length; i++) {
var added = mutations[i].addedNodes;
for (var j = 0; j < added.length; j++) {
var node = added[j];
if (node.nodeType !== 1) continue;
suppress(node);
if (node.querySelectorAll) {
node.querySelectorAll('form, input').forEach(suppress);
}
}
}
});
observer.observe(document.documentElement, { childList: true, subtree: true });
})();