327 lines
12 KiB
C++
327 lines
12 KiB
C++
// Copyright 2020 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/cookies/cookie_inclusion_status.h"
|
|
|
|
#include <initializer_list>
|
|
#include <utility>
|
|
|
|
#include "base/strings/strcat.h"
|
|
#include "url/gurl.h"
|
|
|
|
namespace net {
|
|
|
|
CookieInclusionStatus::CookieInclusionStatus() = default;
|
|
|
|
CookieInclusionStatus::CookieInclusionStatus(ExclusionReason reason) {
|
|
exclusion_reasons_[reason] = true;
|
|
}
|
|
|
|
CookieInclusionStatus::CookieInclusionStatus(ExclusionReason reason,
|
|
WarningReason warning) {
|
|
exclusion_reasons_[reason] = true;
|
|
warning_reasons_[warning] = true;
|
|
}
|
|
|
|
CookieInclusionStatus::CookieInclusionStatus(WarningReason warning) {
|
|
warning_reasons_[warning] = true;
|
|
}
|
|
|
|
CookieInclusionStatus::CookieInclusionStatus(
|
|
const CookieInclusionStatus& other) = default;
|
|
|
|
CookieInclusionStatus& CookieInclusionStatus::operator=(
|
|
const CookieInclusionStatus& other) = default;
|
|
|
|
bool CookieInclusionStatus::operator==(
|
|
const CookieInclusionStatus& other) const {
|
|
return exclusion_reasons_ == other.exclusion_reasons_ &&
|
|
warning_reasons_ == other.warning_reasons_;
|
|
}
|
|
|
|
bool CookieInclusionStatus::operator!=(
|
|
const CookieInclusionStatus& other) const {
|
|
return !operator==(other);
|
|
}
|
|
|
|
bool CookieInclusionStatus::IsInclude() const {
|
|
return exclusion_reasons_.none();
|
|
}
|
|
|
|
bool CookieInclusionStatus::HasExclusionReason(ExclusionReason reason) const {
|
|
return exclusion_reasons_[reason];
|
|
}
|
|
|
|
bool CookieInclusionStatus::HasOnlyExclusionReason(
|
|
ExclusionReason reason) const {
|
|
return exclusion_reasons_[reason] && exclusion_reasons_.count() == 1;
|
|
}
|
|
|
|
void CookieInclusionStatus::AddExclusionReason(ExclusionReason reason) {
|
|
exclusion_reasons_[reason] = true;
|
|
// If the cookie would be excluded for reasons other than the new SameSite
|
|
// rules, don't bother warning about it.
|
|
MaybeClearSameSiteWarning();
|
|
}
|
|
|
|
void CookieInclusionStatus::RemoveExclusionReason(ExclusionReason reason) {
|
|
exclusion_reasons_[reason] = false;
|
|
}
|
|
|
|
void CookieInclusionStatus::RemoveExclusionReasons(
|
|
const std::vector<ExclusionReason>& reasons) {
|
|
exclusion_reasons_ = ExclusionReasonsWithout(reasons);
|
|
}
|
|
|
|
CookieInclusionStatus::ExclusionReasonBitset
|
|
CookieInclusionStatus::ExclusionReasonsWithout(
|
|
const std::vector<ExclusionReason>& reasons) const {
|
|
CookieInclusionStatus::ExclusionReasonBitset result(exclusion_reasons_);
|
|
for (const ExclusionReason reason : reasons) {
|
|
result[reason] = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void CookieInclusionStatus::MaybeClearSameSiteWarning() {
|
|
if (ExclusionReasonsWithout({
|
|
EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
|
|
EXCLUDE_SAMESITE_NONE_INSECURE,
|
|
}) != 0u) {
|
|
RemoveWarningReason(WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
|
|
RemoveWarningReason(WARN_SAMESITE_NONE_INSECURE);
|
|
RemoveWarningReason(WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
|
|
}
|
|
|
|
if (!ShouldRecordDowngradeMetrics()) {
|
|
RemoveWarningReason(WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE);
|
|
RemoveWarningReason(WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE);
|
|
RemoveWarningReason(WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE);
|
|
RemoveWarningReason(WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE);
|
|
RemoveWarningReason(WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE);
|
|
|
|
RemoveWarningReason(WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION);
|
|
}
|
|
}
|
|
|
|
bool CookieInclusionStatus::ShouldRecordDowngradeMetrics() const {
|
|
return ExclusionReasonsWithout({
|
|
EXCLUDE_SAMESITE_STRICT,
|
|
EXCLUDE_SAMESITE_LAX,
|
|
EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
|
|
}) == 0u;
|
|
}
|
|
|
|
bool CookieInclusionStatus::ShouldWarn() const {
|
|
return warning_reasons_.any();
|
|
}
|
|
|
|
bool CookieInclusionStatus::HasWarningReason(WarningReason reason) const {
|
|
return warning_reasons_[reason];
|
|
}
|
|
|
|
bool CookieInclusionStatus::HasSchemefulDowngradeWarning(
|
|
CookieInclusionStatus::WarningReason* reason) const {
|
|
if (!ShouldWarn())
|
|
return false;
|
|
|
|
const CookieInclusionStatus::WarningReason kDowngradeWarnings[] = {
|
|
WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE,
|
|
WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE,
|
|
WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE,
|
|
WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE,
|
|
WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE,
|
|
};
|
|
|
|
for (auto warning : kDowngradeWarnings) {
|
|
if (!HasWarningReason(warning))
|
|
continue;
|
|
|
|
if (reason)
|
|
*reason = warning;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CookieInclusionStatus::AddWarningReason(WarningReason reason) {
|
|
warning_reasons_[reason] = true;
|
|
}
|
|
|
|
void CookieInclusionStatus::RemoveWarningReason(WarningReason reason) {
|
|
warning_reasons_[reason] = false;
|
|
}
|
|
|
|
CookieInclusionStatus::ContextDowngradeMetricValues
|
|
CookieInclusionStatus::GetBreakingDowngradeMetricsEnumValue(
|
|
const GURL& url) const {
|
|
bool url_is_secure = url.SchemeIsCryptographic();
|
|
|
|
// Start the |reason| as something other than the downgrade warnings.
|
|
WarningReason reason = WarningReason::NUM_WARNING_REASONS;
|
|
|
|
// Don't bother checking the return value because the default switch case
|
|
// will handle if no reason was found.
|
|
HasSchemefulDowngradeWarning(&reason);
|
|
|
|
switch (reason) {
|
|
case WarningReason::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE:
|
|
return url_is_secure
|
|
? ContextDowngradeMetricValues::kStrictLaxStrictSecure
|
|
: ContextDowngradeMetricValues::kStrictLaxStrictInsecure;
|
|
case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE:
|
|
return url_is_secure
|
|
? ContextDowngradeMetricValues::kStrictCrossStrictSecure
|
|
: ContextDowngradeMetricValues::kStrictCrossStrictInsecure;
|
|
case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE:
|
|
return url_is_secure
|
|
? ContextDowngradeMetricValues::kStrictCrossLaxSecure
|
|
: ContextDowngradeMetricValues::kStrictCrossLaxInsecure;
|
|
case WarningReason::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE:
|
|
return url_is_secure
|
|
? ContextDowngradeMetricValues::kLaxCrossStrictSecure
|
|
: ContextDowngradeMetricValues::kLaxCrossStrictInsecure;
|
|
case WarningReason::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE:
|
|
return url_is_secure ? ContextDowngradeMetricValues::kLaxCrossLaxSecure
|
|
: ContextDowngradeMetricValues::kLaxCrossLaxInsecure;
|
|
default:
|
|
return url_is_secure ? ContextDowngradeMetricValues::kNoDowngradeSecure
|
|
: ContextDowngradeMetricValues::kNoDowngradeInsecure;
|
|
}
|
|
}
|
|
|
|
std::string CookieInclusionStatus::GetDebugString() const {
|
|
std::string out;
|
|
|
|
if (IsInclude())
|
|
base::StrAppend(&out, {"INCLUDE, "});
|
|
for (const auto& reason :
|
|
std::initializer_list<std::pair<ExclusionReason, std::string>>{
|
|
{EXCLUDE_UNKNOWN_ERROR, "EXCLUDE_UNKNOWN_ERROR"},
|
|
{EXCLUDE_HTTP_ONLY, "EXCLUDE_HTTP_ONLY"},
|
|
{EXCLUDE_SECURE_ONLY, "EXCLUDE_SECURE_ONLY"},
|
|
{EXCLUDE_DOMAIN_MISMATCH, "EXCLUDE_DOMAIN_MISMATCH"},
|
|
{EXCLUDE_NOT_ON_PATH, "EXCLUDE_NOT_ON_PATH"},
|
|
{EXCLUDE_SAMESITE_STRICT, "EXCLUDE_SAMESITE_STRICT"},
|
|
{EXCLUDE_SAMESITE_LAX, "EXCLUDE_SAMESITE_LAX"},
|
|
{EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
|
|
"EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX"},
|
|
{EXCLUDE_SAMESITE_NONE_INSECURE, "EXCLUDE_SAMESITE_NONE_INSECURE"},
|
|
{EXCLUDE_USER_PREFERENCES, "EXCLUDE_USER_PREFERENCES"},
|
|
{EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT,
|
|
"EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT"},
|
|
{EXCLUDE_FAILURE_TO_STORE, "EXCLUDE_FAILURE_TO_STORE"},
|
|
{EXCLUDE_NONCOOKIEABLE_SCHEME, "EXCLUDE_NONCOOKIEABLE_SCHEME"},
|
|
{EXCLUDE_OVERWRITE_SECURE, "EXCLUDE_OVERWRITE_SECURE"},
|
|
{EXCLUDE_OVERWRITE_HTTP_ONLY, "EXCLUDE_OVERWRITE_HTTP_ONLY"},
|
|
{EXCLUDE_INVALID_DOMAIN, "EXCLUDE_INVALID_DOMAIN"},
|
|
{EXCLUDE_INVALID_PREFIX, "EXCLUDE_INVALID_PREFIX"},
|
|
{EXCLUDE_INVALID_SAMEPARTY, "EXCLUDE_INVALID_SAMEPARTY"},
|
|
{EXCLUDE_INVALID_PARTITIONED, "EXCLUDE_INVALID_PARTITIONED"},
|
|
{EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE,
|
|
"EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE"},
|
|
{EXCLUDE_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE,
|
|
"EXCLUDE_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE"},
|
|
{EXCLUDE_DOMAIN_NON_ASCII, "EXCLUDE_DOMAIN_NON_ASCII"},
|
|
}) {
|
|
if (HasExclusionReason(reason.first))
|
|
base::StrAppend(&out, {reason.second, ", "});
|
|
}
|
|
|
|
// Add warning
|
|
if (!ShouldWarn()) {
|
|
base::StrAppend(&out, {"DO_NOT_WARN"});
|
|
return out;
|
|
}
|
|
|
|
for (const auto& reason :
|
|
std::initializer_list<std::pair<WarningReason, std::string>>{
|
|
{WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT,
|
|
"WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT"},
|
|
{WARN_SAMESITE_NONE_INSECURE, "WARN_SAMESITE_NONE_INSECURE"},
|
|
{WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE,
|
|
"WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE"},
|
|
{WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE,
|
|
"WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE"},
|
|
{WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE,
|
|
"WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE"},
|
|
{WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE,
|
|
"WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE"},
|
|
{WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE,
|
|
"WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE"},
|
|
{WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE,
|
|
"WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE"},
|
|
{WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC,
|
|
"WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC"},
|
|
{WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE,
|
|
"WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE"},
|
|
{WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE,
|
|
"WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE"},
|
|
{WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION,
|
|
"WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION"},
|
|
{WARN_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE,
|
|
"WARN_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE"},
|
|
{WARN_DOMAIN_NON_ASCII, "WARN_DOMAIN_NON_ASCII"},
|
|
}) {
|
|
if (HasWarningReason(reason.first))
|
|
base::StrAppend(&out, {reason.second, ", "});
|
|
}
|
|
|
|
// Strip trailing comma and space.
|
|
out.erase(out.end() - 2, out.end());
|
|
|
|
return out;
|
|
}
|
|
|
|
bool CookieInclusionStatus::HasExactlyExclusionReasonsForTesting(
|
|
std::vector<CookieInclusionStatus::ExclusionReason> reasons) const {
|
|
CookieInclusionStatus expected = MakeFromReasonsForTesting(reasons);
|
|
return expected.exclusion_reasons_ == exclusion_reasons_;
|
|
}
|
|
|
|
bool CookieInclusionStatus::HasExactlyWarningReasonsForTesting(
|
|
std::vector<WarningReason> reasons) const {
|
|
CookieInclusionStatus expected = MakeFromReasonsForTesting({}, reasons);
|
|
return expected.warning_reasons_ == warning_reasons_;
|
|
}
|
|
|
|
// static
|
|
bool CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
|
|
uint32_t exclusion_reasons,
|
|
uint32_t warning_reasons) {
|
|
uint32_t exclusion_mask =
|
|
static_cast<uint32_t>(~0ul << ExclusionReason::NUM_EXCLUSION_REASONS);
|
|
uint32_t warning_mask =
|
|
static_cast<uint32_t>(~0ul << WarningReason::NUM_WARNING_REASONS);
|
|
return (exclusion_reasons & exclusion_mask) == 0 &&
|
|
(warning_reasons & warning_mask) == 0;
|
|
}
|
|
|
|
CookieInclusionStatus CookieInclusionStatus::MakeFromReasonsForTesting(
|
|
std::vector<ExclusionReason> reasons,
|
|
std::vector<WarningReason> warnings) {
|
|
CookieInclusionStatus status;
|
|
for (ExclusionReason reason : reasons) {
|
|
status.AddExclusionReason(reason);
|
|
}
|
|
for (WarningReason warning : warnings) {
|
|
status.AddWarningReason(warning);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
bool CookieInclusionStatus::ExcludedByUserPreferences() const {
|
|
if (HasOnlyExclusionReason(ExclusionReason::EXCLUDE_USER_PREFERENCES))
|
|
return true;
|
|
return exclusion_reasons_.count() == 2 &&
|
|
exclusion_reasons_[ExclusionReason::EXCLUDE_USER_PREFERENCES] &&
|
|
exclusion_reasons_
|
|
[ExclusionReason::
|
|
EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET];
|
|
}
|
|
|
|
} // namespace net
|