aboutsummaryrefslogtreecommitdiffstats
path: root/web_src/js
diff options
context:
space:
mode:
Diffstat (limited to 'web_src/js')
-rw-r--r--web_src/js/features/user-auth-webauthn.js43
-rw-r--r--web_src/js/utils.test.js15
2 files changed, 28 insertions, 30 deletions
diff --git a/web_src/js/features/user-auth-webauthn.js b/web_src/js/features/user-auth-webauthn.js
index 8085313d22..c4c2356cb3 100644
--- a/web_src/js/features/user-auth-webauthn.js
+++ b/web_src/js/features/user-auth-webauthn.js
@@ -1,11 +1,9 @@
import {encodeURLEncodedBase64, decodeURLEncodedBase64} from '../utils.js';
-import {showElem, hideElem} from '../utils/dom.js';
+import {showElem} from '../utils/dom.js';
const {appSubUrl, csrfToken} = window.config;
export async function initUserAuthWebAuthn() {
- hideElem('#webauthn-error');
-
const elPrompt = document.querySelector('.user.signin.webauthn-prompt');
if (!elPrompt) {
return;
@@ -25,10 +23,10 @@ export async function initUserAuthWebAuthn() {
for (const cred of options.publicKey.allowCredentials) {
cred.id = decodeURLEncodedBase64(cred.id);
}
- const credential = await navigator.credentials.get({
- publicKey: options.publicKey
- });
try {
+ const credential = await navigator.credentials.get({
+ publicKey: options.publicKey
+ });
await verifyAssertion(credential);
} catch (err) {
if (!options.publicKey.extensions?.appid) {
@@ -36,10 +34,10 @@ export async function initUserAuthWebAuthn() {
return;
}
delete options.publicKey.extensions.appid;
- const credential = await navigator.credentials.get({
- publicKey: options.publicKey
- });
try {
+ const credential = await navigator.credentials.get({
+ publicKey: options.publicKey
+ });
await verifyAssertion(credential);
} catch (err) {
webAuthnError('general', err.message);
@@ -48,7 +46,7 @@ export async function initUserAuthWebAuthn() {
}
async function verifyAssertion(assertedCredential) {
- // Move data into Arrays incase it is super long
+ // Move data into Arrays in case it is super long
const authData = new Uint8Array(assertedCredential.response.authenticatorData);
const clientDataJSON = new Uint8Array(assertedCredential.response.clientDataJSON);
const rawId = new Uint8Array(assertedCredential.rawId);
@@ -137,15 +135,11 @@ function webAuthnError(errorType, message) {
function detectWebAuthnSupport() {
if (!window.isSecureContext) {
- document.getElementById('register-button').disabled = true;
- document.getElementById('login-button').disabled = true;
webAuthnError('insecure');
return false;
}
if (typeof window.PublicKeyCredential !== 'function') {
- document.getElementById('register-button').disabled = true;
- document.getElementById('login-button').disabled = true;
webAuthnError('browser');
return false;
}
@@ -158,15 +152,13 @@ export function initUserAuthWebAuthnRegister() {
if (!elRegister) {
return;
}
-
- hideElem('#webauthn-error');
-
- elRegister.addEventListener('click', (e) => {
+ if (!detectWebAuthnSupport()) {
+ elRegister.disabled = true;
+ return;
+ }
+ elRegister.addEventListener('click', async (e) => {
e.preventDefault();
- if (!detectWebAuthnSupport()) {
- return;
- }
- webAuthnRegisterRequest();
+ await webAuthnRegisterRequest();
});
}
@@ -203,15 +195,12 @@ async function webAuthnRegisterRequest() {
}
}
- let credential;
try {
- credential = await navigator.credentials.create({
+ const credential = await navigator.credentials.create({
publicKey: options.publicKey
});
+ await webauthnRegistered(credential);
} catch (err) {
webAuthnError('unknown', err);
- return;
}
-
- webauthnRegistered(credential);
}
diff --git a/web_src/js/utils.test.js b/web_src/js/utils.test.js
index cf73b63b99..812ef3bedf 100644
--- a/web_src/js/utils.test.js
+++ b/web_src/js/utils.test.js
@@ -133,8 +133,17 @@ test('toAbsoluteUrl', () => {
expect(() => toAbsoluteUrl('path')).toThrowError('unsupported');
});
+const uint8array = (s) => new TextEncoder().encode(s);
test('encodeURLEncodedBase64, decodeURLEncodedBase64', () => {
- expect(encodeURLEncodedBase64(decodeURLEncodedBase64('foo'))).toEqual('foo'); // No = padding
- expect(encodeURLEncodedBase64(decodeURLEncodedBase64('a-minus'))).toEqual('a-minus');
- expect(encodeURLEncodedBase64(decodeURLEncodedBase64('_underscorc'))).toEqual('_underscorc');
+ expect(encodeURLEncodedBase64(uint8array('AA?'))).toEqual('QUE_'); // standard base64: "QUE/"
+ expect(encodeURLEncodedBase64(uint8array('AA~'))).toEqual('QUF-'); // standard base64: "QUF+"
+
+ expect(decodeURLEncodedBase64('QUE/')).toEqual(uint8array('AA?'));
+ expect(decodeURLEncodedBase64('QUF+')).toEqual(uint8array('AA~'));
+ expect(decodeURLEncodedBase64('QUE_')).toEqual(uint8array('AA?'));
+ expect(decodeURLEncodedBase64('QUF-')).toEqual(uint8array('AA~'));
+
+ expect(encodeURLEncodedBase64(uint8array('a'))).toEqual('YQ'); // standard base64: "YQ=="
+ expect(decodeURLEncodedBase64('YQ')).toEqual(uint8array('a'));
+ expect(decodeURLEncodedBase64('YQ==')).toEqual(uint8array('a'));
});