'use strict'; const wwa_passkey_notice_svg = ''; const wwa_passkey_btn_svg = ''; // Send an AJAX request and get the response const wwa_ajax = function () { let xmlHttpReq = new XMLHttpRequest(); return { /** Send an AJAX GET request and get the response * * @param {string} url URL * @param {string} data Attached data * @param {object} callback Callback function */ get: (url, data = '', callback = () => { }) => { xmlHttpReq.open('GET', url + data, true); xmlHttpReq.send(); xmlHttpReq.onreadystatechange = () => { if (xmlHttpReq.readyState === 4 && xmlHttpReq.status === 200) { callback(xmlHttpReq.responseText.trim(), true); } else if (xmlHttpReq.readyState === 4) { callback('Network Error.', false); } } }, /** Send an AJAX POST request and get the response * * @param {string} url URL * @param {string} data Attached data * @param {object} callback Callback function */ post: (url, data = '', callback = () => { }) => { xmlHttpReq.open('POST', url, true); xmlHttpReq.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xmlHttpReq.send(data); xmlHttpReq.onreadystatechange = () => { if (xmlHttpReq.readyState === 4 && xmlHttpReq.status === 200) { callback(xmlHttpReq.responseText.trim(), true); } else if (xmlHttpReq.readyState === 4) { callback('Network Error.', false); } } } } }; /** Operate selected DOMs * * @param {string} selector DOM selector * @param {object} callback Callbck function * @param {string} method Selecte method */ const wwa_dom = (selector, callback = () => { }, method = 'query') => { let dom_list = []; if (method === 'id') { let dom = document.getElementById(selector); if (dom) { callback(dom); } return; } else if (method === 'class') { dom_list = document.getElementsByClassName(selector); } else if (method === 'tag') { dom_list = document.getElementsByTagName(selector); } else { dom_list = document.querySelectorAll(selector); } for (let dom of dom_list) { callback(dom); } return; } let wwaSupported = true; let wwa_conditional_ui_abort = null; let wwa_conditional_ui_active = false; /** * Start a Conditional UI (passkey autofill) request. * The browser will show a passkey picker in the username autocomplete dropdown. * Aborted automatically when the user manually triggers a normal WebAuthn check. */ function wwa_start_conditional_ui() { if (wwa_conditional_ui_active) return; if (!window.PublicKeyCredential) return; // Prefer getClientCapabilities() (Chrome 128+) for a richer capability check; // fall back to isConditionalMediationAvailable() for older browsers. const conditionalAvailablePromise = typeof PublicKeyCredential.getClientCapabilities === 'function' ? PublicKeyCredential.getClientCapabilities().then((caps) => !!caps.conditionalGet) : typeof PublicKeyCredential.isConditionalMediationAvailable === 'function' ? PublicKeyCredential.isConditionalMediationAvailable() : Promise.resolve(false); conditionalAvailablePromise.then((available) => { if (!available) return; wwa_conditional_ui_active = true; wwa_conditional_ui_abort = new AbortController(); const signal = wwa_conditional_ui_abort.signal; // Request an empty-user challenge (usernameless style: no allowCredentials) let startReq = wwa_ajax(); startReq.get(wwa_login_php_vars.ajax_url, '?action=wwa_auth_start&type=auth&usernameless=true&conditional=true', (rawData, status) => { if (!status || signal.aborted) { wwa_conditional_ui_active = false; return; } let data; try { data = JSON.parse(rawData); } catch (e) { wwa_conditional_ui_active = false; return; } data.challenge = Uint8Array.from( window.atob(base64url2base64(data.challenge)), (c) => c.charCodeAt(0) ); if (data.allowCredentials) { data.allowCredentials = data.allowCredentials.map((item) => { item.id = Uint8Array.from( window.atob(base64url2base64(item.id)), (c) => c.charCodeAt(0) ); return item; }); } const clientID = data.clientID; delete data.clientID; navigator.credentials.get({ publicKey: data, mediation: 'conditional', signal: signal }).then((credentialInfo) => { if (!credentialInfo) { wwa_conditional_ui_active = false; return; } // Show authenticating state wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_5; }, 'class'); wwa_dom('user_login', (dom) => { dom.readOnly = true; }, 'id'); wwa_dom('#wp-webauthn-check, #wp-webauthn', (dom) => { dom.disabled = true; }); const publicKeyCredential = { id: credentialInfo.id, type: credentialInfo.type, rawId: arrayToBase64String(new Uint8Array(credentialInfo.rawId)), response: { authenticatorData: arrayToBase64String(new Uint8Array(credentialInfo.response.authenticatorData)), clientDataJSON: arrayToBase64String(new Uint8Array(credentialInfo.response.clientDataJSON)), signature: arrayToBase64String(new Uint8Array(credentialInfo.response.signature)), userHandle: credentialInfo.response.userHandle ? arrayToBase64String(new Uint8Array(credentialInfo.response.userHandle)) : null } }; const AuthenticatorResponse = JSON.stringify(publicKeyCredential); // The server needs the usernameless path, so username is empty const userField = document.getElementById('user_login'); const username = userField ? userField.value : ''; let response = wwa_ajax(); response.post( `${wwa_login_php_vars.ajax_url}?action=wwa_auth`, `data=${encodeURIComponent(window.btoa(AuthenticatorResponse))}&type=auth&clientid=${clientID}&user=${encodeURIComponent(username)}&conditional=true&remember=${wwa_login_php_vars.remember_me === 'false' ? 'false' : (document.getElementById('rememberme') ? (document.getElementById('rememberme').checked ? 'true' : 'false') : 'false')}` , (resData, resStatus) => { wwa_conditional_ui_active = false; if (resStatus && resData === 'true') { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_6; }, 'class'); const redirectInput = document.querySelector('p.submit input[name="redirect_to"]'); const redirectTo = redirectInput ? redirectInput.value : (getQueryString('redirect_to') || wwa_login_php_vars.admin_url); setTimeout(() => { window.location.href = redirectTo; }, 200); } else { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.terminology === 'passkey' ? `${wwa_passkey_notice_svg} ${wwa_login_php_vars.i18n_2}` : ` ${wwa_login_php_vars.i18n_2}`; }, 'class'); wwa_dom('user_login', (dom) => { dom.readOnly = false; }, 'id'); wwa_dom('#wp-webauthn-check, #wp-webauthn', (dom) => { dom.disabled = false; }); // Restart Conditional UI after a failed attempt wwa_start_conditional_ui(); } } ); }).catch((err) => { wwa_conditional_ui_active = false; // AbortError is expected when check() aborts — do nothing if (err && err.name !== 'AbortError') { console.warn('WP-WebAuthn Conditional UI error:', err); } }); } ); }).catch(() => { // isConditionalMediationAvailable not supported or threw — silently ignore }); } document.addEventListener('DOMContentLoaded', () => { if (document.querySelector('p#nav') && wwa_login_php_vars.password_reset !== 'false') { const placeholder = document.getElementById('wwa-lost-password-link-placeholder'); if (placeholder) { const previous = placeholder.previousSibling; const next = placeholder.nextElementSibling; if (previous && previous.nodeType === Node.TEXT_NODE && previous.data.trim() === wwa_login_php_vars.separator.trim()) { previous.remove(); } else if (next && next.nodeType === Node.TEXT_NODE && next.data.trim() === wwa_login_php_vars.separator.trim() && !next.nextElementSibling) { next.remove(); } placeholder.remove(); } } if (document.querySelectorAll('#lostpasswordform, #registerform, .admin-email-confirm-form, #resetpassform').length > 0) { return; } if (document.getElementById('loginform') === null || document.getElementById('loginform').getAttribute('name') !== 'loginform') { return; } document.addEventListener('keydown', parseKey, false); let button_check = document.createElement('button'); button_check.id = 'wp-webauthn-check'; button_check.type = 'button'; button_check.className = 'button button-large button-primary'; button_check.innerHTML = wwa_login_php_vars.i18n_1; let button_toggle = document.createElement('button'); if (wwa_login_php_vars.webauthn_only !== 'true') { button_toggle.id = 'wp-webauthn'; button_toggle.type = 'button'; button_toggle.className = 'button button-large'; button_toggle.innerHTML = ''; button_toggle.title = wwa_login_php_vars.i18n_13; } let submit = document.getElementById('wp-submit'); if (submit) { if (wwa_login_php_vars.webauthn_only !== 'true') { submit.parentNode.insertBefore(button_toggle, submit.nextElementSibling); } submit.parentNode.insertBefore(button_check, submit.nextElementSibling); } let notice = document.createElement('div'); notice.className = 'wp-webauthn-notice'; notice.innerHTML = wwa_login_php_vars.terminology ==='passkey' ? `${wwa_passkey_notice_svg} ${wwa_login_php_vars.i18n_2}` : ` ${wwa_login_php_vars.i18n_2}`; let forgetmenot = document.getElementsByClassName('forgetmenot'); if (forgetmenot.length > 0) { forgetmenot[0].parentNode.insertBefore(notice, forgetmenot[0]); } wwa_dom('wp-webauthn-notice', (dom) => { const passwordInput = document.getElementsByClassName('user-pass-wrap'); if (passwordInput.length > 0) { dom.style.height = (passwordInput[0].offsetHeight - 10) + 'px'; } else { // WordPress 5.2- const legacyPasswordInput = document.getElementById('loginform').getElementsByTagName('p')[1]; dom.style.height = (legacyPasswordInput.offsetHeight - 10) + 'px'; } }, 'class'); let btnWidth = document.getElementById('wp-submit') ? document.getElementById('wp-submit').clientWidth : 0; if (btnWidth < 20 || btnWidth === undefined) { wwa_dom('wp-webauthn-check', (dom) => { dom.style.width = 'auto' }, 'id'); } else { wwa_dom('wp-webauthn-check', (dom) => { dom.style.width = btnWidth }, 'id'); } if (window.PublicKeyCredential === undefined || navigator.credentials.create === undefined || typeof navigator.credentials.create !== 'function') { wwaSupported = false; wwa_dom('wp-webauthn', (dom) => { dom.style.display = 'none' }, 'id'); } wwa_dom('wp-webauthn-check', (dom) => { dom.addEventListener('click', check, false) }, 'id'); wwa_dom('wp-webauthn', (dom) => { dom.addEventListener('click', toggle, false) }, 'id'); }) window.onresize = function () { if (document.querySelectorAll('#lostpasswordform, #registerform, .admin-email-confirm-form, #resetpassform').length > 0) { return; } let btnWidth = document.getElementById('wp-submit').clientWidth; if (btnWidth < 20 || btnWidth === undefined) { wwa_dom('wp-webauthn-check', (dom) => { dom.style.width = 'auto' }, 'id'); } else { wwa_dom('wp-webauthn-check', (dom) => { dom.style.width = btnWidth }, 'id'); } } function parseKey(event) { if (event.keyCode === 13) { if (wwaSupported && document.getElementById('wp-webauthn-check').style.display === 'block') { event.preventDefault(); wwa_dom('wp-webauthn-check', (dom) => { dom.click() }, 'id'); } } } function base64url2base64(input) { input = input.replace(/=/g, '').replace(/-/g, '+').replace(/_/g, '/'); const pad = input.length % 4; if (pad) { if (pad === 1) { throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding'); } input += new Array(5 - pad).join('='); } return input; } function arrayToBase64String(a) { return btoa(String.fromCharCode(...a)); } function getQueryString(name) { let reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i'); let reg_rewrite = new RegExp(`(^|/)${name}/([^/]*)(/|$)`, 'i'); let r = window.location.search.substr(1).match(reg); let q = window.location.pathname.substr(1).match(reg_rewrite); if (r != null) { return unescape(r[2]); } else if (q != null) { return unescape(q[2]); } else { return null; } } function toggle() { if (document.querySelectorAll('#lostpasswordform, #registerform, .admin-email-confirm-form, #resetpassform').length > 0) { return; } if (document.getElementById('loginform') === null || document.getElementById('loginform').getAttribute('name') !== 'loginform') { return; } if (wwaSupported) { if (document.getElementsByClassName('wp-webauthn-notice')[0].style.display === 'flex') { if (document.getElementsByClassName('user-pass-wrap').length > 0) { wwa_dom('.user-pass-wrap, .forgetmenot, #wp-submit', (dom) => { dom.style.display = 'block' }); } else { // WordPress 5.2- wwa_dom('.forgetmenot, #wp-submit', (dom) => { dom.style.display = 'block' }); document.getElementById('loginform').getElementsByTagName('p')[1].style.display = 'block'; } wwa_dom('wp-webauthn-notice', (dom) => { dom.style.display = 'none' }, 'class'); wwa_dom('wp-webauthn-check', (dom) => { dom.style.cssText = `${dom.style.cssText.split('display: block !important')[0]}display: none !important` }, 'id'); wwa_dom('user_pass', (dom) => { dom.disabled = false }, 'id'); wwa_dom('user_login', (dom) => { dom.setAttribute('autocomplete', 'username'); setTimeout(() => { dom.focus(); }, 0); }, 'id'); wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.terminology ==='passkey' ? `${wwa_passkey_notice_svg} ${wwa_login_php_vars.i18n_2}` : ` ${wwa_login_php_vars.i18n_2}` }, 'class'); wwa_dom('wp-submit', (dom) => { dom.disabled = false }, 'id'); wwa_dom('wp-webauthn', wwa_login_php_vars.terminology ==='passkey' ? (dom) => { dom.innerHTML = wwa_passkey_btn_svg; dom.title = wwa_login_php_vars.i18n_14; dom.style.lineHeight = '0'; } : (dom) => { dom.innerHTML = ''; dom.title = wwa_login_php_vars.i18n_14; }, 'id'); let inputDom = document.querySelectorAll('#loginform label') if (inputDom.length > 0) { if (document.getElementById('wwa-username-label')) { // WordPress 5.2- document.getElementById('wwa-username-label').innerText = wwa_login_php_vars.i18n_10; } else { inputDom[0].innerText = wwa_login_php_vars.i18n_10; } } } else { if (document.getElementsByClassName('user-pass-wrap').length > 0) { wwa_dom('.user-pass-wrap, #wp-submit', (dom) => { dom.style.display = 'none' }); if (wwa_login_php_vars.remember_me === 'false' ) { wwa_dom('.forgetmenot', (dom) => { dom.style.display = 'none' }); } } else { // WordPress 5.2- wwa_dom('#wp-submit', (dom) => { dom.style.display = 'none' }); if (wwa_login_php_vars.remember_me === 'false' ) { wwa_dom('.forgetmenot', (dom) => { dom.style.display = 'none' }); } document.getElementById('loginform').getElementsByTagName('p')[1].style.display = 'none'; } wwa_dom('wp-webauthn-notice', (dom) => { dom.style.display = 'flex' }, 'class'); wwa_dom('wp-webauthn-check', (dom) => { dom.style.cssText = `${dom.style.cssText.split('display: none !important')[0]}display: block !important` }, 'id'); wwa_dom('user_login', (dom) => { dom.setAttribute('autocomplete', 'username webauthn'); setTimeout(() => { dom.focus(); }, 0); }, 'id'); wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.terminology ==='passkey' ? `${wwa_passkey_notice_svg} ${wwa_login_php_vars.i18n_2}` : ` ${wwa_login_php_vars.i18n_2}` }, 'class'); wwa_dom('wp-submit', (dom) => { dom.disabled = true }, 'id'); wwa_dom('wp-webauthn', (dom) => { dom.innerHTML = ''; dom.title = wwa_login_php_vars.i18n_13; dom.style.lineHeight = ''; }, 'id'); let inputDom = document.querySelectorAll('#loginform label') if (inputDom.length > 0) { if (document.getElementById('wwa-username-label')) { // WordPress 5.2- document.getElementById('wwa-username-label').innerText = wwa_login_php_vars.email_login === 'true' ? wwa_login_php_vars.i18n_10 : wwa_login_php_vars.i18n_9; } else { inputDom[0].innerText = wwa_login_php_vars.email_login === 'true' ? wwa_login_php_vars.i18n_10 : wwa_login_php_vars.i18n_9; } } // Start Conditional UI when switching into WebAuthn mode wwa_start_conditional_ui(); } } } // Shake the login form, code from WordPress function wwa_shake(id, a, d) { const c = a.shift(); document.getElementById(id).style.left = c + 'px'; if (a.length > 0) { setTimeout(() => { wwa_shake(id, a, d); }, d); } else { try { document.getElementById(id).style.position = 'static'; wwa_dom('user_login', (dom) => { dom.focus() }, 'id'); } catch (e) { } } } function check() { if (document.querySelectorAll('#lostpasswordform, #registerform, .admin-email-confirm-form, #resetpassform').length > 0) { return; } if (wwaSupported) { if (document.getElementById('user_login').value === '' && wwa_login_php_vars.usernameless !== 'true') { wwa_dom('login_error', (dom) => { dom.remove() }, 'id'); wwa_dom('p.message', (dom) => { dom.remove() }); if (document.querySelectorAll('#login > h1').length > 0) { let dom = document.createElement('div'); dom.id = 'login_error'; dom.innerHTML = wwa_login_php_vars.i18n_11; document.querySelectorAll('#login > h1')[0].parentNode.insertBefore(dom, document.querySelectorAll('#login > h1')[0].nextElementSibling) } // Shake the login form, code from WordPress let shake = new Array(15, 30, 15, 0, -15, -30, -15, 0); shake = shake.concat(shake.concat(shake)); var form = document.forms[0].id; document.getElementById(form).style.position = 'relative'; wwa_shake(form, shake, 20); return; } // Abort any pending Conditional UI before starting a new modal request if (wwa_conditional_ui_abort) { wwa_conditional_ui_abort.abort(); wwa_conditional_ui_abort = null; wwa_conditional_ui_active = false; } wwa_dom('user_login', (dom) => { dom.readOnly = true }, 'id'); wwa_dom('#wp-webauthn-check, #wp-webauthn', (dom) => { dom.disabled = true }); wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_3 }, 'class'); let request = wwa_ajax(); request.get(wwa_login_php_vars.ajax_url, `?action=wwa_auth_start&user=${encodeURIComponent(document.getElementById('user_login').value)}&type=auth`, (rawData, status) => { if (status) { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_4 }, 'class'); let data = rawData; try { data = JSON.parse(rawData); } catch (e) { console.warn(rawData); if (wwa_login_php_vars.usernameless === 'true' && document.getElementById('user_login').value === '') { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_7 + wwa_login_php_vars.i18n_12 }, 'class'); } else { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_7 }, 'class'); } wwa_dom('user_login', (dom) => { dom.readOnly = false }, 'id'); wwa_dom('#wp-webauthn-check, #wp-webauthn', (dom) => { dom.disabled = false }); return; } data.challenge = Uint8Array.from(window.atob(base64url2base64(data.challenge)), (c) => c.charCodeAt(0)); if (data.allowCredentials) { data.allowCredentials = data.allowCredentials.map((item) => { item.id = Uint8Array.from(window.atob(base64url2base64(item.id)), (c) => c.charCodeAt(0)); return item; }); } if (data.allowCredentials && wwa_login_php_vars.allow_authenticator_type && wwa_login_php_vars.allow_authenticator_type !== 'none') { for (let credential of data.allowCredentials) { if (wwa_login_php_vars.allow_authenticator_type === 'cross-platform') { credential.transports = ['usb', 'nfc', 'ble']; } else if (wwa_login_php_vars.allow_authenticator_type === 'platform') { credential.transports = ['internal']; } } } // Save client ID const clientID = data.clientID; delete data.clientID; navigator.credentials.get({ 'publicKey': data }).then((credentialInfo) => { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_5 }, 'class'); return credentialInfo; }).then((data) => { const publicKeyCredential = { id: data.id, type: data.type, rawId: arrayToBase64String(new Uint8Array(data.rawId)), response: { authenticatorData: arrayToBase64String(new Uint8Array(data.response.authenticatorData)), clientDataJSON: arrayToBase64String(new Uint8Array(data.response.clientDataJSON)), signature: arrayToBase64String(new Uint8Array(data.response.signature)), userHandle: data.response.userHandle ? arrayToBase64String(new Uint8Array(data.response.userHandle)) : null } }; return publicKeyCredential; }).then(JSON.stringify).then((AuthenticatorResponse) => { let response = wwa_ajax(); response.post(`${wwa_login_php_vars.ajax_url}?action=wwa_auth`, `data=${encodeURIComponent(window.btoa(AuthenticatorResponse))}&type=auth&clientid=${clientID}&user=${encodeURIComponent(document.getElementById('user_login').value)}&remember=${wwa_login_php_vars.remember_me === 'false' ? 'false' : (document.getElementById('rememberme') ? (document.getElementById('rememberme').checked ? 'true' : 'false') : 'false')}`, (data, status) => { if (status) { if (data === 'true') { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_6 }, 'class'); if (document.querySelectorAll('p.submit input[name="redirect_to"]').length > 0) { setTimeout(() => { window.location.href = document.querySelectorAll('p.submit input[name="redirect_to"]')[0].value; }, 200); } else { if (getQueryString('redirect_to')) { setTimeout(() => { window.location.href = getQueryString('redirect_to'); }, 200); } else { setTimeout(() => { window.location.href = wwa_login_php_vars.admin_url }, 200); } } } else { if (wwa_login_php_vars.usernameless === 'true' && document.getElementById('user_login').value === '') { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_7 + wwa_login_php_vars.i18n_12 }, 'class'); } else { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_7 }, 'class'); } wwa_dom('user_login', (dom) => { dom.readOnly = false }, 'id'); wwa_dom('#wp-webauthn-check, #wp-webauthn', (dom) => { dom.disabled = false }); } } else { if (wwa_login_php_vars.usernameless === 'true' && document.getElementById('user_login').value === '') { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_7 + wwa_login_php_vars.i18n_12 }, 'class'); } else { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_7 }, 'class'); } wwa_dom('user_login', (dom) => { dom.readOnly = false }, 'id'); wwa_dom('#wp-webauthn-check, #wp-webauthn', (dom) => { dom.disabled = false }); } }) }).catch((error) => { console.warn(error); if (wwa_login_php_vars.usernameless === 'true' && document.getElementById('user_login').value === '') { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_7 + wwa_login_php_vars.i18n_12 }, 'class'); } else { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_7 }, 'class'); } wwa_dom('user_login', (dom) => { dom.readOnly = false }, 'id'); wwa_dom('#wp-webauthn-check, #wp-webauthn', (dom) => { dom.disabled = false }); }) } else { if (wwa_login_php_vars.usernameless === 'true' && document.getElementById('user_login').value === '') { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_7 + wwa_login_php_vars.i18n_12 }, 'class'); } else { wwa_dom('wp-webauthn-notice', (dom) => { dom.innerHTML = wwa_login_php_vars.i18n_7 }, 'class'); } wwa_dom('user_login', (dom) => { dom.readOnly = false }, 'id'); wwa_dom('#wp-webauthn-check, #wp-webauthn', (dom) => { dom.disabled = false }); } }) } }