blob: a696f0c804aa6f4c151c3a391a129721feec2bca [file] [log] [blame]
// 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/compiler_specific.h"
#include "base/single_thread_task_runner.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/web_feature/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/page/page.h"
namespace blink {
namespace {
// 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())
.Set(identifiable_surface, IdentifiableToken(value.Utf8()))
.Record(execution_context->UkmRecorder());
}
} // namespace
NavigatorUAData::NavigatorUAData(ExecutionContext* context)
: ExecutionContextClient(context) {
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::SetBrandVersionList(
const UserAgentBrandList& brand_version_list) {
for (const auto& brand_version : brand_version_list) {
AddBrandVersion(String::FromUTF8(brand_version.brand),
String::FromUTF8(brand_version.major_version));
}
}
void NavigatorUAData::SetMobile(bool mobile) {
is_mobile_ = mobile;
}
void NavigatorUAData::SetPlatform(const String& brand, const String& version) {
platform_ = brand;
platform_version_ = version;
}
void NavigatorUAData::SetArchitecture(const String& architecture) {
architecture_ = architecture;
}
void NavigatorUAData::SetModel(const String& model) {
model_ = model;
}
void NavigatorUAData::SetUAFullVersion(const String& ua_full_version) {
ua_full_version_ = ua_full_version;
}
bool NavigatorUAData::mobile() const {
if (GetExecutionContext()) {
return is_mobile_;
}
return false;
}
const HeapVector<Member<NavigatorUABrandVersion>>& NavigatorUAData::brands()
const {
if (GetExecutionContext()) {
return brand_set_;
}
return empty_brand_set_;
}
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()->ShouldSample(
IdentifiableSurface::Type::kNavigatorUAData_GetHighEntropyValues);
UADataValues* values = MakeGarbageCollected<UADataValues>();
for (const String& hint : hints) {
if (hint == "platform") {
values->setPlatform(platform_);
MaybeRecordMetric(record_identifiability, hint, platform_,
execution_context);
} else 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);
}
}
execution_context->GetTaskRunner(TaskType::kPermission)
->PostTask(
FROM_HERE,
WTF::Bind([](ScriptPromiseResolver* resolver,
UADataValues* values) { resolver->Resolve(values); },
WrapPersistent(resolver), WrapPersistent(values)));
return promise;
}
void NavigatorUAData::Trace(Visitor* visitor) const {
visitor->Trace(brand_set_);
visitor->Trace(empty_brand_set_);
ScriptWrappable::Trace(visitor);
ExecutionContextClient::Trace(visitor);
}
} // namespace blink