blob: 9557ac783f4a44bbfa00c7458901f2e973ab2d34 [file] [log] [blame]
// Copyright 2021 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/chromeos/dbus/encrypted_reporting_service_provider.h"
#include <memory>
#include <utility>
#include "base/strings/strcat.h"
#include "base/task/thread_pool.h"
#include "chrome/browser/policy/messaging_layer/upload/upload_client.h"
#include "chrome/browser/policy/messaging_layer/util/get_cloud_policy_client.h"
#include "chromeos/dbus/missive/missive_client.h"
#include "components/reporting/proto/interface.pb.h"
#include "components/reporting/storage/storage_module_interface.h"
#include "components/reporting/util/backoff_settings.h"
#include "components/reporting/util/status.h"
#include "components/reporting/util/status.pb.h"
#include "components/reporting/util/statusor.h"
#include "dbus/bus.h"
#include "dbus/exported_object.h"
#include "dbus/message.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
namespace {
void SendStatusAsResponse(std::unique_ptr<dbus::Response> response,
dbus::ExportedObject::ResponseSender response_sender,
const reporting::Status& status) {
// Build StatusProto
reporting::StatusProto status_proto;
status.SaveTo(&status_proto);
dbus::MessageWriter writer(response.get());
writer.AppendProtoAsArrayOfBytes(status_proto);
// Send Response
std::move(response_sender).Run(std::move(response));
}
} // namespace
EncryptedReportingServiceProvider::EncryptedReportingServiceProvider()
: sequenced_task_runner_(
base::ThreadPool::CreateSequencedTaskRunner(base::TaskTraits())),
backoff_entry_(reporting::GetBackoffEntry()),
storage_module_(MissiveClient::Get()->GetMissiveStorageModule()) {}
EncryptedReportingServiceProvider::~EncryptedReportingServiceProvider() =
default;
void EncryptedReportingServiceProvider::Start(
scoped_refptr<dbus::ExportedObject> exported_object) {
exported_object->ExportMethod(
kChromeReportingServiceInterface,
kChromeReportingServiceUploadEncryptedRecordMethod,
base::BindRepeating(
&EncryptedReportingServiceProvider::RequestUploadEncryptedRecord,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&EncryptedReportingServiceProvider::OnExported,
weak_ptr_factory_.GetWeakPtr()));
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&EncryptedReportingServiceProvider::PostNewCloudPolicyClientRequest,
weak_ptr_factory_.GetWeakPtr()));
}
void EncryptedReportingServiceProvider::OnExported(
const std::string& interface_name,
const std::string& method_name,
bool success) {
if (!success) {
LOG(ERROR) << "Failed to export " << interface_name << "." << method_name;
}
}
void EncryptedReportingServiceProvider::PostNewCloudPolicyClientRequest() {
if (upload_client_ != nullptr) {
return;
}
if (upload_client_request_in_progress_) {
return;
}
upload_client_request_in_progress_ = true;
sequenced_task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(
[](base::OnceCallback<void(
reporting::StatusOr<policy::CloudPolicyClient*>)> callback) {
reporting::GetCloudPolicyClientCb().Run(std::move(callback));
},
base::BindOnce(
&EncryptedReportingServiceProvider::OnCloudPolicyClientResult,
weak_ptr_factory_.GetWeakPtr())),
backoff_entry_->GetTimeUntilRelease());
// Increase backoff_entry_ for next request.
backoff_entry_->InformOfRequest(/*succeeded=*/false);
}
void EncryptedReportingServiceProvider::OnCloudPolicyClientResult(
reporting::StatusOr<policy::CloudPolicyClient*> client_result) {
if (!client_result.ok()) {
upload_client_request_in_progress_ = false;
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&EncryptedReportingServiceProvider::PostNewCloudPolicyClientRequest,
weak_ptr_factory_.GetWeakPtr()));
return;
}
BuildUploadClient(client_result.ValueOrDie());
}
void EncryptedReportingServiceProvider::BuildUploadClient(
policy::CloudPolicyClient* client) {
reporting::UploadClient::ReportSuccessfulUploadCallback successful_upload_cb =
base::BindRepeating(&reporting::StorageModuleInterface::ReportSuccess,
storage_module_);
reporting::UploadClient::EncryptionKeyAttachedCallback encryption_key_cb =
base::BindRepeating(
&reporting::StorageModuleInterface::UpdateEncryptionKey,
storage_module_);
base::OnceCallback<void(
reporting::StatusOr<std::unique_ptr<reporting::UploadClient>>)>
update_upload_client_cb = base::BindOnce(
&EncryptedReportingServiceProvider::OnUploadClientResult,
weak_ptr_factory_.GetWeakPtr());
reporting::UploadClient::Create(client, std::move(successful_upload_cb),
std::move(encryption_key_cb),
std::move(update_upload_client_cb));
}
void EncryptedReportingServiceProvider::OnUploadClientResult(
reporting::StatusOr<std::unique_ptr<reporting::UploadClient>>
client_result) {
if (!client_result.ok()) {
upload_client_request_in_progress_ = false;
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&EncryptedReportingServiceProvider::PostNewCloudPolicyClientRequest,
weak_ptr_factory_.GetWeakPtr()));
return;
}
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&EncryptedReportingServiceProvider::UpdateUploadClient,
weak_ptr_factory_.GetWeakPtr(),
std::move(client_result.ValueOrDie())));
}
void EncryptedReportingServiceProvider::UpdateUploadClient(
std::unique_ptr<reporting::UploadClient> upload_client) {
upload_client_ = std::move(upload_client);
backoff_entry_->InformOfRequest(/*succeeded*/ true);
upload_client_request_in_progress_ = false;
}
void EncryptedReportingServiceProvider::RequestUploadEncryptedRecord(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
auto response = dbus::Response::FromMethodCall(method_call);
if (upload_client_ == nullptr) {
reporting::Status status{reporting::error::UNAVAILABLE,
"UploadClient isn't ready"};
SendStatusAsResponse(std::move(response), std::move(response_sender),
status);
return;
}
reporting::UploadEncryptedRecordRequest request;
dbus::MessageReader reader(method_call);
if (!reader.PopArrayOfBytesAsProto(&request)) {
reporting::Status status{
reporting::error::INVALID_ARGUMENT,
"Message was not decipherable as an UploadEncryptedRecordRequest"};
LOG(ERROR) << "Unable to process UploadEncryptedRecordRequest. status: "
<< status;
SendStatusAsResponse(std::move(response), std::move(response_sender),
status);
return;
}
auto records = std::make_unique<std::vector<reporting::EncryptedRecord>>();
for (auto& record : request.encrypted_record()) {
records->push_back(std::move(record));
}
auto enqueue_status = upload_client_->EnqueueUpload(
request.need_encryption_keys(), std::move(records));
SendStatusAsResponse(std::move(response), std::move(response_sender),
enqueue_status);
}
} // namespace chromeos