[tbb-commits] [tor-browser] 17/65: Bug 19273: Avoid JavaScript patching of the external app helper dialog.

gitolite role git at cupani.torproject.org
Thu Sep 22 19:28:25 UTC 2022


This is an automated email from the git hooks/post-receive script.

richard pushed a commit to branch geckoview-102.3.0esr-12.0-1
in repository tor-browser.

commit 54e3be72303977a4c459b269edd11224bab93479
Author: Kathy Brade <brade at pearlcrescent.com>
AuthorDate: Tue Jun 28 15:13:05 2016 -0400

    Bug 19273: Avoid JavaScript patching of the external app helper dialog.
    
    When handling an external URI or downloading a file, invoke Torbutton's
    external app blocker component (which will present a download warning
    dialog unless the user has checked the "Automatically download files
    from now on" box).
    
    For e10s compatibility, avoid using a modal dialog and instead use
    a callback interface (nsIHelperAppWarningLauncher) to allow Torbutton
    to indicate the user's desire to cancel or continue each request.
    
    Other bugs fixed:
     Bug 21766: Crash with e10s enabled while trying to download a file
     Bug 21886: Download is stalled in non-e10s mode
     Bug 22471: Downloading files via the PDF viewer download button is broken
     Bug 22472: Fix FTP downloads when external helper app dialog is shown
     Bug 22610: Avoid crashes when canceling external helper app downloads
     Bug 22618: Downloading pdf file via file:/// is stalling
---
 .../exthandler/nsExternalHelperAppService.cpp      | 206 +++++++++++++++++----
 uriloader/exthandler/nsExternalHelperAppService.h  |   3 +
 .../exthandler/nsIExternalHelperAppService.idl     |  47 +++++
 3 files changed, 224 insertions(+), 32 deletions(-)

diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
index 0ec02e346617..2a99aa516f4b 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -146,6 +146,9 @@ static const char NEVER_ASK_FOR_OPEN_FILE_PREF[] =
 
 StaticRefPtr<nsIFile> sFallbackDownloadDir;
 
+static const char WARNING_DIALOG_CONTRACT_ID[] =
+    "@torproject.org/torbutton-extAppBlocker;1";
+
 // Helper functions for Content-Disposition headers
 
 /**
@@ -362,6 +365,22 @@ static nsresult GetDownloadDirectory(nsIFile** _directory,
   return NS_OK;
 }
 
+static already_AddRefed<nsIInterfaceRequestor> GetDialogParentAux(
+    BrowsingContext* aBrowsingContext, nsIInterfaceRequestor* aWindowContext) {
+  nsCOMPtr<nsIInterfaceRequestor> dialogParent = aWindowContext;
+
+  if (!dialogParent && aBrowsingContext) {
+    dialogParent = do_QueryInterface(aBrowsingContext->GetDOMWindow());
+  }
+  if (!dialogParent && aBrowsingContext && XRE_IsParentProcess()) {
+    RefPtr<Element> element = aBrowsingContext->Top()->GetEmbedderElement();
+    if (element) {
+      dialogParent = do_QueryInterface(element->OwnerDoc()->GetWindow());
+    }
+  }
+  return dialogParent.forget();
+}
+
 /**
  * Helper for random bytes for the filename of downloaded part files.
  */
@@ -592,6 +611,96 @@ static const char* descriptionOverwriteExtensions[] = {
     "avif", "jxl", "pdf", "svg", "webp", "xml",
 };
 
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+// begin nsExternalLoadURIHandler class definition and implementation
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+class nsExternalLoadURIHandler final : public nsIHelperAppWarningLauncher {
+ public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIHELPERAPPWARNINGLAUNCHER
+
+  nsExternalLoadURIHandler(nsIHandlerInfo* aHandlerInfo, nsIURI* aURI,
+                           nsIPrincipal* aTriggeringPrincipal,
+                           BrowsingContext* aBrowsingContext,
+                           bool aTriggeredExternally);
+
+ protected:
+  ~nsExternalLoadURIHandler();
+
+  nsCOMPtr<nsIHandlerInfo> mHandlerInfo;
+  nsCOMPtr<nsIURI> mURI;
+  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
+  RefPtr<BrowsingContext> mBrowsingContext;
+  bool mTriggeredExternally;
+  nsCOMPtr<nsIHelperAppWarningDialog> mWarningDialog;
+};
+
+NS_IMPL_ADDREF(nsExternalLoadURIHandler)
+NS_IMPL_RELEASE(nsExternalLoadURIHandler)
+
+NS_INTERFACE_MAP_BEGIN(nsExternalLoadURIHandler)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHelperAppWarningLauncher)
+  NS_INTERFACE_MAP_ENTRY(nsIHelperAppWarningLauncher)
+NS_INTERFACE_MAP_END
+
+nsExternalLoadURIHandler::nsExternalLoadURIHandler(
+    nsIHandlerInfo* aHandlerInfo, nsIURI* aURI,
+    nsIPrincipal* aTriggeringPrincipal, BrowsingContext* aBrowsingContext,
+    bool aTriggeredExternally)
+    : mHandlerInfo(aHandlerInfo),
+      mURI(aURI),
+      mTriggeringPrincipal(aTriggeringPrincipal),
+      mBrowsingContext(aBrowsingContext),
+      mTriggeredExternally(aTriggeredExternally)
+
+{
+  nsresult rv = NS_OK;
+  mWarningDialog = do_CreateInstance(WARNING_DIALOG_CONTRACT_ID, &rv);
+  if (NS_SUCCEEDED(rv) && mWarningDialog) {
+    // This will create a reference cycle (the dialog holds a reference to us
+    // as nsIHelperAppWarningLauncher), which will be broken in ContinueRequest
+    // or CancelRequest.
+    nsCOMPtr<nsIInterfaceRequestor> dialogParent =
+        GetDialogParentAux(aBrowsingContext, nullptr);
+    rv = mWarningDialog->MaybeShow(this, dialogParent);
+  }
+
+  if (NS_FAILED(rv)) {
+    // If for some reason we could not open the download warning prompt,
+    // continue with the request.
+    ContinueRequest();
+  }
+}
+
+nsExternalLoadURIHandler::~nsExternalLoadURIHandler() {}
+
+NS_IMETHODIMP nsExternalLoadURIHandler::ContinueRequest() {
+  MOZ_ASSERT(mURI);
+  MOZ_ASSERT(mHandlerInfo);
+
+  // Break our reference cycle with the download warning dialog (set up in
+  // LoadURI).
+  mWarningDialog = nullptr;
+
+  nsresult rv = NS_OK;
+  nsCOMPtr<nsIContentDispatchChooser> chooser =
+      do_CreateInstance("@mozilla.org/content-dispatch-chooser;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return chooser->HandleURI(mHandlerInfo, mURI, mTriggeringPrincipal,
+                            mBrowsingContext, mTriggeredExternally);
+}
+
+NS_IMETHODIMP nsExternalLoadURIHandler::CancelRequest(nsresult aReason) {
+  NS_ENSURE_ARG(NS_FAILED(aReason));
+
+  // Break our reference cycle with the download warning dialog (set up in
+  // LoadURI).
+  mWarningDialog = nullptr;
+
+  return NS_OK;
+}
+
 static StaticRefPtr<nsExternalHelperAppService> sExtHelperAppSvcSingleton;
 
 /**
@@ -614,6 +723,9 @@ nsExternalHelperAppService::GetSingleton() {
   return do_AddRef(sExtHelperAppSvcSingleton);
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+// nsExternalHelperAppService definition and implementation
+//////////////////////////////////////////////////////////////////////////////////////////////////////
 NS_IMPL_ISUPPORTS(nsExternalHelperAppService, nsIExternalHelperAppService,
                   nsPIExternalAppLauncher, nsIExternalProtocolService,
                   nsIMIMEService, nsIObserver, nsISupportsWeakReference)
@@ -1106,14 +1218,14 @@ nsExternalHelperAppService::LoadURI(nsIURI* aURI,
   rv = GetProtocolHandlerInfo(scheme, getter_AddRefs(handler));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIContentDispatchChooser> chooser =
-      do_CreateInstance("@mozilla.org/content-dispatch-chooser;1", &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+  RefPtr<nsExternalLoadURIHandler> h = new nsExternalLoadURIHandler(
+      handler, escapedURI, aTriggeringPrincipal, aBrowsingContext,
+      aTriggeredExternally);
+  if (!h) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
 
-  return chooser->HandleURI(
-      handler, escapedURI,
-      aRedirectPrincipal ? aRedirectPrincipal : aTriggeringPrincipal,
-      aBrowsingContext, aTriggeredExternally);
+  return NS_OK;
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1258,6 +1370,7 @@ NS_INTERFACE_MAP_BEGIN(nsExternalAppHandler)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
   NS_INTERFACE_MAP_ENTRY(nsIHelperAppLauncher)
+  NS_INTERFACE_MAP_ENTRY(nsIHelperAppWarningLauncher)
   NS_INTERFACE_MAP_ENTRY(nsICancelable)
   NS_INTERFACE_MAP_ENTRY(nsIBackgroundFileSaverObserver)
   NS_INTERFACE_MAP_ENTRY(nsINamed)
@@ -1513,18 +1626,7 @@ void nsExternalAppHandler::MaybeApplyDecodingForExtension(
 
 already_AddRefed<nsIInterfaceRequestor>
 nsExternalAppHandler::GetDialogParent() {
-  nsCOMPtr<nsIInterfaceRequestor> dialogParent = mWindowContext;
-
-  if (!dialogParent && mBrowsingContext) {
-    dialogParent = do_QueryInterface(mBrowsingContext->GetDOMWindow());
-  }
-  if (!dialogParent && mBrowsingContext && XRE_IsParentProcess()) {
-    RefPtr<Element> element = mBrowsingContext->Top()->GetEmbedderElement();
-    if (element) {
-      dialogParent = do_QueryInterface(element->OwnerDoc()->GetWindow());
-    }
-  }
-  return dialogParent.forget();
+  return GetDialogParentAux(mBrowsingContext, mWindowContext);
 }
 
 NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
@@ -1672,6 +1774,34 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
     loadInfo->SetForceAllowDataURI(true);
   }
 
+  mWarningDialog = do_CreateInstance(WARNING_DIALOG_CONTRACT_ID, &rv);
+  if (NS_SUCCEEDED(rv) && mWarningDialog) {
+    // This will create a reference cycle (the dialog holds a reference to us
+    // as nsIHelperAppWarningLauncher), which will be broken in ContinueRequest
+    // or CancelRequest.
+    nsCOMPtr<nsIInterfaceRequestor> dialogParent = GetDialogParent();
+    rv = mWarningDialog->MaybeShow(this, dialogParent);
+  }
+
+  if (NS_FAILED(rv)) {
+    // If for some reason we could not open the download warning prompt,
+    // continue with the request.
+    ContinueRequest();
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsExternalAppHandler::ContinueRequest() {
+  nsAutoCString MIMEType;
+  if (mMimeInfo) {
+    mMimeInfo->GetMIMEType(MIMEType);
+  }
+
+  // Break our reference cycle with the download warning dialog (set up in
+  // OnStartRequest).
+  mWarningDialog = nullptr;
+
   // now that the temp file is set up, find out if we need to invoke a dialog
   // asking the user what they want us to do with this content...
 
@@ -1833,20 +1963,24 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
   }
 #endif
 
-  nsAutoCString actionTelem;
-  if (alwaysAsk) {
-    actionTelem.AssignLiteral("ask");
-  } else if (shouldAutomaticallyHandleInternally) {
-    actionTelem.AssignLiteral("internal");
-  } else if (action == nsIMIMEInfo::useHelperApp ||
-             action == nsIMIMEInfo::useSystemDefault) {
-    actionTelem.AssignLiteral("external");
-  } else {
-    actionTelem.AssignLiteral("save");
-  }
+  nsCOMPtr<nsIChannel> aChannel;
+  if (mRequest && (aChannel = do_QueryInterface(mRequest))) {
+    nsAutoCString actionTelem;
+    if (alwaysAsk) {
+      actionTelem.AssignLiteral("ask");
+    } else if (shouldAutomaticallyHandleInternally) {
+      actionTelem.AssignLiteral("internal");
+    } else if (action == nsIMIMEInfo::useHelperApp ||
+              action == nsIMIMEInfo::useSystemDefault) {
+      actionTelem.AssignLiteral("external");
+    } else {
+      actionTelem.AssignLiteral("save");
+    }
 
-  RecordDownloadTelemetry(aChannel, actionTelem.get());
+    RecordDownloadTelemetry(aChannel, actionTelem.get());
+  }
 
+  nsresult rv = NS_OK;
   if (alwaysAsk) {
     // Display the dialog
     mDialog = do_CreateInstance(NS_HELPERAPPLAUNCHERDLG_CONTRACTID, &rv);
@@ -1975,6 +2109,14 @@ bool nsExternalAppHandler::IsDownloadSpam(nsIChannel* aChannel) {
   return false;
 }
 
+NS_IMETHODIMP nsExternalAppHandler::CancelRequest(nsresult aReason) {
+  // Break our reference cycle with the download warning dialog (set up in
+  // OnStartRequest).
+  mWarningDialog = nullptr;
+
+  return Cancel(aReason);
+}
+
 // Convert error info into proper message text and send OnStatusChange
 // notification to the dialog progress listener or nsITransfer implementation.
 void nsExternalAppHandler::SendStatusChange(ErrorType type, nsresult rv,
@@ -2742,7 +2884,7 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) {
   }
 
   // Break our reference cycle with the helper app dialog (set up in
-  // OnStartRequest)
+  // ContinueRequest)
   mDialog = nullptr;
   mDialogShowing = false;
 
diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h
index 439be1645f4f..af5668d4034b 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.h
+++ b/uriloader/exthandler/nsExternalHelperAppService.h
@@ -256,6 +256,7 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
  */
 class nsExternalAppHandler final : public nsIStreamListener,
                                    public nsIHelperAppLauncher,
+                                   public nsIHelperAppWarningLauncher,
                                    public nsIBackgroundFileSaverObserver,
                                    public nsINamed {
  public:
@@ -263,6 +264,7 @@ class nsExternalAppHandler final : public nsIStreamListener,
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSIHELPERAPPLAUNCHER
+  NS_DECL_NSIHELPERAPPWARNINGLAUNCHER
   NS_DECL_NSICANCELABLE
   NS_DECL_NSIBACKGROUNDFILESAVEROBSERVER
   NS_DECL_NSINAMED
@@ -539,6 +541,7 @@ class nsExternalAppHandler final : public nsIStreamListener,
   nsCOMPtr<nsITransfer> mTransfer;
 
   nsCOMPtr<nsIHelperAppLauncherDialog> mDialog;
+  nsCOMPtr<nsIHelperAppWarningDialog> mWarningDialog;
 
   /**
 
diff --git a/uriloader/exthandler/nsIExternalHelperAppService.idl b/uriloader/exthandler/nsIExternalHelperAppService.idl
index 307e6196a89d..632c6d585ffb 100644
--- a/uriloader/exthandler/nsIExternalHelperAppService.idl
+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl
@@ -189,3 +189,50 @@ interface nsIHelperAppLauncher : nsICancelable
    */
   readonly attribute uint64_t browsingContextId;
 };
+
+/**
+  * nsIHelperAppWarningLauncher is implemented by two classes:
+  *   nsExternalLoadURIHandler
+  *   nsExternalAppHandler
+  */
+[scriptable, uuid(cffd508b-4aaf-43ad-99c6-671d35cbc558)]
+interface nsIHelperAppWarningLauncher : nsISupports
+{
+  /**
+   * Callback invoked by the external app warning dialog to continue the
+   * request.
+   * NOTE: This will release the reference to the nsIHelperAppWarningDialog.
+   */
+  void continueRequest();
+
+  /**
+   * Callback invoked by the external app warning dialog to cancel the request.
+   * NOTE: This will release the reference to the nsIHelperAppWarningDialog.
+   *
+   * @param aReason
+   *        Pass a failure code to indicate the reason why this operation is
+   *        being canceled. It is an error to pass a success code.
+   */
+  void cancelRequest(in nsresult aReason);
+};
+
+/**
+ * nsIHelperAppWarningDialog is implemented by Torbutton's external app
+ * blocker (src/components/external-app-blocker.js).
+ */
+[scriptable, uuid(f4899a3f-0df3-42cc-9db8-bdf599e5a208)]
+interface nsIHelperAppWarningDialog : nsISupports
+{
+  /**
+   * Possibly show a launch warning dialog (it will not be shown if the user
+   * has chosen to not see the warning again).
+   *
+   * @param aLauncher
+   *        A nsIHelperAppWarningLauncher to be invoked after the user confirms
+   *        or cancels the download.
+   * @param aWindowContext
+   *        The window associated with the download.
+   */
+  void maybeShow(in nsIHelperAppWarningLauncher aLauncher,
+                 in nsISupports aWindowContext);
+};

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the tbb-commits mailing list