| // Copyright 2018 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 "chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/task/post_task.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/util/managed_browser_utils.h" |
| #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 !defined(OS_CHROMEOS) |
| const char kEndpointVerificationRetrievalFailed[] = |
| "Failed to retrieve the endpoint verification data."; |
| const char kEndpointVerificationStoreFailed[] = |
| "Failed to store the endpoint verification data."; |
| |
| api::enterprise_reporting_private::SettingValue ToInfoSettingValue( |
| enterprise_signals::DeviceInfo::SettingValue value) { |
| using SettingValue = enterprise_signals::DeviceInfo::SettingValue; |
| switch (value) { |
| case SettingValue::NONE: |
| return api::enterprise_reporting_private::SETTING_VALUE_NONE; |
| case SettingValue::UNKNOWN: |
| return api::enterprise_reporting_private::SETTING_VALUE_UNKNOWN; |
| case SettingValue::DISABLED: |
| return api::enterprise_reporting_private::SETTING_VALUE_DISABLED; |
| case SettingValue::ENABLED: |
| return api::enterprise_reporting_private::SETTING_VALUE_ENABLED; |
| } |
| } |
| #endif // !defined(OS_CHROMEOS) |
| |
| api::enterprise_reporting_private::ContextInfo ToContextInfo( |
| enterprise_signals::ContextInfo&& signals) { |
| api::enterprise_reporting_private::ContextInfo info; |
| |
| info.browser_affiliation_ids = std::move(signals.browser_affiliation_ids); |
| info.profile_affiliation_ids = std::move(signals.profile_affiliation_ids); |
| info.on_file_attached_providers = |
| std::move(signals.on_file_attached_providers); |
| info.on_file_downloaded_providers = |
| std::move(signals.on_file_downloaded_providers); |
| info.on_bulk_data_entry_providers = |
| std::move(signals.on_bulk_data_entry_providers); |
| info.on_security_event_providers = |
| std::move(signals.on_security_event_providers); |
| info.site_isolation_enabled = signals.site_isolation_enabled; |
| info.chrome_cleanup_enabled = |
| signals.chrome_cleanup_enabled.has_value() |
| ? std::make_unique<bool>(signals.chrome_cleanup_enabled.value()) |
| : nullptr; |
| info.chrome_remote_desktop_app_blocked = |
| signals.chrome_remote_desktop_app_blocked; |
| switch (signals.realtime_url_check_mode) { |
| case safe_browsing::REAL_TIME_CHECK_DISABLED: |
| info.realtime_url_check_mode = extensions::api:: |
| enterprise_reporting_private::REALTIME_URL_CHECK_MODE_DISABLED; |
| break; |
| case safe_browsing::REAL_TIME_CHECK_FOR_MAINFRAME_ENABLED: |
| info.realtime_url_check_mode = |
| extensions::api::enterprise_reporting_private:: |
| REALTIME_URL_CHECK_MODE_ENABLED_MAIN_FRAME; |
| break; |
| } |
| info.browser_version = std::move(signals.browser_version); |
| info.built_in_dns_client_enabled = signals.built_in_dns_client_enabled; |
| |
| switch (signals.safe_browsing_protection_level) { |
| case safe_browsing::NO_SAFE_BROWSING: |
| info.safe_browsing_protection_level = extensions::api:: |
| enterprise_reporting_private::SAFE_BROWSING_LEVEL_DISABLED; |
| break; |
| case safe_browsing::STANDARD_PROTECTION: |
| info.safe_browsing_protection_level = extensions::api:: |
| enterprise_reporting_private::SAFE_BROWSING_LEVEL_STANDARD; |
| break; |
| case safe_browsing::ENHANCED_PROTECTION: |
| info.safe_browsing_protection_level = extensions::api:: |
| enterprise_reporting_private::SAFE_BROWSING_LEVEL_ENHANCED; |
| break; |
| } |
| if (!signals.password_protection_warning_trigger.has_value()) { |
| info.password_protection_warning_trigger = extensions::api:: |
| enterprise_reporting_private::PASSWORD_PROTECTION_TRIGGER_POLICY_UNSET; |
| } else { |
| switch (signals.password_protection_warning_trigger.value()) { |
| case safe_browsing::PASSWORD_PROTECTION_OFF: |
| info.password_protection_warning_trigger = |
| extensions::api::enterprise_reporting_private:: |
| PASSWORD_PROTECTION_TRIGGER_PASSWORD_PROTECTION_OFF; |
| break; |
| case safe_browsing::PASSWORD_REUSE: |
| info.password_protection_warning_trigger = |
| extensions::api::enterprise_reporting_private:: |
| PASSWORD_PROTECTION_TRIGGER_PASSWORD_REUSE; |
| break; |
| case safe_browsing::PHISHING_REUSE: |
| info.password_protection_warning_trigger = |
| extensions::api::enterprise_reporting_private:: |
| PASSWORD_PROTECTION_TRIGGER_PHISHING_REUSE; |
| break; |
| case safe_browsing::PASSWORD_PROTECTION_TRIGGER_MAX: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| return info; |
| } |
| |
| } // namespace |
| |
| #if !defined(OS_CHROMEOS) |
| namespace enterprise_reporting { |
| const char kDeviceIdNotFound[] = "Failed to retrieve the device id."; |
| } // namespace enterprise_reporting |
| |
| // GetDeviceId |
| |
| EnterpriseReportingPrivateGetDeviceIdFunction:: |
| EnterpriseReportingPrivateGetDeviceIdFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| EnterpriseReportingPrivateGetDeviceIdFunction::Run() { |
| std::string client_id = |
| policy::BrowserDMTokenStorage::Get()->RetrieveClientId(); |
| if (client_id.empty()) |
| return RespondNow(Error(enterprise_reporting::kDeviceIdNotFound)); |
| return RespondNow(OneArgument(base::Value(client_id))); |
| } |
| |
| EnterpriseReportingPrivateGetDeviceIdFunction:: |
| ~EnterpriseReportingPrivateGetDeviceIdFunction() = default; |
| |
| // getPersistentSecret |
| |
| #if !defined(OS_LINUX) |
| |
| EnterpriseReportingPrivateGetPersistentSecretFunction:: |
| EnterpriseReportingPrivateGetPersistentSecretFunction() = default; |
| EnterpriseReportingPrivateGetPersistentSecretFunction:: |
| ~EnterpriseReportingPrivateGetPersistentSecretFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| EnterpriseReportingPrivateGetPersistentSecretFunction::Run() { |
| std::unique_ptr< |
| api::enterprise_reporting_private::GetPersistentSecret::Params> |
| params(api::enterprise_reporting_private::GetPersistentSecret::Params:: |
| Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| 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::ThreadTaskRunnerHandle::Get()))); |
| return RespondLater(); |
| } |
| |
| void EnterpriseReportingPrivateGetPersistentSecretFunction::OnDataRetrieved( |
| scoped_refptr<base::SequencedTaskRunner> task_runner, |
| const std::string& data, |
| long int status) { |
| task_runner->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &EnterpriseReportingPrivateGetPersistentSecretFunction::SendResponse, |
| this, data, status)); |
| } |
| |
| void EnterpriseReportingPrivateGetPersistentSecretFunction::SendResponse( |
| const std::string& data, |
| long int status) { |
| if (status == 0) { // Success. |
| VLOG(1) << "The Endpoint Verification secret was retrieved."; |
| Respond(OneArgument(base::Value(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("%ld", static_cast<long int>(status)))); |
| } |
| } |
| |
| #endif // !defined(OS_LINUX) |
| |
| // getDeviceData |
| |
| EnterpriseReportingPrivateGetDeviceDataFunction:: |
| EnterpriseReportingPrivateGetDeviceDataFunction() = default; |
| EnterpriseReportingPrivateGetDeviceDataFunction:: |
| ~EnterpriseReportingPrivateGetDeviceDataFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| EnterpriseReportingPrivateGetDeviceDataFunction::Run() { |
| std::unique_ptr<api::enterprise_reporting_private::GetDeviceData::Params> |
| params(api::enterprise_reporting_private::GetDeviceData::Params::Create( |
| *args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| base::ThreadPool::PostTask( |
| FROM_HERE, |
| {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, |
| base::BindOnce( |
| &RetrieveDeviceData, params->id, |
| base::BindOnce( |
| &EnterpriseReportingPrivateGetDeviceDataFunction::OnDataRetrieved, |
| this, base::ThreadTaskRunnerHandle::Get()))); |
| return RespondLater(); |
| } |
| |
| void EnterpriseReportingPrivateGetDeviceDataFunction::OnDataRetrieved( |
| scoped_refptr<base::SequencedTaskRunner> task_runner, |
| const std::string& data, |
| RetrieveDeviceDataStatus status) { |
| task_runner->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &EnterpriseReportingPrivateGetDeviceDataFunction::SendResponse, this, |
| data, status)); |
| } |
| |
| void EnterpriseReportingPrivateGetDeviceDataFunction::SendResponse( |
| const std::string& data, |
| RetrieveDeviceDataStatus status) { |
| switch (status) { |
| case RetrieveDeviceDataStatus::kSuccess: |
| VLOG(1) << "The Endpoint Verification data was retrieved."; |
| Respond(OneArgument(base::Value(base::Value::BlobStorage( |
| reinterpret_cast<const uint8_t*>(data.data()), |
| reinterpret_cast<const uint8_t*>(data.data() + data.size()))))); |
| return; |
| case RetrieveDeviceDataStatus::kDataRecordNotFound: |
| VLOG(1) << "The Endpoint Verification data is not present."; |
| Respond(OneArgument(base::Value(base::Value::BlobStorage()))); |
| return; |
| default: |
| VLOG(1) << "Endpoint Verification data retrieval error: " |
| << static_cast<long int>(status); |
| Respond(Error(kEndpointVerificationRetrievalFailed)); |
| } |
| } |
| |
| // setDeviceData |
| |
| EnterpriseReportingPrivateSetDeviceDataFunction:: |
| EnterpriseReportingPrivateSetDeviceDataFunction() = default; |
| EnterpriseReportingPrivateSetDeviceDataFunction:: |
| ~EnterpriseReportingPrivateSetDeviceDataFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| EnterpriseReportingPrivateSetDeviceDataFunction::Run() { |
| std::unique_ptr<api::enterprise_reporting_private::SetDeviceData::Params> |
| params(api::enterprise_reporting_private::SetDeviceData::Params::Create( |
| *args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| base::ThreadPool::PostTask( |
| FROM_HERE, |
| {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, |
| base::BindOnce( |
| &StoreDeviceData, params->id, std::move(params->data), |
| base::BindOnce( |
| &EnterpriseReportingPrivateSetDeviceDataFunction::OnDataStored, |
| this, base::ThreadTaskRunnerHandle::Get()))); |
| return RespondLater(); |
| } |
| |
| void EnterpriseReportingPrivateSetDeviceDataFunction::OnDataStored( |
| scoped_refptr<base::SequencedTaskRunner> task_runner, |
| bool status) { |
| task_runner->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &EnterpriseReportingPrivateSetDeviceDataFunction::SendResponse, this, |
| status)); |
| } |
| |
| void EnterpriseReportingPrivateSetDeviceDataFunction::SendResponse( |
| bool status) { |
| if (status) { |
| VLOG(1) << "The Endpoint Verification data was stored."; |
| Respond(NoArguments()); |
| } else { |
| VLOG(1) << "Endpoint Verification data storage error."; |
| Respond(Error(kEndpointVerificationStoreFailed)); |
| } |
| } |
| |
| // getDeviceInfo |
| |
| EnterpriseReportingPrivateGetDeviceInfoFunction:: |
| EnterpriseReportingPrivateGetDeviceInfoFunction() = default; |
| EnterpriseReportingPrivateGetDeviceInfoFunction:: |
| ~EnterpriseReportingPrivateGetDeviceInfoFunction() = default; |
| |
| // static |
| api::enterprise_reporting_private::DeviceInfo |
| EnterpriseReportingPrivateGetDeviceInfoFunction::ToDeviceInfo( |
| enterprise_signals::DeviceInfo&& device_signals) { |
| api::enterprise_reporting_private::DeviceInfo device_info; |
| |
| device_info.os_name = std::move(device_signals.os_name); |
| device_info.os_version = std::move(device_signals.os_version); |
| device_info.device_host_name = std::move(device_signals.device_host_name); |
| device_info.device_model = std::move(device_signals.device_model); |
| device_info.serial_number = std::move(device_signals.serial_number); |
| device_info.screen_lock_secured = |
| ToInfoSettingValue(device_signals.screen_lock_secured); |
| device_info.disk_encrypted = |
| ToInfoSettingValue(device_signals.disk_encrypted); |
| device_info.mac_addresses = std::move(device_signals.mac_addresses); |
| |
| return device_info; |
| } |
| |
| ExtensionFunction::ResponseAction |
| EnterpriseReportingPrivateGetDeviceInfoFunction::Run() { |
| #if defined(OS_WIN) |
| base::PostTaskAndReplyWithResult( |
| base::ThreadPool::CreateCOMSTATaskRunner({}).get(), FROM_HERE, |
| base::BindOnce(&enterprise_signals::DeviceInfoFetcher::Fetch, |
| enterprise_signals::DeviceInfoFetcher::CreateInstance()), |
| base::BindOnce(&EnterpriseReportingPrivateGetDeviceInfoFunction:: |
| OnDeviceInfoRetrieved, |
| this)); |
| #else |
| base::PostTaskAndReplyWithResult( |
| base::ThreadPool::CreateTaskRunner({base::MayBlock()}).get(), FROM_HERE, |
| base::BindOnce(&enterprise_signals::DeviceInfoFetcher::Fetch, |
| enterprise_signals::DeviceInfoFetcher::CreateInstance()), |
| base::BindOnce(&EnterpriseReportingPrivateGetDeviceInfoFunction:: |
| OnDeviceInfoRetrieved, |
| this)); |
| #endif // defined(OS_WIN) |
| |
| return RespondLater(); |
| } |
| |
| void EnterpriseReportingPrivateGetDeviceInfoFunction::OnDeviceInfoRetrieved( |
| enterprise_signals::DeviceInfo device_signals) { |
| Respond(OneArgument(base::Value::FromUniquePtrValue( |
| ToDeviceInfo(std::move(device_signals)).ToValue()))); |
| } |
| |
| #endif // !defined(OS_CHROMEOS) |
| |
| // getContextInfo |
| |
| EnterpriseReportingPrivateGetContextInfoFunction:: |
| EnterpriseReportingPrivateGetContextInfoFunction() = default; |
| EnterpriseReportingPrivateGetContextInfoFunction:: |
| ~EnterpriseReportingPrivateGetContextInfoFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| EnterpriseReportingPrivateGetContextInfoFunction::Run() { |
| auto* connectors_service = |
| enterprise_connectors::ConnectorsServiceFactory::GetInstance() |
| ->GetForBrowserContext(browser_context()); |
| DCHECK(connectors_service); |
| |
| context_info_fetcher_ = |
| enterprise_signals::ContextInfoFetcher::CreateInstance( |
| browser_context(), connectors_service); |
| context_info_fetcher_->Fetch(base::BindOnce( |
| &EnterpriseReportingPrivateGetContextInfoFunction::OnContextInfoRetrieved, |
| this)); |
| |
| return RespondLater(); |
| } |
| |
| void EnterpriseReportingPrivateGetContextInfoFunction::OnContextInfoRetrieved( |
| enterprise_signals::ContextInfo context_info) { |
| Respond(OneArgument(base::Value::FromUniquePtrValue( |
| ToContextInfo(std::move(context_info)).ToValue()))); |
| } |
| |
| // getCertificate |
| |
| EnterpriseReportingPrivateGetCertificateFunction:: |
| EnterpriseReportingPrivateGetCertificateFunction() = default; |
| EnterpriseReportingPrivateGetCertificateFunction:: |
| ~EnterpriseReportingPrivateGetCertificateFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| EnterpriseReportingPrivateGetCertificateFunction::Run() { |
| std::unique_ptr<api::enterprise_reporting_private::GetCertificate::Params> |
| params(api::enterprise_reporting_private::GetCertificate::Params::Create( |
| *args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| |
| // If AutoSelectCertificateForUrl is not set at the machine level, this |
| // operation is not supported and should return immediately with the |
| // appropriate status field value. |
| if (!chrome::enterprise_util::IsMachinePolicyPref( |
| prefs::kManagedAutoSelectCertificateForUrls)) { |
| api::enterprise_reporting_private::Certificate ret; |
| ret.status = extensions::api::enterprise_reporting_private:: |
| CERTIFICATE_STATUS_POLICY_UNSET; |
| return RespondNow( |
| OneArgument(base::Value::FromUniquePtrValue(ret.ToValue()))); |
| } |
| |
| client_cert_fetcher_ = |
| enterprise_signals::ClientCertificateFetcher::Create(browser_context()); |
| client_cert_fetcher_->FetchAutoSelectedCertificateForUrl( |
| GURL(params->url), |
| base::BindOnce(&EnterpriseReportingPrivateGetCertificateFunction:: |
| OnClientCertFetched, |
| this)); |
| |
| return RespondLater(); |
| } |
| |
| void EnterpriseReportingPrivateGetCertificateFunction::OnClientCertFetched( |
| std::unique_ptr<net::ClientCertIdentity> cert) { |
| api::enterprise_reporting_private::Certificate ret; |
| |
| // Getting here means the status is always OK, but the |encoded_certificate| |
| // field is only set if there actually was a certificate selected. |
| ret.status = |
| extensions::api::enterprise_reporting_private::CERTIFICATE_STATUS_OK; |
| if (cert) { |
| base::StringPiece der_cert = net::x509_util::CryptoBufferAsStringPiece( |
| cert->certificate()->cert_buffer()); |
| ret.encoded_certificate = std::make_unique<std::vector<uint8_t>>( |
| der_cert.begin(), der_cert.end()); |
| } |
| |
| Respond(OneArgument(base::Value::FromUniquePtrValue(ret.ToValue()))); |
| } |
| |
| } // namespace extensions |