I want to modify user agent data using browser itself, so I tried to add some switches to do it.
I modified codes below, to get startup argument through base::CommandLine and use it.
Build succeed, but result is not what I expected.
if I run .\chrome.exe --platform="Linux armv8l" or .\chrome.exe --mobile=true and something like it, nothing changed in javascript. navigator.userAgentData.getHighEntropyValues(["mobile"]) still returns false, navigator.platform still returns ‘Win32’.
I am new to C. I don’t know what I am missing. If anybody knows what is wrong, please let me know.
// Copyright 2019 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 "third_party/blink/renderer/core/frame/navigator_ua.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
#include "third_party/blink/renderer/core/frame/navigator_ua_data.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
const char kUADataBrands[] = "ua-data-brands";
const char kIsMobile[] = "is-mobile";
const char kUADataPlatform[] = "ua-data-platform";
const char kUADataPlatformVersion[] = "ua-data-platform-version";
const char kUADataArchitecture[] = "ua-data-architecture";
const char kUADataModel[] = "ua-data-model";
const char kUADataUAFullVersion[] = "ua-data-ua-full-version";
const char kUADataBitness[] = "ua-data-bitness";
const char kUADataWow64[] = "ua-data-wow64";
const char kUADataBrandFullVersionList[] = "ua-data-brand-full-version-list";
NavigatorUAData* NavigatorUA::userAgentData() {
NavigatorUAData* ua_data =
MakeGarbageCollected<NavigatorUAData>(GetUAExecutionContext());
UserAgentMetadata metadata = GetUserAgentMetadata();
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string uaDataBrands =
command_line->GetSwitchValueASCII(kUADataBrands);
blink::UserAgentBrandList brandVersionList;
if (command_line->HasSwitch(kUADataBrands)) {
// uaDataBrands' format is "brand1/version1,brand2/version2,...".
// The version is optional.
if (!uaDataBrands.empty()) {
String strUADataBrands;
strUADataBrands = String::FromUTF8(uaDataBrands.c_str());
Vector<String> brands;
strUADataBrands.Split(',', brands);
for (const auto& brand : brands) {
Vector<String> brand_and_version;
brand.Split('/', brand_and_version);
UserAgentBrandVersion* dict = new UserAgentBrandVersion(
brand_and_version[0].Utf8(), brand_and_version[1].Utf8());
brandVersionList.push_back(*dict);
}
ua_data->SetBrandVersionList(brandVersionList);
} else {
ua_data->SetBrandVersionList(metadata.brand_version_list);
}
}
const bool isMobile = command_line->HasSwitch(kIsMobile);
if (command_line->HasSwitch(kIsMobile)) {
ua_data->SetMobile(isMobile);
} else {
ua_data->SetMobile(metadata.mobile);
}
const std::string uaDataPlatform =
command_line->GetSwitchValueASCII(kUADataPlatform);
if (command_line->HasSwitch(kUADataPlatform) &&
command_line->HasSwitch(kUADataPlatformVersion)) {
const std::string uaDataPlatformVersion =
command_line->GetSwitchValueASCII(kUADataPlatformVersion);
ua_data->SetPlatform(String::FromUTF8(uaDataPlatform),
String::FromUTF8(uaDataPlatformVersion));
} else {
ua_data->SetPlatform(String::FromUTF8(metadata.platform),
String::FromUTF8(metadata.platform_version));
}
const std::string uaDataArchitecture =
command_line->GetSwitchValueASCII(kUADataArchitecture);
if (command_line->HasSwitch(kUADataArchitecture)) {
ua_data->SetArchitecture(String::FromUTF8(uaDataArchitecture));
} else {
ua_data->SetArchitecture(String::FromUTF8(metadata.architecture));
}
const std::string uaDataModel =
command_line->GetSwitchValueASCII(kUADataModel);
if (command_line->HasSwitch(kUADataModel)) {
ua_data->SetModel(String::FromUTF8(uaDataModel));
} else {
ua_data->SetModel(String::FromUTF8(metadata.model));
}
const std::string uaDataUAFullVersion =
command_line->GetSwitchValueASCII(kUADataUAFullVersion);
if (command_line->HasSwitch(kUADataUAFullVersion)) {
ua_data->SetUAFullVersion(String::FromUTF8(uaDataUAFullVersion));
} else {
ua_data->SetUAFullVersion(String::FromUTF8(metadata.full_version));
}
const std::string uaDataBitness =
command_line->GetSwitchValueASCII(kUADataBitness);
if (command_line->HasSwitch(kUADataBitness)) {
ua_data->SetBitness(String::FromUTF8(uaDataBitness));
} else {
ua_data->SetBitness(String::FromUTF8(metadata.bitness));
}
if (command_line->HasSwitch(kUADataWow64)) {
ua_data->SetWoW64(true);
} else {
ua_data->SetWoW64(metadata.wow64);
}
if (command_line->HasSwitch(kUADataBrandFullVersionList)) {
const std::string uaDataBrandFullVersionList =
command_line->GetSwitchValueASCII(kUADataBrandFullVersionList);
// uaDataBrandFullVersionList' format is
// "brand1/version1,brand2/version2,...".
blink::UserAgentBrandList brandFullVersionList;
if (!uaDataBrandFullVersionList.empty()) {
String strUADataBrandFullVersionList;
strUADataBrandFullVersionList =
String::FromUTF8(uaDataBrandFullVersionList.c_str());
Vector<String> brands;
strUADataBrandFullVersionList.Split(',', brands);
for (const auto& brand : brands) {
Vector<String> brand_and_version;
brand.Split('/', brand_and_version);
UserAgentBrandVersion* dict = new UserAgentBrandVersion(
brand_and_version[0].Utf8(), brand_and_version[1].Utf8());
brandFullVersionList.push_back(*dict);
}
ua_data->SetFullVersionList(brandFullVersionList);
}
} else {
ua_data->SetFullVersionList(metadata.brand_full_version_list);
}
return ua_data;
}
} // namespace blink
// 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 "third_party/blink/renderer/core/frame/navigator_ua_data.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/task/single_thread_task_runner.h"
#include "chrome/common/chrome_switches.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
#include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_ua_data_values.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/dactyloscoper.h"
#include "third_party/blink/renderer/core/frame/web_feature_forward.h"
#include "third_party/blink/renderer/core/page/page.h"
namespace blink {
namespace {
const char kUADataBrands[] = "ua-data-brands";
const char kIsMobile[] = "is-mobile";
const char kUADataPlatform[] = "ua-data-platform";
const char kUADataPlatformVersion[] = "ua-data-platform-version";
const char kUADataArchitecture[] = "ua-data-architecture";
const char kUADataModel[] = "ua-data-model";
const char kUADataUAFullVersion[] = "ua-data-ua-full-version";
const char kUADataBitness[] = "ua-data-bitness";
const char kUADataWow64[] = "ua-data-wow64";
// Record identifiability study metrics for a single field requested by a
// getHighEntropyValues() call if the user is in the study.
void MaybeRecordMetric(bool record_identifiability,
const String& hint,
const String& value,
ExecutionContext* execution_context) {
if (LIKELY(!record_identifiability))
return;
auto identifiable_surface = IdentifiableSurface::FromTypeAndToken(
IdentifiableSurface::Type::kNavigatorUAData_GetHighEntropyValues,
IdentifiableToken(hint.Utf8()));
IdentifiabilityMetricBuilder(execution_context->UkmSourceID())
.Add(identifiable_surface, IdentifiableToken(value.Utf8()))
.Record(execution_context->UkmRecorder());
}
} // namespace
NavigatorUAData::NavigatorUAData(ExecutionContext* context)
: ExecutionContextClient(context) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string uaDataBrands =
command_line->GetSwitchValueASCII(kUADataBrands);
// uaDataBrands' format is "brand1/version1,brand2/version2,...".
// The version is optional.
if (!uaDataBrands.empty()) {
String strUADataBrands;
strUADataBrands = String::FromUTF8(uaDataBrands.c_str());
Vector<String> brands;
strUADataBrands.Split(',', brands);
for (const auto& brand : brands) {
Vector<String> brand_and_version;
brand.Split('/', brand_and_version);
NavigatorUABrandVersion* dict = NavigatorUABrandVersion::Create();
dict->setBrand(brand_and_version[0]);
if (brand_and_version.size() > 1)
dict->setVersion(brand_and_version[1]);
empty_brand_set_.push_back(dict);
}
return;
}
NavigatorUABrandVersion* dict = NavigatorUABrandVersion::Create();
dict->setBrand("");
dict->setVersion("");
empty_brand_set_.push_back(dict);
}
void NavigatorUAData::AddBrandVersion(const String& brand,
const String& version) {
NavigatorUABrandVersion* dict = NavigatorUABrandVersion::Create();
dict->setBrand(brand);
dict->setVersion(version);
brand_set_.push_back(dict);
}
void NavigatorUAData::AddBrandFullVersion(const String& brand,
const String& version) {
NavigatorUABrandVersion* dict = NavigatorUABrandVersion::Create();
dict->setBrand(brand);
dict->setVersion(version);
full_version_list_.push_back(dict);
}
void NavigatorUAData::SetBrandVersionList(
const UserAgentBrandList& brand_version_list) {
for (const auto& brand_version : brand_version_list) {
AddBrandVersion(String::FromUTF8(brand_version.brand),
String::FromUTF8(brand_version.version));
}
}
void NavigatorUAData::SetFullVersionList(
const UserAgentBrandList& full_version_list) {
for (const auto& brand_version : full_version_list) {
AddBrandFullVersion(String::FromUTF8(brand_version.brand),
String::FromUTF8(brand_version.version));
}
}
void NavigatorUAData::SetMobile(bool mobile) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string is_mobile = command_line->GetSwitchValueASCII(kIsMobile);
if (!is_mobile.empty()) {
is_mobile_ = is_mobile == "true";
return;
}
is_mobile_ = mobile;
}
void NavigatorUAData::SetPlatform(const String& brand, const String& version) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string platform =
command_line->GetSwitchValueASCII(kUADataPlatform);
const std::string platformVersion =
command_line->GetSwitchValueASCII(kUADataPlatformVersion);
if (!platform.empty()) {
platform_ = String::FromUTF8(platform.c_str());
} else {
platform_ = brand;
}
if (!platformVersion.empty()) {
platform_version_ = String::FromUTF8(platformVersion.c_str());
} else {
platform_version_ = version;
}
}
void NavigatorUAData::SetArchitecture(const String& architecture) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string customArchitecture =
command_line->GetSwitchValueASCII(kUADataArchitecture);
if (!customArchitecture.empty()) {
architecture_ = String::FromUTF8(customArchitecture.c_str());
} else {
architecture_ = architecture;
}
}
void NavigatorUAData::SetModel(const String& model) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string customModel =
command_line->GetSwitchValueASCII(kUADataModel);
if (!customModel.empty()) {
model_ = String::FromUTF8(customModel.c_str());
} else {
model_ = model;
}
}
void NavigatorUAData::SetUAFullVersion(const String& ua_full_version) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string uaFullVersion =
command_line->GetSwitchValueASCII(kUADataUAFullVersion);
if (!uaFullVersion.empty()) {
ua_full_version_ = String::FromUTF8(uaFullVersion.c_str());
} else {
ua_full_version_ = ua_full_version;
}
}
void NavigatorUAData::SetBitness(const String& bitness) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string customBitness =
command_line->GetSwitchValueASCII(kUADataBitness);
if (!customBitness.empty()) {
bitness_ = String::FromUTF8(customBitness.c_str());
} else {
bitness_ = bitness;
}
}
void NavigatorUAData::SetWoW64(bool wow64) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string is_wow64 = command_line->GetSwitchValueASCII(kUADataWow64);
if (!is_wow64.empty()) {
is_wow64_ = is_wow64 == "true";
return;
}
is_wow64_ = wow64;
}
bool NavigatorUAData::mobile() const {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string is_mobile = command_line->GetSwitchValueASCII(kIsMobile);
if (!is_mobile.empty()) {
return is_mobile == "true";
}
if (GetExecutionContext()) {
return is_mobile_;
}
return false;
}
const HeapVector<Member<NavigatorUABrandVersion>>& NavigatorUAData::brands()
const {
constexpr auto identifiable_surface = IdentifiableSurface::FromTypeAndToken(
IdentifiableSurface::Type::kWebFeature,
WebFeature::kNavigatorUAData_Brands);
ExecutionContext* context = GetExecutionContext();
if (context) {
// Record IdentifiabilityStudy metrics if the client is in the study.
if (UNLIKELY(IdentifiabilityStudySettings::Get()->ShouldSampleSurface(
identifiable_surface))) {
IdentifiableTokenBuilder token_builder;
for (const auto& brand : brand_set_) {
token_builder.AddValue(brand->hasBrand());
if (brand->hasBrand())
token_builder.AddAtomic(brand->brand().Utf8());
token_builder.AddValue(brand->hasVersion());
if (brand->hasVersion())
token_builder.AddAtomic(brand->version().Utf8());
}
IdentifiabilityMetricBuilder(context->UkmSourceID())
.Add(identifiable_surface, token_builder.GetToken())
.Record(context->UkmRecorder());
}
return brand_set_;
}
return empty_brand_set_;
}
const String& NavigatorUAData::platform() const {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string platform =
command_line->GetSwitchValueASCII(kUADataPlatform);
if (!platform.empty()) {
static const String& platformString = String::FromUTF8(platform.c_str());
return platformString;
}
if (GetExecutionContext()) {
return platform_;
}
return WTF::g_empty_string;
}
ScriptPromise NavigatorUAData::getHighEntropyValues(
ScriptState* script_state,
Vector<String>& hints) const {
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
auto* execution_context =
ExecutionContext::From(script_state); // GetExecutionContext();
DCHECK(execution_context);
bool record_identifiability =
IdentifiabilityStudySettings::Get()->ShouldSampleType(
IdentifiableSurface::Type::kNavigatorUAData_GetHighEntropyValues);
UADataValues* values = MakeGarbageCollected<UADataValues>();
// TODO: It'd be faster to compare hint when turning |hints| into an
// AtomicString vector and turning the const string literals |hint| into
// AtomicStrings as well.
// According to
// https://wicg.github.io/ua-client-hints/#getHighEntropyValues, brands,
// mobile and platform should be included regardless of whether they were
// asked for.
// Use `brands()` and not `brand_set_` directly since the former also
// records IdentifiabilityStudy metrics.
values->setBrands(brands());
values->setMobile(is_mobile_);
values->setPlatform(platform_);
// Record IdentifiabilityStudy metrics for `mobile()` and `platform()` (the
// `brands()` part is already recorded inside that function).
Dactyloscoper::RecordDirectSurface(
GetExecutionContext(), WebFeature::kNavigatorUAData_Mobile, mobile());
Dactyloscoper::RecordDirectSurface(
GetExecutionContext(), WebFeature::kNavigatorUAData_Platform, platform());
for (const String& hint : hints) {
if (hint == "platformVersion") {
values->setPlatformVersion(platform_version_);
MaybeRecordMetric(record_identifiability, hint, platform_version_,
execution_context);
} else if (hint == "architecture") {
values->setArchitecture(architecture_);
MaybeRecordMetric(record_identifiability, hint, architecture_,
execution_context);
} else if (hint == "model") {
values->setModel(model_);
MaybeRecordMetric(record_identifiability, hint, model_,
execution_context);
} else if (hint == "uaFullVersion") {
values->setUaFullVersion(ua_full_version_);
MaybeRecordMetric(record_identifiability, hint, ua_full_version_,
execution_context);
} else if (hint == "bitness") {
values->setBitness(bitness_);
MaybeRecordMetric(record_identifiability, hint, bitness_,
execution_context);
} else if (hint == "fullVersionList") {
values->setFullVersionList(full_version_list_);
} else if (hint == "wow64") {
values->setWow64(is_wow64_);
MaybeRecordMetric(record_identifiability, hint, is_wow64_ ? "?1" : "?0",
execution_context);
}
}
execution_context->GetTaskRunner(TaskType::kPermission)
->PostTask(
FROM_HERE,
WTF::Bind([](ScriptPromiseResolver* resolver,
UADataValues* values) { resolver->Resolve(values); },
WrapPersistent(resolver), WrapPersistent(values)));
return promise;
}
ScriptValue NavigatorUAData::toJSON(ScriptState* script_state) const {
V8ObjectBuilder builder(script_state);
builder.Add("brands", brands());
builder.Add("mobile", mobile());
builder.Add("platform", platform());
// Record IdentifiabilityStudy metrics for `mobile()` and `platform()`
// (the `brands()` part is already recorded inside that function).
Dactyloscoper::RecordDirectSurface(
GetExecutionContext(), WebFeature::kNavigatorUAData_Mobile, mobile());
Dactyloscoper::RecordDirectSurface(
GetExecutionContext(), WebFeature::kNavigatorUAData_Platform, platform());
return builder.GetScriptValue();
}
void NavigatorUAData::Trace(Visitor* visitor) const {
visitor->Trace(brand_set_);
visitor->Trace(full_version_list_);
visitor->Trace(empty_brand_set_);
ScriptWrappable::Trace(visitor);
ExecutionContextClient::Trace(visitor);
}
} // namespace blink
// All switches in alphabetical order. The switches should be documented
// alongside the definition of their values in the .cc file.
extern const char kAcceptLang[];
extern const char kPlatform[];
extern const char kUADataBrands[];
extern const char kIsMobile[];
extern const char kUADataPlatform[];
extern const char kUADataPlatformVersion[];
extern const char kUADataArchitecture[];
extern const char kUADataModel[];
extern const char kUADataUAFullVersion[];
extern const char kUADataWow64[];
extern const char kUADataBrandFullVersionList[];
extern const char kUADataBitness[];
extern const char kAllowCrossOriginAuthPrompt[];
// ...
namespace switches {
// -----------------------------------------------------------------------------
// Can't find the switch you are looking for? Try looking in:
// ash/constants/ash_switches.cc
// base/base_switches.cc
// etc.
//
// When commenting your switch, please use the same voice as surrounding
// comments. Imagine "This switch..." at the beginning of the phrase, and it'll
// all work out.
// -----------------------------------------------------------------------------
// Specifies Accept-Language to send to servers and expose to JavaScript via the
// navigator.language DOM property. language[-country] where language is the 2
// letter code from ISO-639.
const char kAcceptLang[] = "accept-lang";
const char kPlatform[] = "platform";
const char kUADataBrands[] = "ua-data-brands";
const char kIsMobile[] = "is-mobile";
const char kUADataPlatform[] = "ua-data-platform";
const char kUADataPlatformVersion[] = "ua-data-platform-version";
const char kUADataArchitecture[] = "ua-data-architecture";
const char kUADataModel[] = "ua-data-model";
const char kUADataUAFullVersion[] = "ua-data-ua-full-version";
const char kUADataBitness[] = "ua-data-bitness";
const char kUADataWow64[] = "ua-data-wow64";
const char kUADataBrandFullVersionList[] = "ua-data-brand-full-version-list";
// ...
--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/07e17c98-8264-4ca2-8fcc-10aee86c1703n%40chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CABc02_Jvn63KDbFS2i_NcfWb-dzUKd3Q4mNCG69qdn5vzEApXg%40mail.gmail.com.