From 4c3a16774db0d03ada6e83b7882c8e69bf885d2a Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Tue, 26 Mar 2024 10:11:56 +0100 Subject: [PATCH] add handlers to get configuration of a mfa provider --- .../mocks/handlers/user/current.handlers.ts | 21 ++++ .../mfa-login/mfa-provider-default.element.ts | 107 ++++++++++++++++-- 2 files changed, 116 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/user/current.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/user/current.handlers.ts index 4ab1ee22b7..b59917d21e 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/user/current.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/user/current.handlers.ts @@ -12,6 +12,27 @@ export const handlers = [ const mfaLoginProviders = umbUserMockDb.getMfaLoginProviders(); return res(ctx.status(200), ctx.json(mfaLoginProviders)); }), + rest.get(umbracoPath(`${UMB_SLUG}/current/2fa/:providerName`), (req, res, ctx) => { + if (!req.params.providerName) { + return res(ctx.status(400)); + } + + const mfaProviders = umbUserMockDb.getMfaLoginProviders(); + const mfaProvider = mfaProviders.find((p) => p.providerName === req.params.providerName.toString()); + + if (!mfaProvider) { + return res(ctx.status(404)); + } + + return res( + ctx.status(200), + ctx.json({ + $type: 'TwoFactorAuthInfo', + qrCodeSetupImageUrl: 'https://placekitten.com/200/200', + secret: '8b713fc7-8f17-4f5d-b2ac-b53879c75953', + }), + ); + }), rest.post<{ code: string; secret: string }>( umbracoPath(`${UMB_SLUG}/current/2fa/:providerName`), async (req, res, ctx) => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/mfa-login/mfa-provider-default.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/mfa-login/mfa-provider-default.element.ts index 7e3160c8a6..8b3e6665ec 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/mfa-login/mfa-provider-default.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/mfa-login/mfa-provider-default.element.ts @@ -1,6 +1,10 @@ import type { UmbMfaProviderConfigurationElementProps } from '../types.js'; -import { customElement, html, property } from '@umbraco-cms/backoffice/external/lit'; +import { UserResource } from '@umbraco-cms/backoffice/external/backend-api'; +import { css, customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; +import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; @customElement('umb-mfa-provider-default') export class UmbMfaProviderDefaultElement extends UmbLitElement implements UmbMfaProviderConfigurationElementProps { @@ -16,24 +20,103 @@ export class UmbMfaProviderDefaultElement extends UmbLitElement implements UmbMf @property({ attribute: false }) onClose = () => {}; + @state() + _loading = true; + + @state() + _secret = ''; + + @state() + _qrCodeSetupImageUrl = ''; + + #notificationContext?: typeof UMB_NOTIFICATION_CONTEXT.TYPE; + + constructor() { + super(); + + this.consumeContext(UMB_NOTIFICATION_CONTEXT, (context) => { + this.#notificationContext = context; + }); + } + + async firstUpdated() { + await this.#load(); + this._loading = false; + } + + async #load() { + if (!this.providerName) { + this.#peek('Provider name is required'); + throw new Error('Provider name is required'); + } + const { data } = await tryExecuteAndNotify( + this, + UserResource.getUserCurrent2FaByProviderName({ providerName: this.providerName }), + ); + + if (!data) { + this.#peek('No data returned'); + throw new Error('No data returned'); + } + + // Verify that there is a secret + if (!data.secret) { + this.#peek('The provider did not return a secret.'); + throw new Error('No secret returned'); + } + + this._secret = data.secret; + this._qrCodeSetupImageUrl = data.qrCodeSetupImageUrl; + } + render() { + if (this._loading) { + return html``; + } + return html` - -
- - ${this.localize.term('general_close')} - - - ${this.localize.term('general_submit')} - -
-
+
+ +
+
+ + ${this.localize.term('general_close')} + + + ${this.localize.term('general_submit')} + +
+
+
`; } - #onSubmit() { + #peek(message: string) { + this.#notificationContext?.peek('danger', { + data: { + headline: this.localize.term('member_2fa'), + message, + }, + }); + } + + #onSubmit(e: SubmitEvent) { + e.preventDefault(); this.onSubmit({ code: '123456', secret: '123' }); } + + static styles = [ + UmbTextStyles, + css` + #authForm { + height: 100%; + } + `, + ]; } export default UmbMfaProviderDefaultElement;