author | Narcis Beleuzu <nbeleuzu@mozilla.com> |
Wed, 19 Aug 2020 16:39:33 +0300 | |
changeset 545318 | 269b14751fb00398e6f6ca0d0b48904b0739dd7f |
parent 545317 | 07e51bfc3436c293202dab8f0ef693192c392ec5 |
child 545319 | 2ee74dd329ceac5ae14c04a640013044a087e15b |
push id | 124511 |
push user | nbeleuzu@mozilla.com |
push date | Wed, 19 Aug 2020 13:41:08 +0000 |
treeherder | autoland@269b14751fb0 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1656296 |
milestone | 81.0a1 |
backs out | 1b7eb33c8ec9c16e3023973f3e03175ebf41ec98 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/components/downloads/DownloadsViewUI.jsm +++ b/browser/components/downloads/DownloadsViewUI.jsm @@ -534,17 +534,16 @@ DownloadsViewUI.DownloadElementShell.pro hover = { l10n: "downloads-show-more-information" }; } else { // This download was blocked temporarily by reputation check. In the // Downloads View, the interface depends on the threat severity. switch (verdict) { case Downloads.Error.BLOCK_VERDICT_UNCOMMON: this.showButton("askOpenOrRemoveFile"); break; - case Downloads.Error.BLOCK_VERDICT_INSECURE: case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED: this.showButton("askRemoveFileOrAllow"); break; default: // Assume Downloads.Error.BLOCK_VERDICT_MALWARE this.showButton("removeFile"); break; } @@ -622,18 +621,16 @@ DownloadsViewUI.DownloadElementShell.pro !this.download.error || !this.download.error.becauseBlockedByReputationCheck ) { return [null, null]; } switch (this.download.error.reputationCheckVerdict) { case Downloads.Error.BLOCK_VERDICT_UNCOMMON: return [s.blockedUncommon2, [s.unblockTypeUncommon2, s.unblockTip2]]; - case Downloads.Error.BLOCK_VERDICT_INSECURE: - return [s.blockedInsecure, [s.blockedInsecure, s.unblockTip2]]; case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED: return [ s.blockedPotentiallyUnwanted, [s.unblockTypePotentiallyUnwanted2, s.unblockTip2], ]; case Downloads.Error.BLOCK_VERDICT_MALWARE: return [s.blockedMalware, [s.unblockTypeMalware, s.unblockTip2]]; }
--- a/browser/components/downloads/test/browser/browser_downloads_panel_block.js +++ b/browser/components/downloads/test/browser/browser_downloads_panel_block.js @@ -3,17 +3,16 @@ add_task(async function mainTest() { await task_resetState(); let verdicts = [ Downloads.Error.BLOCK_VERDICT_UNCOMMON, Downloads.Error.BLOCK_VERDICT_MALWARE, Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED, - Downloads.Error.BLOCK_VERDICT_INSECURE, ]; await task_addDownloads(verdicts.map(v => makeDownload(v))); // Check that the richlistitem for each download is correct. for (let i = 0; i < verdicts.length; i++) { await openPanel(); // The current item is always the first one in the listbox since each
--- a/browser/locales/en-US/chrome/browser/downloads/downloads.properties +++ b/browser/locales/en-US/chrome/browser/downloads/downloads.properties @@ -27,17 +27,16 @@ stateCompleted=Completed stateBlockedParentalControls=Blocked by Parental Controls # LOCALIZATION NOTE (blockedMalware, blockedPotentiallyUnwanted, # blockedUncommon2): # These strings are shown in the panel for some types of blocked downloads. You # may need to adjust "downloads.width" in "downloads.dtd" if this turns out to # be longer than the other existing status strings. blockedMalware=This file contains a virus or malware. blockedPotentiallyUnwanted=This file may harm your computer. -blockedInsecure = This file could not be downloaded securely. blockedUncommon2=This file is not commonly downloaded. # LOCALIZATION NOTE (fileMovedOrMissing): # Displayed when a complete download which is not at the original folder. fileMovedOrMissing=File moved or missing # LOCALIZATION NOTE (unblockHeaderUnblock, unblockHeaderOpen, # unblockTypeMalware, unblockTypePotentiallyUnwanted2,
--- a/dom/security/nsContentSecurityUtils.cpp +++ b/dom/security/nsContentSecurityUtils.cpp @@ -8,17 +8,16 @@ #include "nsContentSecurityUtils.h" #include "nsIContentSecurityPolicy.h" #include "nsIChannel.h" #include "nsIHttpChannel.h" #include "nsIMultiPartChannel.h" #include "nsIURI.h" -#include "nsITransfer.h" #if defined(XP_WIN) # include "WinUtils.h" # include <wininet.h> #endif #include "js/Array.h" // JS::GetArrayLength #include "mozilla/ExtensionPolicyService.h" #include "mozilla/Logging.h" @@ -1111,17 +1110,17 @@ void nsContentSecurityUtils::LogMessageT return; } nsContentUtils::ReportToConsoleByWindowID( localizedMsg, nsIScriptError::warningFlag, "Security"_ns, windowID, uri); } /* static */ -long nsContentSecurityUtils::ClassifyDownload( +bool nsContentSecurityUtils::IsDownloadAllowed( nsIChannel* aChannel, const nsAutoCString& aMimeTypeGuess) { MOZ_ASSERT(aChannel, "IsDownloadAllowed without channel?"); nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); nsCOMPtr<nsIURI> contentLocation; aChannel->GetURI(getter_AddRefs(contentLocation)); @@ -1147,33 +1146,33 @@ long nsContentSecurityUtils::ClassifyDow decission != nsIContentPolicy::ACCEPT); if (StaticPrefs::dom_block_download_insecure() && decission != nsIContentPolicy::ACCEPT) { nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); if (httpChannel) { LogMessageToConsole(httpChannel, "MixedContentBlockedDownload"); } - return nsITransfer::DOWNLOAD_POTENTIALLY_UNSAFE; + return false; } if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal()) { - return nsITransfer::DOWNLOAD_ACCEPTABLE; + return true; } if (!StaticPrefs::dom_block_download_in_sandboxed_iframes()) { - return nsITransfer::DOWNLOAD_ACCEPTABLE; + return true; } uint32_t triggeringFlags = loadInfo->GetTriggeringSandboxFlags(); uint32_t currentflags = loadInfo->GetSandboxFlags(); if ((triggeringFlags & SANDBOXED_ALLOW_DOWNLOADS) || (currentflags & SANDBOXED_ALLOW_DOWNLOADS)) { nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); if (httpChannel) { LogMessageToConsole(httpChannel, "IframeSandboxBlockedDownload"); } - return nsITransfer::DOWNLOAD_FORBIDDEN; + return false; } - return nsITransfer::DOWNLOAD_ACCEPTABLE; -} \ No newline at end of file + return true; +}
--- a/dom/security/nsContentSecurityUtils.h +++ b/dom/security/nsContentSecurityUtils.h @@ -46,22 +46,26 @@ class nsContentSecurityUtils { // Helper function which performs the following framing checks // * CSP frame-ancestors // * x-frame-options // If any of the two disallows framing, the channel will be cancelled. static void PerformCSPFrameAncestorAndXFOCheck(nsIChannel* aChannel); // Helper function to Check if a Download is allowed; - static long ClassifyDownload(nsIChannel* aChannel, - const nsAutoCString& aMimeTypeGuess); + static bool IsDownloadAllowed(nsIChannel* aChannel, + const nsAutoCString& aMimeTypeGuess); #if defined(DEBUG) static void AssertAboutPageHasCSP(mozilla::dom::Document* aDocument); #endif static bool ValidateScriptFilename(const char* aFilename, bool aIsSystemRealm); + /* + * Checks if a Channel should be able to proceed a download. + */ + static bool IsDownloadAllowed(nsIChannel* aChannel); // Helper Function to Post a message to the corresponding JS-Console static void LogMessageToConsole(nsIHttpChannel* aChannel, const char* aMsg); }; #endif /* nsContentSecurityUtils_h___ */
--- a/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js +++ b/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js @@ -1,14 +1,8 @@ -ChromeUtils.defineModuleGetter( - this, - "Downloads", - "resource://gre/modules/Downloads.jsm" -); - let INSECURE_BASE_URL = getRootDirectory(gTestPath).replace( "chrome://mochitests/content/", "http://example.com/" ) + "download_page.html"; let SECURE_BASE_URL = getRootDirectory(gTestPath).replace( "chrome://mochitests/content/", @@ -50,50 +44,20 @@ function shouldConsoleError() { Services.console.unregisterListener(listener); resolve(); } } Services.console.registerListener(listener); }); } -async function resetDownloads() { - // Removes all downloads from the download List - let publicList = await Downloads.getList(Downloads.PUBLIC); - let downloads = await publicList.getAll(); - for (let download of downloads) { - publicList.remove(download); - await download.finalize(true); - } -} - -async function shouldNotifyDownloadUI() { - // Waits until a Blocked download was added to the Download List - let list = await Downloads.getList(Downloads.ALL); - await new Promise(res => { - const view = { - onDownloadAdded: aDownload => { - let { error } = aDownload; - if ( - error.becauseBlockedByReputationCheck && - error.reputationCheckVerdict == Downloads.Error.BLOCK_VERDICT_INSECURE - ) { - res(true); - list.removeView(view); - } - }, - }; - }); -} - async function runTest(url, link, checkFunction, decscription) { await SpecialPowers.pushPrefEnv({ set: [["dom.block_download_insecure", true]], }); - await resetDownloads(); let tab = BrowserTestUtils.addTab(gBrowser, url); gBrowser.selectedTab = tab; let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); info("Checking: " + decscription); @@ -123,17 +87,17 @@ add_task(async function() { INSECURE_BASE_URL, "secure", shouldPromptDownload, "Insecure -> Secure should download" ); await runTest( SECURE_BASE_URL, "insecure", - () => Promise.all([shouldNotifyDownloadUI(), shouldConsoleError()]), + shouldConsoleError, "Secure -> Insecure should Error" ); await runTest( SECURE_BASE_URL, "secure", shouldPromptDownload, "Secure -> Secure should Download" );
--- a/toolkit/components/downloads/DownloadCore.jsm +++ b/toolkit/components/downloads/DownloadCore.jsm @@ -1685,17 +1685,16 @@ var DownloadError = function(aProperties /** * These constants are used by the reputationCheckVerdict property and indicate * the detailed reason why a download is blocked. * * @note These values should not be changed because they can be serialized. */ DownloadError.BLOCK_VERDICT_MALWARE = "Malware"; DownloadError.BLOCK_VERDICT_POTENTIALLY_UNWANTED = "PotentiallyUnwanted"; -DownloadError.BLOCK_VERDICT_INSECURE = "Insecure"; DownloadError.BLOCK_VERDICT_UNCOMMON = "Uncommon"; DownloadError.prototype = { __proto__: Error.prototype, /** * The result code associated with this error. */
--- a/toolkit/components/downloads/DownloadLegacy.jsm +++ b/toolkit/components/downloads/DownloadLegacy.jsm @@ -14,21 +14,16 @@ "use strict"; ChromeUtils.defineModuleGetter( this, "Downloads", "resource://gre/modules/Downloads.jsm" ); -ChromeUtils.defineModuleGetter( - this, - "DownloadError", - "resource://gre/modules/DownloadCore.jsm" -); /** * nsITransfer implementation that provides a bridge to a Download object. * * Legacy downloads work differently than the JavaScript implementation. In the * latter, the caller only provides the properties for the Download object and * the entire process is handled by the "start" method. In the legacy * implementation, the caller must create a separate object to execute the @@ -269,43 +264,40 @@ DownloadLegacyTransfer.prototype = { init: function DLT_init( aSource, aTarget, aDisplayName, aMIMEInfo, aStartTime, aTempFile, aCancelable, - aIsPrivate, - aDownloadClassification + aIsPrivate ) { return this._nsITransferInitInternal( aSource, aTarget, aDisplayName, aMIMEInfo, aStartTime, aTempFile, aCancelable, - aIsPrivate, - aDownloadClassification + aIsPrivate ); }, // nsITransfer initWithBrowsingContext( aSource, aTarget, aDisplayName, aMIMEInfo, aStartTime, aTempFile, aCancelable, aIsPrivate, - aDownloadClassification, aBrowsingContext, aHandleInternally ) { let browsingContextId; let userContextId; if (aBrowsingContext && aBrowsingContext.currentWindowGlobal) { browsingContextId = aBrowsingContext.id; let windowGlobal = aBrowsingContext.currentWindowGlobal; @@ -316,33 +308,31 @@ DownloadLegacyTransfer.prototype = { aSource, aTarget, aDisplayName, aMIMEInfo, aStartTime, aTempFile, aCancelable, aIsPrivate, - aDownloadClassification, userContextId, browsingContextId, aHandleInternally ); }, _nsITransferInitInternal( aSource, aTarget, aDisplayName, aMIMEInfo, aStartTime, aTempFile, aCancelable, isPrivate, - aDownloadClassification, userContextId = 0, browsingContextId = 0, handleInternally = false ) { this._cancelable = aCancelable; let launchWhenSucceeded = false, contentType = null, @@ -356,70 +346,54 @@ DownloadLegacyTransfer.prototype = { let appHandler = aMIMEInfo.preferredApplicationHandler; if ( aMIMEInfo.preferredAction == Ci.nsIMIMEInfo.useHelperApp && appHandler instanceof Ci.nsILocalHandlerApp ) { launcherPath = appHandler.executable.path; } } + // Create a new Download object associated to a DownloadLegacySaver, and // wait for it to be available. This operation may cause the entire // download system to initialize before the object is created. - let serialisedDownload = { + Downloads.createDownload({ source: { url: aSource.spec, isPrivate, userContextId, browsingContextId, }, target: { path: aTarget.QueryInterface(Ci.nsIFileURL).file.path, partFilePath: aTempFile && aTempFile.path, }, saver: "legacy", launchWhenSucceeded, contentType, launcherPath, handleInternally, - }; - - // In case the Download was classified as insecure/dangerous - // it is already canceled, so we need to generate and attach the - // corresponding error to the download. - if (aDownloadClassification == Ci.nsITransfer.DOWNLOAD_POTENTIALLY_UNSAFE) { - serialisedDownload.errorObj = { - becauseBlockedByReputationCheck: true, - reputationCheckVerdict: DownloadError.BLOCK_VERDICT_INSECURE, - }; - } - - Downloads.createDownload(serialisedDownload) - .then(async aDownload => { + }) + .then(aDownload => { // Legacy components keep partial data when they use a ".part" file. if (aTempFile) { aDownload.tryToKeepPartialData = true; } // Start the download before allowing it to be controlled. Ignore errors. aDownload.start().catch(() => {}); // Start processing all the other events received through nsITransfer. this._download = aDownload; this._resolveDownload(aDownload); // Add the download to the list, allowing it to be seen and canceled. - await (await Downloads.getList(Downloads.ALL)).add(aDownload); - if (serialisedDownload.errorObj) { - // In case we added an already canceled dummy download - // we need to manually trigger a change event - // as all the animations for finishing downloads are - // listening on onChange. - aDownload._notifyChange(); - } + return Downloads.getList(Downloads.ALL).then(list => + list.add(aDownload) + ); }) .catch(Cu.reportError); }, setSha256Hash(hash) { this._sha256Hash = hash; },
--- a/uriloader/base/nsITransfer.idl +++ b/uriloader/base/nsITransfer.idl @@ -10,20 +10,16 @@ interface nsIURI; interface nsICancelable; interface nsIMIMEInfo; interface nsIFile; webidl BrowsingContext; [scriptable, uuid(37ec75d3-97ad-4da8-afaa-eabe5b4afd73)] interface nsITransfer : nsIWebProgressListener2 { - const unsigned long DOWNLOAD_ACCEPTABLE = 0; - const unsigned long DOWNLOAD_FORBIDDEN = 1; - const unsigned long DOWNLOAD_POTENTIALLY_UNSAFE = 2; - /** * Initializes the transfer with certain properties. This function must * be called prior to accessing any properties on this interface. * * @param aSource The source URI of the transfer. Must not be null. * * @param aTarget The target URI of the transfer. Must not be null. * @@ -50,28 +46,25 @@ interface nsITransfer : nsIWebProgressLi * reference to this object until the download is * finished, at which point they should release the * reference. * * @param aIsPrivate Used to determine the privacy status of the new transfer. * If true, indicates that the transfer was initiated from * a source that desires privacy. * - * @param aDownloadClassification Indicates wheter the dowload is unwanted, - * should be considered dangerous or insecure. */ void init(in nsIURI aSource, in nsIURI aTarget, in AString aDisplayName, in nsIMIMEInfo aMIMEInfo, in PRTime startTime, in nsIFile aTempFile, in nsICancelable aCancelable, - in boolean aIsPrivate, - in long aDownloadClassification); + in boolean aIsPrivate); /** * Same as init, but allows for passing the browsingContext * which will allow for opening the download with the same * userContextId * * @param aBrowsingContext BrowsingContext of the initiating document. * @@ -81,17 +74,16 @@ interface nsITransfer : nsIWebProgressLi void initWithBrowsingContext(in nsIURI aSource, in nsIURI aTarget, in AString aDisplayName, in nsIMIMEInfo aMIMEInfo, in PRTime startTime, in nsIFile aTempFile, in nsICancelable aCancelable, in boolean aIsPrivate, - in long aDownloadClassification, in BrowsingContext aBrowsingContext, in boolean aHandleInternally); /* * Used to notify the transfer object of the hash of the downloaded file. * Must be called on the main thread, only after the download has finished * successfully. * @param aHash The SHA-256 hash in raw bytes of the downloaded file.
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -1573,32 +1573,20 @@ NS_IMETHODIMP nsExternalAppHandler::OnSt nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request); nsresult rv; nsAutoCString MIMEType; if (mMimeInfo) { mMimeInfo->GetMIMEType(MIMEType); } - // Now get the URI - if (aChannel) { - aChannel->GetURI(getter_AddRefs(mSourceUrl)); - } - - mDownloadClassification = - nsContentSecurityUtils::ClassifyDownload(aChannel, MIMEType); - if (mDownloadClassification != nsITransfer::DOWNLOAD_ACCEPTABLE) { - // If the download is rated as forbidden, - // we need to silently cancel the request to make sure - // it wont show up in the download ui. + + if (!nsContentSecurityUtils::IsDownloadAllowed(aChannel, MIMEType)) { mCanceled = true; request->Cancel(NS_ERROR_ABORT); - if (mDownloadClassification != nsITransfer::DOWNLOAD_FORBIDDEN) { - CreateFailedTransfer(); - } return NS_OK; } nsCOMPtr<nsIFileChannel> fileChan(do_QueryInterface(request)); mIsFileChannel = fileChan != nullptr; if (!mIsFileChannel) { // It's possible that this request came from the child process and the // file channel actually lives there. If this returns true, then our @@ -1622,16 +1610,21 @@ NS_IMETHODIMP nsExternalAppHandler::OnSt bool tmp = false; if (NS_SUCCEEDED( props->GetPropertyAsBool(u"docshell.newWindowTarget"_ns, &tmp))) { mMaybeCloseWindowHelper->SetShouldCloseWindow(tmp); } } } + // Now get the URI + if (aChannel) { + aChannel->GetURI(getter_AddRefs(mSourceUrl)); + } + // retarget all load notifications to our docloader instead of the original // window's docloader... RetargetLoadNotifications(request); // Close the underlying DOMWindow if it was opened specifically for the // download. We don't run this in the content process, since we have // an instance running in the parent as well, which will handle this // if needed. @@ -2182,22 +2175,21 @@ nsresult nsExternalAppHandler::CreateTra rv = NS_NewFileURI(getter_AddRefs(target), mFinalFileDestination); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest); if (mBrowsingContext) { rv = transfer->InitWithBrowsingContext( mSourceUrl, target, EmptyString(), mMimeInfo, mTimeDownloadStarted, mTempFile, this, channel && NS_UsePrivateBrowsing(channel), - mDownloadClassification, mBrowsingContext, mHandleInternally); + mBrowsingContext, mHandleInternally); } else { rv = transfer->Init(mSourceUrl, target, EmptyString(), mMimeInfo, mTimeDownloadStarted, mTempFile, this, - channel && NS_UsePrivateBrowsing(channel), - mDownloadClassification); + channel && NS_UsePrivateBrowsing(channel)); } NS_ENSURE_SUCCESS(rv, rv); // If we were cancelled since creating the transfer, just return. It is // always ok to return NS_OK if we are cancelled. Callers of this function // must call Cancel if CreateTransfer fails, but there's no need to cancel // twice. @@ -2251,23 +2243,22 @@ nsresult nsExternalAppHandler::CreateFai rv = NS_NewFileURI(getter_AddRefs(pseudoTarget), pseudoFile); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest); if (mBrowsingContext) { rv = transfer->InitWithBrowsingContext( mSourceUrl, pseudoTarget, EmptyString(), mMimeInfo, mTimeDownloadStarted, nullptr, this, - channel && NS_UsePrivateBrowsing(channel), mDownloadClassification, - mBrowsingContext, mHandleInternally); + channel && NS_UsePrivateBrowsing(channel), mBrowsingContext, + mHandleInternally); } else { rv = transfer->Init(mSourceUrl, pseudoTarget, EmptyString(), mMimeInfo, mTimeDownloadStarted, nullptr, this, - channel && NS_UsePrivateBrowsing(channel), - mDownloadClassification); + channel && NS_UsePrivateBrowsing(channel)); } NS_ENSURE_SUCCESS(rv, rv); // Our failed transfer is ready. mTransfer = std::move(transfer); return NS_OK; }
--- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h @@ -329,23 +329,16 @@ class nsExternalAppHandler final : publi /** * One of the REASON_ constants from nsIHelperAppLauncherDialog. Indicates the * reason the dialog was shown (unknown content type, server requested it, * etc). */ uint32_t mReason; /** - * Indicates if the nsContentSecurityUtils rate this download as - * acceptable, potentialy unwanted or illigal request. - * - */ - int32_t mDownloadClassification; - - /** * Track the executable-ness of the temporary file. */ bool mTempFileIsExecutable; PRTime mTimeDownloadStarted; int64_t mContentLength; int64_t mProgress; /**< Number of bytes received (for sending progress notifications). */