diff --git a/src/core/directives/format-text.ts b/src/core/directives/format-text.ts index 7abae64d9..f98e15bfa 100644 --- a/src/core/directives/format-text.ts +++ b/src/core/directives/format-text.ts @@ -688,7 +688,10 @@ export class CoreFormatTextDirective implements OnChanges { if (currentSite?.containsUrl(src)) { // URL points to current site, try to use auto-login. - const finalUrl = await currentSite.getAutoLoginUrl(src, false); + // Remove iframe src, otherwise it can cause auto-login issues if there are several iframes with auto-login. + iframe.src = ''; + + const finalUrl = await CoreIframeUtils.getAutoLoginUrlForIframe(iframe, src); await CoreIframeUtils.fixIframeCookies(finalUrl); iframe.src = finalUrl; diff --git a/src/core/services/utils/iframe.ts b/src/core/services/utils/iframe.ts index 800883601..b9bb6c531 100644 --- a/src/core/services/utils/iframe.ts +++ b/src/core/services/utils/iframe.ts @@ -23,7 +23,7 @@ import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUrlUtils } from '@services/utils/url'; -import { CoreUtils } from '@services/utils/utils'; +import { CoreUtils, PromiseDefer } from '@services/utils/utils'; import { makeSingleton, Network, Platform, NgZone, Translate, Diagnostic } from '@singletons'; import { CoreLogger } from '@singletons/logger'; @@ -48,6 +48,7 @@ export class CoreIframeUtilsProvider { static readonly FRAME_TAGS = ['iframe', 'frame', 'object', 'embed']; protected logger: CoreLogger; + protected waitAutoLoginDefer?: PromiseDefer; constructor() { this.logger = CoreLogger.getInstance('CoreUtilsProvider'); @@ -182,6 +183,50 @@ export class CoreIframeUtilsProvider { element.parentElement?.insertBefore(div, element); } + /** + * Get auto-login URL for an iframe. + * + * @param iframe Iframe element. + * @param url Original URL. + * @return Promise resolved with the URL. + */ + async getAutoLoginUrlForIframe(iframe: HTMLIFrameElement, url: string): Promise { + const currentSite = CoreSites.getCurrentSite(); + if (!currentSite) { + return url; + } + + if (this.waitAutoLoginDefer) { + // Another iframe is already using auto-login. Wait for it to finish. + await this.waitAutoLoginDefer.promise; + + // Return the original URL, we can't request a new auto-login. + return url; + } + + // First iframe requesting auto-login. + this.waitAutoLoginDefer = CoreUtils.promiseDefer(); + + const finalUrl = await currentSite.getAutoLoginUrl(url, false); + + // Resolve the promise once the iframe is loaded, or after a certain time. + let unblocked = false; + const unblock = () => { + if (unblocked) { + return; + } + + unblocked = true; + this.waitAutoLoginDefer!.resolve(); + delete this.waitAutoLoginDefer; + }; + + iframe.addEventListener('load', () => unblock()); + setTimeout(() => unblock(), 15000); + + return finalUrl; + } + /** * Given an element, return the content window and document. * Please notice that the element should be an iframe, embed or similar.