| // Copyright 2022 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/updater/usage_stats_permissions.h" |
| |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <vector> |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/bind.h" |
| #include "build/branding_buildflags.h" |
| #include "build/build_config.h" |
| #include "build/buildflag.h" |
| #include "chrome/updater/branded_constants.h" |
| #include "chrome/updater/constants.h" |
| #include "chrome/updater/crash_client.h" |
| #include "chrome/updater/test/test_scope.h" |
| #include "chrome/updater/updater_branding.h" |
| #include "chrome/updater/util/util.h" |
| #include "components/update_client/update_client.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/crashpad/crashpad/client/crash_report_database.h" |
| #include "third_party/crashpad/crashpad/client/settings.h" |
| |
| #if BUILDFLAG(IS_MAC) |
| #include "base/files/scoped_temp_dir.h" |
| #include "chrome/enterprise_companion/installer_paths.h" |
| #include "chrome/updater/util/mac_util.h" |
| #elif BUILDFLAG(IS_WIN) |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/test/test_reg_util_win.h" |
| #include "base/win/registry.h" |
| #include "base/win/windows_types.h" |
| #include "chrome/enterprise_companion/global_constants.h" |
| #include "chrome/updater/util/win_util.h" |
| #include "chrome/updater/win/win_constants.h" |
| #endif |
| |
| namespace updater { |
| |
| class UsageStatsPermissionsTest : public testing::Test { |
| protected: |
| std::string fake_permission_provider_ = "UsageStatsTestPermissionProvider"; |
| #if BUILDFLAG(IS_MAC) |
| base::ScopedTempDir fake_user_directory_; |
| base::ScopedTempDir fake_system_directory_; |
| |
| void SetUpdaterUsageStats(bool enabled, UpdaterScope scope) { |
| SetAppUsageStats(PRODUCT_FULLNAME_STRING, enabled, scope); |
| } |
| |
| void SetCECAUsageStats(bool enabled, UpdaterScope scope) { |
| std::optional<base::FilePath> ceca_path = |
| enterprise_companion::GetInstallDirectory(); |
| ASSERT_TRUE(ceca_path); |
| SetAppUsageStats(ceca_path->BaseName().value(), enabled, scope); |
| } |
| |
| void SetAppUsageStats(const std::string& app_id, |
| bool enabled, |
| UpdaterScope scope) { |
| base::FilePath install_dir = IsSystemInstall(scope) |
| ? fake_system_directory_.GetPath() |
| : fake_user_directory_.GetPath(); |
| base::FilePath app_dir = install_dir.Append(app_id); |
| |
| ASSERT_TRUE(base::CreateDirectory(app_dir)); |
| std::unique_ptr<crashpad::CrashReportDatabase> database = |
| crashpad::CrashReportDatabase::Initialize(app_dir.Append("Crashpad")); |
| ASSERT_TRUE(database && |
| database->GetSettings()->SetUploadsEnabled(enabled)); |
| } |
| |
| void SetUp() override { |
| ASSERT_TRUE(fake_user_directory_.CreateUniqueTempDir()); |
| ASSERT_TRUE(fake_system_directory_.CreateUniqueTempDir()); |
| } |
| |
| bool AnyAppEnablesUsageStats() { |
| return ::updater::AnyAppEnablesUsageStats(InstallDirectories()); |
| } |
| |
| bool RemoteEventLoggingAllowed() { |
| return ::updater::RemoteEventLoggingAllowed(InstallDirectories(), |
| fake_permission_provider_); |
| } |
| |
| #elif BUILDFLAG(IS_WIN) |
| |
| void SetUpdaterUsageStats(bool enabled, UpdaterScope scope) { |
| SetAppUsageStats(kUpdaterAppId, enabled, scope); |
| } |
| |
| void SetCECAUsageStats(bool enabled, UpdaterScope scope) { |
| SetAppUsageStats(enterprise_companion::kCompanionAppId, enabled, scope); |
| } |
| void SetAppUsageStats(const std::string& app_id, |
| bool enabled, |
| UpdaterScope scope) { |
| std::wstring path = |
| IsSystemInstall(scope) ? system_key_path_ : user_key_path_; |
| base::win::RegKey key; |
| ASSERT_EQ(key.Open(hive_, path.c_str(), Wow6432(KEY_WRITE)), ERROR_SUCCESS); |
| ASSERT_EQ( |
| key.CreateKey(base::SysUTF8ToWide(app_id).c_str(), Wow6432(KEY_WRITE)), |
| ERROR_SUCCESS); |
| ASSERT_EQ(key.WriteValue(L"usagestats", enabled ? 1 : 0), ERROR_SUCCESS); |
| } |
| |
| void SetUp() override { |
| base::win::RegKey key; |
| ASSERT_EQ(key.Create(hive_, user_key_path_.c_str(), Wow6432(KEY_WRITE)), |
| ERROR_SUCCESS); |
| ASSERT_EQ(key.Create(hive_, system_key_path_.c_str(), Wow6432(KEY_WRITE)), |
| ERROR_SUCCESS); |
| } |
| |
| void TearDown() override { |
| for (const std::wstring& key_path : |
| std::vector<std::wstring>({user_key_path_, system_key_path_})) { |
| LONG result = base::win::RegKey(hive_, key_path.c_str(), Wow6432(DELETE)) |
| .DeleteKey(L""); |
| EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND || |
| result == ERROR_INVALID_HANDLE); |
| } |
| } |
| |
| bool AnyAppEnablesUsageStats() { |
| return ::updater::AnyAppEnablesUsageStats(hive_, InstallRegistryPaths()); |
| } |
| |
| bool RemoteEventLoggingAllowed() { |
| return ::updater::RemoteEventLoggingAllowed(hive_, InstallRegistryPaths(), |
| fake_permission_provider_); |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| UpdaterScope scope_ = GetUpdaterScopeForTesting(); |
| |
| private: |
| #if BUILDFLAG(IS_MAC) |
| std::vector<base::FilePath> InstallDirectories() { |
| std::vector<base::FilePath> install_directories( |
| {fake_user_directory_.GetPath()}); |
| if (IsSystemInstall(scope_)) { |
| install_directories.push_back(fake_system_directory_.GetPath()); |
| } |
| return install_directories; |
| } |
| #elif BUILDFLAG(IS_WIN) |
| |
| std::vector<std::wstring> InstallRegistryPaths() { |
| std::vector<std::wstring> key_paths({user_key_path_}); |
| if (IsSystemInstall(scope_)) { |
| key_paths.push_back(system_key_path_); |
| } |
| return key_paths; |
| } |
| HKEY hive_ = UpdaterScopeToHKeyRoot(GetUpdaterScopeForTesting()); |
| std::wstring user_key_path_ = |
| base::StrCat({UPDATER_KEY, L"UsageStatsProviderTestUserKey\\"}); |
| std::wstring system_key_path_ = |
| base::StrCat({UPDATER_KEY, L"UsageStatsProviderTestSystemkey\\"}); |
| #endif |
| }; |
| |
| #if BUILDFLAG(IS_LINUX) |
| TEST_F(UsageStatsPermissionsTest, LinuxAlwaysFalse) { |
| ASSERT_FALSE(AnyAppEnablesUsageStats(scope_)); |
| ASSERT_FALSE(RemoteEventLoggingAllowed(scope_, fake_permission_provider_)); |
| } |
| #else |
| |
| TEST_F(UsageStatsPermissionsTest, NoApps) { |
| ASSERT_FALSE(AnyAppEnablesUsageStats()); |
| } |
| |
| TEST_F(UsageStatsPermissionsTest, OneAppDisabled) { |
| SetAppUsageStats("app1", false, scope_); |
| SetAppUsageStats("app2", false, scope_); |
| ASSERT_FALSE(AnyAppEnablesUsageStats()); |
| } |
| |
| TEST_F(UsageStatsPermissionsTest, OneAppEnabled) { |
| SetAppUsageStats("app1", true, scope_); |
| SetAppUsageStats("app2", false, scope_); |
| ASSERT_TRUE(AnyAppEnablesUsageStats()); |
| } |
| |
| TEST_F(UsageStatsPermissionsTest, UserInstallIgnoresSystem) { |
| if (IsSystemInstall(scope_)) { |
| GTEST_SKIP() << "Not applicable to system-scoped installs"; |
| } |
| SetAppUsageStats("app1", false, UpdaterScope::kUser); |
| SetAppUsageStats("app1", true, UpdaterScope::kSystem); |
| ASSERT_FALSE(AnyAppEnablesUsageStats()); |
| } |
| |
| TEST_F(UsageStatsPermissionsTest, SystemInstallLooksAtUser) { |
| if (!IsSystemInstall(scope_)) { |
| GTEST_SKIP() << "Not applicable to user-scoped installs"; |
| } |
| SetAppUsageStats("app1", true, UpdaterScope::kUser); |
| SetAppUsageStats("app1", false, UpdaterScope::kSystem); |
| ASSERT_TRUE(AnyAppEnablesUsageStats()); |
| } |
| |
| TEST_F(UsageStatsPermissionsTest, PermissionProviderAllowsRemoteLogging) { |
| SetAppUsageStats(fake_permission_provider_, true, scope_); |
| ASSERT_TRUE(RemoteEventLoggingAllowed()); |
| } |
| |
| TEST_F(UsageStatsPermissionsTest, |
| PermissionProviderAllowsRemoteLoggingWithCECAAndUpdater) { |
| SetUpdaterUsageStats(true, scope_); |
| SetCECAUsageStats(true, scope_); |
| SetAppUsageStats(fake_permission_provider_, true, scope_); |
| ASSERT_TRUE(RemoteEventLoggingAllowed()); |
| } |
| |
| TEST_F(UsageStatsPermissionsTest, UsageStatsProviderChecksPermissionProvider) { |
| SetUpdaterUsageStats(true, scope_); |
| SetCECAUsageStats(true, scope_); |
| SetAppUsageStats(fake_permission_provider_, false, scope_); |
| ASSERT_FALSE(RemoteEventLoggingAllowed()); |
| } |
| |
| TEST_F(UsageStatsPermissionsTest, |
| PermissionProviderDisallowsRemoteLoggingWithOtherAppDisabled) { |
| SetUpdaterUsageStats(true, scope_); |
| SetCECAUsageStats(true, scope_); |
| SetAppUsageStats(fake_permission_provider_, true, scope_); |
| SetAppUsageStats("unsupported_app", false, scope_); |
| ASSERT_FALSE(RemoteEventLoggingAllowed()); |
| } |
| |
| TEST_F(UsageStatsPermissionsTest, |
| PermissionProviderDisallowsRemoteLoggingWithOtherAppEnabled) { |
| SetUpdaterUsageStats(true, scope_); |
| SetCECAUsageStats(true, scope_); |
| SetAppUsageStats(fake_permission_provider_, true, scope_); |
| SetAppUsageStats("unsupported_app", true, scope_); |
| ASSERT_FALSE(RemoteEventLoggingAllowed()); |
| } |
| |
| TEST_F(UsageStatsPermissionsTest, |
| SystemPermissionProviderAllowsRemoteLoggingWithUserAppEnabled) { |
| if (!IsSystemInstall(scope_)) { |
| GTEST_SKIP() << "Not applicable to user-scoped installs"; |
| } |
| SetUpdaterUsageStats(true, scope_); |
| SetCECAUsageStats(true, scope_); |
| SetAppUsageStats(fake_permission_provider_, true, UpdaterScope::kUser); |
| SetAppUsageStats(fake_permission_provider_, false, UpdaterScope::kSystem); |
| ASSERT_TRUE(RemoteEventLoggingAllowed()); |
| } |
| |
| #endif |
| |
| } // namespace updater |