Merge pull request #3421 from NoelDeMartin/MOBILE-4145

MOBILE-4145: Remove REQUEST_INSTALL_PACKAGES permission
main
Dani Palou 2022-11-03 09:40:16 +01:00 committed by GitHub
commit 61e12d32fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 76 additions and 51 deletions

24
package-lock.json generated
View File

@ -5263,6 +5263,11 @@
} }
} }
}, },
"@moodlehq/cordova-plugin-file-opener": {
"version": "3.0.5-moodle.1",
"resolved": "https://registry.npmjs.org/@moodlehq/cordova-plugin-file-opener/-/cordova-plugin-file-opener-3.0.5-moodle.1.tgz",
"integrity": "sha512-YOa76EQnnanOHDR7swDH2/K6z29rcBkdZPEak7m8lhb2O5f/kvcpJxXjf1JqVsuetsOQ2hdRDAuFLMX5mRKUJw=="
},
"@moodlehq/cordova-plugin-file-transfer": { "@moodlehq/cordova-plugin-file-transfer": {
"version": "1.7.1-moodle.5", "version": "1.7.1-moodle.5",
"resolved": "https://registry.npmjs.org/@moodlehq/cordova-plugin-file-transfer/-/cordova-plugin-file-transfer-1.7.1-moodle.5.tgz", "resolved": "https://registry.npmjs.org/@moodlehq/cordova-plugin-file-transfer/-/cordova-plugin-file-transfer-1.7.1-moodle.5.tgz",
@ -5273,6 +5278,11 @@
"resolved": "https://registry.npmjs.org/@moodlehq/cordova-plugin-inappbrowser/-/cordova-plugin-inappbrowser-5.0.0-moodle.3.tgz", "resolved": "https://registry.npmjs.org/@moodlehq/cordova-plugin-inappbrowser/-/cordova-plugin-inappbrowser-5.0.0-moodle.3.tgz",
"integrity": "sha512-BDW53W8BzHIJY6lqV3IyYIO9Rh3qi/nA3qkwZjvJiw7iohlQMeR67LV+bXjM4I8N1PTGoBSXiS5BmaS9NFi/1A==" "integrity": "sha512-BDW53W8BzHIJY6lqV3IyYIO9Rh3qi/nA3qkwZjvJiw7iohlQMeR67LV+bXjM4I8N1PTGoBSXiS5BmaS9NFi/1A=="
}, },
"@moodlehq/cordova-plugin-intent": {
"version": "2.2.0-moodle.1",
"resolved": "https://registry.npmjs.org/@moodlehq/cordova-plugin-intent/-/cordova-plugin-intent-2.2.0-moodle.1.tgz",
"integrity": "sha512-Pmd+Xa146LcNlU39z8NLElAk7dxp2g75IRQ+zyXkRTzj7h+0JtNgWWw14jFVxOINoMWo0C7ZihJfeQdn+vrVmA=="
},
"@moodlehq/cordova-plugin-ionic-webview": { "@moodlehq/cordova-plugin-ionic-webview": {
"version": "5.0.0-moodle.1", "version": "5.0.0-moodle.1",
"resolved": "https://registry.npmjs.org/@moodlehq/cordova-plugin-ionic-webview/-/cordova-plugin-ionic-webview-5.0.0-moodle.1.tgz", "resolved": "https://registry.npmjs.org/@moodlehq/cordova-plugin-ionic-webview/-/cordova-plugin-ionic-webview-5.0.0-moodle.1.tgz",
@ -13250,11 +13260,6 @@
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
}, },
"com-darryncampbell-cordova-plugin-intent": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/com-darryncampbell-cordova-plugin-intent/-/com-darryncampbell-cordova-plugin-intent-2.2.0.tgz",
"integrity": "sha512-4ESoeYghE9GGuxKi4pnG+6CUJyYjS2j1tOmvlXXEM/9d5aBU47EpWbKKU1gjcfZFM4KCUbyba1NX6xNcH/L/wA=="
},
"combined-stream": { "combined-stream": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -13339,7 +13344,7 @@
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
}, },
"concat-stream": { "concat-stream": {
"version": "1.6.2", "version": "1.6.2",
@ -14230,11 +14235,6 @@
"resolved": "https://registry.npmjs.org/cordova-plugin-file/-/cordova-plugin-file-6.0.2.tgz", "resolved": "https://registry.npmjs.org/cordova-plugin-file/-/cordova-plugin-file-6.0.2.tgz",
"integrity": "sha512-m7cughw327CjONN/qjzsTpSesLaeybksQh420/gRuSXJX5Zt9NfgsSbqqKDon6jnQ9Mm7h7imgyO2uJ34XMBtA==" "integrity": "sha512-m7cughw327CjONN/qjzsTpSesLaeybksQh420/gRuSXJX5Zt9NfgsSbqqKDon6jnQ9Mm7h7imgyO2uJ34XMBtA=="
}, },
"cordova-plugin-file-opener2": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/cordova-plugin-file-opener2/-/cordova-plugin-file-opener2-3.0.5.tgz",
"integrity": "sha512-tjLHDamH5+y0bJZYVe2967L1S4R8tL4Y0rJUzJGoxsyiw3FUlrJNS199POOpzZZ6Xhlntn9a2o7+84r1dMN21A=="
},
"cordova-plugin-geolocation": { "cordova-plugin-geolocation": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/cordova-plugin-geolocation/-/cordova-plugin-geolocation-4.1.0.tgz", "resolved": "https://registry.npmjs.org/cordova-plugin-geolocation/-/cordova-plugin-geolocation-4.1.0.tgz",
@ -27333,7 +27333,7 @@
"properties-parser": { "properties-parser": {
"version": "0.3.1", "version": "0.3.1",
"resolved": "https://registry.npmjs.org/properties-parser/-/properties-parser-0.3.1.tgz", "resolved": "https://registry.npmjs.org/properties-parser/-/properties-parser-0.3.1.tgz",
"integrity": "sha1-ExbpU5/7/ZOEXjabIRAiq9R4dxo=", "integrity": "sha512-AkSQxQAviJ89x4FIxOyHGfO3uund0gvYo7lfD0E+Gp7gFQKrTNgtoYQklu8EhrfHVZUzTwKGZx2r/KDSfnljcA==",
"requires": { "requires": {
"string.prototype.codepointat": "^0.2.0" "string.prototype.codepointat": "^0.2.0"
} }

View File

@ -74,8 +74,10 @@
"@ionic-native/web-intent": "^5.36.0", "@ionic-native/web-intent": "^5.36.0",
"@ionic-native/zip": "^5.36.0", "@ionic-native/zip": "^5.36.0",
"@ionic/angular": "^5.9.2", "@ionic/angular": "^5.9.2",
"@moodlehq/cordova-plugin-file-opener": "^3.0.5-moodle.1",
"@moodlehq/cordova-plugin-file-transfer": "1.7.1-moodle.5", "@moodlehq/cordova-plugin-file-transfer": "1.7.1-moodle.5",
"@moodlehq/cordova-plugin-inappbrowser": "5.0.0-moodle.3", "@moodlehq/cordova-plugin-inappbrowser": "5.0.0-moodle.3",
"@moodlehq/cordova-plugin-intent": "^2.2.0-moodle.1",
"@moodlehq/cordova-plugin-ionic-webview": "5.0.0-moodle.1", "@moodlehq/cordova-plugin-ionic-webview": "5.0.0-moodle.1",
"@moodlehq/cordova-plugin-local-notification": "0.9.0-moodle.7", "@moodlehq/cordova-plugin-local-notification": "0.9.0-moodle.7",
"@moodlehq/cordova-plugin-qrscanner": "3.0.1-moodle.4", "@moodlehq/cordova-plugin-qrscanner": "3.0.1-moodle.4",
@ -87,7 +89,6 @@
"@types/cordova": "0.0.34", "@types/cordova": "0.0.34",
"@types/dom-mediacapture-record": "^1.0.7", "@types/dom-mediacapture-record": "^1.0.7",
"chart.js": "^2.9.4", "chart.js": "^2.9.4",
"com-darryncampbell-cordova-plugin-intent": "^2.2.0",
"cordova": "^11.0.0", "cordova": "^11.0.0",
"cordova-android": "^10.1.1", "cordova-android": "^10.1.1",
"cordova-clipboard": "^1.3.0", "cordova-clipboard": "^1.3.0",
@ -100,7 +101,6 @@
"cordova-plugin-customurlscheme": "^5.0.2", "cordova-plugin-customurlscheme": "^5.0.2",
"cordova-plugin-device": "^2.1.0", "cordova-plugin-device": "^2.1.0",
"cordova-plugin-file": "6.0.2", "cordova-plugin-file": "6.0.2",
"cordova-plugin-file-opener2": "^3.0.5",
"cordova-plugin-geolocation": "^4.1.0", "cordova-plugin-geolocation": "^4.1.0",
"cordova-plugin-ionic-keyboard": "^2.2.0", "cordova-plugin-ionic-keyboard": "^2.2.0",
"cordova-plugin-media": "5.0.4", "cordova-plugin-media": "5.0.4",
@ -207,7 +207,7 @@
"ANDROID_PATHPREFIX": "/" "ANDROID_PATHPREFIX": "/"
}, },
"cordova-plugin-device": {}, "cordova-plugin-device": {},
"cordova-plugin-file-opener2": { "@moodlehq/cordova-plugin-file-opener": {
"ANDROID_SUPPORT_V4_VERSION": "27.+" "ANDROID_SUPPORT_V4_VERSION": "27.+"
}, },
"cordova-plugin-geolocation": { "cordova-plugin-geolocation": {
@ -235,7 +235,7 @@
"ANDROIDX_CORE_VERSION": "1.6.+", "ANDROIDX_CORE_VERSION": "1.6.+",
"FCM_VERSION": "23.+" "FCM_VERSION": "23.+"
}, },
"com-darryncampbell-cordova-plugin-intent": {}, "@moodlehq/cordova-plugin-intent": {},
"nl.kingsquare.cordova.background-audio": {}, "nl.kingsquare.cordova.background-audio": {},
"cordova.plugins.diagnostic": { "cordova.plugins.diagnostic": {
"ANDROID_SUPPORT_VERSION": "28.+", "ANDROID_SUPPORT_VERSION": "28.+",

View File

@ -1474,6 +1474,7 @@
"core.cannotconnecttrouble": "local_moodlemobileapp", "core.cannotconnecttrouble": "local_moodlemobileapp",
"core.cannotconnectverify": "local_moodlemobileapp", "core.cannotconnectverify": "local_moodlemobileapp",
"core.cannotdownloadfiles": "local_moodlemobileapp", "core.cannotdownloadfiles": "local_moodlemobileapp",
"core.cannotinstallapk": "local_moodlemobileapp",
"core.cannotlogoutpageblocks": "local_moodlemobileapp", "core.cannotlogoutpageblocks": "local_moodlemobileapp",
"core.cannotopeninapp": "local_moodlemobileapp", "core.cannotopeninapp": "local_moodlemobileapp",
"core.cannotopeninappdownload": "local_moodlemobileapp", "core.cannotopeninappdownload": "local_moodlemobileapp",

View File

@ -18,6 +18,7 @@
"cannotconnecttrouble": "We're having trouble connecting to your site.", "cannotconnecttrouble": "We're having trouble connecting to your site.",
"cannotconnectverify": "<strong>Please check the address is correct.</strong>", "cannotconnectverify": "<strong>Please check the address is correct.</strong>",
"cannotdownloadfiles": "File downloading is disabled. Please contact your site administrator.", "cannotdownloadfiles": "File downloading is disabled. Please contact your site administrator.",
"cannotinstallapk": "For security reasons, you can't install unknown apps on your device from this app. Please open the file using a browser.",
"cannotlogoutpageblocks": "Please save or discard your changes before continuing.", "cannotlogoutpageblocks": "Please save or discard your changes before continuing.",
"cannotopeninapp": "This file may not work as expected on this device. Would you like to open it anyway?", "cannotopeninapp": "This file may not work as expected on this device. Would you like to open it anyway?",
"cannotopeninappdownload": "This file may not work as expected on this device. Would you like to download it anyway?", "cannotopeninappdownload": "This file may not work as expected on this device. Would you like to download it anyway?",

View File

@ -30,6 +30,7 @@ import { makeSingleton, Translate } from '@singletons';
import { CoreNetworkError } from '@classes/errors/network-error'; import { CoreNetworkError } from '@classes/errors/network-error';
import { CoreConfig } from './config'; import { CoreConfig } from './config';
import { CoreCanceledError } from '@classes/errors/cancelederror'; import { CoreCanceledError } from '@classes/errors/cancelederror';
import { CoreMimetypeUtils } from '@services/utils/mimetype';
/** /**
* Provider to provide some helper functions regarding files and packages. * Provider to provide some helper functions regarding files and packages.
@ -306,18 +307,23 @@ export class CoreFileHelperProvider {
} }
/** /**
* Whether the file has to be opened in browser (external repository). * Whether the file has to be opened in browser.
* The file must have a mimetype attribute.
* *
* @param file The file to check. * @param file The file to check.
* @return Whether the file should be opened in browser. * @return Whether the file should be opened in browser.
*/ */
shouldOpenInBrowser(file: CoreWSFile): boolean { shouldOpenInBrowser(file: CoreWSFile): boolean {
if (!file || !('isexternalfile' in file) || !file.isexternalfile || !file.mimetype) { if (!file.mimetype) {
return false; return false;
} }
const mimetype = file.mimetype; const mimetype = file.mimetype;
if (!('isexternalfile' in file) || !file.isexternalfile) {
return mimetype === 'application/vnd.android.package-archive'
|| CoreMimetypeUtils.getFileExtension(file.filename ?? '') === 'apk';
}
if (mimetype.indexOf('application/vnd.google-apps.') != -1) { if (mimetype.indexOf('application/vnd.google-apps.') != -1) {
// Google Docs file, always open in browser. // Google Docs file, always open in browser.
return true; return true;

View File

@ -217,8 +217,7 @@ export class CoreFileProvider {
): Promise<FileEntry | DirectoryEntry> { ): Promise<FileEntry | DirectoryEntry> {
await this.init(); await this.init();
// Remove basePath if it's in the path. path = this.removeBasePath(path);
path = this.removeStartingSlash(path.replace(this.basePath, ''));
base = base || this.basePath; base = base || this.basePath;
if (path.indexOf('/') == -1) { if (path.indexOf('/') == -1) {
@ -280,8 +279,7 @@ export class CoreFileProvider {
async removeDir(path: string): Promise<void> { async removeDir(path: string): Promise<void> {
await this.init(); await this.init();
// Remove basePath if it's in the path. path = this.removeBasePath(path);
path = this.removeStartingSlash(path.replace(this.basePath, ''));
this.logger.debug('Remove directory: ' + path); this.logger.debug('Remove directory: ' + path);
await File.removeRecursively(this.basePath, path); await File.removeRecursively(this.basePath, path);
@ -296,8 +294,7 @@ export class CoreFileProvider {
async removeFile(path: string): Promise<void> { async removeFile(path: string): Promise<void> {
await this.init(); await this.init();
// Remove basePath if it's in the path. path = this.removeBasePath(path);
path = this.removeStartingSlash(path.replace(this.basePath, ''));
this.logger.debug('Remove file: ' + path); this.logger.debug('Remove file: ' + path);
try { try {
@ -333,8 +330,7 @@ export class CoreFileProvider {
async getDirectoryContents(path: string): Promise<(FileEntry | DirectoryEntry)[]> { async getDirectoryContents(path: string): Promise<(FileEntry | DirectoryEntry)[]> {
await this.init(); await this.init();
// Remove basePath if it's in the path. path = this.removeBasePath(path);
path = this.removeStartingSlash(path.replace(this.basePath, ''));
this.logger.debug('Get contents of dir: ' + path); this.logger.debug('Get contents of dir: ' + path);
const result = await File.listDir(this.basePath, path); const result = await File.listDir(this.basePath, path);
@ -402,8 +398,7 @@ export class CoreFileProvider {
* @return Promise to be resolved when the size is calculated. * @return Promise to be resolved when the size is calculated.
*/ */
getDirectorySize(path: string): Promise<number> { getDirectorySize(path: string): Promise<number> {
// Remove basePath if it's in the path. path = this.removeBasePath(path);
path = this.removeStartingSlash(path.replace(this.basePath, ''));
this.logger.debug('Get size of dir: ' + path); this.logger.debug('Get size of dir: ' + path);
@ -417,8 +412,7 @@ export class CoreFileProvider {
* @return Promise to be resolved when the size is calculated. * @return Promise to be resolved when the size is calculated.
*/ */
getFileSize(path: string): Promise<number> { getFileSize(path: string): Promise<number> {
// Remove basePath if it's in the path. path = this.removeBasePath(path);
path = this.removeStartingSlash(path.replace(this.basePath, ''));
this.logger.debug('Get size of file: ' + path); this.logger.debug('Get size of file: ' + path);
@ -491,8 +485,7 @@ export class CoreFileProvider {
if (!folder) { if (!folder) {
folder = this.basePath; folder = this.basePath;
// Remove basePath if it's in the path. path = this.removeBasePath(path);
path = this.removeStartingSlash(path.replace(this.basePath, ''));
} }
this.logger.debug(`Read file ${path} with format ${format} in folder ${folder}`); this.logger.debug(`Read file ${path} with format ${format} in folder ${folder}`);
@ -593,8 +586,7 @@ export class CoreFileProvider {
async writeFile(path: string, data: string | Blob, append?: boolean): Promise<FileEntry> { async writeFile(path: string, data: string | Blob, append?: boolean): Promise<FileEntry> {
await this.init(); await this.init();
// Remove basePath if it's in the path. path = this.removeBasePath(path);
path = this.removeStartingSlash(path.replace(this.basePath, ''));
this.logger.debug('Write file: ' + path); this.logger.debug('Write file: ' + path);
// Create file (and parent folders) to prevent errors. // Create file (and parent folders) to prevent errors.
@ -840,9 +832,8 @@ export class CoreFileProvider {
await this.init(); await this.init();
// Paths cannot start with "/". Remove basePath if present. from = this.removeBasePath(from);
from = this.removeStartingSlash(from.replace(this.basePath, '')); to = this.removeBasePath(to);
to = this.removeStartingSlash(to.replace(this.basePath, ''));
const toFileAndDir = this.getFileAndDirectoryFromPath(to); const toFileAndDir = this.getFileAndDirectoryFromPath(to);
@ -925,17 +916,13 @@ export class CoreFileProvider {
} }
/** /**
* Remove the base path from a path. If basePath isn't found, return false. * Remove the base path from a path.
* *
* @param path Path to treat. * @param path Path to treat.
* @return Path without basePath if basePath was found, undefined otherwise. * @return Path without basePath.
*/ */
removeBasePath(path: string): string { removeBasePath(path: string): string {
if (path.indexOf(this.basePath) > -1) { return CoreText.removeStartingSlash(path.replace(this.basePath, ''));
return path.replace(this.basePath, '');
}
return path;
} }
/** /**
@ -1036,13 +1023,10 @@ export class CoreFileProvider {
* *
* @param path Path. * @param path Path.
* @return Path without a slash in the first position. * @return Path without a slash in the first position.
* @deprecated since 4.1. Use CoreText.removeStartingSlash instead.
*/ */
removeStartingSlash(path: string): string { removeStartingSlash(path: string): string {
if (path[0] == '/') { return CoreText.removeStartingSlash(path);
return path.substring(1);
}
return path;
} }
/** /**

View File

@ -1410,6 +1410,19 @@ export class CoreFilepoolProvider {
return this.getFilePath(siteId, fileId); return this.getFilePath(siteId, fileId);
} }
/**
* Get the url of a file form its path.
*
* @param siteId The site ID.
* @param path File path.
* @returns File url.
*/
async getFileUrlByPath(siteId: string, path: string): Promise<string> {
const record = await this.filesTables[siteId].getOne({ path });
return record.url;
}
/** /**
* Get site Filepool Folder Path * Get site Filepool Folder Path
* *

View File

@ -36,6 +36,9 @@ import { CoreWindow } from '@singletons/window';
import { CoreColors } from '@singletons/colors'; import { CoreColors } from '@singletons/colors';
import { CorePromisedValue } from '@classes/promised-value'; import { CorePromisedValue } from '@classes/promised-value';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { CoreErrorWithOptions } from '@classes/errors/errorwithtitle';
import { CoreFilepool } from '@services/filepool';
import { CoreSites } from '@services/sites';
export type TreeNode<T> = T & { children: TreeNode<T>[] }; export type TreeNode<T> = T & { children: TreeNode<T>[] };
@ -988,6 +991,23 @@ export class CoreUtilsProvider {
this.openInApp(path); this.openInApp(path);
return; return;
} else if (extension === 'apk' && CoreApp.isAndroid()) {
const url = await CoreUtils.ignoreErrors(
CoreFilepool.getFileUrlByPath(CoreSites.getCurrentSiteId(), CoreFile.removeBasePath(path)),
);
// @todo MOBILE-4167: Handle urls with expired tokens.
throw new CoreErrorWithOptions(
Translate.instant('core.cannotinstallapk'),
undefined,
url
? [{
text: Translate.instant('core.openinbrowser'),
handler: () => this.openInBrowser(url),
}]
: undefined,
);
} }
// Path needs to be decoded, the file won't be opened if the path has %20 instead of spaces and so. // Path needs to be decoded, the file won't be opened if the path has %20 instead of spaces and so.