Bug 1161831 - Implement moz-extension protocol. r=bz,r=billm,sr=mcmanus
authorBobby Holley <bobbyholley@gmail.com>
Sun, 19 Jul 2015 18:42:16 -0700
changeset 280064 9b10ef08bfbe105055f128afd5a1023a6e754011
parent 280063 7b078b5605a1bc51ba7fb87b5b81f46f9e8dfad1
child 280065 8843374b8ac7c8c823c3fad5e44a3295f02b6e20
push id3697
push userusarracini@mozilla.com
push dateWed, 22 Jul 2015 14:58:08 +0000
reviewersbz, billm, mcmanus
bugs1161831
milestone42.0a1
Bug 1161831 - Implement moz-extension protocol. r=bz,r=billm,sr=mcmanus The heavy lifting all happened in the previous patch, so this is easy now.
caps/nsIAddonPolicyService.idl
caps/nsScriptSecurityManager.cpp
caps/nsScriptSecurityManager.h
netwerk/build/nsNetCID.h
netwerk/build/nsNetModule.cpp
netwerk/protocol/res/ExtensionProtocolHandler.cpp
netwerk/protocol/res/ExtensionProtocolHandler.h
netwerk/protocol/res/moz.build
toolkit/components/utils/simpleServices.js
--- a/caps/nsIAddonPolicyService.idl
+++ b/caps/nsIAddonPolicyService.idl
@@ -6,17 +6,22 @@
 
 #include "nsISupports.idl"
 #include "nsIURI.idl"
 
 /**
  * This interface allows the security manager to query custom per-addon security
  * policy.
  */
-[scriptable,uuid(fedf126c-988e-42df-82c9-f2ac99cd65f3)]
+[scriptable,uuid(3ec203f8-2bd0-4f4c-8f99-f9f056221231)]
 interface nsIAddonPolicyService : nsISupports
 {
   /**
    * Returns true if unprivileged code associated with the given addon may load
    * data from |aURI|.
    */
   boolean addonMayLoadURI(in AString aAddonId, in nsIURI aURI);
+
+  /**
+   * Returns true if a given extension:// URI is web-accessible.
+   */
+  boolean extensionURILoadableByAnyone(in nsIURI aURI);
 };
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -740,16 +740,26 @@ nsScriptSecurityManager::CheckLoadURIWit
 
     // If the schemes don't match, the policy is specified by the protocol
     // flags on the target URI.  Note that the order of policy checks here is
     // very important!  We start from most restrictive and work our way down.
     // Note that since we're working with the innermost URI, we can just use
     // the methods that work on chains of nested URIs and they will only look
     // at the flags for our one URI.
 
+    // Special case: moz-extension has a whitelist of URIs that are loadable by
+    // anyone.
+    if (targetScheme.EqualsLiteral("moz-extension") && GetAddonPolicyService()) {
+      bool loadable = false;
+      rv = GetAddonPolicyService()->ExtensionURILoadableByAnyone(targetBaseURI, &loadable);
+      if (NS_SUCCEEDED(rv) && loadable) {
+        return NS_OK;
+      }
+    }
+
     // Check for system target URI
     rv = DenyAccessIfURIHasFlags(targetBaseURI,
                                  nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
     if (NS_FAILED(rv)) {
         // Deny access, since the origin principal is not system
         if (reportErrors) {
             ReportError(nullptr, errorTag, sourceURI, aTargetURI);
         }
--- a/caps/nsScriptSecurityManager.h
+++ b/caps/nsScriptSecurityManager.h
@@ -3,20 +3,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsScriptSecurityManager_h__
 #define nsScriptSecurityManager_h__
 
 #include "nsIScriptSecurityManager.h"
+
+#include "nsIAddonPolicyService.h"
+#include "mozilla/Maybe.h"
+#include "nsIAddonPolicyService.h"
 #include "nsIPrincipal.h"
 #include "nsCOMPtr.h"
 #include "nsIChannelEventSink.h"
 #include "nsIObserver.h"
+#include "nsServiceManagerUtils.h"
 #include "plstr.h"
 #include "js/TypeDecls.h"
 
 #include <stdint.h>
 
 class nsCString;
 class nsIIOService;
 class nsIStringBundle;
@@ -119,16 +124,27 @@ private:
     bool mPrefInitialized;
     bool mIsJavaScriptEnabled;
     nsTArray<nsCOMPtr<nsIURI>> mFileURIWhitelist;
 
     // This machinery controls new-style domain policies. The old-style
     // policy machinery will be removed soon.
     nsCOMPtr<nsIDomainPolicy> mDomainPolicy;
 
+    // Cached addon policy service. We can't generate this in Init() because
+    // that's too early to get a service.
+    mozilla::Maybe<nsCOMPtr<nsIAddonPolicyService>> mAddonPolicyService;
+    nsIAddonPolicyService* GetAddonPolicyService()
+    {
+        if (mAddonPolicyService.isNothing()) {
+            mAddonPolicyService.emplace(do_GetService("@mozilla.org/addons/policy-service;1"));
+        }
+        return mAddonPolicyService.ref();
+    }
+
     static bool sStrictFileOriginPolicy;
 
     static nsIIOService    *sIOService;
     static nsIStringBundle *sStrBundle;
     static JSRuntime       *sRuntime;
 };
 
 namespace mozilla {
--- a/netwerk/build/nsNetCID.h
+++ b/netwerk/build/nsNetCID.h
@@ -632,16 +632,24 @@
 #define NS_RESPROTOCOLHANDLER_CID                    \
 { /* e64f152a-9f07-11d3-8cda-0060b0fc14a3 */         \
     0xe64f152a,                                      \
     0x9f07,                                          \
     0x11d3,                                          \
     {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \
 }
 
+#define NS_EXTENSIONPROTOCOLHANDLER_CID              \
+{ /* aea16cd0-f020-4138-b068-0716c4a15b5a */         \
+    0xaea16cd0,                                      \
+    0xf020,                                          \
+    0x4138,                                          \
+    {0xb0, 0x68, 0x07, 0x16, 0xc4, 0xa1, 0x5b, 0x5a} \
+}
+
 #define NS_SUBSTITUTINGURL_CID                       \
 { 0xdea9657c,                                        \
   0x18cf,                                            \
   0x4984,                                            \
   { 0xbd, 0xe9, 0xcc, 0xef, 0x5d, 0x8a, 0xb4, 0x73 } \
 }
 
 /******************************************************************************
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -267,20 +267,22 @@ namespace net {
   NS_GENERIC_FACTORY_CONSTRUCTOR(PackagedAppService)
 } // namespace net
 } // namespace mozilla
 #include "AppProtocolHandler.h"
 
 #ifdef NECKO_PROTOCOL_res
 // resource
 #include "nsResProtocolHandler.h"
+#include "ExtensionProtocolHandler.h"
 #include "SubstitutingProtocolHandler.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsResProtocolHandler, Init)
 
 namespace mozilla {
+NS_GENERIC_FACTORY_CONSTRUCTOR(ExtensionProtocolHandler)
 NS_GENERIC_FACTORY_CONSTRUCTOR(SubstitutingURL)
 } // namespace mozilla
 #endif
 
 #ifdef NECKO_PROTOCOL_device
 #include "nsDeviceProtocolHandler.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceProtocolHandler)
 #endif
@@ -755,16 +757,17 @@ NS_DEFINE_NAMED_CID(NS_HTTPAUTHMANAGER_C
 NS_DEFINE_NAMED_CID(NS_HTTPCHANNELAUTHPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_HTTPACTIVITYDISTRIBUTOR_CID);
 #endif // !NECKO_PROTOCOL_http
 #ifdef NECKO_PROTOCOL_ftp
 NS_DEFINE_NAMED_CID(NS_FTPPROTOCOLHANDLER_CID);
 #endif
 #ifdef NECKO_PROTOCOL_res
 NS_DEFINE_NAMED_CID(NS_RESPROTOCOLHANDLER_CID);
+NS_DEFINE_NAMED_CID(NS_EXTENSIONPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_SUBSTITUTINGURL_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_ABOUTPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_SAFEABOUTPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_ABOUT_BLANK_MODULE_CID);
 NS_DEFINE_NAMED_CID(NS_NESTEDABOUTURI_CID);
 #ifdef NECKO_PROTOCOL_about
 #ifdef NS_BUILD_REFCNT_LOGGING
@@ -901,16 +904,17 @@ static const mozilla::Module::CIDEntry k
     { &kNS_HTTPCHANNELAUTHPROVIDER_CID, false, nullptr, mozilla::net::nsHttpChannelAuthProviderConstructor },
     { &kNS_HTTPACTIVITYDISTRIBUTOR_CID, false, nullptr, mozilla::net::nsHttpActivityDistributorConstructor },
 #endif // !NECKO_PROTOCOL_http
 #ifdef NECKO_PROTOCOL_ftp
     { &kNS_FTPPROTOCOLHANDLER_CID, false, nullptr, nsFtpProtocolHandlerConstructor },
 #endif
 #ifdef NECKO_PROTOCOL_res
     { &kNS_RESPROTOCOLHANDLER_CID, false, nullptr, nsResProtocolHandlerConstructor },
+    { &kNS_EXTENSIONPROTOCOLHANDLER_CID, false, nullptr, mozilla::ExtensionProtocolHandlerConstructor },
     { &kNS_SUBSTITUTINGURL_CID, false, nullptr, mozilla::SubstitutingURLConstructor },
 #endif
     { &kNS_ABOUTPROTOCOLHANDLER_CID, false, nullptr, nsAboutProtocolHandlerConstructor },
     { &kNS_SAFEABOUTPROTOCOLHANDLER_CID, false, nullptr, nsSafeAboutProtocolHandlerConstructor },
     { &kNS_ABOUT_BLANK_MODULE_CID, false, nullptr, nsAboutBlank::Create },
     { &kNS_NESTEDABOUTURI_CID, false, nullptr, nsNestedAboutURIConstructor },
 #ifdef NECKO_PROTOCOL_about
 #ifdef NS_BUILD_REFCNT_LOGGING
@@ -1056,16 +1060,17 @@ static const mozilla::Module::ContractID
     { NS_HTTPCHANNELAUTHPROVIDER_CONTRACTID, &kNS_HTTPCHANNELAUTHPROVIDER_CID },
     { NS_HTTPACTIVITYDISTRIBUTOR_CONTRACTID, &kNS_HTTPACTIVITYDISTRIBUTOR_CID },
 #endif // !NECKO_PROTOCOL_http
 #ifdef NECKO_PROTOCOL_ftp
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &kNS_FTPPROTOCOLHANDLER_CID },
 #endif
 #ifdef NECKO_PROTOCOL_res
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "resource", &kNS_RESPROTOCOLHANDLER_CID },
+    { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-extension", &kNS_EXTENSIONPROTOCOLHANDLER_CID },
 #endif
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "about", &kNS_ABOUTPROTOCOLHANDLER_CID },
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-safe-about", &kNS_SAFEABOUTPROTOCOLHANDLER_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "blank", &kNS_ABOUT_BLANK_MODULE_CID },
 #ifdef NECKO_PROTOCOL_about
 #ifdef NS_BUILD_REFCNT_LOGGING
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "bloat", &kNS_ABOUT_BLOAT_MODULE_CID },
 #endif
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp
@@ -0,0 +1,16 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ExtensionProtocolHandler.h"
+
+namespace mozilla {
+
+NS_IMPL_QUERY_INTERFACE(ExtensionProtocolHandler, nsISubstitutingProtocolHandler,
+                        nsIProtocolHandler, nsISupportsWeakReference)
+NS_IMPL_ADDREF_INHERITED(ExtensionProtocolHandler, SubstitutingProtocolHandler)
+NS_IMPL_RELEASE_INHERITED(ExtensionProtocolHandler, SubstitutingProtocolHandler)
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/res/ExtensionProtocolHandler.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef ExtensionProtocolHandler_h___
+#define ExtensionProtocolHandler_h___
+
+#include "SubstitutingProtocolHandler.h"
+#include "nsWeakReference.h"
+
+namespace mozilla {
+
+class ExtensionProtocolHandler final : public nsISubstitutingProtocolHandler,
+                                       public mozilla::SubstitutingProtocolHandler,
+                                       public nsSupportsWeakReference
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_FORWARD_NSIPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::)
+  NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::)
+
+  // In general a moz-extension URI is only loadable by chrome, but a whitelisted
+  // subset are web-accessible (see nsIAddonPolicyService).
+  ExtensionProtocolHandler()
+    : SubstitutingProtocolHandler("moz-extension", URI_STD | URI_DANGEROUS_TO_LOAD | URI_IS_LOCAL_RESOURCE)
+  {}
+
+protected:
+  ~ExtensionProtocolHandler() {}
+};
+
+} // namespace mozilla
+
+#endif /* ExtensionProtocolHandler_h___ */
--- a/netwerk/protocol/res/moz.build
+++ b/netwerk/protocol/res/moz.build
@@ -7,16 +7,17 @@
 XPIDL_SOURCES += [
     'nsIResProtocolHandler.idl',
     'nsISubstitutingProtocolHandler.idl',
 ]
 
 XPIDL_MODULE = 'necko_res'
 
 SOURCES += [
+    'ExtensionProtocolHandler.cpp',
     'nsResProtocolHandler.cpp',
     'SubstitutingProtocolHandler.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/toolkit/components/utils/simpleServices.js
+++ b/toolkit/components/utils/simpleServices.js
@@ -62,18 +62,44 @@ AddonPolicyService.prototype = {
    * @see nsIAddonPolicyService.addonMayLoadURI
    */
   addonMayLoadURI(aAddonId, aURI) {
     let cb = this.mayLoadURICallbacks[aAddonId];
     return cb ? cb(aURI) : false;
   },
 
   /*
+   * Invokes a callback (if any) to determine if an extension URI should be
+   * web-accessible.
+   *
+   * @see nsIAddonPolicyService.extensionURILoadableByAnyone
+   */
+  extensionURILoadableByAnyone(aURI) {
+    if (aURI.scheme != "moz-extension") {
+      throw new TypeError("non-extension URI passed");
+    }
+
+    let cb = this.extensionURILoadCallback;
+    return cb ? cb(aURI) : false;
+  },
+
+  /*
    * Sets the callbacks used in addonMayLoadURI above. Not accessible over
    * XPCOM - callers should use .wrappedJSObject on the service to call it
    * directly.
    */
   setAddonLoadURICallback(aAddonId, aCallback) {
     this.mayLoadURICallbacks[aAddonId] = aCallback;
   },
+
+  /*
+   * Sets the callback used in extensionURILoadableByAnyone above. Not
+   * accessible over XPCOM - callers should use .wrappedJSObject on the
+   * service to call it directly.
+   */
+  setExtensionURILoadCallback(aCallback) {
+    var old = this.extensionURILoadCallback;
+    this.extensionURILoadCallback = aCallback;
+    return old;
+  }
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RemoteTagServiceService, AddonPolicyService]);