diff --git a/src/addon/mod/book/providers/book.ts b/src/addon/mod/book/providers/book.ts index d9cf9cd8c..6944ea73e 100644 --- a/src/addon/mod/book/providers/book.ts +++ b/src/addon/mod/book/providers/book.ts @@ -125,7 +125,7 @@ export class AddonModBookProvider { promise = this.filepoolProvider.downloadUrl(siteId, indexUrl, false, AddonModBookProvider.COMPONENT, moduleId); } else { // We return the live URL. - return Promise.resolve(this.sitesProvider.getCurrentSite().fixPluginfileURL(indexUrl)); + return this.sitesProvider.getCurrentSite().checkAndFixPluginfileURL(indexUrl); } return promise.then((url) => { diff --git a/src/addon/mod/imscp/providers/imscp.ts b/src/addon/mod/imscp/providers/imscp.ts index 26591f768..58667b135 100644 --- a/src/addon/mod/imscp/providers/imscp.ts +++ b/src/addon/mod/imscp/providers/imscp.ts @@ -245,7 +245,7 @@ export class AddonModImscpProvider { if (indexUrl) { return this.sitesProvider.getSite(siteId).then((site) => { - return site.fixPluginfileURL(indexUrl); + return site.checkAndFixPluginfileURL(indexUrl); }); } } diff --git a/src/addon/mod/page/providers/helper.ts b/src/addon/mod/page/providers/helper.ts index 7b2f1852e..43887b52a 100644 --- a/src/addon/mod/page/providers/helper.ts +++ b/src/addon/mod/page/providers/helper.ts @@ -76,7 +76,7 @@ export class AddonModPageHelperProvider { AddonModPageProvider.COMPONENT, moduleId); } else { // We return the live URL. - promise = Promise.resolve(this.sitesProvider.getCurrentSite().fixPluginfileURL(indexUrl)); + promise = this.sitesProvider.getCurrentSite().checkAndFixPluginfileURL(indexUrl); } return promise.then((url) => { diff --git a/src/addon/mod/resource/providers/helper.ts b/src/addon/mod/resource/providers/helper.ts index df5dfc870..401783103 100644 --- a/src/addon/mod/resource/providers/helper.ts +++ b/src/addon/mod/resource/providers/helper.ts @@ -82,7 +82,7 @@ export class AddonModResourceHelperProvider { // Error getting directory, there was an error downloading or we're in browser. Return online URL. if (this.appProvider.isOnline() && mainFile.fileurl) { // This URL is going to be injected in an iframe, we need this to make it work. - return Promise.resolve(this.sitesProvider.getCurrentSite().fixPluginfileURL(mainFile.fileurl)); + return this.sitesProvider.getCurrentSite().checkAndFixPluginfileURL(mainFile.fileurl); } return Promise.reject(null); diff --git a/src/classes/site.ts b/src/classes/site.ts index a038bb3e0..e1f0fb458 100644 --- a/src/classes/site.ts +++ b/src/classes/site.ts @@ -230,6 +230,8 @@ export class CoreSite { protected ongoingRequests: { [cacheId: string]: Promise } = {}; protected requestQueue: RequestQueueItem[] = []; protected requestQueueTimeout = null; + protected tokenPluginFileWorks: boolean; + protected tokenPluginFileWorksPromise: Promise; /** * Create a site. @@ -1226,6 +1228,18 @@ export class CoreSite { return this.db.execute(sql, [key + '%']); } + /** + * Check if tokenpluginfile can be used, and fix the URL afterwards. + * + * @param url The url to be fixed. + * @return Promise resolved with the fixed URL. + */ + checkAndFixPluginfileURL(url: string): Promise { + return this.checkTokenPluginFile(url).then(() => { + return this.fixPluginfileURL(url); + }); + } + /** * Generic function for adding the wstoken to Moodle urls and for pointing to the correct script. * Uses CoreUtilsProvider.fixPluginfileURL, passing site's token. @@ -1234,7 +1248,10 @@ export class CoreSite { * @return Fixed URL. */ fixPluginfileURL(url: string): string { - return this.urlUtils.fixPluginfileURL(url, this.token, this.siteUrl); + const accessKey = this.tokenPluginFileWorks || typeof this.tokenPluginFileWorks == 'undefined' ? + this.infos && this.infos.userprivateaccesskey : undefined; + + return this.urlUtils.fixPluginfileURL(url, this.token, this.siteUrl, accessKey); } /** @@ -1886,4 +1903,44 @@ export class CoreSite { return expirationDelay; } + + /* + * Check if tokenpluginfile script works in the site. + * + * @param url URL to check. + * @return Promise resolved with boolean: whether it works or not. + */ + checkTokenPluginFile(url: string): Promise { + if (!this.infos || !this.infos.userprivateaccesskey) { + // No access key, cannot use tokenpluginfile. + return Promise.resolve(false); + } else if (typeof this.tokenPluginFileWorks != 'undefined') { + // Already checked. + return Promise.resolve(this.tokenPluginFileWorks); + } else if (this.tokenPluginFileWorksPromise) { + // Check ongoing, use the same promise. + return this.tokenPluginFileWorksPromise; + } else if (!this.appProvider.isOnline()) { + // Not online, cannot check it. Assume it's working, but don't save the result. + return Promise.resolve(true); + } else if (!this.urlUtils.isPluginFileUrl(url)) { + // Not a pluginfile URL, ignore it. + return Promise.resolve(false); + } + + url = this.fixPluginfileURL(url); + + this.tokenPluginFileWorksPromise = this.wsProvider.performHead(url).then((result) => { + return result.ok; + }).catch((error) => { + // Error performing head request. + return false; + }).then((result) => { + this.tokenPluginFileWorks = result; + + return result; + }); + + return this.tokenPluginFileWorksPromise; + } } diff --git a/src/core/course/providers/helper.ts b/src/core/course/providers/helper.ts index f4b2f8bcb..d529e5187 100644 --- a/src/core/course/providers/helper.ts +++ b/src/core/course/providers/helper.ts @@ -569,21 +569,22 @@ export class CoreCourseHelperProvider { if (this.fileHelper.shouldOpenInBrowser(mainFile)) { if (this.appProvider.isOnline()) { // Open in browser. - let fixedUrl = site.fixPluginfileURL(fileUrl).replace('&offline=1', ''); - // Remove forcedownload when followed by another param. - fixedUrl = fixedUrl.replace(/forcedownload=\d+&/, ''); - // Remove forcedownload when not followed by any param. - fixedUrl = fixedUrl.replace(/[\?|\&]forcedownload=\d+/, ''); + return site.checkAndFixPluginfileURL(fileUrl).then((fixedUrl) => { + fixedUrl = fixedUrl.replace('&offline=1', ''); + // Remove forcedownload when followed by another param. + fixedUrl = fixedUrl.replace(/forcedownload=\d+&/, ''); + // Remove forcedownload when not followed by any param. + fixedUrl = fixedUrl.replace(/[\?|\&]forcedownload=\d+/, ''); - this.utils.openInBrowser(fixedUrl); + this.utils.openInBrowser(fixedUrl); - if (this.fileProvider.isAvailable()) { - // Download the file if needed (file outdated or not downloaded). - // Download will be in background, don't return the promise. - this.downloadModule(module, courseId, component, componentId, files, siteId); - } + if (this.fileProvider.isAvailable()) { + // Download the file if needed (file outdated or not downloaded). + // Download will be in background, don't return the promise. + this.downloadModule(module, courseId, component, componentId, files, siteId); + } + }); - return; } else { // Not online, get the offline file. It will fail if not found. return this.filepoolProvider.getInternalUrlByUrl(siteId, fileUrl).then((path) => { @@ -664,7 +665,8 @@ export class CoreCourseHelperProvider { }; return this.sitesProvider.getSite(siteId).then((site) => { - const fixedUrl = site.fixPluginfileURL(fileUrl); + return site.checkAndFixPluginfileURL(fileUrl); + }).then((fixedUrl) => { result.fixedUrl = fixedUrl; if (this.fileProvider.isAvailable()) { diff --git a/src/providers/file-helper.ts b/src/providers/file-helper.ts index 1c082111e..a9fc44c1e 100644 --- a/src/providers/file-helper.ts +++ b/src/providers/file-helper.ts @@ -119,7 +119,8 @@ export class CoreFileHelperProvider { siteId = siteId || this.sitesProvider.getCurrentSiteId(); return this.sitesProvider.getSite(siteId).then((site) => { - const fixedUrl = site.fixPluginfileURL(fileUrl); + return site.checkAndFixPluginfileURL(fileUrl); + }).then((fixedUrl) => { if (this.fileProvider.isAvailable()) { let promise; diff --git a/src/providers/filepool.ts b/src/providers/filepool.ts index f2e8afdac..db8b0f9ea 100644 --- a/src/providers/filepool.ts +++ b/src/providers/filepool.ts @@ -1321,7 +1321,7 @@ export class CoreFilepoolProvider { */ protected fixPluginfileURL(siteId: string, fileUrl: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { - return site.fixPluginfileURL(fileUrl); + return site.checkAndFixPluginfileURL(fileUrl); }); } @@ -1417,6 +1417,10 @@ export class CoreFilepoolProvider { // Decode URL. url = this.textUtils.decodeHTML(this.textUtils.decodeURIComponent(url)); + // If site supports it, since 3.8 we use tokenpluginfile instead of pluginfile. + // For compatibility with files already downloaded, we need to use pluginfile to calculate the file ID. + url = url.replace(/\/tokenpluginfile\.php\/[^\/]+\//, '/webservice/pluginfile.php/'); + if (url.indexOf('/webservice/pluginfile') !== -1) { // Remove attributes that do not matter. this.urlAttributes.forEach((regex) => { diff --git a/src/providers/utils/url.ts b/src/providers/utils/url.ts index 2aa7e8ff5..600f84d5e 100644 --- a/src/providers/utils/url.ts +++ b/src/providers/utils/url.ts @@ -130,9 +130,10 @@ export class CoreUrlUtilsProvider { * @param url The url to be fixed. * @param token Token to use. * @param siteUrl The URL of the site the URL belongs to. + * @param accessKey User access key for tokenpluginfile. * @return Fixed URL. */ - fixPluginfileURL(url: string, token: string, siteUrl: string): string { + fixPluginfileURL(url: string, token: string, siteUrl: string, accessKey?: string): string { if (!url) { return ''; } @@ -140,7 +141,7 @@ export class CoreUrlUtilsProvider { url = url.replace(/&/g, '&'); // First check if we need to fix this url or is already fixed. - if (url.indexOf('token=') != -1) { + if (!accessKey && url.indexOf('token=') != -1) { return url; } @@ -149,7 +150,17 @@ export class CoreUrlUtilsProvider { return url; } - // Check if the URL already has params. + const hasSlashParams = !url.match(/[\&?]file=/); + + if (accessKey && hasSlashParams) { + // We have the user access key, use tokenpluginfile.php. + // Do not use it without slash params, the URL doesn't work. + url = url.replace(/(\/webservice)?\/pluginfile\.php/, '/tokenpluginfile.php/' + accessKey); + + return url; + } + + // No access key, use pluginfile.php. Check if the URL already has params. if (url.match(/\?[^=]+=/)) { url += '&'; } else {