summaryrefslogtreecommitdiffstats
path: root/caps/DomainPolicy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'caps/DomainPolicy.cpp')
-rw-r--r--caps/DomainPolicy.cpp222
1 files changed, 222 insertions, 0 deletions
diff --git a/caps/DomainPolicy.cpp b/caps/DomainPolicy.cpp
new file mode 100644
index 0000000000..65ad3d8df4
--- /dev/null
+++ b/caps/DomainPolicy.cpp
@@ -0,0 +1,222 @@
+/* -*- 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 "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;
+ }
+
+ for (uint32_t i = 0; i < parents.Length(); i++) {
+ Unused << parents[i]->SendDomainSetChanged(aSetType, aChangeType, aDomain);
+ }
+ 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 nsTArray<RefPtr<nsIURI>>& aDomains,
+ nsIDomainSet* aSet) {
+ for (uint32_t i = 0; i < aDomains.Length(); i++) {
+ if (NS_WARN_IF(!aDomains[i])) {
+ continue;
+ }
+ aSet->Add(aDomains[i]);
+ }
+}
+
+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(""_ns).SetPathQueryRef(""_ns).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.Insert(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.Remove(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(nsTArray<RefPtr<nsIURI>>* aDomains) {
+ AppendToArray(*aDomains, mHashTable);
+}
+
+} /* namespace mozilla */