From 3880e4c8d71feaf9d53d368058ef40ffaf616194 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Wed, 10 Apr 2024 05:30:10 +0200 Subject: [PATCH] fix: Use `@simplewebauthn` for frontend logic This simplifies the code a lot and fixes errors with the exisiting custom code, where slightly different base64 values were emitted which are not valid according to the standard. ref: https://github.com/web-auth/webauthn-framework/issues/510 Signed-off-by: Ferdinand Thiessen --- .../src/components/WebAuthn/AddDevice.vue | 157 ++++++++---------- .../src/components/WebAuthn/Device.vue | 4 +- .../src/components/WebAuthn/Section.vue | 34 ++-- apps/settings/src/main-personal-webauth.js | 1 - ...erice.js => WebAuthnRegistrationSerice.ts} | 41 +++-- .../login/PasswordLessLoginForm.vue | 134 +++------------ .../services/WebAuthnAuthenticationService.js | 44 ----- .../services/WebAuthnAuthenticationService.ts | 59 +++++++ core/src/views/Login.vue | 2 - package-lock.json | 15 ++ package.json | 2 + 11 files changed, 224 insertions(+), 269 deletions(-) rename apps/settings/src/service/{WebAuthnRegistrationSerice.js => WebAuthnRegistrationSerice.ts} (50%) delete mode 100644 core/src/services/WebAuthnAuthenticationService.js create mode 100644 core/src/services/WebAuthnAuthenticationService.ts diff --git a/apps/settings/src/components/WebAuthn/AddDevice.vue b/apps/settings/src/components/WebAuthn/AddDevice.vue index b9e9d087a0b..72077003cdd 100644 --- a/apps/settings/src/components/WebAuthn/AddDevice.vue +++ b/apps/settings/src/components/WebAuthn/AddDevice.vue @@ -24,11 +24,11 @@ {{ t('settings', 'Passwordless authentication requires a secure connection.') }}
-
- - {{ t('settings', 'Add WebAuthn device') }} - -
+ + {{ t('settings', 'Add WebAuthn device') }} +
@@ -39,13 +39,14 @@
- - - {{ t('settings', 'Add') }} - +
- diff --git a/apps/settings/src/components/WebAuthn/Device.vue b/apps/settings/src/components/WebAuthn/Device.vue index 1de2661b8dc..319c99c3184 100644 --- a/apps/settings/src/components/WebAuthn/Device.vue +++ b/apps/settings/src/components/WebAuthn/Device.vue @@ -20,7 +20,7 @@ --> diff --git a/apps/settings/src/main-personal-webauth.js b/apps/settings/src/main-personal-webauth.js index dc11ecdbba2..edbdde6ea27 100644 --- a/apps/settings/src/main-personal-webauth.js +++ b/apps/settings/src/main-personal-webauth.js @@ -37,6 +37,5 @@ new View({ initialDevices: devices, isHttps: window.location.protocol === 'https:', isLocalhost: window.location.hostname === 'localhost', - hasPublicKeyCredential: typeof (window.PublicKeyCredential) !== 'undefined', }, }).$mount('#security-webauthn') diff --git a/apps/settings/src/service/WebAuthnRegistrationSerice.js b/apps/settings/src/service/WebAuthnRegistrationSerice.ts similarity index 50% rename from apps/settings/src/service/WebAuthnRegistrationSerice.js rename to apps/settings/src/service/WebAuthnRegistrationSerice.ts index 185dbd8cf28..f95395e865a 100644 --- a/apps/settings/src/service/WebAuthnRegistrationSerice.js +++ b/apps/settings/src/service/WebAuthnRegistrationSerice.ts @@ -20,34 +20,55 @@ * */ -import axios from '@nextcloud/axios' +import type { RegistrationResponseJSON } from '@simplewebauthn/types' + +import { translate as t } from '@nextcloud/l10n' import { generateUrl } from '@nextcloud/router' +import { startRegistration as registerWebAuthn } from '@simplewebauthn/browser' + +import Axios from 'axios' +import axios from '@nextcloud/axios' +import logger from '../logger' /** - * + * Start registering a new device + * @return The device attributes */ export async function startRegistration() { const url = generateUrl('/settings/api/personal/webauthn/registration') - const resp = await axios.get(url) - return resp.data + try { + logger.debug('Fetching webauthn registration data') + const { data } = await axios.get(url) + logger.debug('Start webauthn registration') + const attrs = await registerWebAuthn(data) + return attrs + } catch (e) { + logger.error(e as Error) + if (Axios.isAxiosError(e)) { + throw new Error(t('settings', 'Could not register device: Network error')) + } else if ((e as Error).name === 'InvalidStateError') { + throw new Error(t('settings', 'Could not register device: Probably already registered')) + } + throw new Error(t('settings', 'Could not register device')) + } } /** - * @param {any} name - - * @param {any} data - + * @param name Name of the device + * @param data Device attributes */ -export async function finishRegistration(name, data) { +export async function finishRegistration(name: string, data: RegistrationResponseJSON) { const url = generateUrl('/settings/api/personal/webauthn/registration') - const resp = await axios.post(url, { name, data }) + const resp = await axios.post(url, { name, data: JSON.stringify(data) }) return resp.data } /** - * @param {any} id - + * @param id Remove registered device with that id */ -export async function removeRegistration(id) { +export async function removeRegistration(id: string | number) { const url = generateUrl(`/settings/api/personal/webauthn/registration/${id}`) await axios.delete(url) diff --git a/core/src/components/login/PasswordLessLoginForm.vue b/core/src/components/login/PasswordLessLoginForm.vue index 8a3886e52d0..128adddc303 100644 --- a/core/src/components/login/PasswordLessLoginForm.vue +++ b/core/src/components/login/PasswordLessLoginForm.vue @@ -1,5 +1,5 @@