blob: 1cfa21920ff25ebce9903fa0077d1d8be342b544 [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 "chrome/browser/enterprise/remote_commands/clear_browsing_data_job.h"
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/optional.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
#include "chrome/browser/profiles/profile_manager.h"
namespace enterprise_commands {
const char kFailedTypesPath[] = "failed_data_types";
const char kProfilePathField[] = "profile_path";
const char kClearCacheField[] = "clear_cache";
const char kClearCookiesField[] = "clear_cookies";
ClearBrowsingDataJob::ResultPayload::ResultPayload(uint64_t failed_data_types)
: failed_data_types_(failed_data_types) {}
ClearBrowsingDataJob::ResultPayload::~ResultPayload() = default;
std::unique_ptr<std::string> ClearBrowsingDataJob::ResultPayload::Serialize() {
base::Value root(base::Value::Type::DICTIONARY);
base::Value failed_types_list(base::Value::Type::LIST);
if (failed_data_types_ & content::BrowsingDataRemover::DATA_TYPE_CACHE)
failed_types_list.Append(static_cast<int>(CACHE));
if (failed_data_types_ & content::BrowsingDataRemover::DATA_TYPE_COOKIES)
failed_types_list.Append(static_cast<int>(COOKIES));
root.SetPath(kFailedTypesPath, std::move(failed_types_list));
std::string payload;
base::JSONWriter::Write(root, &payload);
return std::make_unique<std::string>(std::move(payload));
}
ClearBrowsingDataJob::ClearBrowsingDataJob(ProfileManager* profile_manager)
: profile_manager_(profile_manager) {}
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) {
base::Optional<base::Value> root(base::JSONReader::Read(command_payload));
if (!root)
return false;
if (!root->is_dict())
return false;
std::string* path = root->FindStringKey(kProfilePathField);
if (!path)
return false;
// On Windows, file paths are wstring as opposed to string on other platforms.
// On POSIX platforms other than MacOS and ChromeOS, the encoding is unknown.
//
// This path is sent from the server, which obtained it from Chrome in a
// previous report, and Chrome casts the path as UTF8 using UTF8Unsafe before
// sending it (see BrowserReportGeneratorDesktop::GenerateProfileInfo).
// Because of that, the best thing we can do everywhere is try to get the
// path from UTF8, and ending up with an invalid path will fail later in
// RunImpl when we attempt to get the profile from the path.
profile_path_ = base::FilePath::FromUTF8Unsafe(*path);
// Not specifying these fields is equivalent to setting them to false.
clear_cache_ = root->FindBoolKey(kClearCacheField).value_or(false);
clear_cookies_ = root->FindBoolKey(kClearCookiesField).value_or(false);
return true;
}
void ClearBrowsingDataJob::RunImpl(CallbackWithResult succeeded_callback,
CallbackWithResult failed_callback) {
DCHECK(profile_manager_);
uint64_t types = 0;
if (clear_cache_)
types |= content::BrowsingDataRemover::DATA_TYPE_CACHE;
if (clear_cookies_)
types |= content::BrowsingDataRemover::DATA_TYPE_COOKIES;
Profile* profile = profile_manager_->GetProfileByPath(profile_path_);
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::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(failed_callback),
std::make_unique<ResultPayload>(types)));
return;
}
succeeded_callback_ = std::move(succeeded_callback);
failed_callback_ = std::move(failed_callback);
if (types == 0) {
// There's nothing to clear, invoke the success callback and be done.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(succeeded_callback_),
std::make_unique<ResultPayload>(
/* failed_types= */ 0)));
return;
}
content::BrowsingDataRemover* remover =
content::BrowserContext::GetBrowsingDataRemover(profile);
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 = profile_manager_->GetProfileByPath(profile_path_);
DCHECK(profile);
content::BrowsingDataRemover* remover =
content::BrowserContext::GetBrowsingDataRemover(profile);
remover->RemoveObserver(this);
auto payload = std::make_unique<ResultPayload>(failed_data_types);
if (failed_data_types != 0) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(failed_callback_), std::move(payload)));
} else {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(succeeded_callback_), std::move(payload)));
}
}
} // namespace enterprise_commands