blob: 8268595a6ba595f266eb367831e3d5d66dbbc209 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/enterprise/remote_commands/clear_browsing_data_job.h"
#include <optional>
#include "base/functional/bind.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/task/single_thread_task_runner.h"
#include "base/values.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/policy/core/common/policy_logger.h"
#include "content/public/browser/browsing_data_remover.h"
namespace enterprise_commands {
namespace {
const char kFailedTypesPath[] = "failed_data_types";
const char kClearCacheField[] = "clear_cache";
const char kClearCookiesField[] = "clear_cookies";
// Define the possibly failed data types here for 2 reasons:
//
// 1. This will be easier to keep in sync with the server, as the latter
// doesn't care about *all* the types in BrowsingDataRemover.
//
// 2. Centralize handling the underlying type of the values here.
// BrowsingDataRemover represents failed types as uint64_t, which isn't
// natively supported by base::Value, so this class needs to convert to a
// type that's supported. This will also allow us to use a list instead of a
// bit mask, which will be easier to parse gracefully on the server in case
// more types are added.
enum class DataTypes {
kCache = 0,
kCookies = 1,
};
std::string CreatePayload(uint64_t failed_data_types) {
base::Value::Dict root;
base::Value::List failed_types_list;
if (failed_data_types & content::BrowsingDataRemover::DATA_TYPE_CACHE)
failed_types_list.Append(static_cast<int>(DataTypes::kCache));
if (failed_data_types & content::BrowsingDataRemover::DATA_TYPE_COOKIES)
failed_types_list.Append(static_cast<int>(DataTypes::kCookies));
root.Set(kFailedTypesPath, std::move(failed_types_list));
std::string payload;
base::JSONWriter::Write(root, &payload);
return payload;
}
} // namespace
ClearBrowsingDataJob::ClearBrowsingDataJob(ProfileManager* profile_manager)
: job_profile_picker_(profile_manager) {}
ClearBrowsingDataJob::ClearBrowsingDataJob(Profile* profile)
: job_profile_picker_(profile) {}
ClearBrowsingDataJob::~ClearBrowsingDataJob() = default;
enterprise_management::RemoteCommand_Type ClearBrowsingDataJob::GetType()
const {
return enterprise_management::RemoteCommand_Type_BROWSER_CLEAR_BROWSING_DATA;
}
bool ClearBrowsingDataJob::ParseCommandPayload(
const std::string& command_payload) {
VLOG_POLICY(2, REMOTE_COMMANDS)
<< "Clear browsing data command payload: " << command_payload;
std::optional<base::Value::Dict> root =
base::JSONReader::ReadDict(command_payload);
if (!root)
return false;
if (!job_profile_picker_.ParseCommandPayload(*root)) {
return false;
}
// Not specifying these fields is equivalent to setting them to false.
clear_cache_ = root->FindBool(kClearCacheField).value_or(false);
clear_cookies_ = root->FindBool(kClearCookiesField).value_or(false);
return true;
}
void ClearBrowsingDataJob::RunImpl(CallbackWithResult result_callback) {
uint64_t types = 0;
if (clear_cache_)
types |= content::BrowsingDataRemover::DATA_TYPE_CACHE;
if (clear_cookies_)
types |= content::BrowsingDataRemover::DATA_TYPE_COOKIES;
Profile* profile = job_profile_picker_.GetProfile();
if (!profile) {
// If the payload's profile path doesn't correspond to an existing profile,
// there's nothing to do. The most likely scenario is that the profile was
// deleted by the time the command was received.
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(result_callback), policy::ResultType::kFailure,
CreatePayload(types)));
return;
}
result_callback_ = std::move(result_callback);
if (types == 0) {
LOG_POLICY(WARNING, REMOTE_COMMANDS)
<< "Clear browsing data command has not specified any "
"data types. Please double check the payload to "
"make sure everything is set as required.";
// There's nothing to clear, invoke the callback with success result and be
// done.
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(result_callback_),
policy::ResultType::kSuccess,
CreatePayload(
/*failed_data_types=*/0)));
return;
}
content::BrowsingDataRemover* remover = profile->GetBrowsingDataRemover();
remover->AddObserver(this);
remover->RemoveAndReply(
base::Time(), base::Time::Max(), types,
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB, this);
}
void ClearBrowsingDataJob::OnBrowsingDataRemoverDone(
uint64_t failed_data_types) {
Profile* profile = job_profile_picker_.GetProfile();
DCHECK(profile);
content::BrowsingDataRemover* remover = profile->GetBrowsingDataRemover();
remover->RemoveObserver(this);
std::string payload = CreatePayload(failed_data_types);
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(result_callback_),
failed_data_types != 0 ? policy::ResultType::kFailure
: policy::ResultType::kSuccess,
std::move(payload)));
}
} // namespace enterprise_commands