MOBILE-3523 ios: Fix embedded iframes cookies in iOS

main
Dani Palou 2020-10-15 10:27:42 +02:00
parent 514ccda794
commit 0124b4d567
3 changed files with 50 additions and 33 deletions

View File

@ -24,9 +24,6 @@ import { CoreUrlUtilsProvider } from '@providers/utils/url';
import { CoreIframeUtilsProvider } from '@providers/utils/iframe';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { CoreUrl } from '@singletons/url';
import { CoreApp } from '@providers/app';
import { WKWebViewCookiesWindow } from 'cordova-plugin-wkwebview-cookies';
@Component({
selector: 'core-iframe',
@ -107,24 +104,7 @@ export class CoreIframeComponent implements OnChanges {
if (changes.src) {
const url = this.urlUtils.getYoutubeEmbedUrl(changes.src.currentValue) || changes.src.currentValue;
if (CoreApp.instance.isIOS() && url && !this.urlUtils.isLocalFileUrl(url)) {
// Save a "fake" cookie for the iframe's domain to fix a bug in WKWebView.
try {
const win = <WKWebViewCookiesWindow> window;
const urlParts = CoreUrl.parse(url);
if (urlParts.domain) {
await win.WKWebViewCookies.setCookie({
name: 'MoodleAppCookieForWKWebView',
value: '1',
domain: urlParts.domain,
});
}
} catch (err) {
// Ignore errors.
this.logger.error('Error setting cookie', err);
}
}
await this.iframeUtils.fixIframeCookies(url);
this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(CoreFile.instance.convertFileSrc(url));

View File

@ -450,6 +450,7 @@ export class CoreFormatTextDirective implements OnChanges {
const div = document.createElement('div'),
canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']),
navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
const promises = [];
div.innerHTML = formatted;
@ -504,7 +505,7 @@ export class CoreFormatTextDirective implements OnChanges {
});
iframes.forEach((iframe) => {
this.treatIframe(iframe, site, canTreatVimeo, navCtrl);
promises.push(this.treatIframe(iframe, site, canTreatVimeo, navCtrl));
});
svgImages.forEach((image) => {
@ -543,10 +544,9 @@ export class CoreFormatTextDirective implements OnChanges {
this.domUtils.handleBootstrapTooltips(div);
// Wait for images to load.
let promise: Promise<any> = null;
if (externalImages.length) {
// Automatically reject the promise after 5 seconds to prevent blocking the user forever.
promise = this.utils.timeoutPromise(this.utils.allPromises(externalImages.map((externalImage): any => {
promises.push(this.utils.timeoutPromise(this.utils.allPromises(externalImages.map((externalImage): any => {
if (externalImage.loaded) {
// Image has already been loaded, no need to wait.
return Promise.resolve();
@ -558,12 +558,10 @@ export class CoreFormatTextDirective implements OnChanges {
resolve();
});
});
})), 5000);
} else {
promise = Promise.resolve();
})), 5000));
}
return promise.catch(() => {
return Promise.all(promises).catch(() => {
// Ignore errors. So content gets always shown.
}).then(() => {
result.div = div;
@ -665,7 +663,8 @@ export class CoreFormatTextDirective implements OnChanges {
* @param canTreatVimeo Whether Vimeo videos can be treated in the site.
* @param navCtrl NavController to use.
*/
protected treatIframe(iframe: HTMLIFrameElement, site: CoreSite, canTreatVimeo: boolean, navCtrl: NavController): void {
protected async treatIframe(iframe: HTMLIFrameElement, site: CoreSite, canTreatVimeo: boolean, navCtrl: NavController)
: Promise<void> {
const src = iframe.src,
currentSite = this.sitesProvider.getCurrentSite();
@ -673,15 +672,19 @@ export class CoreFormatTextDirective implements OnChanges {
if (currentSite && currentSite.containsUrl(src)) {
// URL points to current site, try to use auto-login.
currentSite.getAutoLoginUrl(src, false).then((finalUrl) => {
const finalUrl = await currentSite.getAutoLoginUrl(src, false);
await this.iframeUtils.fixIframeCookies(finalUrl);
iframe.src = finalUrl;
this.iframeUtils.treatFrame(iframe, false, navCtrl);
});
return;
}
await this.iframeUtils.fixIframeCookies(src);
if (src && canTreatVimeo) {
// Check if it's a Vimeo video. If it is, use the wsplayer script instead to make restricted videos work.
const matches = iframe.src.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)/);
@ -714,6 +717,9 @@ export class CoreFormatTextDirective implements OnChanges {
if (site && !site.isVersionGreaterEqualThan('3.7')) {
newUrl += '&width=' + width + '&height=' + height;
}
await this.iframeUtils.fixIframeCookies(newUrl);
iframe.src = newUrl;
if (!iframe.width) {

View File

@ -30,6 +30,7 @@ import { makeSingleton } from '@singletons/core.singletons';
import { CoreUrl } from '@singletons/url';
import { CoreWindow } from '@singletons/window';
import { WKUserScriptWindow, WKUserScriptInjectionTime } from 'cordova-plugin-wkuserscript';
import { WKWebViewCookiesWindow } from 'cordova-plugin-wkwebview-cookies';
/*
* "Utils" service with helper functions for iframes, embed and similar.
@ -488,6 +489,36 @@ export class CoreIframeUtilsProvider {
}
}
}
/**
* Fix cookies for an iframe URL.
*
* @param url URL of the iframe.
* @return Promise resolved when done.
*/
async fixIframeCookies(url: string): Promise<void> {
if (!CoreApp.instance.isIOS() || !url || this.urlUtils.isLocalFileUrl(url)) {
// No need to fix cookies.
return;
}
// Save a "fake" cookie for the iframe's domain to fix a bug in WKWebView.
try {
const win = <WKWebViewCookiesWindow> window;
const urlParts = CoreUrl.parse(url);
if (urlParts.domain) {
await win.WKWebViewCookies.setCookie({
name: 'MoodleAppCookieForWKWebView',
value: '1',
domain: urlParts.domain,
});
}
} catch (err) {
// Ignore errors.
this.logger.error('Error setting cookie', err);
}
}
}
export class CoreIframeUtils extends makeSingleton(CoreIframeUtilsProvider) {}