caps/DomainPolicy.cpp
author L10n Bumper Bot <release+l10nbumper@mozilla.com>
Wed, 21 Aug 2019 14:00:18 +0000
changeset 542026 5f3eeb8c45c22452ed23d0e1b3cb0c529856a3bb
parent 520491 dcdb7860cae8667256dcca87711d1edea92a9bad
permissions -rw-r--r--
no bug - Bumping Fennec l10n changesets r=release a=l10n-bump DONTBUILD br -> 64c36445645f cy -> 1b9e944f37f5 dsb -> ee1d47f04f07 es-ES -> dd46a1c85278 fr -> 6878c4e51516 gn -> 8ced7dbc0005 hsb -> 8e5b3f80dff0 hu -> dd44c146951d it -> 9db7e98fdfff pt-BR -> 3697e7f211a4 ro -> 52296d14daac uk -> 502d6e23d3a3 zh-CN -> 178364c883f9

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=4 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 "DomainPolicy.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/Unused.h"
#include "nsIMessageManager.h"
#include "nsIURIMutator.h"
#include "nsScriptSecurityManager.h"

namespace mozilla {

using namespace ipc;
using namespace dom;

NS_IMPL_ISUPPORTS(DomainPolicy, nsIDomainPolicy)

static nsresult BroadcastDomainSetChange(DomainSetType aSetType,
                                         DomainSetChangeType aChangeType,
                                         nsIURI* aDomain = nullptr) {
  MOZ_ASSERT(XRE_IsParentProcess(),
             "DomainPolicy should only be exposed to the chrome process.");

  nsTArray<ContentParent*> parents;
  ContentParent::GetAll(parents);
  if (!parents.Length()) {
    return NS_OK;
  }

  Maybe<URIParams> uri;
  SerializeURI(aDomain, uri);

  for (uint32_t i = 0; i < parents.Length(); i++) {
    Unused << parents[i]->SendDomainSetChanged(aSetType, aChangeType, uri);
  }
  return NS_OK;
}

DomainPolicy::DomainPolicy()
    : mBlocklist(new DomainSet(BLOCKLIST)),
      mSuperBlocklist(new DomainSet(SUPER_BLOCKLIST)),
      mAllowlist(new DomainSet(ALLOWLIST)),
      mSuperAllowlist(new DomainSet(SUPER_ALLOWLIST)) {
  if (XRE_IsParentProcess()) {
    BroadcastDomainSetChange(NO_TYPE, ACTIVATE_POLICY);
  }
}

DomainPolicy::~DomainPolicy() {
  // The SSM holds a strong ref to the DomainPolicy until Deactivate() is
  // invoked, so we should never hit the destructor until that happens.
  MOZ_ASSERT(!mBlocklist && !mSuperBlocklist && !mAllowlist &&
             !mSuperAllowlist);
}

NS_IMETHODIMP
DomainPolicy::GetBlocklist(nsIDomainSet** aSet) {
  nsCOMPtr<nsIDomainSet> set = mBlocklist.get();
  set.forget(aSet);
  return NS_OK;
}

NS_IMETHODIMP
DomainPolicy::GetSuperBlocklist(nsIDomainSet** aSet) {
  nsCOMPtr<nsIDomainSet> set = mSuperBlocklist.get();
  set.forget(aSet);
  return NS_OK;
}

NS_IMETHODIMP
DomainPolicy::GetAllowlist(nsIDomainSet** aSet) {
  nsCOMPtr<nsIDomainSet> set = mAllowlist.get();
  set.forget(aSet);
  return NS_OK;
}

NS_IMETHODIMP
DomainPolicy::GetSuperAllowlist(nsIDomainSet** aSet) {
  nsCOMPtr<nsIDomainSet> set = mSuperAllowlist.get();
  set.forget(aSet);
  return NS_OK;
}

NS_IMETHODIMP
DomainPolicy::Deactivate() {
  // Clear the hashtables first to free up memory, since script might
  // hold the doomed sets alive indefinitely.
  mBlocklist->Clear();
  mSuperBlocklist->Clear();
  mAllowlist->Clear();
  mSuperAllowlist->Clear();

  // Null them out.
  mBlocklist = nullptr;
  mSuperBlocklist = nullptr;
  mAllowlist = nullptr;
  mSuperAllowlist = nullptr;

  // Inform the SSM.
  nsScriptSecurityManager* ssm =
      nsScriptSecurityManager::GetScriptSecurityManager();
  if (ssm) {
    ssm->DeactivateDomainPolicy();
  }
  if (XRE_IsParentProcess()) {
    BroadcastDomainSetChange(NO_TYPE, DEACTIVATE_POLICY);
  }
  return NS_OK;
}

void DomainPolicy::CloneDomainPolicy(DomainPolicyClone* aClone) {
  aClone->active() = true;
  mBlocklist->CloneSet(&aClone->blocklist());
  mSuperBlocklist->CloneSet(&aClone->superBlocklist());
  mAllowlist->CloneSet(&aClone->allowlist());
  mSuperAllowlist->CloneSet(&aClone->superAllowlist());
}

static void CopyURIs(const InfallibleTArray<URIParams>& aDomains,
                     nsIDomainSet* aSet) {
  for (uint32_t i = 0; i < aDomains.Length(); i++) {
    nsCOMPtr<nsIURI> uri = DeserializeURI(aDomains[i]);
    aSet->Add(uri);
  }
}

void DomainPolicy::ApplyClone(const DomainPolicyClone* aClone) {
  CopyURIs(aClone->blocklist(), mBlocklist);
  CopyURIs(aClone->allowlist(), mAllowlist);
  CopyURIs(aClone->superBlocklist(), mSuperBlocklist);
  CopyURIs(aClone->superAllowlist(), mSuperAllowlist);
}

static already_AddRefed<nsIURI> GetCanonicalClone(nsIURI* aURI) {
  nsCOMPtr<nsIURI> clone;
  nsresult rv = NS_MutateURI(aURI)
                    .SetUserPass(EmptyCString())
                    .SetPathQueryRef(EmptyCString())
                    .Finalize(clone);
  NS_ENSURE_SUCCESS(rv, nullptr);
  return clone.forget();
}

NS_IMPL_ISUPPORTS(DomainSet, nsIDomainSet)

NS_IMETHODIMP
DomainSet::Add(nsIURI* aDomain) {
  nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
  NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
  mHashTable.PutEntry(clone);
  if (XRE_IsParentProcess())
    return BroadcastDomainSetChange(mType, ADD_DOMAIN, aDomain);

  return NS_OK;
}

NS_IMETHODIMP
DomainSet::Remove(nsIURI* aDomain) {
  nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
  NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
  mHashTable.RemoveEntry(clone);
  if (XRE_IsParentProcess())
    return BroadcastDomainSetChange(mType, REMOVE_DOMAIN, aDomain);

  return NS_OK;
}

NS_IMETHODIMP
DomainSet::Clear() {
  mHashTable.Clear();
  if (XRE_IsParentProcess())
    return BroadcastDomainSetChange(mType, CLEAR_DOMAINS);

  return NS_OK;
}

NS_IMETHODIMP
DomainSet::Contains(nsIURI* aDomain, bool* aContains) {
  *aContains = false;
  nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
  NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
  *aContains = mHashTable.Contains(clone);
  return NS_OK;
}

NS_IMETHODIMP
DomainSet::ContainsSuperDomain(nsIURI* aDomain, bool* aContains) {
  *aContains = false;
  nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
  NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
  nsAutoCString domain;
  nsresult rv = clone->GetHost(domain);
  NS_ENSURE_SUCCESS(rv, rv);
  while (true) {
    // Check the current domain.
    if (mHashTable.Contains(clone)) {
      *aContains = true;
      return NS_OK;
    }

    // Chop off everything before the first dot, or break if there are no
    // dots left.
    int32_t index = domain.Find(".");
    if (index == kNotFound) break;
    domain.Assign(Substring(domain, index + 1));
    rv = NS_MutateURI(clone).SetHost(domain).Finalize(clone);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  // No match.
  return NS_OK;
}

void DomainSet::CloneSet(InfallibleTArray<URIParams>* aDomains) {
  for (auto iter = mHashTable.Iter(); !iter.Done(); iter.Next()) {
    nsIURI* key = iter.Get()->GetKey();

    URIParams uri;
    SerializeURI(key, uri);

    aDomains->AppendElement(uri);
  }
}

} /* namespace mozilla */