#include <memory>
#include <string>
#include <utility>
#include "base/test/scoped_feature_list.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/enterprise/browser_management/management_service_factory.h"
#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/signin/chrome_signin_client_factory.h"
#include "chrome/browser/signin/chrome_signin_client_test_util.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/policy/core/common/management/management_service.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/version_info/version_info.h"
#include "content/public/test/browser_test.h"
#include "extensions/common/extension.h"
#include "extensions/test/result_catcher.h"
#include "extensions/test/test_extension_dir.h"
#include "services/network/test/test_url_loader_factory.h"
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
#include "base/files/file_path.h"
#include "base/process/process.h"
#include "base/strings/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "components/device_signals/core/common/signals_features.h"
#include "components/device_signals/core/system_signals/platform_utils.h"
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#include "components/device_signals/test/test_constants.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "base/strings/sys_string_conversions.h"
#include "base/test/test_reg_util_win.h"
#include "base/win/registry.h"
#include "components/device_signals/test/win/scoped_executable_files.h"
#endif
#if !BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.h"
#include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h"
#include "components/policy/core/common/cloud/cloud_policy_core.h"
#include "components/policy/core/common/cloud/cloud_policy_store.h"
#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h"
#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
#include "components/policy/proto/device_management_backend.pb.h"
#endif
#if BUILDFLAG(IS_CHROMEOS)
#include "base/strings/strcat.h"
#include "chrome/browser/enterprise/util/affiliation.h"
#include "chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/login/test/cryptohome_mixin.h"
#include "chrome/browser/ash/policy/affiliation/affiliation_mixin.h"
#include "chrome/browser/ash/policy/affiliation/affiliation_test_helper.h"
#include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/browser_process.h"
#include "chromeos/startup/browser_init_params.h"
#include "components/policy/core/common/policy_loader_lacros.h"
#endif
namespace extensions {
namespace {
#if !BUILDFLAG(IS_CHROMEOS_ASH)
constexpr char kAffiliationId[] = …;
#endif
constexpr char kAuthorizedManifestKey[] = …;
constexpr char kUnauthorizedManifestKey[] = …;
constexpr char kManifestTemplate[] = …;
}
class EnterpriseReportingPrivateApiTest : public extensions::ExtensionApiTest { … };
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest,
ExtensionAvailability) { … }
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetDeviceId) { … }
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetPersistentSecret) { … }
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetDeviceData) { … }
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, SetDeviceData) { … }
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetDeviceInfo) { … }
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetContextInfo) { … }
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetCertificate) { … }
#if BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetAvInfo_Success) {
constexpr char kTest[] = R"(
chrome.test.assertEq(
'function',
typeof chrome.enterprise.reportingPrivate.getAvInfo);
const userContext = {userId: '%s'};
chrome.enterprise.reportingPrivate.getAvInfo(userContext, (avProducts) => {
chrome.test.assertNoLastError();
chrome.test.assertTrue(avProducts instanceof Array);
chrome.test.notifyPass();
});
)";
AccountInfo account_info = SignIn("[email protected]");
RunTest(base::StringPrintf(kTest, account_info.gaia.c_str()));
}
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetHotfixes_Success) {
constexpr char kTest[] = R"(
chrome.test.assertEq(
'function',
typeof chrome.enterprise.reportingPrivate.getHotfixes);
const userContext = {userId: '%s'};
chrome.enterprise.reportingPrivate.getHotfixes(userContext, (hotfixes) => {
chrome.test.assertNoLastError();
chrome.test.assertTrue(hotfixes instanceof Array);
chrome.test.notifyPass();
});
)";
AccountInfo account_info = SignIn("[email protected]");
RunTest(base::StringPrintf(kTest, account_info.gaia.c_str()));
}
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest,
GetRegistrySettings_Success) {
constexpr char kTest[] = R"(
chrome.test.assertEq(
'function',
typeof chrome.enterprise.reportingPrivate.getSettings);
const userContext = {userId: '%s'};
const options = [];
%s
const request = {userContext, options};
chrome.enterprise.reportingPrivate.getSettings(
request,
(settingsItems) => {
%s
});
)";
std::string kOptions = "";
std::string registry_path = "SOFTWARE\\\\Chromium\\\\DeviceTrust\\\\Test";
std::string valid_key = "test_key";
kOptions = base::StringPrintf(
R"(
const test_hive = 'HKEY_CURRENT_USER';
const registry_path = '%s';
const invalid_path = 'SOFTWARE\\Chromium\\DeviceTrust\\Invalid';
const valid_key = '%s';
const invalid_key = 'invalid_key';
options.push({
hive: test_hive,
path: registry_path,
key: valid_key,
getValue: false
});
options.push({
hive: test_hive,
path: registry_path,
key: valid_key,
getValue: true
});
options.push({
hive: test_hive,
path: registry_path,
key: invalid_key,
getValue: true
});
options.push({
hive: test_hive,
path: invalid_path,
key: valid_key,
getValue: true
});
)",
registry_path.c_str(), valid_key.c_str());
registry_util::RegistryOverrideManager registry_override_manager_;
registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
base::win::RegKey key(HKEY_CURRENT_USER,
base::SysUTF8ToWide(registry_path).c_str(),
KEY_ALL_ACCESS);
ASSERT_TRUE(key.WriteValue(base::SysUTF8ToWide(valid_key).c_str(), 37) ==
ERROR_SUCCESS);
constexpr char kAssertions[] = R"(
chrome.test.assertNoLastError();
chrome.test.assertTrue(settingsItems instanceof Array);
chrome.test.assertEq(4, settingsItems.length);
const expectedItems = [];
expectedItems.push({
hive: test_hive,
path: registry_path,
key: valid_key,
presence: 'FOUND',
});
expectedItems.push({
hive: test_hive,
path: registry_path,
key: valid_key,
presence: 'FOUND',
value: '37',
});
expectedItems.push({
hive: test_hive,
path: registry_path,
key: invalid_key,
presence: 'NOT_FOUND',
});
expectedItems.push({
hive: test_hive,
path: invalid_path,
key: valid_key,
presence: 'NOT_FOUND',
});
for (let i = 0; i < settingsItems.length; ++i) {
chrome.test.assertEq(settingsItems[i], expectedItems[i]);
}
chrome.test.notifyPass();
)";
AccountInfo account_info = SignIn("[email protected]");
RunTest(base::StringPrintf(kTest, account_info.gaia.c_str(), kOptions.c_str(),
kAssertions));
}
#endif
#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_MAC)
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest,
GetRegistrySettings_UnsupportedPlatform) { … }
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
#define MAYBE_GetFileSystemInfo_Success …
#else
#define MAYBE_GetFileSystemInfo_Success …
#endif
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest,
MAYBE_GetFileSystemInfo_Success) { … }
#endif
#if BUILDFLAG(IS_MAC)
#if BUILDFLAG(IS_MAC)
#define MAYBE_GetPlistSettings_Success …
#else
#define MAYBE_GetPlistSettings_Success …
#endif
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest,
MAYBE_GetPlistSettings_Success) {
constexpr char kTest[] = R"(
chrome.test.assertEq(
'function',
typeof chrome.enterprise.reportingPrivate.getSettings);
const userContext = {userId: '%s'};
const options = [];
%s
const request = {userContext, options};
chrome.enterprise.reportingPrivate.getSettings(
request,
(settingItems) => {
chrome.test.assertNoLastError();
%s
chrome.test.notifyPass();
});
)";
std::string extra_items = base::StringPrintf(
R"(
const filePath = '%s';
const validKeyPath = "Key1.SubKey1.SubSubKey1[0][10]";
const invalidKeyPath = "Key1.SubKey1.SubSubKey1[0][0][3]";
options.push({
path: filePath,
key: validKeyPath,
getValue: true
});
options.push({
path: filePath,
key: invalidKeyPath,
getValue: true
});
)",
device_signals::test::GetMixArrayDictionaryPlistPath().value().c_str());
constexpr char kAssertions[] = R"(
chrome.test.assertTrue(settingItems instanceof Array);
chrome.test.assertEq(2, settingItems.length);
for (const response of settingItems) {
chrome.test.assertEq(filePath, response.path);
if (response.key == validKeyPath) {
chrome.test.assertEq("FOUND", response.presence);
chrome.test.assertEq(
'\"string10\"', response.value);
} else if (response.key == invalidKeyPath) {
chrome.test.assertEq("NOT_FOUND", response.presence);
chrome.test.assertEq(null, response.value);
} else {
chrome.test.fail();
}
}
)";
AccountInfo account_info = SignIn("[email protected]");
RunTest(base::StringPrintf(kTest, account_info.gaia.c_str(),
extra_items.c_str(), kAssertions));
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
static void RunTestUsingProfile(const std::string& background_js,
Profile* profile) {
ResultCatcher result_catcher;
TestExtensionDir test_dir;
test_dir.WriteManifest(
base::StringPrintf(kManifestTemplate, kAuthorizedManifestKey));
constexpr char kTestWrapper[] = R"(
chrome.test.runTests([
async function asyncAssertions() {
%s
}
]);)";
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
base::StringPrintf(kTestWrapper, background_js.c_str()));
ChromeTestExtensionLoader loader(profile);
loader.set_ignore_manifest_warnings(true);
const Extension* extension =
loader.LoadExtension(test_dir.UnpackedPath()).get();
ASSERT_TRUE(extension);
ASSERT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
static std::string CreateValidRecord() {
std::vector<uint8_t> serialized_record_data;
std::string serialized_data = R"({"TEST_KEY":"TEST_VALUE"})";
reporting::Record record;
record.set_data(serialized_data);
record.set_destination(reporting::Destination::TELEMETRY_METRIC);
record.set_timestamp_us(base::Time::Now().InMillisecondsSinceUnixEpoch() *
base::Time::kMicrosecondsPerMillisecond);
serialized_record_data.resize(record.SerializeAsString().size());
record.SerializeToArray(serialized_record_data.data(),
serialized_record_data.size());
std::string serialized_record_data_str = "[";
for (size_t i = 0; i < serialized_record_data.size(); i++) {
if (i == serialized_record_data.size() - 1) {
base::StrAppend(&serialized_record_data_str,
{base::NumberToString(serialized_record_data[i]), "]"});
} else {
base::StrAppend(&serialized_record_data_str,
{base::NumberToString(serialized_record_data[i]), ","});
}
}
return serialized_record_data_str;
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
struct Params {
explicit Params(bool affiliated) : affiliated(affiliated) {}
bool affiliated;
};
class EnterpriseReportingPrivateEnqueueRecordApiTest
: public ::policy::DevicePolicyCrosBrowserTest,
public ::testing::WithParamInterface<Params> {
protected:
EnterpriseReportingPrivateEnqueueRecordApiTest() {
affiliation_mixin_.set_affiliated(GetParam().affiliated);
crypto_home_mixin_.MarkUserAsExisting(affiliation_mixin_.account_id());
}
~EnterpriseReportingPrivateEnqueueRecordApiTest() override = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
::policy::AffiliationTestHelper::AppendCommandLineSwitchesForLoginManager(
command_line);
::policy::DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line);
}
::policy::DevicePolicyCrosTestHelper test_helper_;
::policy::AffiliationMixin affiliation_mixin_{&mixin_host_, &test_helper_};
ash::CryptohomeMixin crypto_home_mixin_{&mixin_host_};
};
IN_PROC_BROWSER_TEST_P(EnterpriseReportingPrivateEnqueueRecordApiTest,
PRE_EnqueueRecord) {
policy::AffiliationTestHelper::PreLoginUser(affiliation_mixin_.account_id());
}
IN_PROC_BROWSER_TEST_P(EnterpriseReportingPrivateEnqueueRecordApiTest,
EnqueueRecord) {
policy::AffiliationTestHelper::LoginUser(affiliation_mixin_.account_id());
constexpr char kTest[] = R"(
const request = {
eventType: "USER",
priority: 4,
recordData: Uint8Array.from(%s),
};
chrome.enterprise.reportingPrivate.enqueueRecord(request, () =>{
%s
chrome.test.succeed();
});
)";
std::string javascript_assertion =
GetParam().affiliated
? "chrome.test.assertNoLastError();"
: base::StrCat({"chrome.test.assertLastError(\'",
EnterpriseReportingPrivateEnqueueRecordFunction::
kErrorProfileNotAffiliated,
"\');"});
ASSERT_EQ(GetParam().affiliated,
enterprise_util::IsProfileAffiliated(
ash::ProfileHelper::Get()->GetProfileByAccountId(
affiliation_mixin_.account_id())));
RunTestUsingProfile(base::StringPrintf(kTest, CreateValidRecord().c_str(),
javascript_assertion.c_str()),
ash::ProfileHelper::Get()->GetProfileByAccountId(
affiliation_mixin_.account_id()));
}
INSTANTIATE_TEST_SUITE_P(TestAffiliation,
EnterpriseReportingPrivateEnqueueRecordApiTest,
::testing::Values(Params(true),
Params(false)));
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
using EnterpriseReportingPrivateEnqueueRecordApiTest = ExtensionApiTest;
static void SetupAffiliationLacros() {
constexpr char kDomain[] = "fake-domain";
constexpr char kFakeProfileClientId[] = "fake-profile-client-id";
constexpr char kFakeDMToken[] = "fake-dm-token";
enterprise_management::PolicyData profile_policy_data;
profile_policy_data.add_user_affiliation_ids(kAffiliationId);
profile_policy_data.set_managed_by(kDomain);
profile_policy_data.set_device_id(kFakeProfileClientId);
profile_policy_data.set_request_token(kFakeDMToken);
policy::PolicyLoaderLacros::set_main_user_policy_data_for_testing(
std::move(profile_policy_data));
crosapi::mojom::BrowserInitParamsPtr init_params =
crosapi::mojom::BrowserInitParams::New();
init_params->device_properties = crosapi::mojom::DeviceProperties::New();
init_params->device_properties->device_dm_token = kFakeDMToken;
init_params->device_properties->device_affiliation_ids = {kAffiliationId};
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params));
}
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateEnqueueRecordApiTest,
EnqueueRecordFailsWithUnaffiliatedProfile) {
constexpr char kTest[] = R"(
const request = {
eventType: "USER",
priority: 4,
recordData: Uint8Array.from(%s),
};
chrome.enterprise.reportingPrivate.enqueueRecord(request, () =>{
chrome.test.assertLastError('%s');
chrome.test.succeed();
});
)";
const std::string kErrorMsg =
EnterpriseReportingPrivateEnqueueRecordFunction::
kErrorProfileNotAffiliated;
RunTestUsingProfile(
base::StringPrintf(kTest, CreateValidRecord().c_str(), kErrorMsg.c_str()),
profile());
}
IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateEnqueueRecordApiTest,
EnqueueRecordSucceedsWithAffiliatedProfile) {
SetupAffiliationLacros();
constexpr char kTest[] = R"(
const request = {
eventType: "USER",
priority: 4,
recordData: Uint8Array.from(%s),
};
chrome.enterprise.reportingPrivate.enqueueRecord(request, () =>{
chrome.test.assertNoLastError();
chrome.test.succeed();
});
)";
RunTestUsingProfile(base::StringPrintf(kTest, CreateValidRecord().c_str()),
profile());
}
#endif
}