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"
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()) {
32 for (uint32_t i
= 0; i
< parents
.Length(); i
++) {
33 Unused
<< parents
[i
]->SendDomainSetChanged(aSetType
, aChangeType
, aDomain
);
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
&&
56 DomainPolicy::GetBlocklist(nsIDomainSet
** aSet
) {
57 nsCOMPtr
<nsIDomainSet
> set
= mBlocklist
.get();
63 DomainPolicy::GetSuperBlocklist(nsIDomainSet
** aSet
) {
64 nsCOMPtr
<nsIDomainSet
> set
= mSuperBlocklist
.get();
70 DomainPolicy::GetAllowlist(nsIDomainSet
** aSet
) {
71 nsCOMPtr
<nsIDomainSet
> set
= mAllowlist
.get();
77 DomainPolicy::GetSuperAllowlist(nsIDomainSet
** aSet
) {
78 nsCOMPtr
<nsIDomainSet
> set
= mSuperAllowlist
.get();
84 DomainPolicy::Deactivate() {
85 // Clear the hashtables first to free up memory, since script might
86 // hold the doomed sets alive indefinitely.
88 mSuperBlocklist
->Clear();
90 mSuperAllowlist
->Clear();
94 mSuperBlocklist
= nullptr;
96 mSuperAllowlist
= nullptr;
99 nsScriptSecurityManager
* ssm
=
100 nsScriptSecurityManager::GetScriptSecurityManager();
102 ssm
->DeactivateDomainPolicy();
104 if (XRE_IsParentProcess()) {
105 BroadcastDomainSetChange(NO_TYPE
, DEACTIVATE_POLICY
);
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
])) {
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
;
138 NS_MutateURI(aURI
).SetUserPass(""_ns
).SetPathQueryRef(""_ns
).Finalize(
140 NS_ENSURE_SUCCESS(rv
, nullptr);
141 return clone
.forget();
144 NS_IMPL_ISUPPORTS(DomainSet
, nsIDomainSet
)
147 DomainSet::Add(nsIURI
* aDomain
) {
148 nsCOMPtr
<nsIURI
> clone
= GetCanonicalClone(aDomain
);
149 NS_ENSURE_TRUE(clone
, NS_ERROR_FAILURE
);
150 mHashTable
.Insert(clone
);
151 if (XRE_IsParentProcess()) {
152 return BroadcastDomainSetChange(mType
, ADD_DOMAIN
, aDomain
);
159 DomainSet::Remove(nsIURI
* aDomain
) {
160 nsCOMPtr
<nsIURI
> clone
= GetCanonicalClone(aDomain
);
161 NS_ENSURE_TRUE(clone
, NS_ERROR_FAILURE
);
162 mHashTable
.Remove(clone
);
163 if (XRE_IsParentProcess()) {
164 return BroadcastDomainSetChange(mType
, REMOVE_DOMAIN
, aDomain
);
173 if (XRE_IsParentProcess()) {
174 return BroadcastDomainSetChange(mType
, CLEAR_DOMAINS
);
181 DomainSet::Contains(nsIURI
* aDomain
, bool* aContains
) {
183 nsCOMPtr
<nsIURI
> clone
= GetCanonicalClone(aDomain
);
184 NS_ENSURE_TRUE(clone
, NS_ERROR_FAILURE
);
185 *aContains
= mHashTable
.Contains(clone
);
190 DomainSet::ContainsSuperDomain(nsIURI
* aDomain
, bool* aContains
) {
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
);
198 // Check the current domain.
199 if (mHashTable
.Contains(clone
)) {
204 // Chop off everything before the first dot, or break if there are no
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
);
217 void DomainSet::CloneSet(nsTArray
<RefPtr
<nsIURI
>>* aDomains
) {
218 AppendToArray(*aDomains
, mHashTable
);
221 } /* namespace mozilla */