diff options
Diffstat (limited to 'chromium/net/cookies/cookie_inclusion_status.cc')
-rw-r--r-- | chromium/net/cookies/cookie_inclusion_status.cc | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/chromium/net/cookies/cookie_inclusion_status.cc b/chromium/net/cookies/cookie_inclusion_status.cc new file mode 100644 index 00000000000..8e13916ba13 --- /dev/null +++ b/chromium/net/cookies/cookie_inclusion_status.cc @@ -0,0 +1,290 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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 "base/strings/strcat.h" +#include "url/gurl.h" + +namespace net { + +namespace { + +uint32_t GetExclusionBitmask(CookieInclusionStatus::ExclusionReason reason) { + return 1u << static_cast<uint32_t>(reason); +} + +uint32_t GetWarningBitmask(CookieInclusionStatus::WarningReason reason) { + return 1u << static_cast<uint32_t>(reason); +} + +} // namespace + +CookieInclusionStatus::CookieInclusionStatus() + : exclusion_reasons_(0u), warning_reasons_(0u) {} + +CookieInclusionStatus::CookieInclusionStatus(ExclusionReason reason) + : exclusion_reasons_(GetExclusionBitmask(reason)) {} + +CookieInclusionStatus::CookieInclusionStatus(ExclusionReason reason, + WarningReason warning) + : exclusion_reasons_(GetExclusionBitmask(reason)), + warning_reasons_(GetWarningBitmask(warning)) {} + +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_ == 0u; +} + +bool CookieInclusionStatus::HasExclusionReason(ExclusionReason reason) const { + return exclusion_reasons_ & GetExclusionBitmask(reason); +} + +void CookieInclusionStatus::AddExclusionReason(ExclusionReason reason) { + exclusion_reasons_ |= GetExclusionBitmask(reason); + // 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_ &= ~(GetExclusionBitmask(reason)); +} + +void CookieInclusionStatus::MaybeClearSameSiteWarning() { + uint32_t samesite_reasons_mask = + GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX) | + GetExclusionBitmask(EXCLUDE_SAMESITE_NONE_INSECURE); + if (exclusion_reasons_ & ~samesite_reasons_mask) { + RemoveWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + RemoveWarningReason(CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); + RemoveWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); + } + + uint32_t context_reasons_mask = + GetExclusionBitmask(EXCLUDE_SAMESITE_STRICT) | + GetExclusionBitmask(EXCLUDE_SAMESITE_LAX) | + GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); + if (exclusion_reasons_ & ~context_reasons_mask) { + RemoveWarningReason( + CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE); + } +} + +bool CookieInclusionStatus::ShouldRecordDowngradeMetrics() const { + uint32_t context_reasons_mask = + GetExclusionBitmask(EXCLUDE_SAMESITE_STRICT) | + GetExclusionBitmask(EXCLUDE_SAMESITE_LAX) | + GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); + + return (exclusion_reasons_ & ~context_reasons_mask) == 0u; +} + +bool CookieInclusionStatus::ShouldWarn() const { + return warning_reasons_ != 0u; +} + +bool CookieInclusionStatus::HasWarningReason(WarningReason reason) const { + return warning_reasons_ & GetWarningBitmask(reason); +} + +bool CookieInclusionStatus::HasDowngradeWarning( + 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_ |= GetWarningBitmask(reason); +} + +void CookieInclusionStatus::RemoveWarningReason(WarningReason reason) { + warning_reasons_ &= ~(GetWarningBitmask(reason)); +} + +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. + HasDowngradeWarning(&reason); + + switch (reason) { + case WarningReason::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::STRICT_LAX_STRICT_SECURE + : ContextDowngradeMetricValues::STRICT_LAX_STRICT_INSECURE; + case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::STRICT_CROSS_STRICT_SECURE + : ContextDowngradeMetricValues::STRICT_CROSS_STRICT_INSECURE; + case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::STRICT_CROSS_LAX_SECURE + : ContextDowngradeMetricValues::STRICT_CROSS_LAX_INSECURE; + case WarningReason::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::LAX_CROSS_STRICT_SECURE + : ContextDowngradeMetricValues::LAX_CROSS_STRICT_INSECURE; + case WarningReason::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::LAX_CROSS_LAX_SECURE + : ContextDowngradeMetricValues::LAX_CROSS_LAX_INSECURE; + default: + return url_is_secure + ? ContextDowngradeMetricValues::NO_DOWNGRADE_SECURE + : ContextDowngradeMetricValues::NO_DOWNGRADE_INSECURE; + } +} + +std::string CookieInclusionStatus::GetDebugString() const { + std::string out; + + // Inclusion/exclusion + if (IsInclude()) + base::StrAppend(&out, {"INCLUDE, "}); + if (HasExclusionReason(EXCLUDE_UNKNOWN_ERROR)) + base::StrAppend(&out, {"EXCLUDE_UNKNOWN_ERROR, "}); + if (HasExclusionReason(EXCLUDE_HTTP_ONLY)) + base::StrAppend(&out, {"EXCLUDE_HTTP_ONLY, "}); + if (HasExclusionReason(EXCLUDE_SECURE_ONLY)) + base::StrAppend(&out, {"EXCLUDE_SECURE_ONLY, "}); + if (HasExclusionReason(EXCLUDE_DOMAIN_MISMATCH)) + base::StrAppend(&out, {"EXCLUDE_DOMAIN_MISMATCH, "}); + if (HasExclusionReason(EXCLUDE_NOT_ON_PATH)) + base::StrAppend(&out, {"EXCLUDE_NOT_ON_PATH, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_STRICT)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_STRICT, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_LAX)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_LAX, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_NONE_INSECURE)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_NONE_INSECURE, "}); + if (HasExclusionReason(EXCLUDE_USER_PREFERENCES)) + base::StrAppend(&out, {"EXCLUDE_USER_PREFERENCES, "}); + if (HasExclusionReason(EXCLUDE_FAILURE_TO_STORE)) + base::StrAppend(&out, {"EXCLUDE_FAILURE_TO_STORE, "}); + if (HasExclusionReason(EXCLUDE_NONCOOKIEABLE_SCHEME)) + base::StrAppend(&out, {"EXCLUDE_NONCOOKIEABLE_SCHEME, "}); + if (HasExclusionReason(EXCLUDE_OVERWRITE_SECURE)) + base::StrAppend(&out, {"EXCLUDE_OVERWRITE_SECURE, "}); + if (HasExclusionReason(EXCLUDE_OVERWRITE_HTTP_ONLY)) + base::StrAppend(&out, {"EXCLUDE_OVERWRITE_HTTP_ONLY, "}); + if (HasExclusionReason(EXCLUDE_INVALID_DOMAIN)) + base::StrAppend(&out, {"EXCLUDE_INVALID_DOMAIN, "}); + if (HasExclusionReason(EXCLUDE_INVALID_PREFIX)) + base::StrAppend(&out, {"EXCLUDE_INVALID_PREFIX, "}); + + // Add warning + if (!ShouldWarn()) { + base::StrAppend(&out, {"DO_NOT_WARN"}); + return out; + } + + if (HasWarningReason(WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)) + base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT, "}); + if (HasWarningReason(WARN_SAMESITE_NONE_INSECURE)) + base::StrAppend(&out, {"WARN_SAMESITE_NONE_INSECURE, "}); + if (HasWarningReason(WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE)) + base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE, "}); + if (HasWarningReason(WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE)) + base::StrAppend(&out, {"WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, "}); + if (HasWarningReason(WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)) + base::StrAppend(&out, {"WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); + if (HasWarningReason(WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)) + base::StrAppend(&out, {"WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, "}); + if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)) + base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); + if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)) + base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, "}); + if (HasWarningReason(WARN_SAMESITE_COMPAT_PAIR)) + base::StrAppend(&out, {"WARN_SAMESITE_COMPAT_PAIR, "}); + + // Strip trailing comma and space. + out.erase(out.end() - 2, out.end()); + + return out; +} + +bool CookieInclusionStatus::IsValid() const { + // Bit positions where there should not be any true bits. + uint32_t exclusion_mask = ~0u << static_cast<int>(NUM_EXCLUSION_REASONS); + uint32_t warning_mask = ~0u << static_cast<int>(NUM_WARNING_REASONS); + return (exclusion_mask & exclusion_reasons_) == 0u && + (warning_mask & warning_reasons_) == 0u; +} + +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 +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; +} + +} // namespace net |