From 26f1734b671623e7c7d4cd3d850c69f0865a7cd5 Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Fri, 22 Nov 2024 15:28:37 +0100
Subject: [PATCH 1/4] feat: show only a loader on a default login flow
if the flow fails, the app-error component will be shown, or if the flow is initialised inside a popup (i.e. the session was lost)
---
.../src/apps/app/app-oauth.element.ts | 45 +++++++++++++++++++
.../src/apps/app/app.element.ts | 29 ++++++------
2 files changed, 58 insertions(+), 16 deletions(-)
create mode 100644 src/Umbraco.Web.UI.Client/src/apps/app/app-oauth.element.ts
diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/app-oauth.element.ts b/src/Umbraco.Web.UI.Client/src/apps/app/app-oauth.element.ts
new file mode 100644
index 000000000000..658e390d1bf7
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/apps/app/app-oauth.element.ts
@@ -0,0 +1,45 @@
+import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
+import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
+
+import './app-error.element.js';
+
+/**
+ * A full page error element that can be used either solo or for instance as the error 500 page and BootFailed
+ */
+@customElement('umb-app-oauth')
+export class UmbAppOauthElement extends UmbLitElement {
+
+ /**
+ * Set to true if the login failed. A message will be shown instead of the loader.
+ * @attr
+ */
+ @property({ type: Boolean })
+ failure = false;
+
+ override render() {
+ // If we have a message, we show the error page
+ // this is most likely happening inside a popup
+ if (this.failure) {
+ return html``;
+ }
+
+ // If we don't have a message, we show the loader, this is most likely happening in the main app
+ // for the normal login flow
+ return html`
+
+
+
+ `;
+ }
+}
+
+export default UmbAppOauthElement;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-app-oauth': UmbAppOauthElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts b/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts
index d48bbbd57dac..752bffd7a12c 100644
--- a/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts
@@ -20,6 +20,7 @@ import {
} from '@umbraco-cms/backoffice/extension-registry';
import { filter, first, firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs';
import { hasOwnOpener, retrieveStoredPath } from '@umbraco-cms/backoffice/utils';
+import UmbAppOauthElement from "./app-oauth.element.ts";
@customElement('umb-app')
export class UmbAppElement extends UmbLitElement {
@@ -60,31 +61,27 @@ export class UmbAppElement extends UmbLitElement {
},
{
path: 'oauth_complete',
- component: () => import('./app-error.element.js'),
+ component: () => import('./app-oauth.element.js'),
setup: (component) => {
if (!this.#authContext) {
- throw new Error('[Fatal] Auth context is not available');
+ (component as UmbAppOauthElement).failure = true;
+ console.error('[Fatal] Auth context is not available');
+ return;
}
const searchParams = new URLSearchParams(window.location.search);
const hasCode = searchParams.has('code');
- (component as UmbAppErrorElement).hideBackButton = true;
- (component as UmbAppErrorElement).errorHeadline = this.localize.term('general_login');
+ if (!hasCode) {
+ (component as UmbAppOauthElement).failure = true;
+ console.error('[Fatal] No code in query parameters');
+ return;
+ }
- // If there is an opener, we are in a popup window, and we should show a different message
- // than if we are in the main window. If we are in the main window, we should redirect to the root.
+ // If we are in the main window (i.e. no opener), we should redirect to the root after the authorization request is completed.
// The authorization request will be completed in the active window (main or popup) and the authorization signal will be sent.
// If we are in a popup window, the storage event in UmbAuthContext will catch the signal and close the window.
// If we are in the main window, the signal will be caught right here and the user will be redirected to the root.
- if (hasOwnOpener(this.backofficePath)) {
- (component as UmbAppErrorElement).errorMessage = hasCode
- ? this.localize.term('errors_externalLoginSuccess')
- : this.localize.term('errors_externalLoginFailed');
- } else {
- (component as UmbAppErrorElement).errorMessage = hasCode
- ? this.localize.term('errors_externalLoginRedirectSuccess')
- : this.localize.term('errors_externalLoginFailed');
-
+ if (!hasOwnOpener(this.backofficePath)) {
this.observe(this.#authContext.authorizationSignal, () => {
// Redirect to the saved state or root
const url = retrieveStoredPath();
@@ -99,7 +96,7 @@ export class UmbAppElement extends UmbLitElement {
}
// Complete the authorization request, which will send the authorization signal
- this.#authContext.completeAuthorizationRequest();
+ this.#authContext.completeAuthorizationRequest().catch(() => undefined);
},
},
{
From a352e9d2ffce59688b26bc7cd82af669f9001bbe Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Fri, 22 Nov 2024 15:29:52 +0100
Subject: [PATCH 2/4] fix: hasOwnOpener did not recognize the local vite url as
its own pathname
it should work better by checking the `startsWith` comparing the pathname, and besides, it seems to work better for the understanding of the function to inverse the true/false check
---
.../src/packages/core/utils/path/has-own-opener.function.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/has-own-opener.function.ts b/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/has-own-opener.function.ts
index 72e72090af2b..3fda364240ed 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/has-own-opener.function.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/has-own-opener.function.ts
@@ -22,11 +22,11 @@ export function hasOwnOpener(pathname?: string, windowLike: Window = globalThis.
return false;
}
- if (pathname && openerLocation.pathname !== pathname) {
- return false;
+ if (pathname && openerLocation.pathname.startsWith(pathname)) {
+ return true;
}
- return true;
+ return false;
} catch {
// If there is a security error, it means that the opener is from a different origin, so we let it fall through
return false;
From 264cdf815a8360325335fc407e5c4756e6d7bef4 Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Fri, 22 Nov 2024 15:52:24 +0100
Subject: [PATCH 3/4] chore: adjust imports
---
src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts b/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts
index 752bffd7a12c..8b7abc3dc5a5 100644
--- a/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts
@@ -20,7 +20,9 @@ import {
} from '@umbraco-cms/backoffice/extension-registry';
import { filter, first, firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs';
import { hasOwnOpener, retrieveStoredPath } from '@umbraco-cms/backoffice/utils';
-import UmbAppOauthElement from "./app-oauth.element.ts";
+import type { UmbAppOauthElement } from "./app-oauth.element.js";
+
+import './app-oauth.element.js';
@customElement('umb-app')
export class UmbAppElement extends UmbLitElement {
From 8a26424807eb4449db92cc5e88266474e447a4d5 Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Fri, 22 Nov 2024 15:53:09 +0100
Subject: [PATCH 4/4] chore: formatting
---
src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts b/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts
index 8b7abc3dc5a5..57bd044230e1 100644
--- a/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts
@@ -20,7 +20,7 @@ import {
} from '@umbraco-cms/backoffice/extension-registry';
import { filter, first, firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs';
import { hasOwnOpener, retrieveStoredPath } from '@umbraco-cms/backoffice/utils';
-import type { UmbAppOauthElement } from "./app-oauth.element.js";
+import type { UmbAppOauthElement } from './app-oauth.element.js';
import './app-oauth.element.js';