#include "chrome/browser/policy/extension_force_install_mixin.h"
#include <stdint.h>
#include <atomic>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/check.h"
#include "base/check_op.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/important_file_writer.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "base/version.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "components/crx_file/crx_verifier.h"
#include "components/crx_file/id_util.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_namespace.h"
#include "components/policy/core/common/policy_service.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "extensions/browser/extension_creator.h"
#include "extensions/browser/extension_host_test_helper.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/pref_names.h"
#include "extensions/browser/test_extension_registry_observer.h"
#include "extensions/browser/updater/extension_downloader_test_helper.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/file_util.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/mojom/view_type.mojom.h"
#include "extensions/test/extension_test_message_listener.h"
#include "net/http/http_status_code.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/zlib/google/zip.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/login/test/device_state_mixin.h"
#include "chrome/browser/ash/login/test/scoped_policy_update.h"
#include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h"
#include "chrome/browser/ash/policy/test_support/embedded_policy_test_server_mixin.h"
#include "components/policy/proto/chrome_device_policy.pb.h"
#endif
namespace {
constexpr char kServedDirName[] = …;
constexpr char kReadyMessage[] = …;
constexpr char kCrxFileNameTemplate[] = …;
constexpr char kUpdateManifestFileNameTemplate[] = …;
class ForceInstallPrefObserver final { … };
ForceInstallPrefObserver::ForceInstallPrefObserver(
Profile* profile,
const extensions::ExtensionId& extension_id)
: … { … }
ForceInstallPrefObserver::~ForceInstallPrefObserver() = default;
void ForceInstallPrefObserver::Wait() { … }
void ForceInstallPrefObserver::OnPrefChanged() { … }
bool ForceInstallPrefObserver::IsForceInstallPrefSet() const { … }
class ForceInstallWaiter final { … };
ForceInstallWaiter::ForceInstallWaiter(
ExtensionForceInstallMixin::WaitMode wait_mode,
const extensions::ExtensionId& extension_id,
Profile* profile)
: … { … }
ForceInstallWaiter::~ForceInstallWaiter() = default;
bool ForceInstallWaiter::Wait() { … }
void ForceInstallWaiter::WaitImpl(bool* success) { … }
std::string GetServedUpdateManifestFileName(
const extensions::ExtensionId& extension_id) { … }
std::string GetServedCrxFileName(const extensions::ExtensionId& extension_id,
const base::Version& extension_version) { … }
std::string GenerateUpdateManifest(const extensions::ExtensionId& extension_id,
const base::Version& extension_version,
const GURL& crx_url) { … }
bool ParseExtensionManifestData(const base::FilePath& extension_dir_path,
base::Version* extension_version) { … }
bool ParseCrxOuterData(const base::FilePath& crx_path,
extensions::ExtensionId* extension_id) { … }
bool ParseCrxInnerData(const base::FilePath& crx_path,
base::Version* extension_version) { … }
std::string MakeForceInstallPolicyItemValue(
const extensions::ExtensionId& extension_id,
const GURL& update_manifest_url) { … }
void UpdatePolicyViaMockPolicyProvider(
const extensions::ExtensionId& extension_id,
const GURL& update_manifest_url,
policy::MockConfigurationPolicyProvider* mock_policy_provider) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
void UpdatePolicyViaDeviceStateMixin(
const extensions::ExtensionId& extension_id,
const GURL& update_manifest_url,
ash::DeviceStateMixin* device_state_mixin) {
device_state_mixin->RequestDevicePolicyUpdate()
->policy_payload()
->mutable_device_login_screen_extensions()
->add_device_login_screen_extensions(
MakeForceInstallPolicyItemValue(extension_id, update_manifest_url));
}
void UpdatePolicyViaDevicePolicyCrosTestHelper(
const extensions::ExtensionId& extension_id,
const GURL& update_manifest_url,
policy::DevicePolicyCrosTestHelper* device_policy_cros_test_helper) {
device_policy_cros_test_helper->device_policy()
->payload()
.mutable_device_login_screen_extensions()
->add_device_login_screen_extensions(
MakeForceInstallPolicyItemValue(extension_id, update_manifest_url));
device_policy_cros_test_helper->RefreshDevicePolicy();
}
void UpdatePolicyViaEmbeddedPolicyMixin(
const extensions::ExtensionId& extension_id,
const GURL& update_manifest_url,
ash::EmbeddedPolicyTestServerMixin* policy_test_server_mixin,
policy::UserPolicyBuilder* user_policy_builder,
const std::string& account_id,
const std::string& policy_type,
bool* success) {
user_policy_builder->payload()
.mutable_extensioninstallforcelist()
->mutable_value()
->add_entries(
MakeForceInstallPolicyItemValue(extension_id, update_manifest_url));
user_policy_builder->Build();
policy_test_server_mixin->UpdatePolicy(
policy_type, account_id,
user_policy_builder->payload().SerializeAsString());
base::RunLoop run_loop;
g_browser_process->policy_service()->RefreshPolicies(
run_loop.QuitClosure(), policy::PolicyFetchReason::kTest);
ASSERT_NO_FATAL_FAILURE(run_loop.Run());
*success = true;
}
#endif
std::unique_ptr<net::test_server::HttpResponse> ErrorSimulatingRequestHandler(
std::atomic<ExtensionForceInstallMixin::ServerErrorMode>* server_error_mode,
const net::test_server::HttpRequest& ) { … }
}
ExtensionForceInstallMixin::ExtensionForceInstallMixin(
InProcessBrowserTestMixinHost* host)
: … { … }
ExtensionForceInstallMixin::~ExtensionForceInstallMixin() = default;
void ExtensionForceInstallMixin::InitWithMockPolicyProvider(
Profile* profile,
policy::MockConfigurationPolicyProvider* mock_policy_provider) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
void ExtensionForceInstallMixin::InitWithDeviceStateMixin(
Profile* profile,
ash::DeviceStateMixin* device_state_mixin) {
DCHECK(device_state_mixin);
DCHECK(!initialized_) << "Init already called";
DCHECK(!profile_);
DCHECK(!device_state_mixin_);
initialized_ = true;
profile_ = profile;
device_state_mixin_ = device_state_mixin;
}
void ExtensionForceInstallMixin::InitWithDevicePolicyCrosTestHelper(
Profile* profile,
policy::DevicePolicyCrosTestHelper* device_policy_cros_test_helper) {
DCHECK(device_policy_cros_test_helper);
DCHECK(!initialized_) << "Init already called";
DCHECK(!profile_);
DCHECK(!device_policy_cros_test_helper_);
initialized_ = true;
profile_ = profile;
device_policy_cros_test_helper_ = device_policy_cros_test_helper;
}
void ExtensionForceInstallMixin::InitWithEmbeddedPolicyMixin(
Profile* profile,
ash::EmbeddedPolicyTestServerMixin* policy_test_server_mixin,
policy::UserPolicyBuilder* user_policy_builder,
const std::string& account_id,
const std::string& policy_type) {
DCHECK(policy_test_server_mixin);
DCHECK(user_policy_builder);
DCHECK(!account_id.empty());
DCHECK(!policy_type.empty());
DCHECK(!initialized_) << "Init already called";
DCHECK(!profile_);
DCHECK(!policy_test_server_mixin_);
DCHECK(!user_policy_builder_);
DCHECK(account_id_.empty());
DCHECK(policy_type_.empty());
initialized_ = true;
profile_ = profile;
policy_test_server_mixin_ = policy_test_server_mixin;
user_policy_builder_ = user_policy_builder;
account_id_ = account_id;
policy_type_ = policy_type;
}
#endif
bool ExtensionForceInstallMixin::ForceInstallFromCrx(
const base::FilePath& crx_path,
WaitMode wait_mode,
extensions::ExtensionId* extension_id,
base::Version* extension_version) { … }
bool ExtensionForceInstallMixin::ForceInstallFromSourceDir(
const base::FilePath& extension_dir_path,
const std::optional<base::FilePath>& pem_path,
WaitMode wait_mode,
extensions::ExtensionId* extension_id,
base::Version* extension_version) { … }
bool ExtensionForceInstallMixin::UpdateFromCrx(
const base::FilePath& crx_path,
UpdateWaitMode wait_mode,
base::Version* extension_version) { … }
bool ExtensionForceInstallMixin::UpdateFromSourceDir(
const base::FilePath& extension_dir_path,
const extensions::ExtensionId& extension_id,
UpdateWaitMode wait_mode,
base::Version* extension_version) { … }
const extensions::Extension* ExtensionForceInstallMixin::GetInstalledExtension(
const extensions::ExtensionId& extension_id) const { … }
const extensions::Extension* ExtensionForceInstallMixin::GetEnabledExtension(
const extensions::ExtensionId& extension_id) const { … }
void ExtensionForceInstallMixin::SetServerErrorMode(
ServerErrorMode server_error_mode) { … }
void ExtensionForceInstallMixin::SetUpOnMainThread() { … }
base::FilePath ExtensionForceInstallMixin::GetPathInServedDir(
const std::string& file_name) const { … }
GURL ExtensionForceInstallMixin::GetServedUpdateManifestUrl(
const extensions::ExtensionId& extension_id) const { … }
GURL ExtensionForceInstallMixin::GetServedCrxUrl(
const extensions::ExtensionId& extension_id,
const base::Version& extension_version) const { … }
bool ExtensionForceInstallMixin::ServeExistingCrx(
const base::FilePath& source_crx_path,
const extensions::ExtensionId& extension_id,
const base::Version& extension_version) { … }
bool ExtensionForceInstallMixin::CreateAndServeCrx(
const base::FilePath& extension_dir_path,
const std::optional<base::FilePath>& pem_path,
const base::Version& extension_version,
extensions::ExtensionId* extension_id) { … }
bool ExtensionForceInstallMixin::ForceInstallFromServedCrx(
const extensions::ExtensionId& extension_id,
const base::Version& extension_version,
WaitMode wait_mode) { … }
bool ExtensionForceInstallMixin::CreateAndServeUpdateManifestFile(
const extensions::ExtensionId& extension_id,
const base::Version& extension_version) { … }
bool ExtensionForceInstallMixin::UpdatePolicy(
const extensions::ExtensionId& extension_id,
const GURL& update_manifest_url) { … }
bool ExtensionForceInstallMixin::WaitForExtensionUpdate(
const extensions::ExtensionId& extension_id,
const base::Version& extension_version,
UpdateWaitMode wait_mode) { … }