Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 sw=2 et 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/. */
6 :
7 : #include "mozilla/OriginAttributes.h"
8 : #include "mozilla/Preferences.h"
9 : #include "mozilla/dom/URLSearchParams.h"
10 : #include "mozilla/dom/quota/QuotaManager.h"
11 : #include "nsIEffectiveTLDService.h"
12 : #include "nsIURI.h"
13 : #include "nsIURIWithPrincipal.h"
14 :
15 : namespace mozilla {
16 :
17 : using dom::URLParams;
18 :
19 : bool OriginAttributes::sFirstPartyIsolation = false;
20 : bool OriginAttributes::sRestrictedOpenerAccess = false;
21 :
22 : void
23 3 : OriginAttributes::InitPrefs()
24 : {
25 3 : MOZ_ASSERT(NS_IsMainThread());
26 : static bool sInited = false;
27 3 : if (!sInited) {
28 3 : sInited = true;
29 : Preferences::AddBoolVarCache(&sFirstPartyIsolation,
30 3 : "privacy.firstparty.isolate");
31 : Preferences::AddBoolVarCache(&sRestrictedOpenerAccess,
32 3 : "privacy.firstparty.isolate.restrict_opener_access");
33 : }
34 3 : }
35 :
36 : void
37 10 : OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
38 : nsIURI* aURI)
39 : {
40 10 : bool isFirstPartyEnabled = IsFirstPartyEnabled();
41 :
42 : // If the pref is off or this is not a top level load, bail out.
43 10 : if (!isFirstPartyEnabled || !aIsTopLevelDocument) {
44 20 : return;
45 : }
46 :
47 : nsCOMPtr<nsIEffectiveTLDService> tldService =
48 0 : do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
49 0 : MOZ_ASSERT(tldService);
50 0 : if (!tldService) {
51 0 : return;
52 : }
53 :
54 0 : nsAutoCString baseDomain;
55 0 : nsresult rv = tldService->GetBaseDomain(aURI, 0, baseDomain);
56 0 : if (NS_SUCCEEDED(rv)) {
57 0 : mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain);
58 0 : return;
59 : }
60 :
61 0 : nsAutoCString scheme;
62 0 : rv = aURI->GetScheme(scheme);
63 0 : NS_ENSURE_SUCCESS_VOID(rv);
64 0 : if (scheme.EqualsLiteral("about")) {
65 0 : mFirstPartyDomain.AssignLiteral(ABOUT_URI_FIRST_PARTY_DOMAIN);
66 0 : } else if (scheme.EqualsLiteral("blob")) {
67 0 : nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
68 0 : if (uriPrinc) {
69 0 : nsCOMPtr<nsIPrincipal> principal;
70 0 : rv = uriPrinc->GetPrincipal(getter_AddRefs(principal));
71 0 : NS_ENSURE_SUCCESS_VOID(rv);
72 :
73 0 : MOZ_ASSERT(principal, "blob URI but no principal.");
74 0 : if (principal) {
75 0 : mFirstPartyDomain = principal->OriginAttributesRef().mFirstPartyDomain;
76 : }
77 : }
78 : }
79 : }
80 :
81 : void
82 1 : OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
83 : const nsACString& aDomain)
84 : {
85 1 : bool isFirstPartyEnabled = IsFirstPartyEnabled();
86 :
87 : // If the pref is off or this is not a top level load, bail out.
88 1 : if (!isFirstPartyEnabled || !aIsTopLevelDocument) {
89 1 : return;
90 : }
91 :
92 0 : mFirstPartyDomain = NS_ConvertUTF8toUTF16(aDomain);
93 : }
94 :
95 : void
96 549 : OriginAttributes::CreateSuffix(nsACString& aStr) const
97 : {
98 1098 : URLParams params;
99 1098 : nsAutoString value;
100 :
101 : //
102 : // Important: While serializing any string-valued attributes, perform a
103 : // release-mode assertion to make sure that they don't contain characters that
104 : // will break the quota manager when it uses the serialization for file
105 : // naming.
106 : //
107 :
108 549 : if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
109 0 : value.AppendInt(mAppId);
110 0 : params.Set(NS_LITERAL_STRING("appId"), value);
111 : }
112 :
113 549 : if (mInIsolatedMozBrowser) {
114 0 : params.Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1"));
115 : }
116 :
117 549 : if (mUserContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
118 0 : value.Truncate();
119 0 : value.AppendInt(mUserContextId);
120 0 : params.Set(NS_LITERAL_STRING("userContextId"), value);
121 : }
122 :
123 :
124 549 : if (mPrivateBrowsingId) {
125 0 : value.Truncate();
126 0 : value.AppendInt(mPrivateBrowsingId);
127 0 : params.Set(NS_LITERAL_STRING("privateBrowsingId"), value);
128 : }
129 :
130 549 : if (!mFirstPartyDomain.IsEmpty()) {
131 11 : MOZ_RELEASE_ASSERT(mFirstPartyDomain.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound);
132 11 : params.Set(NS_LITERAL_STRING("firstPartyDomain"), mFirstPartyDomain);
133 : }
134 :
135 549 : aStr.Truncate();
136 :
137 549 : params.Serialize(value);
138 549 : if (!value.IsEmpty()) {
139 11 : aStr.AppendLiteral("^");
140 11 : aStr.Append(NS_ConvertUTF16toUTF8(value));
141 : }
142 :
143 : // In debug builds, check the whole string for illegal characters too (just in case).
144 : #ifdef DEBUG
145 1098 : nsAutoCString str;
146 549 : str.Assign(aStr);
147 549 : MOZ_ASSERT(str.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound);
148 : #endif
149 549 : }
150 :
151 : void
152 0 : OriginAttributes::CreateAnonymizedSuffix(nsACString& aStr) const
153 : {
154 0 : OriginAttributes attrs = *this;
155 :
156 0 : if (!attrs.mFirstPartyDomain.IsEmpty()) {
157 0 : attrs.mFirstPartyDomain.AssignLiteral("_anonymizedFirstPartyDomain_");
158 : }
159 :
160 0 : attrs.CreateSuffix(aStr);
161 0 : }
162 :
163 : namespace {
164 :
165 : class MOZ_STACK_CLASS PopulateFromSuffixIterator final
166 : : public URLParams::ForEachIterator
167 : {
168 : public:
169 0 : explicit PopulateFromSuffixIterator(OriginAttributes* aOriginAttributes)
170 0 : : mOriginAttributes(aOriginAttributes)
171 : {
172 0 : MOZ_ASSERT(aOriginAttributes);
173 : // If mPrivateBrowsingId is passed in as >0 and is not present in the suffix,
174 : // then it will remain >0 when it should be 0 according to the suffix. Set to 0 before
175 : // iterating to fix this.
176 0 : mOriginAttributes->mPrivateBrowsingId = 0;
177 0 : }
178 :
179 0 : bool URLParamsIterator(const nsString& aName,
180 : const nsString& aValue) override
181 : {
182 0 : if (aName.EqualsLiteral("appId")) {
183 : nsresult rv;
184 0 : int64_t val = aValue.ToInteger64(&rv);
185 0 : NS_ENSURE_SUCCESS(rv, false);
186 0 : NS_ENSURE_TRUE(val <= UINT32_MAX, false);
187 0 : mOriginAttributes->mAppId = static_cast<uint32_t>(val);
188 :
189 0 : return true;
190 : }
191 :
192 0 : if (aName.EqualsLiteral("inBrowser")) {
193 0 : if (!aValue.EqualsLiteral("1")) {
194 0 : return false;
195 : }
196 :
197 0 : mOriginAttributes->mInIsolatedMozBrowser = true;
198 0 : return true;
199 : }
200 :
201 0 : if (aName.EqualsLiteral("addonId")) {
202 : // No longer supported. Silently ignore so that legacy origin strings
203 : // don't cause failures.
204 0 : return true;
205 : }
206 :
207 0 : if (aName.EqualsLiteral("userContextId")) {
208 : nsresult rv;
209 0 : int64_t val = aValue.ToInteger64(&rv);
210 0 : NS_ENSURE_SUCCESS(rv, false);
211 0 : NS_ENSURE_TRUE(val <= UINT32_MAX, false);
212 0 : mOriginAttributes->mUserContextId = static_cast<uint32_t>(val);
213 :
214 0 : return true;
215 : }
216 :
217 0 : if (aName.EqualsLiteral("privateBrowsingId")) {
218 : nsresult rv;
219 0 : int64_t val = aValue.ToInteger64(&rv);
220 0 : NS_ENSURE_SUCCESS(rv, false);
221 0 : NS_ENSURE_TRUE(val >= 0 && val <= UINT32_MAX, false);
222 0 : mOriginAttributes->mPrivateBrowsingId = static_cast<uint32_t>(val);
223 :
224 0 : return true;
225 : }
226 :
227 0 : if (aName.EqualsLiteral("firstPartyDomain")) {
228 0 : MOZ_RELEASE_ASSERT(mOriginAttributes->mFirstPartyDomain.IsEmpty());
229 0 : mOriginAttributes->mFirstPartyDomain.Assign(aValue);
230 0 : return true;
231 : }
232 :
233 : // No other attributes are supported.
234 0 : return false;
235 : }
236 :
237 : private:
238 : OriginAttributes* mOriginAttributes;
239 : };
240 :
241 : } // namespace
242 :
243 : bool
244 47 : OriginAttributes::PopulateFromSuffix(const nsACString& aStr)
245 : {
246 47 : if (aStr.IsEmpty()) {
247 47 : return true;
248 : }
249 :
250 0 : if (aStr[0] != '^') {
251 0 : return false;
252 : }
253 :
254 0 : URLParams params;
255 0 : params.ParseInput(Substring(aStr, 1, aStr.Length() - 1));
256 :
257 0 : PopulateFromSuffixIterator iterator(this);
258 0 : return params.ForEach(iterator);
259 : }
260 :
261 : bool
262 84 : OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin,
263 : nsACString& aOriginNoSuffix)
264 : {
265 : // RFindChar is only available on nsCString.
266 168 : nsCString origin(aOrigin);
267 84 : int32_t pos = origin.RFindChar('^');
268 :
269 84 : if (pos == kNotFound) {
270 84 : aOriginNoSuffix = origin;
271 84 : return true;
272 : }
273 :
274 0 : aOriginNoSuffix = Substring(origin, 0, pos);
275 0 : return PopulateFromSuffix(Substring(origin, pos));
276 : }
277 :
278 : void
279 105 : OriginAttributes::SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing)
280 : {
281 105 : mPrivateBrowsingId = aInPrivateBrowsing ? 1 : 0;
282 105 : }
283 :
284 : /* static */
285 : bool
286 0 : OriginAttributes::IsPrivateBrowsing(const nsACString& aOrigin)
287 : {
288 0 : nsAutoCString dummy;
289 0 : OriginAttributes attrs;
290 0 : if (NS_WARN_IF(!attrs.PopulateFromOrigin(aOrigin, dummy))) {
291 0 : return false;
292 : }
293 :
294 0 : return !!attrs.mPrivateBrowsingId;
295 : }
296 :
297 : } // namespace mozilla
|