MOBILE-3694 iframe: Fix auto-login when there are several iframes

main
Dani Palou 2021-05-21 08:24:40 +02:00
parent 90aaa8f9d4
commit 780d4f96db
2 changed files with 50 additions and 2 deletions

View File

@ -688,7 +688,10 @@ export class CoreFormatTextDirective implements OnChanges {
if (currentSite?.containsUrl(src)) { if (currentSite?.containsUrl(src)) {
// URL points to current site, try to use auto-login. // 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); await CoreIframeUtils.fixIframeCookies(finalUrl);
iframe.src = finalUrl; iframe.src = finalUrl;

View File

@ -23,7 +23,7 @@ import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreTextUtils } from '@services/utils/text'; import { CoreTextUtils } from '@services/utils/text';
import { CoreUrlUtils } from '@services/utils/url'; 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 { makeSingleton, Network, Platform, NgZone, Translate, Diagnostic } from '@singletons';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
@ -48,6 +48,7 @@ export class CoreIframeUtilsProvider {
static readonly FRAME_TAGS = ['iframe', 'frame', 'object', 'embed']; static readonly FRAME_TAGS = ['iframe', 'frame', 'object', 'embed'];
protected logger: CoreLogger; protected logger: CoreLogger;
protected waitAutoLoginDefer?: PromiseDefer<void>;
constructor() { constructor() {
this.logger = CoreLogger.getInstance('CoreUtilsProvider'); this.logger = CoreLogger.getInstance('CoreUtilsProvider');
@ -182,6 +183,50 @@ export class CoreIframeUtilsProvider {
element.parentElement?.insertBefore(div, element); 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<string> {
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. * Given an element, return the content window and document.
* Please notice that the element should be an iframe, embed or similar. * Please notice that the element should be an iframe, embed or similar.