Bug 1692971 [wpt PR 27638] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / caps / DomainPolicy.cpp
blob578d5963a8668f15c06ee06099211fc0e6e67545
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=4 et sw=2 tw=80: */
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/. */
7 #include "DomainPolicy.h"
8 #include "mozilla/dom/ContentParent.h"
9 #include "mozilla/ipc/URIUtils.h"
10 #include "mozilla/Unused.h"
11 #include "nsScriptSecurityManager.h"
13 namespace mozilla {
15 using namespace ipc;
16 using namespace dom;
18 NS_IMPL_ISUPPORTS(DomainPolicy, nsIDomainPolicy)
20 static nsresult BroadcastDomainSetChange(DomainSetType aSetType,
21 DomainSetChangeType aChangeType,
22 nsIURI* aDomain = nullptr) {
23 MOZ_ASSERT(XRE_IsParentProcess(),
24 "DomainPolicy should only be exposed to the chrome process.");
26 nsTArray<ContentParent*> parents;
27 ContentParent::GetAll(parents);
28 if (!parents.Length()) {
29 return NS_OK;
32 for (uint32_t i = 0; i < parents.Length(); i++) {
33 Unused << parents[i]->SendDomainSetChanged(aSetType, aChangeType, aDomain);
35 return NS_OK;
38 DomainPolicy::DomainPolicy()
39 : mBlocklist(new DomainSet(BLOCKLIST)),
40 mSuperBlocklist(new DomainSet(SUPER_BLOCKLIST)),
41 mAllowlist(new DomainSet(ALLOWLIST)),
42 mSuperAllowlist(new DomainSet(SUPER_ALLOWLIST)) {
43 if (XRE_IsParentProcess()) {
44 BroadcastDomainSetChange(NO_TYPE, ACTIVATE_POLICY);
48 DomainPolicy::~DomainPolicy() {
49 // The SSM holds a strong ref to the DomainPolicy until Deactivate() is
50 // invoked, so we should never hit the destructor until that happens.
51 MOZ_ASSERT(!mBlocklist && !mSuperBlocklist && !mAllowlist &&
52 !mSuperAllowlist);
55 NS_IMETHODIMP
56 DomainPolicy::GetBlocklist(nsIDomainSet** aSet) {
57 nsCOMPtr<nsIDomainSet> set = mBlocklist.get();
58 set.forget(aSet);
59 return NS_OK;
62 NS_IMETHODIMP
63 DomainPolicy::GetSuperBlocklist(nsIDomainSet** aSet) {
64 nsCOMPtr<nsIDomainSet> set = mSuperBlocklist.get();
65 set.forget(aSet);
66 return NS_OK;
69 NS_IMETHODIMP
70 DomainPolicy::GetAllowlist(nsIDomainSet** aSet) {
71 nsCOMPtr<nsIDomainSet> set = mAllowlist.get();
72 set.forget(aSet);
73 return NS_OK;
76 NS_IMETHODIMP
77 DomainPolicy::GetSuperAllowlist(nsIDomainSet** aSet) {
78 nsCOMPtr<nsIDomainSet> set = mSuperAllowlist.get();
79 set.forget(aSet);
80 return NS_OK;
83 NS_IMETHODIMP
84 DomainPolicy::Deactivate() {
85 // Clear the hashtables first to free up memory, since script might
86 // hold the doomed sets alive indefinitely.
87 mBlocklist->Clear();
88 mSuperBlocklist->Clear();
89 mAllowlist->Clear();
90 mSuperAllowlist->Clear();
92 // Null them out.
93 mBlocklist = nullptr;
94 mSuperBlocklist = nullptr;
95 mAllowlist = nullptr;
96 mSuperAllowlist = nullptr;
98 // Inform the SSM.
99 nsScriptSecurityManager* ssm =
100 nsScriptSecurityManager::GetScriptSecurityManager();
101 if (ssm) {
102 ssm->DeactivateDomainPolicy();
104 if (XRE_IsParentProcess()) {
105 BroadcastDomainSetChange(NO_TYPE, DEACTIVATE_POLICY);
107 return NS_OK;
110 void DomainPolicy::CloneDomainPolicy(DomainPolicyClone* aClone) {
111 aClone->active() = true;
112 mBlocklist->CloneSet(&aClone->blocklist());
113 mSuperBlocklist->CloneSet(&aClone->superBlocklist());
114 mAllowlist->CloneSet(&aClone->allowlist());
115 mSuperAllowlist->CloneSet(&aClone->superAllowlist());
118 static void CopyURIs(const nsTArray<RefPtr<nsIURI>>& aDomains,
119 nsIDomainSet* aSet) {
120 for (uint32_t i = 0; i < aDomains.Length(); i++) {
121 if (NS_WARN_IF(!aDomains[i])) {
122 continue;
124 aSet->Add(aDomains[i]);
128 void DomainPolicy::ApplyClone(const DomainPolicyClone* aClone) {
129 CopyURIs(aClone->blocklist(), mBlocklist);
130 CopyURIs(aClone->allowlist(), mAllowlist);
131 CopyURIs(aClone->superBlocklist(), mSuperBlocklist);
132 CopyURIs(aClone->superAllowlist(), mSuperAllowlist);
135 static already_AddRefed<nsIURI> GetCanonicalClone(nsIURI* aURI) {
136 nsCOMPtr<nsIURI> clone;
137 nsresult rv =
138 NS_MutateURI(aURI).SetUserPass(""_ns).SetPathQueryRef(""_ns).Finalize(
139 clone);
140 NS_ENSURE_SUCCESS(rv, nullptr);
141 return clone.forget();
144 NS_IMPL_ISUPPORTS(DomainSet, nsIDomainSet)
146 NS_IMETHODIMP
147 DomainSet::Add(nsIURI* aDomain) {
148 nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
149 NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
150 mHashTable.PutEntry(clone);
151 if (XRE_IsParentProcess()) {
152 return BroadcastDomainSetChange(mType, ADD_DOMAIN, aDomain);
155 return NS_OK;
158 NS_IMETHODIMP
159 DomainSet::Remove(nsIURI* aDomain) {
160 nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
161 NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
162 mHashTable.RemoveEntry(clone);
163 if (XRE_IsParentProcess()) {
164 return BroadcastDomainSetChange(mType, REMOVE_DOMAIN, aDomain);
167 return NS_OK;
170 NS_IMETHODIMP
171 DomainSet::Clear() {
172 mHashTable.Clear();
173 if (XRE_IsParentProcess()) {
174 return BroadcastDomainSetChange(mType, CLEAR_DOMAINS);
177 return NS_OK;
180 NS_IMETHODIMP
181 DomainSet::Contains(nsIURI* aDomain, bool* aContains) {
182 *aContains = false;
183 nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
184 NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
185 *aContains = mHashTable.Contains(clone);
186 return NS_OK;
189 NS_IMETHODIMP
190 DomainSet::ContainsSuperDomain(nsIURI* aDomain, bool* aContains) {
191 *aContains = false;
192 nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
193 NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
194 nsAutoCString domain;
195 nsresult rv = clone->GetHost(domain);
196 NS_ENSURE_SUCCESS(rv, rv);
197 while (true) {
198 // Check the current domain.
199 if (mHashTable.Contains(clone)) {
200 *aContains = true;
201 return NS_OK;
204 // Chop off everything before the first dot, or break if there are no
205 // dots left.
206 int32_t index = domain.Find(".");
207 if (index == kNotFound) break;
208 domain.Assign(Substring(domain, index + 1));
209 rv = NS_MutateURI(clone).SetHost(domain).Finalize(clone);
210 NS_ENSURE_SUCCESS(rv, rv);
213 // No match.
214 return NS_OK;
217 void DomainSet::CloneSet(nsTArray<RefPtr<nsIURI>>* aDomains) {
218 for (auto iter = mHashTable.Iter(); !iter.Done(); iter.Next()) {
219 nsIURI* key = iter.Get()->GetKey();
220 aDomains->AppendElement(key);
224 } /* namespace mozilla */