PageSourceSearch

https://www.bkmf.de/wp-content/plugins/secure-passkeys/assets/frontend/js/webauthn.login.js?ver=1.3.0

js bkmf.de collected 2026-10-02 10:10:23 UTC 8,657 bytes, 284 lines download raw bytes

1const publicKeyCredentialAllowed = window.PublicKeyCredential ? true : false;
2
3document.addEventListener("DOMContentLoaded", function () {
4  const box = document.getElementById("secure-passkey-login-wrapper");
5  const submit = document.querySelector(".submit");
6  if (box && submit) {
7    submit.insertAdjacentElement("afterend", box);
8  }
9  if (box) {
10    box.style.display = "block";
11  }
12});
13
14document.addEventListener("DOMContentLoaded", function () {
15  document
16    .querySelectorAll(
17      'input[name="log"], input[name="username"], input[name="user_login"], #username, #user_login',
18    )
19    .forEach((field) => {
20      if (!field.getAttribute("autocomplete")?.includes("webauthn")) {
21        field.setAttribute("autocomplete", "username webauthn");
22      }
23    });
24
25  let conditionalAbortController = null;
26  let conditionalRequest = null;
27  let isAuthenticating = false;
28
29  document
30    .getElementById("login-via-passkey")
31    .addEventListener("click", async (event) => {
32      event.preventDefault();
33      await loginWithPasskey();
34    });
35
36  async function loginWithPasskey() {
37    if (isAuthenticating) {
38      return;
39    }
40    isAuthenticating = true;
41
42    if (conditionalAbortController) {
43      conditionalAbortController.abort();
44      conditionalAbortController = null;
45    }
46
47    if (conditionalRequest) {
48      try {
49        await conditionalRequest;
50      } catch (e) {}
51      conditionalRequest = null;
52    }
53
54    const errorMessage = document.getElementById("errorMessage");
55    const successMessage = document.getElementById("successMessage");
56    const passkeySigninButton = document.getElementById("login-via-passkey");
57    const spinnerText = document.getElementById("spinnerText");
58    const buttonText = document.getElementById("buttonText");
59
60    errorMessage.style.display = "none";
61    successMessage.style.display = "none";
62    spinnerText.style.display = "inline-block";
63    buttonText.style.display = "none";
64    passkeySigninButton.disabled = true;
65
66    if (!publicKeyCredentialAllowed) {
67      errorMessage.textContent =
68        secure_passkeys_object.i18n.passkeys_not_supported_in_browser;
69      errorMessage.style.display = "block";
70      spinnerText.style.display = "none";
71      buttonText.style.display = "inline";
72      passkeySigninButton.disabled = false;
73      isAuthenticating = false;
74      return;
75    }
76
77    try {
78      const options = await getLoginOptions();
79      let challenge = options.challenge;
80
81      options.challenge = base64ToUint8Array(options.challenge);
82      if (options.allowCredentials && Array.isArray(options.allowCredentials)) {
83        options.allowCredentials = options.allowCredentials.map((cred) => ({
84          ...cred,
85          id: base64ToUint8Array(cred.id),
86        }));
87      }
88
89      const credential = await navigator.credentials.get({
90        publicKey: options,
91      });
92      const data = prepareLoginData(credential);
93      data.challenge = challenge;
94      await postLoginData(data);
95    } catch (error) {
96      if (error instanceof DOMException && error.name === "NotAllowedError") {
97        errorMessage.textContent =
98          secure_passkeys_object.i18n.cancelled_or_no_passkey;
99      } else if (error instanceof DOMException && error.name === "AbortError") {
100        errorMessage.textContent = secure_passkeys_object.i18n.cancelled_login;
101      } else if (error instanceof Error && error.message) {
102        errorMessage.textContent = error.message;
103      } else {
104        errorMessage.textContent = secure_passkeys_object.i18n.failed_login;
105      }
106      errorMessage.style.display = "block";
107      spinnerText.style.display = "none";
108      buttonText.style.display = "inline";
109      passkeySigninButton.disabled = false;
110      isAuthenticating = false;
111    }
112  }
113
114  async function getLoginOptions() {
115    let params = {
116      nonce: secure_passkeys_object.nonce,
117      action: "secure_passkeys_frontend_get_login_options",
118    };
119
120    try {
121      const response = await fetch(secure_passkeys_object.url, {
122        method: "POST",
123        body: new URLSearchParams(params),
124      });
125      const data = await response.json();
126
127      if (data.success) {
128        return data.data;
129      } else if (!data.success && data?.data) {
130        throw new Error(data.data);
131      } else {
132        throw new Error(secure_passkeys_object.i18n.failed_load_options);
133      }
134    } catch (error) {
135      if (error instanceof Error && error.message) {
136        throw error;
137      }
138      throw new Error(secure_passkeys_object.i18n.failed_load_options);
139    }
140  }
141
142  async function postLoginData(params) {
143    params.nonce = secure_passkeys_object.nonce;
144    params.action = "secure_passkeys_frontend_login";
145
146    if (secure_passkeys_object.redirect_to) {
147      params.redirect_to = secure_passkeys_object.redirect_to;
148    }
149
150    const formData = appendParamsToFormData(params);
151
152    try {
153      const response = await fetch(secure_passkeys_object.url, {
154        method: "POST",
155        body: formData,
156      });
157      const data = await response.json();
158
159      if (data.success) {
160        document.getElementById("successMessage").textContent =
161          secure_passkeys_object.i18n.success_login;
162        document.getElementById("successMessage").style.display = "block";
163
164        if (data.data.redirect_url) {
165          window.location.href = data.data.redirect_url;
166        } else {
167          window.location.reload();
168        }
169      } else {
170        throw new Error(data.data);
171      }
172    } catch (error) {
173      if (error instanceof Error && error.message) {
174        throw error;
175      }
176      throw new Error(secure_passkeys_object.i18n.failed_load_options);
177    }
178  }
179
180  function prepareLoginData(credential) {
181    return {
182      id: credential.id,
183      rawId: decodeBase64EncodedASCII(credential.rawId),
184      type: credential.type,
185      response: {
186        clientDataJSON: decodeBase64EncodedASCII(
187          credential.response.clientDataJSON,
188        ),
189        authenticatorData: decodeBase64EncodedASCII(
190          credential.response.authenticatorData,
191        ),
192        signature: decodeBase64EncodedASCII(credential.response.signature),
193        userHandle: credential.response.userHandle
194          ? decodeBase64EncodedASCII(credential.response.userHandle)
195          : null,
196      },
197    };
198  }
199
200  function base64ToUint8Array(value) {
201    return Uint8Array.from(atob(value), (c) =>
201 c.charCodeAt(0));
202  }
203
204  function decodeBase64EncodedASCII(data) {
205    return btoa(String.fromCharCode(...new Uint8Array(data)));
206  }
207
208  function appendParamsToFormData(params) {
209    const formData = new FormData();
210
211    for (let key in params) {
212      if (params.hasOwnProperty(key)) {
213        let paramValue = params[key];
214
215        if (typeof paramValue === "object" && paramValue !== null) {
216          if (Array.isArray(paramValue)) {
217            paramValue.forEach((item, index) => {
218              formData.append(`${key}[${index}]`, item);
219            });
220          } else {
221            for (let subKey in paramValue) {
222              if (paramValue.hasOwnProperty(subKey)) {
223                const subValue = paramValue[subKey];
224                formData.append(`${key}[${subKey}]`, subValue);
225              }
226            }
227          }
228        } else {
229          formData.append(key, paramValue);
230        }
231      }
232    }
233
234    return formData;
235  }
236
237  async function initConditionalUI() {
238    if (
239      !publicKeyCredentialAllowed ||
240      !window.PublicKeyCredential.isConditionalMediationAvailable
241    ) {
242      return;
243    }
244
245    const isCMA =
246      await window.PublicKeyCredential.isConditionalMediationAvailable();
247    if (!isCMA) {
248      return;
249    }
250
251    try {
252      const options = await getLoginOptions();
253      let challenge = options.challenge;
254
255      options.challenge = base64ToUint8Array(options.challenge);
256      if (options.allowCredentials && Array.isArray(options.allowCredentials)) {
257        options.allowCredentials = options.allowCredentials.map((cred) => ({
258          ...cred,
259          id: base64ToUint8Array(cred.id),
260        }));
261      }
262
263      conditionalAbortController = new AbortController();
264
265      conditionalRequest = navigator.credentials.get({
266        publicKey: options,
267        mediation: "conditional",
268        signal: conditionalAbortController.signal,
269      });
270
271      const credential = await conditionalRequest;
272
273      if (credential) {
274        const data = prepareLoginData(credential);
275        data.challenge = challenge;
276        await postLoginData(data);
277      }
278    } catch (error) {
279      // Ignore errors for conditional UI as they are expected when user logs in manually or aborts
280    }
281  }
282
283  initConditionalUI();
284});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.