1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 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/. */
6
7 #include "mozilla/AntiTrackingUtils.h"
8 #include "mozilla/BasePrincipal.h"
9 #include "mozilla/ClearOnShutdown.h"
10 #include "mozilla/ContentBlockingAllowList.h"
11 #include "mozilla/dom/BrowsingContext.h"
12 #include "mozilla/net/CookieJarSettings.h"
13 #include "mozilla/net/NeckoChannelParams.h"
14 #include "mozilla/Permission.h"
15 #include "mozilla/PermissionManager.h"
16 #include "mozilla/SchedulerGroup.h"
17 #include "mozilla/StaticPrefs_network.h"
18 #include "mozilla/Unused.h"
19 #include "nsGlobalWindowInner.h"
20 #include "nsIPrincipal.h"
21 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
22 # include "nsIProtocolHandler.h"
23 #endif
24 #include "nsIClassInfoImpl.h"
25 #include "nsIChannel.h"
26 #include "nsICookieManager.h"
27 #include "nsICookieService.h"
28 #include "nsIObjectInputStream.h"
29 #include "nsIObjectOutputStream.h"
30 #include "nsNetUtil.h"
31
32 namespace mozilla {
33 namespace net {
34
35 NS_IMPL_CLASSINFO(CookieJarSettings, nullptr, nsIClassInfo::THREADSAFE,
36 COOKIEJARSETTINGS_CID)
37
38 NS_IMPL_ISUPPORTS_CI(CookieJarSettings, nsICookieJarSettings, nsISerializable)
39
40 static StaticRefPtr<CookieJarSettings> sBlockinAll;
41
42 namespace {
43
44 class PermissionComparator {
45 public:
Equals(nsIPermission * aA,nsIPermission * aB)46 static bool Equals(nsIPermission* aA, nsIPermission* aB) {
47 nsCOMPtr<nsIPrincipal> principalA;
48 nsresult rv = aA->GetPrincipal(getter_AddRefs(principalA));
49 if (NS_WARN_IF(NS_FAILED(rv))) {
50 return false;
51 }
52
53 nsCOMPtr<nsIPrincipal> principalB;
54 rv = aB->GetPrincipal(getter_AddRefs(principalB));
55 if (NS_WARN_IF(NS_FAILED(rv))) {
56 return false;
57 }
58
59 bool equals = false;
60 rv = principalA->Equals(principalB, &equals);
61 if (NS_WARN_IF(NS_FAILED(rv))) {
62 return false;
63 }
64
65 return equals;
66 }
67 };
68
69 class ReleaseCookiePermissions final : public Runnable {
70 public:
ReleaseCookiePermissions(nsTArray<RefPtr<nsIPermission>> && aArray)71 explicit ReleaseCookiePermissions(nsTArray<RefPtr<nsIPermission>>&& aArray)
72 : Runnable("ReleaseCookiePermissions"), mArray(std::move(aArray)) {}
73
Run()74 NS_IMETHOD Run() override {
75 MOZ_ASSERT(NS_IsMainThread());
76 mArray.Clear();
77 return NS_OK;
78 }
79
80 private:
81 nsTArray<RefPtr<nsIPermission>> mArray;
82 };
83
84 } // namespace
85
86 // static
GetBlockingAll()87 already_AddRefed<nsICookieJarSettings> CookieJarSettings::GetBlockingAll() {
88 MOZ_ASSERT(NS_IsMainThread());
89
90 if (sBlockinAll) {
91 return do_AddRef(sBlockinAll);
92 }
93
94 sBlockinAll =
95 new CookieJarSettings(nsICookieService::BEHAVIOR_REJECT,
96 OriginAttributes::IsFirstPartyEnabled(), eFixed);
97 ClearOnShutdown(&sBlockinAll);
98
99 return do_AddRef(sBlockinAll);
100 }
101
102 // static
Create(CreateMode aMode)103 already_AddRefed<nsICookieJarSettings> CookieJarSettings::Create(
104 CreateMode aMode) {
105 MOZ_ASSERT(NS_IsMainThread());
106
107 RefPtr<CookieJarSettings> cookieJarSettings;
108
109 switch (aMode) {
110 case eRegular:
111 case ePrivate:
112 cookieJarSettings = new CookieJarSettings(
113 nsICookieManager::GetCookieBehavior(aMode == ePrivate),
114 OriginAttributes::IsFirstPartyEnabled(), eProgressive);
115 break;
116
117 default:
118 MOZ_CRASH("Unexpected create mode.");
119 }
120
121 return cookieJarSettings.forget();
122 }
123
124 // static
Create(nsIPrincipal * aPrincipal)125 already_AddRefed<nsICookieJarSettings> CookieJarSettings::Create(
126 nsIPrincipal* aPrincipal) {
127 MOZ_ASSERT(NS_IsMainThread());
128
129 if (aPrincipal && aPrincipal->OriginAttributesRef().mPrivateBrowsingId > 0) {
130 return Create(ePrivate);
131 }
132
133 return Create(eRegular);
134 }
135
136 // static
Create(uint32_t aCookieBehavior,const nsAString & aPartitionKey,bool aIsFirstPartyIsolated,bool aIsOnContentBlockingAllowList)137 already_AddRefed<nsICookieJarSettings> CookieJarSettings::Create(
138 uint32_t aCookieBehavior, const nsAString& aPartitionKey,
139 bool aIsFirstPartyIsolated, bool aIsOnContentBlockingAllowList) {
140 MOZ_ASSERT(NS_IsMainThread());
141
142 RefPtr<CookieJarSettings> cookieJarSettings = new CookieJarSettings(
143 aCookieBehavior, aIsFirstPartyIsolated, eProgressive);
144 cookieJarSettings->mPartitionKey = aPartitionKey;
145 cookieJarSettings->mIsOnContentBlockingAllowList =
146 aIsOnContentBlockingAllowList;
147
148 return cookieJarSettings.forget();
149 }
150
151 // static
CreateForXPCOM()152 already_AddRefed<nsICookieJarSettings> CookieJarSettings::CreateForXPCOM() {
153 MOZ_ASSERT(NS_IsMainThread());
154 return Create(eRegular);
155 }
156
CookieJarSettings(uint32_t aCookieBehavior,bool aIsFirstPartyIsolated,State aState)157 CookieJarSettings::CookieJarSettings(uint32_t aCookieBehavior,
158 bool aIsFirstPartyIsolated, State aState)
159 : mCookieBehavior(aCookieBehavior),
160 mIsFirstPartyIsolated(aIsFirstPartyIsolated),
161 mIsOnContentBlockingAllowList(false),
162 mState(aState),
163 mToBeMerged(false) {
164 MOZ_ASSERT(NS_IsMainThread());
165 MOZ_ASSERT_IF(
166 mIsFirstPartyIsolated,
167 mCookieBehavior !=
168 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
169 }
170
~CookieJarSettings()171 CookieJarSettings::~CookieJarSettings() {
172 if (!NS_IsMainThread() && !mCookiePermissions.IsEmpty()) {
173 RefPtr<Runnable> r =
174 new ReleaseCookiePermissions(std::move(mCookiePermissions));
175 MOZ_ASSERT(mCookiePermissions.IsEmpty());
176
177 SchedulerGroup::Dispatch(TaskCategory::Other, r.forget());
178 }
179 }
180
181 NS_IMETHODIMP
InitWithURI(nsIURI * aURI,bool aIsPrivate)182 CookieJarSettings::InitWithURI(nsIURI* aURI, bool aIsPrivate) {
183 NS_ENSURE_ARG(aURI);
184
185 mCookieBehavior = nsICookieManager::GetCookieBehavior(aIsPrivate);
186
187 SetPartitionKey(aURI);
188 return NS_OK;
189 }
190
191 NS_IMETHODIMP
GetCookieBehavior(uint32_t * aCookieBehavior)192 CookieJarSettings::GetCookieBehavior(uint32_t* aCookieBehavior) {
193 *aCookieBehavior = mCookieBehavior;
194 return NS_OK;
195 }
196
197 NS_IMETHODIMP
GetIsFirstPartyIsolated(bool * aIsFirstPartyIsolated)198 CookieJarSettings::GetIsFirstPartyIsolated(bool* aIsFirstPartyIsolated) {
199 *aIsFirstPartyIsolated = mIsFirstPartyIsolated;
200 return NS_OK;
201 }
202
203 NS_IMETHODIMP
GetRejectThirdPartyContexts(bool * aRejectThirdPartyContexts)204 CookieJarSettings::GetRejectThirdPartyContexts(
205 bool* aRejectThirdPartyContexts) {
206 *aRejectThirdPartyContexts =
207 CookieJarSettings::IsRejectThirdPartyContexts(mCookieBehavior);
208 return NS_OK;
209 }
210
211 NS_IMETHODIMP
GetLimitForeignContexts(bool * aLimitForeignContexts)212 CookieJarSettings::GetLimitForeignContexts(bool* aLimitForeignContexts) {
213 *aLimitForeignContexts =
214 mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
215 (StaticPrefs::privacy_dynamic_firstparty_limitForeign() &&
216 mCookieBehavior ==
217 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
218 return NS_OK;
219 }
220
221 NS_IMETHODIMP
GetBlockingAllThirdPartyContexts(bool * aBlockingAllThirdPartyContexts)222 CookieJarSettings::GetBlockingAllThirdPartyContexts(
223 bool* aBlockingAllThirdPartyContexts) {
224 // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
225 // simply rejecting the request to use the storage. In the future, if we
226 // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
227 // for non-cookie storage types, this may change.
228 *aBlockingAllThirdPartyContexts =
229 mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
230 (!StaticPrefs::network_cookie_rejectForeignWithExceptions_enabled() &&
231 mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN);
232 return NS_OK;
233 }
234
235 NS_IMETHODIMP
GetBlockingAllContexts(bool * aBlockingAllContexts)236 CookieJarSettings::GetBlockingAllContexts(bool* aBlockingAllContexts) {
237 *aBlockingAllContexts = mCookieBehavior == nsICookieService::BEHAVIOR_REJECT;
238 return NS_OK;
239 }
240
241 NS_IMETHODIMP
GetPartitionForeign(bool * aPartitionForeign)242 CookieJarSettings::GetPartitionForeign(bool* aPartitionForeign) {
243 *aPartitionForeign =
244 mCookieBehavior ==
245 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
246 return NS_OK;
247 }
248
249 NS_IMETHODIMP
SetPartitionForeign(bool aPartitionForeign)250 CookieJarSettings::SetPartitionForeign(bool aPartitionForeign) {
251 if (mIsFirstPartyIsolated) {
252 return NS_OK;
253 }
254
255 if (aPartitionForeign) {
256 mCookieBehavior =
257 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
258 }
259 return NS_OK;
260 }
261
262 NS_IMETHODIMP
GetIsOnContentBlockingAllowList(bool * aIsOnContentBlockingAllowList)263 CookieJarSettings::GetIsOnContentBlockingAllowList(
264 bool* aIsOnContentBlockingAllowList) {
265 *aIsOnContentBlockingAllowList = mIsOnContentBlockingAllowList;
266 return NS_OK;
267 }
268
269 NS_IMETHODIMP
GetPartitionKey(nsAString & aPartitionKey)270 CookieJarSettings::GetPartitionKey(nsAString& aPartitionKey) {
271 aPartitionKey = mPartitionKey;
272 return NS_OK;
273 }
274
275 NS_IMETHODIMP
CookiePermission(nsIPrincipal * aPrincipal,uint32_t * aCookiePermission)276 CookieJarSettings::CookiePermission(nsIPrincipal* aPrincipal,
277 uint32_t* aCookiePermission) {
278 MOZ_ASSERT(NS_IsMainThread());
279 NS_ENSURE_ARG_POINTER(aPrincipal);
280 NS_ENSURE_ARG_POINTER(aCookiePermission);
281
282 *aCookiePermission = nsIPermissionManager::UNKNOWN_ACTION;
283
284 nsresult rv;
285
286 // Let's see if we know this permission.
287 if (!mCookiePermissions.IsEmpty()) {
288 for (const RefPtr<nsIPermission>& permission : mCookiePermissions) {
289 bool match = false;
290 rv = permission->Matches(aPrincipal, false, &match);
291 if (NS_WARN_IF(NS_FAILED(rv)) || !match) {
292 continue;
293 }
294
295 rv = permission->GetCapability(aCookiePermission);
296 if (NS_WARN_IF(NS_FAILED(rv))) {
297 return rv;
298 }
299
300 return NS_OK;
301 }
302 }
303
304 // Let's ask the permission manager.
305 PermissionManager* pm = PermissionManager::GetInstance();
306 if (NS_WARN_IF(!pm)) {
307 return NS_ERROR_FAILURE;
308 }
309
310 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
311 // Check if this protocol doesn't allow cookies.
312 bool hasFlags;
313 nsCOMPtr<nsIURI> uri;
314 BasePrincipal::Cast(aPrincipal)->GetURI(getter_AddRefs(uri));
315
316 rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_FORBIDS_COOKIE_ACCESS,
317 &hasFlags);
318 if (NS_FAILED(rv) || hasFlags) {
319 *aCookiePermission = PermissionManager::DENY_ACTION;
320 rv = NS_OK; // Reset, so it's not caught as a bad status after the `else`.
321 } else // Note the tricky `else` which controls the call below.
322 #endif
323
324 rv = pm->TestPermissionFromPrincipal(aPrincipal, "cookie"_ns,
325 aCookiePermission);
326 if (NS_WARN_IF(NS_FAILED(rv))) {
327 return rv;
328 }
329
330 // Let's store the permission, also if the result is UNKNOWN in order to avoid
331 // race conditions.
332
333 nsCOMPtr<nsIPermission> permission =
334 Permission::Create(aPrincipal, "cookie"_ns, *aCookiePermission, 0, 0, 0);
335 if (permission) {
336 mCookiePermissions.AppendElement(permission);
337 }
338
339 mToBeMerged = true;
340 return NS_OK;
341 }
342
Serialize(CookieJarSettingsArgs & aData)343 void CookieJarSettings::Serialize(CookieJarSettingsArgs& aData) {
344 MOZ_ASSERT(NS_IsMainThread());
345
346 aData.isFixed() = mState == eFixed;
347 aData.cookieBehavior() = mCookieBehavior;
348 aData.isFirstPartyIsolated() = mIsFirstPartyIsolated;
349 aData.isOnContentBlockingAllowList() = mIsOnContentBlockingAllowList;
350 aData.partitionKey() = mPartitionKey;
351
352 for (const RefPtr<nsIPermission>& permission : mCookiePermissions) {
353 nsCOMPtr<nsIPrincipal> principal;
354 nsresult rv = permission->GetPrincipal(getter_AddRefs(principal));
355 if (NS_WARN_IF(NS_FAILED(rv))) {
356 continue;
357 }
358
359 ipc::PrincipalInfo principalInfo;
360 rv = PrincipalToPrincipalInfo(principal, &principalInfo,
361 true /* aSkipBaseDomain */);
362 if (NS_WARN_IF(NS_FAILED(rv))) {
363 continue;
364 }
365
366 uint32_t cookiePermission = 0;
367 rv = permission->GetCapability(&cookiePermission);
368 if (NS_WARN_IF(NS_FAILED(rv))) {
369 continue;
370 }
371
372 aData.cookiePermissions().AppendElement(
373 CookiePermissionData(principalInfo, cookiePermission));
374 }
375
376 mToBeMerged = false;
377 }
378
Deserialize(const CookieJarSettingsArgs & aData,nsICookieJarSettings ** aCookieJarSettings)379 /* static */ void CookieJarSettings::Deserialize(
380 const CookieJarSettingsArgs& aData,
381 nsICookieJarSettings** aCookieJarSettings) {
382 MOZ_ASSERT(NS_IsMainThread());
383
384 CookiePermissionList list;
385 for (const CookiePermissionData& data : aData.cookiePermissions()) {
386 auto principalOrErr = PrincipalInfoToPrincipal(data.principalInfo());
387 if (NS_WARN_IF(principalOrErr.isErr())) {
388 continue;
389 }
390
391 nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
392
393 nsCOMPtr<nsIPermission> permission = Permission::Create(
394 principal, "cookie"_ns, data.cookiePermission(), 0, 0, 0);
395 if (NS_WARN_IF(!permission)) {
396 continue;
397 }
398
399 list.AppendElement(permission);
400 }
401
402 RefPtr<CookieJarSettings> cookieJarSettings = new CookieJarSettings(
403 aData.cookieBehavior(), aData.isFirstPartyIsolated(),
404 aData.isFixed() ? eFixed : eProgressive);
405
406 cookieJarSettings->mIsOnContentBlockingAllowList =
407 aData.isOnContentBlockingAllowList();
408 cookieJarSettings->mCookiePermissions = std::move(list);
409 cookieJarSettings->mPartitionKey = aData.partitionKey();
410
411 cookieJarSettings.forget(aCookieJarSettings);
412 }
413
Merge(const CookieJarSettingsArgs & aData)414 void CookieJarSettings::Merge(const CookieJarSettingsArgs& aData) {
415 MOZ_ASSERT(NS_IsMainThread());
416 MOZ_ASSERT(
417 mCookieBehavior == aData.cookieBehavior() ||
418 (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER &&
419 aData.cookieBehavior() ==
420 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) ||
421 (mCookieBehavior ==
422 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
423 aData.cookieBehavior() == nsICookieService::BEHAVIOR_REJECT_TRACKER));
424
425 if (mState == eFixed) {
426 return;
427 }
428
429 // Merge cookie behavior pref values
430 if (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER &&
431 aData.cookieBehavior() ==
432 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
433 // If the other side has decided to partition third-party cookies, update
434 // our side when first-party isolation is disabled.
435 if (!mIsFirstPartyIsolated) {
436 mCookieBehavior =
437 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
438 }
439 }
440 if (mCookieBehavior ==
441 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
442 aData.cookieBehavior() == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
443 // If we've decided to partition third-party cookies, the other side may not
444 // have caught up yet unless it has first-party isolation enabled.
445 if (aData.isFirstPartyIsolated()) {
446 mCookieBehavior = nsICookieService::BEHAVIOR_REJECT_TRACKER;
447 mIsFirstPartyIsolated = true;
448 }
449 }
450 // Ignore all other cases.
451 MOZ_ASSERT_IF(
452 mIsFirstPartyIsolated,
453 mCookieBehavior !=
454 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
455
456 PermissionComparator comparator;
457
458 for (const CookiePermissionData& data : aData.cookiePermissions()) {
459 auto principalOrErr = PrincipalInfoToPrincipal(data.principalInfo());
460 if (NS_WARN_IF(principalOrErr.isErr())) {
461 continue;
462 }
463
464 nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
465 nsCOMPtr<nsIPermission> permission = Permission::Create(
466 principal, "cookie"_ns, data.cookiePermission(), 0, 0, 0);
467 if (NS_WARN_IF(!permission)) {
468 continue;
469 }
470
471 if (!mCookiePermissions.Contains(permission, comparator)) {
472 mCookiePermissions.AppendElement(permission);
473 }
474 }
475 }
476
SetPartitionKey(nsIURI * aURI)477 void CookieJarSettings::SetPartitionKey(nsIURI* aURI) {
478 MOZ_ASSERT(aURI);
479
480 OriginAttributes attrs;
481 attrs.SetPartitionKey(aURI);
482 mPartitionKey = std::move(attrs.mPartitionKey);
483 }
484
UpdateIsOnContentBlockingAllowList(nsIChannel * aChannel)485 void CookieJarSettings::UpdateIsOnContentBlockingAllowList(
486 nsIChannel* aChannel) {
487 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
488 MOZ_ASSERT(aChannel);
489 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
490
491 nsCOMPtr<nsIURI> uri;
492 nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
493 if (NS_WARN_IF(NS_FAILED(rv))) {
494 return;
495 }
496
497 // We need to recompute the ContentBlockingAllowListPrincipal here for the
498 // top level channel because we might navigate from the the initial
499 // about:blank page or the existing page which may have a different origin
500 // than the URI we are going to load here. Thus, we need to recompute the
501 // prinicpal in order to get the correct ContentBlockingAllowListPrincipal.
502 nsCOMPtr<nsIPrincipal> contentBlockingAllowListPrincipal;
503 OriginAttributes attrs;
504 loadInfo->GetOriginAttributes(&attrs);
505 ContentBlockingAllowList::RecomputePrincipal(
506 uri, attrs, getter_AddRefs(contentBlockingAllowListPrincipal));
507
508 if (!contentBlockingAllowListPrincipal ||
509 !contentBlockingAllowListPrincipal->GetIsContentPrincipal()) {
510 return;
511 }
512
513 Unused << ContentBlockingAllowList::Check(contentBlockingAllowListPrincipal,
514 NS_UsePrivateBrowsing(aChannel),
515 mIsOnContentBlockingAllowList);
516 }
517
518 // static
IsRejectThirdPartyContexts(uint32_t aCookieBehavior)519 bool CookieJarSettings::IsRejectThirdPartyContexts(uint32_t aCookieBehavior) {
520 return aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
521 aCookieBehavior ==
522 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN ||
523 IsRejectThirdPartyWithExceptions(aCookieBehavior);
524 }
525
526 // static
IsRejectThirdPartyWithExceptions(uint32_t aCookieBehavior)527 bool CookieJarSettings::IsRejectThirdPartyWithExceptions(
528 uint32_t aCookieBehavior) {
529 return aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
530 StaticPrefs::network_cookie_rejectForeignWithExceptions_enabled();
531 }
532
533 NS_IMETHODIMP
Read(nsIObjectInputStream * aStream)534 CookieJarSettings::Read(nsIObjectInputStream* aStream) {
535 nsresult rv = aStream->Read32(&mCookieBehavior);
536 if (NS_WARN_IF(NS_FAILED(rv))) {
537 return rv;
538 }
539
540 rv = aStream->ReadBoolean(&mIsFirstPartyIsolated);
541 if (NS_WARN_IF(NS_FAILED(rv))) {
542 return rv;
543 }
544
545 bool isFixed;
546 aStream->ReadBoolean(&isFixed);
547 if (NS_WARN_IF(NS_FAILED(rv))) {
548 return rv;
549 }
550 mState = isFixed ? eFixed : eProgressive;
551
552 rv = aStream->ReadBoolean(&mIsOnContentBlockingAllowList);
553 if (NS_WARN_IF(NS_FAILED(rv))) {
554 return rv;
555 }
556
557 rv = aStream->ReadString(mPartitionKey);
558 if (NS_WARN_IF(NS_FAILED(rv))) {
559 return rv;
560 }
561
562 // Deserializing the cookie permission list.
563 uint32_t cookiePermissionsLength;
564 rv = aStream->Read32(&cookiePermissionsLength);
565 if (NS_WARN_IF(NS_FAILED(rv))) {
566 return rv;
567 }
568
569 if (!cookiePermissionsLength) {
570 // Bailing out early because there is no cookie permission.
571 return NS_OK;
572 }
573
574 CookiePermissionList list;
575 mCookiePermissions.SetCapacity(cookiePermissionsLength);
576 for (uint32_t i = 0; i < cookiePermissionsLength; ++i) {
577 nsAutoCString principalJSON;
578 aStream->ReadCString(principalJSON);
579 if (NS_WARN_IF(NS_FAILED(rv))) {
580 return rv;
581 }
582
583 nsCOMPtr<nsIPrincipal> principal = BasePrincipal::FromJSON(principalJSON);
584
585 if (NS_WARN_IF(!principal)) {
586 continue;
587 }
588
589 uint32_t cookiePermission;
590 aStream->Read32(&cookiePermission);
591 if (NS_WARN_IF(NS_FAILED(rv))) {
592 return rv;
593 }
594
595 nsCOMPtr<nsIPermission> permission =
596 Permission::Create(principal, "cookie"_ns, cookiePermission, 0, 0, 0);
597 if (NS_WARN_IF(!permission)) {
598 continue;
599 }
600
601 list.AppendElement(permission);
602 }
603
604 mCookiePermissions = std::move(list);
605
606 return NS_OK;
607 }
608
609 NS_IMETHODIMP
Write(nsIObjectOutputStream * aStream)610 CookieJarSettings::Write(nsIObjectOutputStream* aStream) {
611 nsresult rv = aStream->Write32(mCookieBehavior);
612 if (NS_WARN_IF(NS_FAILED(rv))) {
613 return rv;
614 }
615
616 rv = aStream->WriteBoolean(mIsFirstPartyIsolated);
617 if (NS_WARN_IF(NS_FAILED(rv))) {
618 return rv;
619 }
620
621 rv = aStream->WriteBoolean(mState == eFixed);
622 if (NS_WARN_IF(NS_FAILED(rv))) {
623 return rv;
624 }
625
626 rv = aStream->WriteBoolean(mIsOnContentBlockingAllowList);
627 if (NS_WARN_IF(NS_FAILED(rv))) {
628 return rv;
629 }
630
631 rv = aStream->WriteWStringZ(mPartitionKey.get());
632 if (NS_WARN_IF(NS_FAILED(rv))) {
633 return rv;
634 }
635
636 // Serializing the cookie permission list. It will first write the length of
637 // the list, and then, write the cookie permission consecutively.
638 uint32_t cookiePermissionsLength = mCookiePermissions.Length();
639 rv = aStream->Write32(cookiePermissionsLength);
640 if (NS_WARN_IF(NS_FAILED(rv))) {
641 return rv;
642 }
643
644 for (const RefPtr<nsIPermission>& permission : mCookiePermissions) {
645 nsCOMPtr<nsIPrincipal> principal;
646 nsresult rv = permission->GetPrincipal(getter_AddRefs(principal));
647 if (NS_WARN_IF(NS_FAILED(rv))) {
648 continue;
649 }
650
651 nsAutoCString principalJSON;
652 BasePrincipal::Cast(principal)->ToJSON(principalJSON);
653
654 rv = aStream->WriteStringZ(principalJSON.get());
655 if (NS_WARN_IF(NS_FAILED(rv))) {
656 return rv;
657 }
658
659 uint32_t cookiePermission = 0;
660 rv = permission->GetCapability(&cookiePermission);
661 if (NS_WARN_IF(NS_FAILED(rv))) {
662 continue;
663 }
664
665 rv = aStream->Write32(cookiePermission);
666 if (NS_WARN_IF(NS_FAILED(rv))) {
667 return rv;
668 }
669 }
670
671 return NS_OK;
672 }
673
674 } // namespace net
675 } // namespace mozilla
676