tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsChromeRegistry.cpp (11409B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 sw=2 et tw=78: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "nsChromeRegistry.h"
      8 #include "nsChromeRegistryChrome.h"
      9 #include "nsChromeRegistryContent.h"
     10 
     11 #include "nsCOMPtr.h"
     12 #include "nsComponentManagerUtils.h"
     13 #include "nsError.h"
     14 #include "nsEscape.h"
     15 #include "nsNetUtil.h"
     16 #include "nsString.h"
     17 #include "nsQueryObject.h"
     18 #include "nsIURIMutator.h"
     19 #include "nsIURL.h"
     20 
     21 #include "mozilla/dom/URL.h"
     22 #include "nsIConsoleService.h"
     23 #include "mozilla/dom/Document.h"
     24 #include "nsIObserverService.h"
     25 #include "nsIScriptError.h"
     26 #include "mozilla/Preferences.h"
     27 #include "mozilla/PresShell.h"
     28 #include "mozilla/Printf.h"
     29 #include "mozilla/StyleSheet.h"
     30 #include "mozilla/StyleSheetInlines.h"
     31 #include "mozilla/dom/Location.h"
     32 
     33 nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
     34 
     35 // DO NOT use namespace mozilla; it'll break due to a naming conflict between
     36 // mozilla::TextRange and a TextRange in OSX headers.
     37 using mozilla::PresShell;
     38 using mozilla::StyleSheet;
     39 using mozilla::dom::Document;
     40 using mozilla::dom::Location;
     41 
     42 ////////////////////////////////////////////////////////////////////////////////
     43 
     44 void nsChromeRegistry::LogMessage(const char* aMsg, ...) {
     45  nsCOMPtr<nsIConsoleService> console(
     46      do_GetService(NS_CONSOLESERVICE_CONTRACTID));
     47  if (!console) return;
     48 
     49  va_list args;
     50  va_start(args, aMsg);
     51  mozilla::SmprintfPointer formatted = mozilla::Vsmprintf(aMsg, args);
     52  va_end(args);
     53  if (!formatted) return;
     54 
     55  console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted.get()).get());
     56 }
     57 
     58 void nsChromeRegistry::LogMessageWithContext(nsIURI* aURL, uint32_t aLineNumber,
     59                                             uint32_t flags, const char* aMsg,
     60                                             ...) {
     61  nsresult rv;
     62 
     63  nsCOMPtr<nsIConsoleService> console(
     64      do_GetService(NS_CONSOLESERVICE_CONTRACTID));
     65 
     66  nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
     67  if (!console || !error) return;
     68 
     69  va_list args;
     70  va_start(args, aMsg);
     71  mozilla::SmprintfPointer formatted = mozilla::Vsmprintf(aMsg, args);
     72  va_end(args);
     73  if (!formatted) return;
     74 
     75  nsCString spec;
     76  if (aURL) aURL->GetSpec(spec);
     77 
     78  rv = error->Init(NS_ConvertUTF8toUTF16(formatted.get()), spec, aLineNumber, 0,
     79                   flags, "chrome registration"_ns,
     80                   false /* from private window */,
     81                   true /* from chrome context */);
     82 
     83  if (NS_FAILED(rv)) return;
     84 
     85  console->LogMessage(error);
     86 }
     87 
     88 nsChromeRegistry::~nsChromeRegistry() { gChromeRegistry = nullptr; }
     89 
     90 NS_INTERFACE_MAP_BEGIN(nsChromeRegistry)
     91  NS_INTERFACE_MAP_ENTRY(nsIChromeRegistry)
     92  NS_INTERFACE_MAP_ENTRY(nsIXULChromeRegistry)
     93  NS_INTERFACE_MAP_ENTRY(nsIToolkitChromeRegistry)
     94  NS_INTERFACE_MAP_ENTRY(nsIObserver)
     95  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     96  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChromeRegistry)
     97 NS_INTERFACE_MAP_END
     98 
     99 NS_IMPL_ADDREF(nsChromeRegistry)
    100 NS_IMPL_RELEASE(nsChromeRegistry)
    101 
    102 ////////////////////////////////////////////////////////////////////////////////
    103 // nsIChromeRegistry methods:
    104 
    105 already_AddRefed<nsIChromeRegistry> nsChromeRegistry::GetService() {
    106  if (!gChromeRegistry) {
    107    // We don't actually want this ref, we just want the service to
    108    // initialize if it hasn't already.
    109    nsCOMPtr<nsIChromeRegistry> reg(
    110        do_GetService(NS_CHROMEREGISTRY_CONTRACTID));
    111    if (!gChromeRegistry) return nullptr;
    112  }
    113  nsCOMPtr<nsIChromeRegistry> registry = gChromeRegistry;
    114  return registry.forget();
    115 }
    116 
    117 nsresult nsChromeRegistry::Init() {
    118  // This initialization process is fairly complicated and may cause reentrant
    119  // getservice calls to resolve chrome URIs (especially locale files). We
    120  // don't want that, so we inform the protocol handler about our existence
    121  // before we are actually fully initialized.
    122  gChromeRegistry = this;
    123 
    124  mInitialized = true;
    125 
    126  return NS_OK;
    127 }
    128 
    129 nsresult nsChromeRegistry::GetProviderAndPath(nsIURI* aChromeURL,
    130                                              nsACString& aProvider,
    131                                              nsACString& aPath) {
    132  nsresult rv;
    133 
    134  NS_ASSERTION(aChromeURL->SchemeIs("chrome"), "Non-chrome URI?");
    135 
    136  nsAutoCString path;
    137  rv = aChromeURL->GetPathQueryRef(path);
    138  NS_ENSURE_SUCCESS(rv, rv);
    139 
    140  if (path.Length() < 3) {
    141 #ifdef DEBUG
    142    LogMessage("Invalid chrome URI (need path): %s",
    143               aChromeURL->GetSpecOrDefault().get());
    144 #endif
    145    return NS_ERROR_FAILURE;
    146  }
    147 
    148  path.SetLength(nsUnescapeCount(path.BeginWriting()));
    149  NS_ASSERTION(path.First() == '/', "Path should always begin with a slash!");
    150 
    151  int32_t slash = path.FindChar('/', 1);
    152  if (slash == 1) {
    153 #ifdef DEBUG
    154    LogMessage("Invalid chrome URI (path cannot start with another slash): %s",
    155               aChromeURL->GetSpecOrDefault().get());
    156 #endif
    157    return NS_ERROR_FAILURE;
    158  }
    159 
    160  if (slash == -1) {
    161    aPath.Truncate();
    162  } else {
    163    if (slash == (int32_t)path.Length() - 1)
    164      aPath.Truncate();
    165    else
    166      aPath.Assign(path.get() + slash + 1, path.Length() - slash - 1);
    167 
    168    --slash;
    169  }
    170 
    171  aProvider.Assign(path.get() + 1, slash);
    172  return NS_OK;
    173 }
    174 
    175 nsresult nsChromeRegistry::Canonify(nsCOMPtr<nsIURI>& aChromeURL) {
    176  constexpr auto kSlash = "/"_ns;
    177 
    178  nsresult rv;
    179 
    180  nsAutoCString provider, path;
    181  rv = GetProviderAndPath(aChromeURL, provider, path);
    182  NS_ENSURE_SUCCESS(rv, rv);
    183 
    184  if (path.IsEmpty()) {
    185    nsAutoCString package;
    186    rv = aChromeURL->GetHost(package);
    187    NS_ENSURE_SUCCESS(rv, rv);
    188 
    189    // we re-use the "path" local string to build a new URL path
    190    path.Assign(kSlash + provider + kSlash + package);
    191    if (provider.EqualsLiteral("content")) {
    192      path.AppendLiteral(".xul");
    193    } else if (provider.EqualsLiteral("locale")) {
    194      path.AppendLiteral(".dtd");
    195    } else if (provider.EqualsLiteral("skin")) {
    196      path.AppendLiteral(".css");
    197    } else {
    198      return NS_ERROR_INVALID_ARG;
    199    }
    200    return NS_MutateURI(aChromeURL).SetPathQueryRef(path).Finalize(aChromeURL);
    201  }
    202 
    203  // prevent directory traversals ("..")
    204  // path is already unescaped once, but uris can get unescaped twice
    205  const char* pos = path.BeginReading();
    206  const char* end = path.EndReading();
    207  // Must start with [a-zA-Z0-9].
    208  if (!('a' <= *pos && *pos <= 'z') && !('A' <= *pos && *pos <= 'Z') &&
    209      !('0' <= *pos && *pos <= '9')) {
    210    return NS_ERROR_DOM_BAD_URI;
    211  }
    212  while (pos < end) {
    213    switch (*pos) {
    214      case ':':
    215        return NS_ERROR_DOM_BAD_URI;
    216      case '.':
    217        if (pos[1] == '.') {
    218          return NS_ERROR_DOM_BAD_URI;
    219        }
    220        break;
    221      case '%':
    222        // chrome: URIs with double-escapes are trying to trick us.
    223        // watch for %2e, and %25 in case someone triple unescapes
    224        if (pos[1] == '2' &&
    225            (pos[2] == 'e' || pos[2] == 'E' || pos[2] == '5')) {
    226          return NS_ERROR_DOM_BAD_URI;
    227        }
    228        break;
    229      case '?':
    230      case '#':
    231        pos = end;
    232        continue;
    233    }
    234    ++pos;
    235  }
    236 
    237  return NS_OK;
    238 }
    239 
    240 NS_IMETHODIMP
    241 nsChromeRegistry::ConvertChromeURL(nsIURI* aChromeURI, nsIURI** aResult) {
    242  nsresult rv;
    243  if (NS_WARN_IF(!aChromeURI)) {
    244    return NS_ERROR_INVALID_ARG;
    245  }
    246 
    247  if (mOverrideTable.Get(aChromeURI, aResult)) return NS_OK;
    248 
    249  nsCOMPtr<nsIURL> chromeURL(do_QueryInterface(aChromeURI));
    250  NS_ENSURE_TRUE(chromeURL, NS_NOINTERFACE);
    251 
    252  nsAutoCString package, provider, path;
    253  rv = chromeURL->GetHostPort(package);
    254  NS_ENSURE_SUCCESS(rv, rv);
    255 
    256  rv = GetProviderAndPath(chromeURL, provider, path);
    257  NS_ENSURE_SUCCESS(rv, rv);
    258 
    259  nsIURI* baseURI = GetBaseURIFromPackage(package, provider, path);
    260 
    261  uint32_t flags;
    262  rv = GetFlagsFromPackage(package, &flags);
    263  if (NS_FAILED(rv)) return rv;
    264 
    265  if (!baseURI) {
    266    LogMessage("No chrome package registered for chrome://%s/%s/%s",
    267               package.get(), provider.get(), path.get());
    268    return NS_ERROR_FILE_NOT_FOUND;
    269  }
    270 
    271  return NS_NewURI(aResult, path, nullptr, baseURI);
    272 }
    273 
    274 ////////////////////////////////////////////////////////////////////////
    275 
    276 void nsChromeRegistry::FlushAllCaches() {
    277  nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
    278  NS_ASSERTION(obsSvc, "Couldn't get observer service.");
    279 
    280  obsSvc->NotifyObservers((nsIChromeRegistry*)this, NS_CHROME_FLUSH_TOPIC,
    281                          nullptr);
    282 }
    283 
    284 NS_IMETHODIMP
    285 nsChromeRegistry::AllowScriptsForPackage(nsIURI* aChromeURI, bool* aResult) {
    286  nsresult rv;
    287  *aResult = false;
    288 
    289  NS_ASSERTION(aChromeURI->SchemeIs("chrome"),
    290               "Non-chrome URI passed to AllowScriptsForPackage!");
    291 
    292  nsCOMPtr<nsIURL> url(do_QueryInterface(aChromeURI));
    293  NS_ENSURE_TRUE(url, NS_NOINTERFACE);
    294 
    295  nsAutoCString provider, file;
    296  rv = GetProviderAndPath(url, provider, file);
    297  NS_ENSURE_SUCCESS(rv, rv);
    298 
    299  if (!provider.EqualsLiteral("skin")) *aResult = true;
    300 
    301  return NS_OK;
    302 }
    303 
    304 NS_IMETHODIMP
    305 nsChromeRegistry::AllowContentToAccess(nsIURI* aURI, bool* aResult) {
    306  nsresult rv;
    307 
    308  *aResult = false;
    309 
    310  NS_ASSERTION(aURI->SchemeIs("chrome"),
    311               "Non-chrome URI passed to AllowContentToAccess!");
    312 
    313  nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
    314  if (!url) {
    315    NS_ERROR("Chrome URL doesn't implement nsIURL.");
    316    return NS_ERROR_UNEXPECTED;
    317  }
    318 
    319  nsAutoCString package;
    320  rv = url->GetHostPort(package);
    321  NS_ENSURE_SUCCESS(rv, rv);
    322 
    323  uint32_t flags;
    324  rv = GetFlagsFromPackage(package, &flags);
    325 
    326  if (NS_SUCCEEDED(rv)) {
    327    *aResult = !!(flags & CONTENT_ACCESSIBLE);
    328  }
    329  return NS_OK;
    330 }
    331 
    332 NS_IMETHODIMP
    333 nsChromeRegistry::CanLoadURLRemotely(nsIURI* aURI, bool* aResult) {
    334  nsresult rv;
    335 
    336  *aResult = false;
    337 
    338  NS_ASSERTION(aURI->SchemeIs("chrome"),
    339               "Non-chrome URI passed to CanLoadURLRemotely!");
    340 
    341  nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
    342  if (!url) {
    343    NS_ERROR("Chrome URL doesn't implement nsIURL.");
    344    return NS_ERROR_UNEXPECTED;
    345  }
    346 
    347  nsAutoCString package;
    348  rv = url->GetHostPort(package);
    349  NS_ENSURE_SUCCESS(rv, rv);
    350 
    351  uint32_t flags;
    352  rv = GetFlagsFromPackage(package, &flags);
    353 
    354  if (NS_SUCCEEDED(rv)) {
    355    *aResult = !!(flags & REMOTE_ALLOWED);
    356  }
    357  return NS_OK;
    358 }
    359 
    360 NS_IMETHODIMP
    361 nsChromeRegistry::MustLoadURLRemotely(nsIURI* aURI, bool* aResult) {
    362  nsresult rv;
    363 
    364  *aResult = false;
    365 
    366  NS_ASSERTION(aURI->SchemeIs("chrome"),
    367               "Non-chrome URI passed to MustLoadURLRemotely!");
    368 
    369  nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
    370  if (!url) {
    371    NS_ERROR("Chrome URL doesn't implement nsIURL.");
    372    return NS_ERROR_UNEXPECTED;
    373  }
    374 
    375  nsAutoCString package;
    376  rv = url->GetHostPort(package);
    377  NS_ENSURE_SUCCESS(rv, rv);
    378 
    379  uint32_t flags;
    380  rv = GetFlagsFromPackage(package, &flags);
    381 
    382  if (NS_SUCCEEDED(rv)) {
    383    *aResult = !!(flags & REMOTE_REQUIRED);
    384  }
    385  return NS_OK;
    386 }
    387 
    388 already_AddRefed<nsChromeRegistry> nsChromeRegistry::GetSingleton() {
    389  if (gChromeRegistry) {
    390    RefPtr<nsChromeRegistry> registry = gChromeRegistry;
    391    return registry.forget();
    392  }
    393 
    394  RefPtr<nsChromeRegistry> cr;
    395  if (GeckoProcessType_Content == XRE_GetProcessType())
    396    cr = new nsChromeRegistryContent();
    397  else
    398    cr = new nsChromeRegistryChrome();
    399 
    400  if (NS_FAILED(cr->Init())) return nullptr;
    401 
    402  return cr.forget();
    403 }