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 "nsIURIMutator.h"
12 #include "nsScriptSecurityManager.h"
19 NS_IMPL_ISUPPORTS(DomainPolicy
, nsIDomainPolicy
)
21 static nsresult
BroadcastDomainSetChange(DomainSetType aSetType
,
22 DomainSetChangeType aChangeType
,
23 nsIURI
* aDomain
= nullptr) {
24 MOZ_ASSERT(XRE_IsParentProcess(),
25 "DomainPolicy should only be exposed to the chrome process.");
27 nsTArray
<ContentParent
*> parents
;
28 ContentParent::GetAll(parents
);
29 if (!parents
.Length()) {
33 for (uint32_t i
= 0; i
< parents
.Length(); i
++) {
34 Unused
<< parents
[i
]->SendDomainSetChanged(aSetType
, aChangeType
, aDomain
);
39 DomainPolicy::DomainPolicy()
40 : mBlocklist(new DomainSet(BLOCKLIST
)),
41 mSuperBlocklist(new DomainSet(SUPER_BLOCKLIST
)),
42 mAllowlist(new DomainSet(ALLOWLIST
)),
43 mSuperAllowlist(new DomainSet(SUPER_ALLOWLIST
)) {
44 if (XRE_IsParentProcess()) {
45 BroadcastDomainSetChange(NO_TYPE
, ACTIVATE_POLICY
);
49 DomainPolicy::~DomainPolicy() {
50 // The SSM holds a strong ref to the DomainPolicy until Deactivate() is
51 // invoked, so we should never hit the destructor until that happens.
52 MOZ_ASSERT(!mBlocklist
&& !mSuperBlocklist
&& !mAllowlist
&&
57 DomainPolicy::GetBlocklist(nsIDomainSet
** aSet
) {
58 nsCOMPtr
<nsIDomainSet
> set
= mBlocklist
.get();
64 DomainPolicy::GetSuperBlocklist(nsIDomainSet
** aSet
) {
65 nsCOMPtr
<nsIDomainSet
> set
= mSuperBlocklist
.get();
71 DomainPolicy::GetAllowlist(nsIDomainSet
** aSet
) {
72 nsCOMPtr
<nsIDomainSet
> set
= mAllowlist
.get();
78 DomainPolicy::GetSuperAllowlist(nsIDomainSet
** aSet
) {
79 nsCOMPtr
<nsIDomainSet
> set
= mSuperAllowlist
.get();
85 DomainPolicy::Deactivate() {
86 // Clear the hashtables first to free up memory, since script might
87 // hold the doomed sets alive indefinitely.
89 mSuperBlocklist
->Clear();
91 mSuperAllowlist
->Clear();
95 mSuperBlocklist
= nullptr;
97 mSuperAllowlist
= nullptr;
100 nsScriptSecurityManager
* ssm
=
101 nsScriptSecurityManager::GetScriptSecurityManager();
103 ssm
->DeactivateDomainPolicy();
105 if (XRE_IsParentProcess()) {
106 BroadcastDomainSetChange(NO_TYPE
, DEACTIVATE_POLICY
);
111 void DomainPolicy::CloneDomainPolicy(DomainPolicyClone
* aClone
) {
112 aClone
->active() = true;
113 mBlocklist
->CloneSet(&aClone
->blocklist());
114 mSuperBlocklist
->CloneSet(&aClone
->superBlocklist());
115 mAllowlist
->CloneSet(&aClone
->allowlist());
116 mSuperAllowlist
->CloneSet(&aClone
->superAllowlist());
119 static void CopyURIs(const nsTArray
<RefPtr
<nsIURI
>>& aDomains
,
120 nsIDomainSet
* aSet
) {
121 for (uint32_t i
= 0; i
< aDomains
.Length(); i
++) {
122 if (NS_WARN_IF(!aDomains
[i
])) {
125 aSet
->Add(aDomains
[i
]);
129 void DomainPolicy::ApplyClone(const DomainPolicyClone
* aClone
) {
130 CopyURIs(aClone
->blocklist(), mBlocklist
);
131 CopyURIs(aClone
->allowlist(), mAllowlist
);
132 CopyURIs(aClone
->superBlocklist(), mSuperBlocklist
);
133 CopyURIs(aClone
->superAllowlist(), mSuperAllowlist
);
136 static already_AddRefed
<nsIURI
> GetCanonicalClone(nsIURI
* aURI
) {
137 nsCOMPtr
<nsIURI
> clone
;
139 NS_MutateURI(aURI
).SetUserPass(""_ns
).SetPathQueryRef(""_ns
).Finalize(
141 NS_ENSURE_SUCCESS(rv
, nullptr);
142 return clone
.forget();
145 NS_IMPL_ISUPPORTS(DomainSet
, nsIDomainSet
)
148 DomainSet::Add(nsIURI
* aDomain
) {
149 nsCOMPtr
<nsIURI
> clone
= GetCanonicalClone(aDomain
);
150 NS_ENSURE_TRUE(clone
, NS_ERROR_FAILURE
);
151 mHashTable
.Insert(clone
);
152 if (XRE_IsParentProcess()) {
153 return BroadcastDomainSetChange(mType
, ADD_DOMAIN
, aDomain
);
160 DomainSet::Remove(nsIURI
* aDomain
) {
161 nsCOMPtr
<nsIURI
> clone
= GetCanonicalClone(aDomain
);
162 NS_ENSURE_TRUE(clone
, NS_ERROR_FAILURE
);
163 mHashTable
.Remove(clone
);
164 if (XRE_IsParentProcess()) {
165 return BroadcastDomainSetChange(mType
, REMOVE_DOMAIN
, aDomain
);
174 if (XRE_IsParentProcess()) {
175 return BroadcastDomainSetChange(mType
, CLEAR_DOMAINS
);
182 DomainSet::Contains(nsIURI
* aDomain
, bool* aContains
) {
184 nsCOMPtr
<nsIURI
> clone
= GetCanonicalClone(aDomain
);
185 NS_ENSURE_TRUE(clone
, NS_ERROR_FAILURE
);
186 *aContains
= mHashTable
.Contains(clone
);
191 DomainSet::ContainsSuperDomain(nsIURI
* aDomain
, bool* aContains
) {
193 nsCOMPtr
<nsIURI
> clone
= GetCanonicalClone(aDomain
);
194 NS_ENSURE_TRUE(clone
, NS_ERROR_FAILURE
);
195 nsAutoCString domain
;
196 nsresult rv
= clone
->GetHost(domain
);
197 NS_ENSURE_SUCCESS(rv
, rv
);
199 // Check the current domain.
200 if (mHashTable
.Contains(clone
)) {
205 // Chop off everything before the first dot, or break if there are no
207 int32_t index
= domain
.Find(".");
208 if (index
== kNotFound
) break;
209 domain
.Assign(Substring(domain
, index
+ 1));
210 rv
= NS_MutateURI(clone
).SetHost(domain
).Finalize(clone
);
211 NS_ENSURE_SUCCESS(rv
, rv
);
218 void DomainSet::CloneSet(nsTArray
<RefPtr
<nsIURI
>>* aDomains
) {
219 AppendToArray(*aDomains
, mHashTable
);
222 } /* namespace mozilla */