#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h"
#include <memory>
#include <string_view>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/strings/stringprintf.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/enterprise/connectors/connectors_service.h"
#include "chrome/browser/enterprise/signals/device_info_fetcher.h"
#include "chrome/browser/enterprise/signals/signals_common.h"
#include "chrome/browser/enterprise/util/affiliation.h"
#include "chrome/browser/enterprise/util/managed_browser_utils.h"
#include "chrome/browser/profiles/profile.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/policy/dm_token_utils.h"
#include "chromeos/dbus/missive/missive_client.h"
#include "components/policy/core/common/cloud/dm_token.h"
#include "components/reporting/client/report_queue_configuration.h"
#include "components/reporting/proto/synced/record.pb.h"
#include "components/reporting/proto/synced/record_constants.pb.h"
#include "components/reporting/util/statusor.h"
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
#include <optional>
#include "base/strings/string_util.h"
#include "chrome/browser/enterprise/signals/signals_aggregator_factory.h"
#include "chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.h"
#include "components/device_signals/core/browser/metrics_utils.h"
#include "components/device_signals/core/browser/signals_aggregator.h"
#include "components/device_signals/core/browser/signals_types.h"
#include "components/device_signals/core/browser/user_context.h"
#include "components/device_signals/core/common/signals_features.h"
#endif
#include "components/content_settings/core/common/pref_names.h"
#include "components/enterprise/browser/controller/browser_dm_token_storage.h"
#include "net/cert/x509_util.h"
namespace extensions {
namespace {
#if !BUILDFLAG(IS_CHROMEOS)
const char kEndpointVerificationRetrievalFailed[] = …;
const char kEndpointVerificationStoreFailed[] = …;
#endif
api::enterprise_reporting_private::SettingValue ToInfoSettingValue(
enterprise_signals::SettingValue value) { … }
api::enterprise_reporting_private::ContextInfo ToContextInfo(
enterprise_signals::ContextInfo&& signals) { … }
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
device_signals::SignalsAggregationRequest CreateAggregationRequest(
device_signals::SignalName signal_name) { … }
void StartSignalCollection(
const std::string& user_id,
device_signals::SignalsAggregationRequest request,
content::BrowserContext* browser_context,
base::OnceCallback<void(device_signals::SignalsAggregationResponse)>
callback) { … }
bool CanReturnResponse(content::BrowserContext* browser_context) { … }
#endif
}
#if !BUILDFLAG(IS_CHROMEOS)
namespace enterprise_reporting {
const char kDeviceIdNotFound[] = …;
}
EnterpriseReportingPrivateGetDeviceIdFunction::
EnterpriseReportingPrivateGetDeviceIdFunction() { … }
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateGetDeviceIdFunction::Run() { … }
EnterpriseReportingPrivateGetDeviceIdFunction::
~EnterpriseReportingPrivateGetDeviceIdFunction() = default;
#if !BUILDFLAG(IS_LINUX)
EnterpriseReportingPrivateGetPersistentSecretFunction::
EnterpriseReportingPrivateGetPersistentSecretFunction() = default;
EnterpriseReportingPrivateGetPersistentSecretFunction::
~EnterpriseReportingPrivateGetPersistentSecretFunction() = default;
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateGetPersistentSecretFunction::Run() {
std::optional<api::enterprise_reporting_private::GetPersistentSecret::Params>
params = api::enterprise_reporting_private::GetPersistentSecret::Params::
Create(args());
EXTENSION_FUNCTION_VALIDATE(params);
bool force_create = params->reset_secret ? *params->reset_secret : false;
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce(
&RetrieveDeviceSecret, force_create,
base::BindOnce(
&EnterpriseReportingPrivateGetPersistentSecretFunction::
OnDataRetrieved,
this, base::SingleThreadTaskRunner::GetCurrentDefault())));
return RespondLater();
}
void EnterpriseReportingPrivateGetPersistentSecretFunction::OnDataRetrieved(
scoped_refptr<base::SequencedTaskRunner> task_runner,
const std::string& data,
int32_t status) {
task_runner->PostTask(
FROM_HERE,
base::BindOnce(
&EnterpriseReportingPrivateGetPersistentSecretFunction::SendResponse,
this, data, status));
}
void EnterpriseReportingPrivateGetPersistentSecretFunction::SendResponse(
const std::string& data,
int32_t status) {
if (status == 0) {
VLOG(1) << "The Endpoint Verification secret was retrieved.";
Respond(WithArguments(base::Value::BlobStorage(
reinterpret_cast<const uint8_t*>(data.data()),
reinterpret_cast<const uint8_t*>(data.data() + data.size()))));
} else {
VLOG(1) << "Endpoint Verification secret retrieval error: " << status;
Respond(Error(base::StringPrintf("%d", status)));
}
}
#endif
EnterpriseReportingPrivateGetDeviceDataFunction::
EnterpriseReportingPrivateGetDeviceDataFunction() = default;
EnterpriseReportingPrivateGetDeviceDataFunction::
~EnterpriseReportingPrivateGetDeviceDataFunction() = default;
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateGetDeviceDataFunction::Run() { … }
void EnterpriseReportingPrivateGetDeviceDataFunction::OnDataRetrieved(
scoped_refptr<base::SequencedTaskRunner> task_runner,
const std::string& data,
RetrieveDeviceDataStatus status) { … }
void EnterpriseReportingPrivateGetDeviceDataFunction::SendResponse(
const std::string& data,
RetrieveDeviceDataStatus status) { … }
EnterpriseReportingPrivateSetDeviceDataFunction::
EnterpriseReportingPrivateSetDeviceDataFunction() = default;
EnterpriseReportingPrivateSetDeviceDataFunction::
~EnterpriseReportingPrivateSetDeviceDataFunction() = default;
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateSetDeviceDataFunction::Run() { … }
void EnterpriseReportingPrivateSetDeviceDataFunction::OnDataStored(
scoped_refptr<base::SequencedTaskRunner> task_runner,
bool status) { … }
void EnterpriseReportingPrivateSetDeviceDataFunction::SendResponse(
bool status) { … }
EnterpriseReportingPrivateGetDeviceInfoFunction::
EnterpriseReportingPrivateGetDeviceInfoFunction() = default;
EnterpriseReportingPrivateGetDeviceInfoFunction::
~EnterpriseReportingPrivateGetDeviceInfoFunction() = default;
api::enterprise_reporting_private::DeviceInfo
EnterpriseReportingPrivateGetDeviceInfoFunction::ToDeviceInfo(
const enterprise_signals::DeviceInfo& device_signals) { … }
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateGetDeviceInfoFunction::Run() { … }
void EnterpriseReportingPrivateGetDeviceInfoFunction::OnDeviceInfoRetrieved(
const enterprise_signals::DeviceInfo& device_signals) { … }
#endif
EnterpriseReportingPrivateGetContextInfoFunction::
EnterpriseReportingPrivateGetContextInfoFunction() = default;
EnterpriseReportingPrivateGetContextInfoFunction::
~EnterpriseReportingPrivateGetContextInfoFunction() = default;
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateGetContextInfoFunction::Run() { … }
void EnterpriseReportingPrivateGetContextInfoFunction::OnContextInfoRetrieved(
enterprise_signals::ContextInfo context_info) { … }
EnterpriseReportingPrivateGetCertificateFunction::
EnterpriseReportingPrivateGetCertificateFunction() = default;
EnterpriseReportingPrivateGetCertificateFunction::
~EnterpriseReportingPrivateGetCertificateFunction() = default;
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateGetCertificateFunction::Run() { … }
void EnterpriseReportingPrivateGetCertificateFunction::OnClientCertFetched(
std::unique_ptr<net::ClientCertIdentity> cert) { … }
#if BUILDFLAG(IS_CHROMEOS)
EnterpriseReportingPrivateEnqueueRecordFunction::
EnterpriseReportingPrivateEnqueueRecordFunction() = default;
EnterpriseReportingPrivateEnqueueRecordFunction::
~EnterpriseReportingPrivateEnqueueRecordFunction() = default;
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateEnqueueRecordFunction::Run() {
auto* profile = Profile::FromBrowserContext(browser_context());
DCHECK(profile);
if (!IsProfileAffiliated(profile)) {
return RespondNow(Error(kErrorProfileNotAffiliated));
}
std::optional<api::enterprise_reporting_private::EnqueueRecord::Params>
params = api::enterprise_reporting_private::EnqueueRecord::Params::Create(
args());
EXTENSION_FUNCTION_VALIDATE(params);
const auto event_type = params->request.event_type;
::reporting::Record record;
::reporting::Priority priority;
if (!TryParseParams(std::move(params), record, priority)) {
return RespondNow(Error(kErrorInvalidEnqueueRecordRequest));
}
if (!TryAttachDMTokenToRecord(record, event_type)) {
return RespondNow(Error(kErrorCannotAssociateRecordWithUser));
}
auto enqueue_completion_cb = base::BindOnce(
&EnterpriseReportingPrivateEnqueueRecordFunction::OnRecordEnqueued, this);
auto* reporting_client = ::chromeos::MissiveClient::Get();
DCHECK(reporting_client);
reporting_client->EnqueueRecord(priority, record,
std::move(enqueue_completion_cb));
return RespondLater();
}
bool EnterpriseReportingPrivateEnqueueRecordFunction::TryParseParams(
std::optional<api::enterprise_reporting_private::EnqueueRecord::Params>
params,
::reporting::Record& record,
::reporting::Priority& priority) {
if (params->request.record_data.empty()) {
return false;
}
const auto* record_data =
reinterpret_cast<const char*>(params->request.record_data.data());
if (!record.ParseFromArray(record_data, params->request.record_data.size())) {
return false;
}
if (!record.has_timestamp_us()) {
return false;
}
if (!::reporting::Priority_IsValid(params->request.priority) ||
!::reporting::Priority_Parse(
::reporting::Priority_Name(params->request.priority), &priority)) {
return false;
}
return true;
}
bool EnterpriseReportingPrivateEnqueueRecordFunction::TryAttachDMTokenToRecord(
::reporting::Record& record,
api::enterprise_reporting_private::EventType event_type) {
if (event_type == api::enterprise_reporting_private::EventType::kDevice) {
return true;
}
auto* profile = Profile::FromBrowserContext(browser_context());
const policy::DMToken& dm_token = policy::GetDMToken(profile);
if (!dm_token.is_valid()) {
return false;
}
record.set_dm_token(dm_token.value());
return true;
}
void EnterpriseReportingPrivateEnqueueRecordFunction::OnRecordEnqueued(
::reporting::Status result) {
if (!result.ok()) {
Respond(Error(kUnexpectedErrorEnqueueRecordRequest));
return;
}
Respond(NoArguments());
}
bool EnterpriseReportingPrivateEnqueueRecordFunction::IsProfileAffiliated(
Profile* profile) {
if (profile_is_affiliated_for_testing_) {
return true;
}
return enterprise_util::IsProfileAffiliated(profile);
}
void EnterpriseReportingPrivateEnqueueRecordFunction::
SetProfileIsAffiliatedForTesting(bool is_affiliated) {
profile_is_affiliated_for_testing_ = is_affiliated;
}
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
EnterpriseReportingPrivateGetFileSystemInfoFunction::
EnterpriseReportingPrivateGetFileSystemInfoFunction() = default;
EnterpriseReportingPrivateGetFileSystemInfoFunction::
~EnterpriseReportingPrivateGetFileSystemInfoFunction() = default;
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateGetFileSystemInfoFunction::Run() { … }
void EnterpriseReportingPrivateGetFileSystemInfoFunction::OnSignalRetrieved(
base::TimeTicks start_time,
size_t request_items_count,
device_signals::SignalsAggregationResponse response) { … }
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
EnterpriseReportingPrivateGetSettingsFunction::
EnterpriseReportingPrivateGetSettingsFunction() = default;
EnterpriseReportingPrivateGetSettingsFunction::
~EnterpriseReportingPrivateGetSettingsFunction() = default;
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateGetSettingsFunction::Run() {
if (!IsNewFunctionEnabled(
enterprise_signals::features::NewEvFunction::kSettings)) {
return RespondNow(Error(device_signals::ErrorToString(
device_signals::SignalCollectionError::kUnsupported)));
}
std::optional<api::enterprise_reporting_private::GetSettings::Params> params =
api::enterprise_reporting_private::GetSettings::Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(params);
bool paths_are_all_utf8 = true;
for (const auto& api_options_param : params->request.options) {
if (!base::IsStringUTF8(api_options_param.path)) {
paths_are_all_utf8 = false;
break;
}
}
EXTENSION_FUNCTION_VALIDATE(paths_are_all_utf8);
auto aggregation_request = CreateAggregationRequest(signal_name());
aggregation_request.settings_signal_parameters =
ConvertSettingsOptions(params->request.options);
const size_t number_of_items =
aggregation_request.settings_signal_parameters.size();
LogSignalCollectionRequestedWithItems(signal_name(), number_of_items);
StartSignalCollection(
params->request.user_context.user_id, aggregation_request,
browser_context(),
base::BindOnce(
&EnterpriseReportingPrivateGetSettingsFunction::OnSignalRetrieved,
this, base::TimeTicks::Now(), number_of_items));
return RespondLater();
}
void EnterpriseReportingPrivateGetSettingsFunction::OnSignalRetrieved(
base::TimeTicks start_time,
size_t request_items_count,
device_signals::SignalsAggregationResponse response) {
if (!CanReturnResponse(browser_context())) {
return;
}
std::vector<api::enterprise_reporting_private::GetSettingsResponse> arg_list;
auto parsed_error = ConvertSettingsResponse(response, &arg_list);
if (parsed_error) {
LogSignalCollectionFailed(signal_name(), start_time, parsed_error->error,
parsed_error->is_top_level_error);
Respond(Error(device_signals::ErrorToString(parsed_error->error)));
return;
}
LogSignalCollectionSucceeded(signal_name(), start_time, arg_list.size(),
request_items_count);
Respond(ArgumentList(
api::enterprise_reporting_private::GetSettings::Results::Create(
arg_list)));
}
#endif
#if BUILDFLAG(IS_WIN)
EnterpriseReportingPrivateGetAvInfoFunction::
EnterpriseReportingPrivateGetAvInfoFunction() = default;
EnterpriseReportingPrivateGetAvInfoFunction::
~EnterpriseReportingPrivateGetAvInfoFunction() = default;
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateGetAvInfoFunction::Run() {
if (!IsNewFunctionEnabled(
enterprise_signals::features::NewEvFunction::kAntiVirus)) {
return RespondNow(Error(device_signals::ErrorToString(
device_signals::SignalCollectionError::kUnsupported)));
}
std::optional<api::enterprise_reporting_private::GetAvInfo::Params> params =
api::enterprise_reporting_private::GetAvInfo::Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(params);
StartSignalCollection(
params->user_context.user_id, CreateAggregationRequest(signal_name()),
browser_context(),
base::BindOnce(
&EnterpriseReportingPrivateGetAvInfoFunction::OnSignalRetrieved, this,
base::TimeTicks::Now()));
return RespondLater();
}
void EnterpriseReportingPrivateGetAvInfoFunction::OnSignalRetrieved(
base::TimeTicks start_time,
device_signals::SignalsAggregationResponse response) {
if (!CanReturnResponse(browser_context())) {
return;
}
std::vector<api::enterprise_reporting_private::AntiVirusSignal> arg_list;
auto parsed_error = ConvertAvProductsResponse(response, &arg_list);
if (parsed_error) {
LogSignalCollectionFailed(signal_name(), start_time, parsed_error->error,
parsed_error->is_top_level_error);
Respond(Error(device_signals::ErrorToString(parsed_error->error)));
return;
}
LogSignalCollectionSucceeded(signal_name(), start_time, arg_list.size());
Respond(ArgumentList(
api::enterprise_reporting_private::GetAvInfo::Results::Create(arg_list)));
}
EnterpriseReportingPrivateGetHotfixesFunction::
EnterpriseReportingPrivateGetHotfixesFunction() = default;
EnterpriseReportingPrivateGetHotfixesFunction::
~EnterpriseReportingPrivateGetHotfixesFunction() = default;
ExtensionFunction::ResponseAction
EnterpriseReportingPrivateGetHotfixesFunction::Run() {
if (!IsNewFunctionEnabled(
enterprise_signals::features::NewEvFunction::kHotfix)) {
return RespondNow(Error(device_signals::ErrorToString(
device_signals::SignalCollectionError::kUnsupported)));
}
std::optional<api::enterprise_reporting_private::GetHotfixes::Params> params =
api::enterprise_reporting_private::GetHotfixes::Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(params);
StartSignalCollection(
params->user_context.user_id, CreateAggregationRequest(signal_name()),
browser_context(),
base::BindOnce(
&EnterpriseReportingPrivateGetHotfixesFunction::OnSignalRetrieved,
this, base::TimeTicks::Now()));
return RespondLater();
}
void EnterpriseReportingPrivateGetHotfixesFunction::OnSignalRetrieved(
base::TimeTicks start_time,
device_signals::SignalsAggregationResponse response) {
if (!CanReturnResponse(browser_context())) {
return;
}
std::vector<api::enterprise_reporting_private::HotfixSignal> arg_list;
auto parsed_error = ConvertHotfixesResponse(response, &arg_list);
if (parsed_error) {
LogSignalCollectionFailed(signal_name(), start_time, parsed_error->error,
parsed_error->is_top_level_error);
Respond(Error(device_signals::ErrorToString(parsed_error->error)));
return;
}
LogSignalCollectionSucceeded(signal_name(), start_time, arg_list.size());
Respond(ArgumentList(
api::enterprise_reporting_private::GetHotfixes::Results::Create(
arg_list)));
}
#endif
}