Skip to content

Commit 0124b4d

Browse files
committed
MOBILE-3523 ios: Fix embedded iframes cookies in iOS
1 parent 514ccda commit 0124b4d

File tree

3 files changed

+50
-33
lines changed

3 files changed

+50
-33
lines changed

src/components/iframe/iframe.ts

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ import { CoreUrlUtilsProvider } from '@providers/utils/url';
2424
import { CoreIframeUtilsProvider } from '@providers/utils/iframe';
2525
import { CoreUtilsProvider } from '@providers/utils/utils';
2626
import { CoreSplitViewComponent } from '@components/split-view/split-view';
27-
import { CoreUrl } from '@singletons/url';
28-
import { CoreApp } from '@providers/app';
29-
import { WKWebViewCookiesWindow } from 'cordova-plugin-wkwebview-cookies';
3027

3128
@Component({
3229
selector: 'core-iframe',
@@ -107,24 +104,7 @@ export class CoreIframeComponent implements OnChanges {
107104
if (changes.src) {
108105
const url = this.urlUtils.getYoutubeEmbedUrl(changes.src.currentValue) || changes.src.currentValue;
109106

110-
if (CoreApp.instance.isIOS() && url && !this.urlUtils.isLocalFileUrl(url)) {
111-
// Save a "fake" cookie for the iframe's domain to fix a bug in WKWebView.
112-
try {
113-
const win = <WKWebViewCookiesWindow> window;
114-
const urlParts = CoreUrl.parse(url);
115-
116-
if (urlParts.domain) {
117-
await win.WKWebViewCookies.setCookie({
118-
name: 'MoodleAppCookieForWKWebView',
119-
value: '1',
120-
domain: urlParts.domain,
121-
});
122-
}
123-
} catch (err) {
124-
// Ignore errors.
125-
this.logger.error('Error setting cookie', err);
126-
}
127-
}
107+
await this.iframeUtils.fixIframeCookies(url);
128108

129109
this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(CoreFile.instance.convertFileSrc(url));
130110

src/directives/format-text.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ export class CoreFormatTextDirective implements OnChanges {
450450
const div = document.createElement('div'),
451451
canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']),
452452
navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
453+
const promises = [];
453454

454455
div.innerHTML = formatted;
455456

@@ -504,7 +505,7 @@ export class CoreFormatTextDirective implements OnChanges {
504505
});
505506

506507
iframes.forEach((iframe) => {
507-
this.treatIframe(iframe, site, canTreatVimeo, navCtrl);
508+
promises.push(this.treatIframe(iframe, site, canTreatVimeo, navCtrl));
508509
});
509510

510511
svgImages.forEach((image) => {
@@ -543,10 +544,9 @@ export class CoreFormatTextDirective implements OnChanges {
543544
this.domUtils.handleBootstrapTooltips(div);
544545

545546
// Wait for images to load.
546-
let promise: Promise<any> = null;
547547
if (externalImages.length) {
548548
// Automatically reject the promise after 5 seconds to prevent blocking the user forever.
549-
promise = this.utils.timeoutPromise(this.utils.allPromises(externalImages.map((externalImage): any => {
549+
promises.push(this.utils.timeoutPromise(this.utils.allPromises(externalImages.map((externalImage): any => {
550550
if (externalImage.loaded) {
551551
// Image has already been loaded, no need to wait.
552552
return Promise.resolve();
@@ -558,12 +558,10 @@ export class CoreFormatTextDirective implements OnChanges {
558558
resolve();
559559
});
560560
});
561-
})), 5000);
562-
} else {
563-
promise = Promise.resolve();
561+
})), 5000));
564562
}
565563

566-
return promise.catch(() => {
564+
return Promise.all(promises).catch(() => {
567565
// Ignore errors. So content gets always shown.
568566
}).then(() => {
569567
result.div = div;
@@ -665,23 +663,28 @@ export class CoreFormatTextDirective implements OnChanges {
665663
* @param canTreatVimeo Whether Vimeo videos can be treated in the site.
666664
* @param navCtrl NavController to use.
667665
*/
668-
protected treatIframe(iframe: HTMLIFrameElement, site: CoreSite, canTreatVimeo: boolean, navCtrl: NavController): void {
666+
protected async treatIframe(iframe: HTMLIFrameElement, site: CoreSite, canTreatVimeo: boolean, navCtrl: NavController)
667+
: Promise<void> {
669668
const src = iframe.src,
670669
currentSite = this.sitesProvider.getCurrentSite();
671670

672671
this.addMediaAdaptClass(iframe);
673672

674673
if (currentSite && currentSite.containsUrl(src)) {
675674
// URL points to current site, try to use auto-login.
676-
currentSite.getAutoLoginUrl(src, false).then((finalUrl) => {
677-
iframe.src = finalUrl;
675+
const finalUrl = await currentSite.getAutoLoginUrl(src, false);
678676

679-
this.iframeUtils.treatFrame(iframe, false, navCtrl);
680-
});
677+
await this.iframeUtils.fixIframeCookies(finalUrl);
678+
679+
iframe.src = finalUrl;
680+
681+
this.iframeUtils.treatFrame(iframe, false, navCtrl);
681682

682683
return;
683684
}
684685

686+
await this.iframeUtils.fixIframeCookies(src);
687+
685688
if (src && canTreatVimeo) {
686689
// Check if it's a Vimeo video. If it is, use the wsplayer script instead to make restricted videos work.
687690
const matches = iframe.src.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)/);
@@ -714,6 +717,9 @@ export class CoreFormatTextDirective implements OnChanges {
714717
if (site && !site.isVersionGreaterEqualThan('3.7')) {
715718
newUrl += '&width=' + width + '&height=' + height;
716719
}
720+
721+
await this.iframeUtils.fixIframeCookies(newUrl);
722+
717723
iframe.src = newUrl;
718724

719725
if (!iframe.width) {

src/providers/utils/iframe.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { makeSingleton } from '@singletons/core.singletons';
3030
import { CoreUrl } from '@singletons/url';
3131
import { CoreWindow } from '@singletons/window';
3232
import { WKUserScriptWindow, WKUserScriptInjectionTime } from 'cordova-plugin-wkuserscript';
33+
import { WKWebViewCookiesWindow } from 'cordova-plugin-wkwebview-cookies';
3334

3435
/*
3536
* "Utils" service with helper functions for iframes, embed and similar.
@@ -488,6 +489,36 @@ export class CoreIframeUtilsProvider {
488489
}
489490
}
490491
}
492+
493+
/**
494+
* Fix cookies for an iframe URL.
495+
*
496+
* @param url URL of the iframe.
497+
* @return Promise resolved when done.
498+
*/
499+
async fixIframeCookies(url: string): Promise<void> {
500+
if (!CoreApp.instance.isIOS() || !url || this.urlUtils.isLocalFileUrl(url)) {
501+
// No need to fix cookies.
502+
return;
503+
}
504+
505+
// Save a "fake" cookie for the iframe's domain to fix a bug in WKWebView.
506+
try {
507+
const win = <WKWebViewCookiesWindow> window;
508+
const urlParts = CoreUrl.parse(url);
509+
510+
if (urlParts.domain) {
511+
await win.WKWebViewCookies.setCookie({
512+
name: 'MoodleAppCookieForWKWebView',
513+
value: '1',
514+
domain: urlParts.domain,
515+
});
516+
}
517+
} catch (err) {
518+
// Ignore errors.
519+
this.logger.error('Error setting cookie', err);
520+
}
521+
}
491522
}
492523

493524
export class CoreIframeUtils extends makeSingleton(CoreIframeUtilsProvider) {}

0 commit comments

Comments
 (0)