зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1216537 - Check and request storage permission if file download is started. r=nalexander,paolo
--HG-- extra : commitid : 6O78T9MWQsE extra : rebase_source : 40b9684f95c8b0c98cd67bed59400496b7b07a25
This commit is contained in:
Родитель
d62ad989e5
Коммит
ff06a08f37
|
@ -460,6 +460,12 @@ this.Download.prototype = {
|
|||
throw new DownloadError({ becauseBlockedByParentalControls: true });
|
||||
}
|
||||
|
||||
// Disallow download if needed runtime permissions have not been granted
|
||||
// by user.
|
||||
if (yield DownloadIntegration.shouldBlockForRuntimePermissions()) {
|
||||
throw new DownloadError({ becauseBlockedByRuntimePermissions: true });
|
||||
}
|
||||
|
||||
// We should check if we have been canceled in the meantime, after all
|
||||
// the previous asynchronous operations have been executed and just
|
||||
// before we call the "execute" method of the saver.
|
||||
|
@ -1495,7 +1501,8 @@ this.DownloadError = function (aProperties)
|
|||
this.message = aProperties.message;
|
||||
} else if (aProperties.becauseBlocked ||
|
||||
aProperties.becauseBlockedByParentalControls ||
|
||||
aProperties.becauseBlockedByReputationCheck) {
|
||||
aProperties.becauseBlockedByReputationCheck ||
|
||||
aProperties.becauseBlockedByRuntimePermissions) {
|
||||
this.message = "Download blocked.";
|
||||
} else {
|
||||
let exception = new Components.Exception("", this.result);
|
||||
|
@ -1522,6 +1529,9 @@ this.DownloadError = function (aProperties)
|
|||
} else if (aProperties.becauseBlockedByReputationCheck) {
|
||||
this.becauseBlocked = true;
|
||||
this.becauseBlockedByReputationCheck = true;
|
||||
} else if (aProperties.becauseBlockedByRuntimePermissions) {
|
||||
this.becauseBlocked = true;
|
||||
this.becauseBlockedByRuntimePermissions = true;
|
||||
} else if (aProperties.becauseBlocked) {
|
||||
this.becauseBlocked = true;
|
||||
}
|
||||
|
@ -1569,6 +1579,15 @@ this.DownloadError.prototype = {
|
|||
*/
|
||||
becauseBlockedByReputationCheck: false,
|
||||
|
||||
/**
|
||||
* Indicates the download was blocked because a runtime permission required to
|
||||
* download files was not granted.
|
||||
*
|
||||
* This does not apply to all systems. On Android this flag is set to true if
|
||||
* a needed runtime permission (storage) has not been granted by the user.
|
||||
*/
|
||||
becauseBlockedByRuntimePermissions: false,
|
||||
|
||||
/**
|
||||
* If this DownloadError was caused by an exception this property will
|
||||
* contain the original exception. This will not be serialized when saving
|
||||
|
@ -1591,6 +1610,7 @@ this.DownloadError.prototype = {
|
|||
becauseBlocked: this.becauseBlocked,
|
||||
becauseBlockedByParentalControls: this.becauseBlockedByParentalControls,
|
||||
becauseBlockedByReputationCheck: this.becauseBlockedByReputationCheck,
|
||||
becauseBlockedByRuntimePermissions: this.becauseBlockedByRuntimePermissions,
|
||||
};
|
||||
|
||||
serializeUnknownProperties(this, serializable);
|
||||
|
@ -1615,7 +1635,8 @@ this.DownloadError.fromSerializable = function (aSerializable) {
|
|||
property != "becauseTargetFailed" &&
|
||||
property != "becauseBlocked" &&
|
||||
property != "becauseBlockedByParentalControls" &&
|
||||
property != "becauseBlockedByReputationCheck");
|
||||
property != "becauseBlockedByReputationCheck" &&
|
||||
property != "becauseBlockedByRuntimePermissions");
|
||||
|
||||
return e;
|
||||
};
|
||||
|
@ -2316,14 +2337,18 @@ this.DownloadLegacySaver.prototype = {
|
|||
*/
|
||||
onProgressBytes: function DLS_onProgressBytes(aCurrentBytes, aTotalBytes)
|
||||
{
|
||||
this.progressWasNotified = true;
|
||||
|
||||
// Ignore progress notifications until we are ready to process them.
|
||||
if (!this.setProgressBytesFn) {
|
||||
// Keep the data from the last progress notification that was received.
|
||||
this.currentBytes = aCurrentBytes;
|
||||
this.totalBytes = aTotalBytes;
|
||||
return;
|
||||
}
|
||||
|
||||
let hasPartFile = !!this.download.target.partFilePath;
|
||||
|
||||
this.progressWasNotified = true;
|
||||
this.setProgressBytesFn(aCurrentBytes, aTotalBytes,
|
||||
aCurrentBytes > 0 && hasPartFile);
|
||||
},
|
||||
|
@ -2433,6 +2458,9 @@ this.DownloadLegacySaver.prototype = {
|
|||
}
|
||||
|
||||
this.setProgressBytesFn = aSetProgressBytesFn;
|
||||
if (this.progressWasNotified) {
|
||||
this.onProgressBytes(this.currentBytes, this.totalBytes);
|
||||
}
|
||||
|
||||
return Task.spawn(function* task_DLS_execute() {
|
||||
try {
|
||||
|
|
|
@ -68,6 +68,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gMIMEService",
|
|||
XPCOMUtils.defineLazyServiceGetter(this, "gExternalProtocolService",
|
||||
"@mozilla.org/uriloader/external-protocol-service;1",
|
||||
"nsIExternalProtocolService");
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "RuntimePermissions",
|
||||
"resource://gre/modules/RuntimePermissions.jsm");
|
||||
#endif
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gParentalControlsService", function() {
|
||||
if ("@mozilla.org/parental-controls-service;1" in Cc) {
|
||||
|
@ -136,6 +140,8 @@ this.DownloadIntegration = {
|
|||
dontLoadObservers: false,
|
||||
dontCheckParentalControls: false,
|
||||
shouldBlockInTest: false,
|
||||
dontCheckRuntimePermissions: false,
|
||||
shouldBlockInTestForRuntimePermissions: false,
|
||||
#ifdef MOZ_URL_CLASSIFIER
|
||||
dontCheckApplicationReputation: false,
|
||||
#else
|
||||
|
@ -498,6 +504,25 @@ this.DownloadIntegration = {
|
|||
return Promise.resolve(shouldBlock);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks to determine whether to block downloads for not granted runtime permissions.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves The boolean indicates to block downloads or not.
|
||||
*/
|
||||
shouldBlockForRuntimePermissions: function DI_shouldBlockForRuntimePermissions() {
|
||||
if (this.dontCheckRuntimePermissions) {
|
||||
return Promise.resolve(this.shouldBlockInTestForRuntimePermissions);
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
return RuntimePermissions.waitForPermissions(RuntimePermissions.WRITE_EXTERNAL_STORAGE)
|
||||
.then(permissionGranted => !permissionGranted);
|
||||
#else
|
||||
return Promise.resolve(false);
|
||||
#endif
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks to determine whether to block downloads because they might be
|
||||
* malware, based on application reputation checks.
|
||||
|
|
|
@ -1640,6 +1640,47 @@ add_task(function* test_blocked_parental_controls_httpstatus450()
|
|||
do_check_false(yield OS.File.exists(download.target.path));
|
||||
});
|
||||
|
||||
/**
|
||||
* Download with runtime permissions
|
||||
*/
|
||||
add_task(function* test_blocked_runtime_permissions()
|
||||
{
|
||||
function cleanup() {
|
||||
DownloadIntegration.shouldBlockInTestForRuntimePermissions = false;
|
||||
}
|
||||
do_register_cleanup(cleanup);
|
||||
DownloadIntegration.shouldBlockInTestForRuntimePermissions = true;
|
||||
|
||||
let download;
|
||||
try {
|
||||
if (!gUseLegacySaver) {
|
||||
// When testing DownloadCopySaver, we want to check that the promise
|
||||
// returned by the "start" method is rejected.
|
||||
download = yield promiseNewDownload();
|
||||
yield download.start();
|
||||
} else {
|
||||
// When testing DownloadLegacySaver, we cannot be sure whether we are
|
||||
// testing the promise returned by the "start" method or we are testing
|
||||
// the "error" property checked by promiseDownloadStopped. This happens
|
||||
// because we don't have control over when the download is started.
|
||||
download = yield promiseStartLegacyDownload();
|
||||
yield promiseDownloadStopped(download);
|
||||
}
|
||||
do_throw("The download should have blocked.");
|
||||
} catch (ex) {
|
||||
if (!(ex instanceof Downloads.Error) || !ex.becauseBlocked) {
|
||||
throw ex;
|
||||
}
|
||||
do_check_true(ex.becauseBlockedByRuntimePermissions);
|
||||
do_check_true(download.error.becauseBlockedByRuntimePermissions);
|
||||
}
|
||||
|
||||
// Now that the download stopped, the target file should not exist.
|
||||
do_check_false(yield OS.File.exists(download.target.path));
|
||||
|
||||
cleanup();
|
||||
});
|
||||
|
||||
/**
|
||||
* Check that DownloadCopySaver can always retrieve the hash.
|
||||
* DownloadLegacySaver can only retrieve the hash when
|
||||
|
|
|
@ -798,6 +798,8 @@ add_task(function test_common_initialize()
|
|||
DownloadIntegration.dontOpenFileAndFolder = true;
|
||||
DownloadIntegration._deferTestOpenFile = Promise.defer();
|
||||
DownloadIntegration._deferTestShowDir = Promise.defer();
|
||||
// Disable checking runtime permissions.
|
||||
DownloadIntegration.dontCheckRuntimePermissions = true;
|
||||
|
||||
// Avoid leaking uncaught promise errors
|
||||
DownloadIntegration._deferTestOpenFile.promise.then(null, () => undefined);
|
||||
|
|
Загрузка…
Ссылка в новой задаче