Bug 1951750 - Handle domain argument in CookieStoreParent r=baku,edgul,cookie-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D240695
This commit is contained in:
Valentin Gosu
2025-03-28 13:48:31 +00:00
parent 5b45039391
commit 67f73cbb7b
9 changed files with 274 additions and 199 deletions

View File

@@ -87,23 +87,49 @@ bool ValidateCookieNameAndValue(const nsAString& aName, const nsAString& aValue,
return true;
}
bool ValidateCookieDomain(const nsAString& aHost, const nsAString& aDomain,
Promise* aPromise) {
bool HasSecurePrefix(const nsAString& aString) {
return StringBeginsWith(aString, u"__Secure-"_ns,
nsCaseInsensitiveStringComparator);
}
bool HasHostPrefix(const nsAString& aString) {
return StringBeginsWith(aString, u"__Host-"_ns,
nsCaseInsensitiveStringComparator);
}
bool ValidateCookieDomain(nsIPrincipal* aPrincipal, const nsAString& aName,
const nsAString& aDomain, Promise* aPromise) {
MOZ_ASSERT(aPromise);
if (aDomain.IsEmpty()) {
return true;
}
nsAutoCString utf8Domain;
nsresult rv =
nsContentUtils::GetHostOrIPv6WithBrackets(aPrincipal, utf8Domain);
if (NS_WARN_IF(NS_FAILED(rv))) {
aPromise->MaybeRejectWithNotAllowedError("Permission denied");
return false;
}
// If the name has a __Host- prefix, then aDomain must be empty.
if (HasHostPrefix(aName) && !aDomain.IsEmpty()) {
aPromise->MaybeRejectWithTypeError(
"Cookie domain is not allowed for cookies with a __Host- prefix");
return false;
}
if (aDomain[0] == '.') {
aPromise->MaybeRejectWithTypeError("Cookie domain cannot start with '.'");
return false;
}
if (aHost != aDomain) {
if ((aHost.Length() < aDomain.Length() + 1) ||
!StringEndsWith(aHost, aDomain) ||
aHost[aHost.Length() - aDomain.Length() - 1] != '.') {
NS_ConvertUTF8toUTF16 host(utf8Domain);
if (host != aDomain) {
if ((host.Length() < aDomain.Length() + 1) ||
!StringEndsWith(host, aDomain) ||
host[host.Length() - aDomain.Length() - 1] != '.') {
aPromise->MaybeRejectWithTypeError(
"Cookie domain must domain-match current host");
return false;
@@ -143,16 +169,6 @@ bool ValidateCookiePath(const nsAString& aPath, nsAString& retPath,
return true;
}
bool HasSecurePrefix(const nsAString& aString) {
return StringBeginsWith(aString, u"__Secure-"_ns,
nsCaseInsensitiveStringComparator);
}
bool HasHostPrefix(const nsAString& aString) {
return StringBeginsWith(aString, u"__Host-"_ns,
nsCaseInsensitiveStringComparator);
}
// Reject cookies whose name starts with the magic prefixes from
// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis
// if they do not meet the criteria required by the prefix.
@@ -369,17 +385,8 @@ already_AddRefed<Promise> CookieStore::Set(const CookieInit& aOptions,
return;
}
nsAutoCString baseDomainUtf8;
nsresult rv =
net::CookieCommons::GetBaseDomain(cookiePrincipal, baseDomainUtf8);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeRejectWithNotAllowedError("Permission denied");
return;
}
NS_ConvertUTF8toUTF16 baseDomain(baseDomainUtf8);
if (!ValidateCookieDomain(baseDomain, aOptions.mDomain, promise)) {
if (!ValidateCookieDomain(cookiePrincipal, aOptions.mName,
aOptions.mDomain, promise)) {
return;
}
@@ -415,7 +422,7 @@ already_AddRefed<Promise> CookieStore::Set(const CookieInit& aOptions,
}
nsID operationID;
rv = nsID::GenerateUUIDInPlace(operationID);
nsresult rv = nsID::GenerateUUIDInPlace(operationID);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeReject(NS_ERROR_UNEXPECTED);
return;
@@ -424,19 +431,19 @@ already_AddRefed<Promise> CookieStore::Set(const CookieInit& aOptions,
self->mNotificationWatcher->ResolvePromiseWhenNotified(operationID,
promise);
nsCOMPtr<nsIURI> cookieURI = cookiePrincipal->GetURI();
RefPtr<CookieStoreChild::SetRequestPromise> ipcPromise =
self->mActor->SendSetRequest(
aOptions.mDomain.IsEmpty() ? nsString(baseDomain)
: nsString(aOptions.mDomain),
cookiePrincipal->OriginAttributesRef(), thirdPartyContext,
partitionForeign, usingStorageAccess, isOn3PCBExceptionList,
nsString(aOptions.mName), nsString(aOptions.mValue),
cookieURI, cookiePrincipal->OriginAttributesRef(),
thirdPartyContext, partitionForeign, usingStorageAccess,
isOn3PCBExceptionList, nsString(aOptions.mName),
nsString(aOptions.mValue),
// If expires is not set, it's a session cookie.
aOptions.mExpires.IsNull(),
aOptions.mExpires.IsNull()
? INT64_MAX
: static_cast<int64_t>(aOptions.mExpires.Value() / 1000),
path, SameSiteToConst(aOptions.mSameSite),
aOptions.mDomain, path, SameSiteToConst(aOptions.mSameSite),
aOptions.mPartitioned, operationID);
if (NS_WARN_IF(!ipcPromise)) {
promise->MaybeResolveWithUndefined();
@@ -503,8 +510,8 @@ already_AddRefed<Promise> CookieStore::Delete(
return;
}
NS_ConvertUTF8toUTF16 baseDomain(baseDomainUtf8);
if (!ValidateCookieDomain(baseDomain, aOptions.mDomain, promise)) {
if (!ValidateCookieDomain(cookiePrincipal, aOptions.mName,
aOptions.mDomain, promise)) {
return;
}
@@ -548,14 +555,13 @@ already_AddRefed<Promise> CookieStore::Delete(
self->mNotificationWatcher->ResolvePromiseWhenNotified(operationID,
promise);
nsCOMPtr<nsIURI> cookieURI = cookiePrincipal->GetURI();
RefPtr<CookieStoreChild::DeleteRequestPromise> ipcPromise =
self->mActor->SendDeleteRequest(
aOptions.mDomain.IsEmpty() ? nsString(baseDomain)
: nsString(aOptions.mDomain),
cookiePrincipal->OriginAttributesRef(), thirdPartyContext,
partitionForeign, usingStorageAccess, isOn3PCBExceptionList,
nsString(aOptions.mName), path, aOptions.mPartitioned,
cookieURI, cookiePrincipal->OriginAttributesRef(),
thirdPartyContext, partitionForeign, usingStorageAccess,
isOn3PCBExceptionList, nsString(aOptions.mName),
nsString(aOptions.mDomain), path, aOptions.mPartitioned,
operationID);
if (NS_WARN_IF(!ipcPromise)) {
promise->MaybeResolveWithUndefined();
@@ -750,10 +756,10 @@ already_AddRefed<Promise> CookieStore::GetInternal(
return;
}
nsCOMPtr<nsIURI> cookieURI = cookiePrincipal->GetURI();
RefPtr<CookieStoreChild::GetRequestPromise> ipcPromise =
self->mActor->SendGetRequest(
NS_ConvertUTF8toUTF16(baseDomain),
cookiePrincipal->OriginAttributesRef(),
cookieURI, cookiePrincipal->OriginAttributesRef(),
partitionedCookiePrincipal
? Some(partitionedCookiePrincipal->OriginAttributesRef())
: Nothing(),

View File

@@ -11,6 +11,8 @@
#include "mozilla/Maybe.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/net/Cookie.h"
#include "mozilla/net/CookieParser.h"
#include "mozilla/Components.h"
#include "mozilla/net/CookieCommons.h"
#include "mozilla/net/CookieServiceParent.h"
#include "mozilla/net/NeckoParent.h"
@@ -18,6 +20,8 @@
#include "nsICookieManager.h"
#include "nsICookieService.h"
#include "nsProxyRelease.h"
#include "mozilla/ipc/URIUtils.h" // for IPDLParamTraits<nsIURI*>
#include "nsIEffectiveTLDService.h"
using namespace mozilla::ipc;
using namespace mozilla::net;
@@ -69,7 +73,7 @@ CookieStoreParent::~CookieStoreParent() {
}
mozilla::ipc::IPCResult CookieStoreParent::RecvGetRequest(
const nsString& aDomain, const OriginAttributes& aOriginAttributes,
nsIURI* aCookieURI, const OriginAttributes& aOriginAttributes,
const Maybe<OriginAttributes>& aPartitionedOriginAttributes,
const bool& aThirdPartyContext, const bool& aPartitionForeign,
const bool& aUsingStorageAccess, const bool& aIsOn3PCBExceptionList,
@@ -78,13 +82,13 @@ mozilla::ipc::IPCResult CookieStoreParent::RecvGetRequest(
AssertIsOnBackgroundThread();
InvokeAsync(GetMainThreadSerialEventTarget(), __func__,
[self = RefPtr(this), aDomain, aOriginAttributes,
[self = RefPtr(this), uri = RefPtr{aCookieURI}, aOriginAttributes,
aPartitionedOriginAttributes, aThirdPartyContext,
aPartitionForeign, aUsingStorageAccess, aIsOn3PCBExceptionList,
aMatchName, aName, aPath, aOnlyFirstMatch]() {
CopyableTArray<CookieData> results;
self->GetRequestOnMainThread(
aDomain, aOriginAttributes, aPartitionedOriginAttributes,
uri, aOriginAttributes, aPartitionedOriginAttributes,
aThirdPartyContext, aPartitionForeign, aUsingStorageAccess,
aIsOn3PCBExceptionList, aMatchName, aName, aPath,
aOnlyFirstMatch, results);
@@ -102,13 +106,13 @@ mozilla::ipc::IPCResult CookieStoreParent::RecvGetRequest(
}
mozilla::ipc::IPCResult CookieStoreParent::RecvSetRequest(
const nsString& aDomain, const OriginAttributes& aOriginAttributes,
nsIURI* aCookieURI, const OriginAttributes& aOriginAttributes,
const bool& aThirdPartyContext, const bool& aPartitionForeign,
const bool& aUsingStorageAccess, const bool& aIsOn3PCBExceptionList,
const nsString& aName, const nsString& aValue, const bool& aSession,
const int64_t& aExpires, const nsString& aPath, const int32_t& aSameSite,
const bool& aPartitioned, const nsID& aOperationID,
SetRequestResolver&& aResolver) {
const int64_t& aExpires, const nsString& aDomain, const nsString& aPath,
const int32_t& aSameSite, const bool& aPartitioned,
const nsID& aOperationID, SetRequestResolver&& aResolver) {
AssertIsOnBackgroundThread();
RefPtr<ThreadsafeContentParentHandle> parent =
@@ -116,12 +120,12 @@ mozilla::ipc::IPCResult CookieStoreParent::RecvSetRequest(
InvokeAsync(
GetMainThreadSerialEventTarget(), __func__,
[self = RefPtr(this), parent = RefPtr(parent), aDomain, aOriginAttributes,
aThirdPartyContext, aPartitionForeign, aUsingStorageAccess,
aIsOn3PCBExceptionList, aName, aValue, aSession, aExpires, aPath,
aSameSite, aPartitioned, aOperationID]() {
[self = RefPtr(this), parent = RefPtr(parent), uri = RefPtr{aCookieURI},
aDomain, aOriginAttributes, aThirdPartyContext, aPartitionForeign,
aUsingStorageAccess, aIsOn3PCBExceptionList, aName, aValue, aSession,
aExpires, aPath, aSameSite, aPartitioned, aOperationID]() {
bool waitForNotification = self->SetRequestOnMainThread(
parent, aDomain, aOriginAttributes, aThirdPartyContext,
parent, uri, aDomain, aOriginAttributes, aThirdPartyContext,
aPartitionForeign, aUsingStorageAccess, aIsOn3PCBExceptionList,
aName, aValue, aSession, aExpires, aPath, aSameSite, aPartitioned,
aOperationID);
@@ -139,11 +143,12 @@ mozilla::ipc::IPCResult CookieStoreParent::RecvSetRequest(
}
mozilla::ipc::IPCResult CookieStoreParent::RecvDeleteRequest(
const nsString& aDomain, const OriginAttributes& aOriginAttributes,
nsIURI* aCookieURI, const OriginAttributes& aOriginAttributes,
const bool& aThirdPartyContext, const bool& aPartitionForeign,
const bool& aUsingStorageAccess, const bool& aIsOn3PCBExceptionList,
const nsString& aName, const nsString& aPath, const bool& aPartitioned,
const nsID& aOperationID, DeleteRequestResolver&& aResolver) {
const nsString& aName, const nsString& aDomain, const nsString& aPath,
const bool& aPartitioned, const nsID& aOperationID,
DeleteRequestResolver&& aResolver) {
AssertIsOnBackgroundThread();
RefPtr<ThreadsafeContentParentHandle> parent =
@@ -151,11 +156,12 @@ mozilla::ipc::IPCResult CookieStoreParent::RecvDeleteRequest(
InvokeAsync(
GetMainThreadSerialEventTarget(), __func__,
[self = RefPtr(this), parent = RefPtr(parent), aDomain, aOriginAttributes,
aThirdPartyContext, aPartitionForeign, aUsingStorageAccess,
aIsOn3PCBExceptionList, aName, aPath, aPartitioned, aOperationID]() {
[self = RefPtr(this), parent = RefPtr(parent), uri = RefPtr{aCookieURI},
aDomain, aOriginAttributes, aThirdPartyContext, aPartitionForeign,
aUsingStorageAccess, aIsOn3PCBExceptionList, aName, aPath, aPartitioned,
aOperationID]() {
bool waitForNotification = self->DeleteRequestOnMainThread(
parent, aDomain, aOriginAttributes, aThirdPartyContext,
parent, uri, aDomain, aOriginAttributes, aThirdPartyContext,
aPartitionForeign, aUsingStorageAccess, aIsOn3PCBExceptionList,
aName, aPath, aPartitioned, aOperationID);
return SetDeleteRequestPromise::CreateAndResolve(waitForNotification,
@@ -248,13 +254,23 @@ mozilla::ipc::IPCResult CookieStoreParent::RecvClose() {
return IPC_OK();
}
namespace util {
bool HasHostPrefix(const nsAString& aCookieName) {
return StringBeginsWith(aCookieName, u"__Host-"_ns,
nsCaseInsensitiveStringComparator);
}
} // namespace util
void CookieStoreParent::GetRequestOnMainThread(
const nsAString& aDomain, const OriginAttributes& aOriginAttributes,
nsIURI* aCookieURI, const OriginAttributes& aOriginAttributes,
const Maybe<OriginAttributes>& aPartitionedOriginAttributes,
bool aThirdPartyContext, bool aPartitionForeign, bool aUsingStorageAccess,
bool aIsOn3PCBExceptionList, bool aMatchName, const nsAString& aName,
const nsACString& aPath, bool aOnlyFirstMatch,
nsTArray<CookieData>& aResults) {
nsresult rv;
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsICookieService> service =
@@ -263,6 +279,21 @@ void CookieStoreParent::GetRequestOnMainThread(
return;
}
nsAutoCString baseDomain;
nsCOMPtr<nsIEffectiveTLDService> etld =
mozilla::components::EffectiveTLD::Service();
bool requireMatch = false;
rv = CookieCommons::GetBaseDomain(etld, aCookieURI, baseDomain, requireMatch);
if (NS_FAILED(rv)) {
return;
}
nsAutoCString hostName;
rv = nsContentUtils::GetHostOrIPv6WithBrackets(aCookieURI, hostName);
if (NS_FAILED(rv)) {
return;
}
NS_ConvertUTF16toUTF8 matchName(aName);
nsTArray<OriginAttributes> attrsList;
@@ -276,9 +307,12 @@ void CookieStoreParent::GetRequestOnMainThread(
for (const OriginAttributes& attrs : attrsList) {
nsTArray<RefPtr<Cookie>> cookies;
service->GetCookiesFromHost(NS_ConvertUTF16toUTF8(aDomain), attrs, cookies);
service->GetCookiesFromHost(baseDomain, attrs, cookies);
for (Cookie* cookie : cookies) {
if (!CookieCommons::DomainMatches(cookie, hostName)) {
continue;
}
if (cookie->IsHttpOnly()) {
continue;
}
@@ -316,16 +350,40 @@ void CookieStoreParent::GetRequestOnMainThread(
}
bool CookieStoreParent::SetRequestOnMainThread(
ThreadsafeContentParentHandle* aParent, const nsAString& aDomain,
const OriginAttributes& aOriginAttributes, bool aThirdPartyContext,
bool aPartitionForeign, bool aUsingStorageAccess,
ThreadsafeContentParentHandle* aParent, nsIURI* aCookieURI,
const nsAString& aDomain, const OriginAttributes& aOriginAttributes,
bool aThirdPartyContext, bool aPartitionForeign, bool aUsingStorageAccess,
bool aIsOn3PCBExceptionList, const nsAString& aName,
const nsAString& aValue, bool aSession, int64_t aExpires,
const nsAString& aPath, int32_t aSameSite, bool aPartitioned,
const nsID& aOperationID) {
MOZ_ASSERT(NS_IsMainThread());
nsresult rv;
bool requireMatch = false;
NS_ConvertUTF16toUTF8 domain(aDomain);
nsAutoCString domainWithDot;
if (util::HasHostPrefix(aName) && !domain.IsEmpty()) {
MOZ_DIAGNOSTIC_CRASH("This should not be allowed by CookieStore");
return false;
}
// If aDomain is `domain.com` then domainWithDot will be `.domain.com`
// Otherwise, when aDomain is empty, domain and domainWithDot will both
// be the host of aCookieURI
if (!domain.IsEmpty()) {
MOZ_ASSERT(!domain.IsEmpty());
domainWithDot.Insert('.', 0);
} else {
domain.Truncate();
rv = nsContentUtils::GetHostOrIPv6WithBrackets(aCookieURI, domain);
if (NS_FAILED(rv)) {
return false;
}
requireMatch = true;
}
domainWithDot.Append(domain);
if (!CheckContentProcessSecurity(aParent, domain, aOriginAttributes)) {
return false;
@@ -357,13 +415,18 @@ bool CookieStoreParent::SetRequestOnMainThread(
notificationWatcher->CallbackWhenNotified(aOperationID, notificationCb);
OriginAttributes attrs(aOriginAttributes);
nsresult rv = service->AddNative(
domain, NS_ConvertUTF16toUTF8(aPath), NS_ConvertUTF16toUTF8(aName),
NS_ConvertUTF16toUTF8(aValue),
rv = service->AddNative(
aCookieURI, domainWithDot, NS_ConvertUTF16toUTF8(aPath),
NS_ConvertUTF16toUTF8(aName), NS_ConvertUTF16toUTF8(aValue),
true, // secure
false, // mHttpOnly,
aSession, aSession ? INT64_MAX : aExpires, &attrs, aSameSite,
nsICookie::SCHEME_HTTPS, aPartitioned, &aOperationID);
nsICookie::SCHEME_HTTPS, aPartitioned, &aOperationID,
[&](mozilla::net::CookieStruct& aCookieStruct) -> bool {
return CookieParser::CheckCookieStruct(aCookieStruct, aCookieURI, ""_ns,
domain, requireMatch, false) ==
CookieParser::NoRejection;
});
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
@@ -374,77 +437,64 @@ bool CookieStoreParent::SetRequestOnMainThread(
}
bool CookieStoreParent::DeleteRequestOnMainThread(
ThreadsafeContentParentHandle* aParent, const nsAString& aDomain,
const OriginAttributes& aOriginAttributes, bool aThirdPartyContext,
bool aPartitionForeign, bool aUsingStorageAccess,
ThreadsafeContentParentHandle* aParent, nsIURI* aCookieURI,
const nsAString& aDomain, const OriginAttributes& aOriginAttributes,
bool aThirdPartyContext, bool aPartitionForeign, bool aUsingStorageAccess,
bool aIsOn3PCBExceptionList, const nsAString& aName, const nsAString& aPath,
bool aPartitioned, const nsID& aOperationID) {
MOZ_ASSERT(NS_IsMainThread());
nsresult rv;
NS_ConvertUTF16toUTF8 domain(aDomain);
nsAutoCString hostName;
nsContentUtils::GetHostOrIPv6WithBrackets(aCookieURI, hostName);
if (!CheckContentProcessSecurity(aParent, domain, aOriginAttributes)) {
nsAutoCString cookiesForDomain;
if (aDomain.IsEmpty()) {
cookiesForDomain = hostName;
} else {
cookiesForDomain = NS_ConvertUTF16toUTF8(aDomain);
}
if (!CheckContentProcessSecurity(aParent, cookiesForDomain,
aOriginAttributes)) {
return false;
}
nsCOMPtr<nsICookieManager> service =
do_GetService(NS_COOKIEMANAGER_CONTRACTID);
nsCOMPtr<nsICookieService> service =
do_GetService(NS_COOKIESERVICE_CONTRACTID);
if (!service) {
return false;
}
OriginAttributes attrs(aOriginAttributes);
nsTArray<RefPtr<nsICookie>> results;
nsresult rv =
service->GetCookiesFromHostNative(domain, &attrs, false, results);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
nsCOMPtr<nsICookieManager> cookieManager = do_QueryInterface(service);
NS_ConvertUTF16toUTF8 matchName(aName);
NS_ConvertUTF16toUTF8 matchPath(aPath);
for (nsICookie* cookie : results) {
nsTArray<RefPtr<Cookie>> cookies;
OriginAttributes attrs(aOriginAttributes);
service->GetCookiesFromHost(cookiesForDomain, attrs, cookies);
for (Cookie* cookie : cookies) {
MOZ_ASSERT(cookie);
nsAutoCString name;
rv = cookie->GetName(name);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
if (!matchName.Equals(cookie->Name())) {
continue;
}
if (!matchName.Equals(name)) {
if (!CookieCommons::DomainMatches(cookie, hostName)) {
continue;
}
nsAutoCString path;
rv = cookie->GetPath(path);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
if (!matchPath.IsEmpty() && !matchPath.Equals(path)) {
if (!matchPath.IsEmpty() && !matchPath.Equals(cookie->Path())) {
continue;
}
bool isPartitioned = false;
rv = cookie->GetIsPartitioned(&isPartitioned);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
if (isPartitioned != aPartitioned) continue;
if (cookie->IsPartitioned() != aPartitioned) continue;
if (aThirdPartyContext) {
int32_t sameSiteAttr = 0;
rv = cookie->GetSameSite(&sameSiteAttr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
int32_t sameSiteAttr = cookie->SameSite();
if (!CookieCommons::ShouldIncludeCrossSiteCookie(
sameSiteAttr,
isPartitioned && !aOriginAttributes.mPartitionKey.IsEmpty(),
aPartitioned && !aOriginAttributes.mPartitionKey.IsEmpty(),
aPartitionForeign, attrs.IsPrivateBrowsing(), aUsingStorageAccess,
aIsOn3PCBExceptionList)) {
return false;
@@ -462,7 +512,8 @@ bool CookieStoreParent::DeleteRequestOnMainThread(
notificationWatcher->CallbackWhenNotified(aOperationID, notificationCb);
rv = service->RemoveNative(domain, matchName, path, &attrs, &aOperationID);
rv = cookieManager->RemoveNative(cookie->Host(), matchName, cookie->Path(),
&attrs, &aOperationID);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}

View File

@@ -34,7 +34,7 @@ class CookieStoreParent final : public PCookieStoreParent {
~CookieStoreParent();
mozilla::ipc::IPCResult RecvGetRequest(
const nsString& aDomain, const OriginAttributes& aOriginAttributes,
nsIURI* aCookieURI, const OriginAttributes& aOriginAttributes,
const Maybe<OriginAttributes>& aPartitionedOriginAttributes,
const bool& aThirdPartyContext, const bool& aPartitionForeign,
const bool& aUsingStorageAccess, const bool& aIsOn3PCBExceptionList,
@@ -42,20 +42,21 @@ class CookieStoreParent final : public PCookieStoreParent {
const bool& aOnlyFirstMatch, GetRequestResolver&& aResolver);
mozilla::ipc::IPCResult RecvSetRequest(
const nsString& aDomain, const OriginAttributes& aOriginAttributes,
nsIURI* aCookieURI, const OriginAttributes& aOriginAttributes,
const bool& aThirdPartyContext, const bool& aPartitionForeign,
const bool& aUsingStorageAccess, const bool& aIsOn3PCBExceptionList,
const nsString& aName, const nsString& aValue, const bool& aSession,
const int64_t& aExpires, const nsString& aPath, const int32_t& aSameSite,
const bool& aPartitioned, const nsID& aOperationID,
SetRequestResolver&& aResolver);
const int64_t& aExpires, const nsString& aDomain, const nsString& aPath,
const int32_t& aSameSite, const bool& aPartitioned,
const nsID& aOperationID, SetRequestResolver&& aResolver);
mozilla::ipc::IPCResult RecvDeleteRequest(
const nsString& aDomain, const OriginAttributes& aOriginAttributes,
nsIURI* aCookieURI, const OriginAttributes& aOriginAttributes,
const bool& aThirdPartyContext, const bool& aPartitionForeign,
const bool& aUsingStorageAccess, const bool& aIsOn3PCBExceptionList,
const nsString& aName, const nsString& aPath, const bool& aPartitioned,
const nsID& aOperationID, DeleteRequestResolver&& aResolver);
const nsString& aName, const nsString& aDomain, const nsString& aPath,
const bool& aPartitioned, const nsID& aOperationID,
DeleteRequestResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetSubscriptionsRequest(
const PrincipalInfo& aPrincipalInfo, const nsCString& aScopeURL,
@@ -69,7 +70,7 @@ class CookieStoreParent final : public PCookieStoreParent {
mozilla::ipc::IPCResult RecvClose();
void GetRequestOnMainThread(
const nsAString& aDomain, const OriginAttributes& aOriginAttributes,
nsIURI* aCookieURI, const OriginAttributes& aOriginAttributes,
const Maybe<OriginAttributes>& aPartitionedOriginAttributes,
bool aThirdPartyContext, bool aPartitionForeign, bool aUsingStorageAccess,
bool aIsOn3PCBExceptionList, bool aMatchName, const nsAString& aName,
@@ -79,7 +80,7 @@ class CookieStoreParent final : public PCookieStoreParent {
// Returns true if a cookie notification has been generated while completing
// the operation.
bool SetRequestOnMainThread(ThreadsafeContentParentHandle* aParent,
const nsAString& aDomain,
nsIURI* aCookieURI, const nsAString& aDomain,
const OriginAttributes& aOriginAttributes,
bool aThirdPartyContext, bool aPartitionForeign,
bool aUsingStorageAccess,
@@ -92,9 +93,9 @@ class CookieStoreParent final : public PCookieStoreParent {
// Returns true if a cookie notification has been generated while completing
// the operation.
bool DeleteRequestOnMainThread(
ThreadsafeContentParentHandle* aParent, const nsAString& aDomain,
const OriginAttributes& aOriginAttributes, bool aThirdPartyContext,
bool aPartitionForeign, bool aUsingStorageAccess,
ThreadsafeContentParentHandle* aParent, nsIURI* aCookieURI,
const nsAString& aDomain, const OriginAttributes& aOriginAttributes,
bool aThirdPartyContext, bool aPartitionForeign, bool aUsingStorageAccess,
bool aIsOn3PCBExceptionList, const nsAString& aName,
const nsAString& aPath, bool aPartitioned, const nsID& aOperationID);

View File

@@ -8,6 +8,7 @@ include PBackgroundSharedTypes;
using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
using struct nsID from "nsID.h";
[RefCounted] using class nsIURI from "mozilla/ipc/URIUtils.h";
namespace mozilla {
namespace dom {
@@ -37,7 +38,7 @@ protocol PCookieStore
manager PBackground;
parent:
async GetRequest(nsString domain,
async GetRequest(nullable nsIURI cookieURI,
OriginAttributes attrs,
OriginAttributes? partitionedAttrs,
bool thirdPartyContext,
@@ -49,7 +50,7 @@ parent:
nsCString path,
bool onlyFirstMatch) returns (CookieData[] data);
async SetRequest(nsString domain,
async SetRequest(nullable nsIURI cookieURI,
OriginAttributes attrs,
bool thirdPartyContext,
bool partitionForeign,
@@ -59,18 +60,20 @@ parent:
nsString value,
bool session,
int64_t expires,
nsString domain,
nsString path,
int32_t sameSite,
bool partitioned,
nsID operationId) returns (bool waitForNotification);
async DeleteRequest(nsString domain,
async DeleteRequest(nullable nsIURI cookieURI,
OriginAttributes attrs,
bool thirdPartyContext,
bool partitionForeign,
bool usingStorageAccess,
bool isOn3PCBExceptionList,
nsString name,
nsString domain,
nsString path,
bool partitioned,
nsID operationID) returns (bool waitForNotification);

View File

@@ -719,18 +719,21 @@ CookieService::Add(const nsACString& aHost, const nsACString& aPath,
return NS_ERROR_INVALID_ARG;
}
return AddNative(aHost, aPath, aName, aValue, aIsSecure, aIsHttpOnly,
return AddNative(nullptr, aHost, aPath, aName, aValue, aIsSecure, aIsHttpOnly,
aIsSession, aExpiry, &attrs, aSameSite, aSchemeMap,
aIsPartitioned, nullptr);
aIsPartitioned, nullptr,
[](CookieStruct&) -> bool { return true; });
}
NS_IMETHODIMP_(nsresult)
CookieService::AddNative(const nsACString& aHost, const nsACString& aPath,
const nsACString& aName, const nsACString& aValue,
bool aIsSecure, bool aIsHttpOnly, bool aIsSession,
int64_t aExpiry, OriginAttributes* aOriginAttributes,
int32_t aSameSite, nsICookie::schemeType aSchemeMap,
bool aIsPartitioned, const nsID* aOperationID) {
CookieService::AddNative(nsIURI* aCookieURI, const nsACString& aHost,
const nsACString& aPath, const nsACString& aName,
const nsACString& aValue, bool aIsSecure,
bool aIsHttpOnly, bool aIsSession, int64_t aExpiry,
OriginAttributes* aOriginAttributes, int32_t aSameSite,
nsICookie::schemeType aSchemeMap, bool aIsPartitioned,
const nsID* aOperationID,
const std::function<bool(CookieStruct&)>& aCheck) {
if (NS_WARN_IF(!aOriginAttributes)) {
return NS_ERROR_FAILURE;
}
@@ -751,20 +754,22 @@ CookieService::AddNative(const nsACString& aHost, const nsACString& aPath,
NS_ENSURE_SUCCESS(rv, rv);
int64_t currentTimeInUsec = PR_Now();
CookieKey key = CookieKey(baseDomain, *aOriginAttributes);
CookieStruct cookieData(nsCString(aName), nsCString(aValue), nsCString(aHost),
CookieStruct cookieData(nsCString(aName), nsCString(aValue), host,
nsCString(aPath), aExpiry, currentTimeInUsec,
Cookie::GenerateUniqueCreationTime(currentTimeInUsec),
aIsHttpOnly, aIsSession, aIsSecure, aIsPartitioned,
aSameSite, aSameSite, aSchemeMap);
RefPtr<Cookie> cookie = Cookie::Create(cookieData, key.mOriginAttributes);
if (!aCheck(cookieData)) {
return NS_ERROR_FAILURE;
}
RefPtr<Cookie> cookie = Cookie::Create(cookieData, *aOriginAttributes);
MOZ_ASSERT(cookie);
CookieStorage* storage = PickStorage(*aOriginAttributes);
storage->AddCookie(nullptr, baseDomain, *aOriginAttributes, cookie,
currentTimeInUsec, nullptr, VoidCString(), true,
currentTimeInUsec, aCookieURI, VoidCString(), true,
!aOriginAttributes->mPartitionKey.IsEmpty(), nullptr,
aOperationID);
return NS_OK;

View File

@@ -6,14 +6,20 @@
#include "nsISupports.idl"
#include "nsICookie.idl"
#include "nsIThirdPartyCookieBlockingExceptionListService.idl"
#include "nsIURI.idl"
%{ C++
#include <functional>
namespace mozilla {
class OriginAttributes;
namespace net {
class CookieStruct;
} // namespace net
} // mozilla namespace
%}
[ptr] native OriginAttributesPtr(mozilla::OriginAttributes);
native CheckStructFunctionRef(const std::function< bool(mozilla::net::CookieStruct&) > &);
/**
* An optional interface for accessing or removing the cookies
@@ -139,7 +145,8 @@ interface nsICookieManager : nsISupports
[optional] in boolean aIsPartitioned);
[notxpcom]
nsresult addNative(in AUTF8String aHost,
nsresult addNative(in nsIURI aCookieURI,
in AUTF8String aHost,
in AUTF8String aPath,
in ACString aName,
in AUTF8String aValue,
@@ -151,7 +158,8 @@ interface nsICookieManager : nsISupports
in int32_t aSameSite,
in nsICookie_schemeType aSchemeMap,
in boolean aIsPartitioned,
in nsIDPtr aOperationID);
in nsIDPtr aOperationID,
in CheckStructFunctionRef aCheckValid);
/**
* Find whether a given cookie already exists.

View File

@@ -750,53 +750,59 @@ TEST(TestCookie, TestCookieMain)
const nsCOMPtr<nsICookieManager>& cookieMgr2 = cookieMgr;
ASSERT_TRUE(cookieMgr2);
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), "https://cookie.test"_ns);
mozilla::OriginAttributes attrs;
// first, ensure a clean slate
EXPECT_NS_SUCCEEDED(cookieMgr->RemoveAll());
// add some cookies
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative("cookiemgr.test"_ns, // domain
"/foo"_ns, // path
"test1"_ns, // name
"yes"_ns, // value
false, // is secure
false, // is httponly
true, // is session
INT64_MAX, // expiry time
&attrs, // originAttributes
nsICookie::SAMESITE_NONE,
nsICookie::SCHEME_HTTPS,
false, // is partitioned
nullptr // operation ID
)));
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(
"cookiemgr.test"_ns, // domain
"/foo"_ns, // path
"test2"_ns, // name
"yes"_ns, // value
false, // is secure
true, // is httponly
true, // is session
PR_Now() / PR_USEC_PER_SEC + 2, // expiry time
&attrs, // originAttributes
nsICookie::SAMESITE_NONE, nsICookie::SCHEME_HTTPS,
false, // is partitioned
nullptr // operation ID
)));
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative("new.domain"_ns, // domain
"/rabbit"_ns, // path
"test3"_ns, // name
"yes"_ns, // value
false, // is secure
false, // is httponly
true, // is session
INT64_MAX, // expiry time
&attrs, // originAttributes
nsICookie::SAMESITE_NONE,
nsICookie::SCHEME_HTTPS,
false, // is partitioned
nullptr // operation ID
)));
EXPECT_TRUE(NS_SUCCEEDED(
cookieMgr2->AddNative(uri,
"cookiemgr.test"_ns, // domain
"/foo"_ns, // path
"test1"_ns, // name
"yes"_ns, // value
false, // is secure
false, // is httponly
true, // is session
INT64_MAX, // expiry time
&attrs, // originAttributes
nsICookie::SAMESITE_NONE, nsICookie::SCHEME_HTTPS,
false, // is partitioned
nullptr, // operation ID
[](CookieStruct&) -> bool { return true; })));
EXPECT_TRUE(NS_SUCCEEDED(
cookieMgr2->AddNative(uri,
"cookiemgr.test"_ns, // domain
"/foo"_ns, // path
"test2"_ns, // name
"yes"_ns, // value
false, // is secure
true, // is httponly
true, // is session
PR_Now() / PR_USEC_PER_SEC + 2, // expiry time
&attrs, // originAttributes
nsICookie::SAMESITE_NONE, nsICookie::SCHEME_HTTPS,
false, // is partitioned
nullptr, // operation ID
[](CookieStruct&) -> bool { return true; })));
EXPECT_TRUE(NS_SUCCEEDED(
cookieMgr2->AddNative(uri,
"new.domain"_ns, // domain
"/rabbit"_ns, // path
"test3"_ns, // name
"yes"_ns, // value
false, // is secure
false, // is httponly
true, // is session
INT64_MAX, // expiry time
&attrs, // originAttributes
nsICookie::SAMESITE_NONE, nsICookie::SCHEME_HTTPS,
false, // is partitioned
nullptr, // operation ID
[](CookieStruct&) -> bool { return true; })));
// confirm using enumerator
nsTArray<RefPtr<nsICookie>> cookies;
EXPECT_NS_SUCCEEDED(cookieMgr->GetCookies(cookies));

View File

@@ -1,14 +1,8 @@
[cookieStore_set_arguments.https.any.html]
[cookieStore.set default domain is null and differs from current hostname]
expected: FAIL
[cookieStore.set adds / to path that does not end with /]
expected: FAIL
[cookieStore_set_arguments.https.any.serviceworker.html]
[cookieStore.set default domain is null and differs from current hostname]
expected: FAIL
[cookieStore.set adds / to path that does not end with /]
expected: FAIL

View File

@@ -324,10 +324,11 @@ nsresult nsCookieInjector::InjectCookiesFromRules(
("Setting cookie: %s, %s, %s, %s\n", c.Host().get(), c.Name().get(),
c.Path().get(), c.Value().get()));
rv = cookieManager->AddNative(
c.Host(), c.Path(), c.Name(), c.Value(), c.IsSecure(), c.IsHttpOnly(),
c.IsSession(), c.Expiry(), &aOriginAttributes, c.SameSite(),
static_cast<nsICookie::schemeType>(c.SchemeMap()),
/* is partitioned: */ false, nullptr);
nullptr, c.Host(), c.Path(), c.Name(), c.Value(), c.IsSecure(),
c.IsHttpOnly(), c.IsSession(), c.Expiry(), &aOriginAttributes,
c.SameSite(), static_cast<nsICookie::schemeType>(c.SchemeMap()),
/* is partitioned: */ false, nullptr,
[](mozilla::net::CookieStruct&) { return true; });
NS_ENSURE_SUCCESS(rv, rv);
aHasInjectedCookie = true;