1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.h"
#include <string>
#include "base/base64.h"
#include "base/containers/span.h"
#include "base/feature_list.h"
#include "base/hash/sha1.h"
#include "base/strings/string_util.h"
#include "build/branding_buildflags.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/request_header_integrity/build_derived_values.h"
#include "components/embedder_support/user_agent_utils.h"
#include "components/google/core/common/google_util.h"
#include "google_apis/google_api_keys.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/network_context.mojom.h"
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
#include "chrome/common/request_header_integrity/internal/google_header_names.h"
#endif
#if !defined(CHANNEL_NAME_HEADER_NAME)
#define CHANNEL_NAME_HEADER_NAME "X-Placeholder-1"
#endif
#if !defined(LASTCHANGE_YEAR_HEADER_NAME)
#define LASTCHANGE_YEAR_HEADER_NAME "X-Placeholder-2"
#endif
#if !defined(VALIDATE_HEADER_NAME)
#define VALIDATE_HEADER_NAME "X-Placeholder-3"
#endif
#if !defined(COPYRIGHT_HEADER_NAME)
#define COPYRIGHT_HEADER_NAME "X-Placeholder-4"
#endif
namespace request_header_integrity {
namespace {
BASE_FEATURE(kRequestHeaderIntegrity,
"RequestHeaderIntegrity",
base::FEATURE_ENABLED_BY_DEFAULT);
// Returns extended, stable, beta, dev, or canary if a channel is available,
// otherwise the empty string.
std::string GetChannelName() {
std::string channel_name =
chrome::GetChannelName(chrome::WithExtendedStable(true));
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
if (channel_name.empty()) {
// For branded builds, stable is represented as the empty string.
channel_name = "stable";
}
#endif
if (base::ToLowerASCII(channel_name) == "unknown") {
return "";
}
return channel_name;
}
} // namespace
RequestHeaderIntegrityURLLoaderThrottle::
RequestHeaderIntegrityURLLoaderThrottle() = default;
RequestHeaderIntegrityURLLoaderThrottle::
~RequestHeaderIntegrityURLLoaderThrottle() = default;
void RequestHeaderIntegrityURLLoaderThrottle::DetachFromCurrentSequence() {}
void RequestHeaderIntegrityURLLoaderThrottle::WillStartRequest(
network::ResourceRequest* request,
bool* defer) {
if (!google_util::IsGoogleAssociatedDomainUrl(request->url)) {
return;
}
const std::string digest =
base::Base64Encode(base::SHA1Hash(base::as_byte_span(
google_apis::GetAPIKey() + embedder_support::GetUserAgent())));
const std::string channel_name = GetChannelName();
if (!channel_name.empty()) {
request->cors_exempt_headers.SetHeader(CHANNEL_NAME_HEADER_NAME,
channel_name);
}
request->cors_exempt_headers.SetHeader(LASTCHANGE_YEAR_HEADER_NAME,
LASTCHANGE_YEAR);
request->cors_exempt_headers.SetHeader(VALIDATE_HEADER_NAME, digest);
request->cors_exempt_headers.SetHeader(COPYRIGHT_HEADER_NAME,
CHROME_COPYRIGHT);
}
// static
bool RequestHeaderIntegrityURLLoaderThrottle::IsFeatureEnabled() {
return base::FeatureList::IsEnabled(kRequestHeaderIntegrity);
}
// static
void RequestHeaderIntegrityURLLoaderThrottle::UpdateCorsExemptHeaders(
network::mojom::NetworkContextParams* params) {
params->cors_exempt_header_list.push_back(CHANNEL_NAME_HEADER_NAME);
params->cors_exempt_header_list.push_back(LASTCHANGE_YEAR_HEADER_NAME);
params->cors_exempt_header_list.push_back(VALIDATE_HEADER_NAME);
params->cors_exempt_header_list.push_back(COPYRIGHT_HEADER_NAME);
}
} // namespace request_header_integrity
|