// Copyright 2021 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/chromeos/extensions/telemetry/api/common/api_guard_delegate.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "ash/session/session_controller_impl.h"
#include "base/check_deref.h"
#include "base/command_line.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/test/test_future.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/chromeos/extensions/telemetry/api/common/hardware_info_delegate.h"
#include "chrome/browser/chromeos/extensions/telemetry/api/common/remote_probe_service_strategy.h"
#include "chrome/browser/extensions/extension_management_test_util.h"
#include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chromeos/crosapi/cpp/telemetry/fake_probe_service.h"
#include "chromeos/crosapi/mojom/probe_service.mojom.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/ssl_status.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/extension_urls.h"
#include "net/base/net_errors.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/x509_certificate.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/session/session_controller.h"
#include "ash/public/cpp/session/session_types.h"
#include "ash/shell.h"
#include "ash/webui/shimless_rma/backend/external_app_dialog.h"
#include "base/command_line.h"
#include "base/strings/string_util.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/common/chromeos/extensions/chromeos_system_extension_info.h" // nogncheck
#include "chrome/common/url_constants.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_types.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user.h"
#include "content/public/browser/web_contents_observer.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/startup/browser_init_params.h"
#include "components/policy/core/common/policy_loader_lacros.h"
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
namespace chromeos {
namespace {
namespace crosapi = crosapi::mojom;
}
struct ExtensionInfoTestParams {
ExtensionInfoTestParams(const std::string& extension_id,
const std::string& app_ui_url,
const std::string& matches_origin,
const std::string& manufacturer)
: extension_id(extension_id),
app_ui_url(app_ui_url),
matches_origin(matches_origin),
manufacturer(manufacturer) {}
ExtensionInfoTestParams(const ExtensionInfoTestParams& other) = default;
~ExtensionInfoTestParams() = default;
const std::string extension_id;
const std::string app_ui_url;
const std::string matches_origin;
const std::string manufacturer;
};
const std::vector<ExtensionInfoTestParams> kAllExtensionInfoTestParams{
// Make sure the Google extension is allowed for every OEM.
ExtensionInfoTestParams(
/*extension_id=*/"gogonhoemckpdpadfnjnpgbjpbjnodgc",
/*app_ui_url=*/"https://googlechromelabs.github.io/",
/*matches_origin=*/"*://googlechromelabs.github.io/*",
/*manufacturer=*/"HP"),
ExtensionInfoTestParams(
/*extension_id=*/"gogonhoemckpdpadfnjnpgbjpbjnodgc",
/*app_ui_url=*/"https://googlechromelabs.github.io/",
/*matches_origin=*/"*://googlechromelabs.github.io/*",
/*manufacturer=*/"ASUS"),
// Make sure the extensions of each OEM are allowed on their device.
ExtensionInfoTestParams(
/*extension_id=*/"alnedpmllcfpgldkagbfbjkloonjlfjb",
/*app_ui_url=*/"https://hpcs-appschr.hpcloud.hp.com",
/*matches_origin=*/"https://hpcs-appschr.hpcloud.hp.com/*",
/*manufacturer=*/"HP"),
ExtensionInfoTestParams(
/*extension_id=*/"hdnhcpcfohaeangjpkcjkgmgmjanbmeo",
/*app_ui_url=*/
"https://dlcdnccls.asus.com/app/myasus_for_chromebook/ ",
/*matches_origin=*/"https://dlcdnccls.asus.com/*",
/*manufacturer=*/"ASUS"),
};
#if BUILDFLAG(IS_CHROMEOS_ASH)
constexpr char kUserEmail[] = "[email protected]";
#endif // IS_CHROMEOS_ASH
// Tests that Chrome OS System Extensions must fulfill the requirements to
// access Telemetry Extension APIs. All tests are parameterized with the
// following parameters:
// * |extension_id| - id of the extension under test.
// * |app_ui_url| - page URL of the app associated with the extension's id.
// * |matches_origin| - externally_connectable's matches entry of the
// extension's manifest.json.
// Note: All tests must be defined using the TEST_P macro and must use the
// INSTANTIATE_TEST_SUITE_P macro to instantiate the test suite.
class ApiGuardDelegateTest
: public BrowserWithTestWindowTest,
public testing::WithParamInterface<ExtensionInfoTestParams> {
public:
ApiGuardDelegateTest() = default;
~ApiGuardDelegateTest() override = default;
// BrowserWithTestWindowTest:
void SetUp() override {
BrowserWithTestWindowTest::SetUp();
CreateExtension();
fake_probe_service_ = std::make_unique<FakeProbeService>();
RemoteProbeServiceStrategy::Get()->SetServiceForTesting(
fake_probe_service_->BindNewPipeAndPassRemote());
// Make sure device manufacturer is allowlisted.
SetDeviceManufacturer(manufacturer());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto params = crosapi::BrowserInitParams::New();
params->is_current_user_device_owner = true;
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(params));
profile()->SetIsMainProfile(true);
ASSERT_TRUE(profile()->IsMainProfile());
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
std::string GetDefaultProfileName() override { return kUserEmail; }
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
protected:
extensions::ExtensionId extension_id() const {
return GetParam().extension_id;
}
std::string app_ui_url() const { return GetParam().app_ui_url; }
std::string matches_origin() const { return GetParam().matches_origin; }
std::string manufacturer() const { return GetParam().manufacturer; }
const extensions::Extension* extension() { return extension_.get(); }
#if BUILDFLAG(IS_CHROMEOS_ASH)
void SetUserAsOwner() {
// Make sure the current user is affiliated.
const AccountId account_id = AccountId::FromUserEmail(kUserEmail);
user_manager()->SetOwnerId(account_id);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void SetDeviceManufacturer(const std::string& manufacturer) {
HardwareInfoDelegate::Get().ClearCacheForTesting();
auto telemetry_info = crosapi::ProbeTelemetryInfo::New();
telemetry_info->system_result = crosapi::ProbeSystemResult::NewSystemInfo(
crosapi::ProbeSystemInfo::New(crosapi::ProbeOsInfo::New(manufacturer)));
fake_probe_service_->SetProbeTelemetryInfoResponse(
std::move(telemetry_info));
}
void OpenAppUIUrlAndSetCertificateWithStatus(net::CertStatus cert_status) {
const base::FilePath certs_dir = net::GetTestCertsDirectory();
scoped_refptr<net::X509Certificate> test_cert(
net::ImportCertFromFile(certs_dir, "ok_cert.pem"));
ASSERT_TRUE(test_cert);
// Open the app page url and set valid certificate to bypass the
// IsAppUiOpenAndSecure() check.
AddTab(browser(), GURL(app_ui_url()));
// AddTab() adds a new tab at index 0.
auto* web_contents = browser()->tab_strip_model()->GetWebContentsAt(0);
auto* entry = web_contents->GetController().GetVisibleEntry();
content::SSLStatus& ssl = entry->GetSSL();
ssl.certificate = test_cert;
ssl.cert_status = cert_status;
}
private:
void CreateExtension() {
extension_ =
extensions::ExtensionBuilder("Test ChromeOS System Extension")
.SetManifestVersion(3)
.SetManifestKey("chromeos_system_extension", base::Value::Dict())
.SetManifestKey(
"externally_connectable",
base::Value::Dict().Set(
"matches", base::Value::List().Append(matches_origin())))
.SetID(extension_id())
.SetLocation(extensions::mojom::ManifestLocation::kInternal)
.Build();
}
scoped_refptr<const extensions::Extension> extension_;
std::unique_ptr<FakeProbeService> fake_probe_service_;
};
TEST_P(ApiGuardDelegateTest, CurrentUserNotOwner) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
// Make sure the current user is not the device owner.
const AccountId regular_user = AccountId::FromUserEmail("[email protected]");
user_manager()->SetOwnerId(regular_user);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto params = crosapi::BrowserInitParams::New();
params->is_current_user_device_owner = false;
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(params));
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("This extension is not run by the device owner", error.value());
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_P(ApiGuardDelegateTest, OwnershipDelayed) {
OpenAppUIUrlAndSetCertificateWithStatus(/*cert_status=*/net::OK);
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
// Trigger async ownership retrieval.
SetUserAsOwner();
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
EXPECT_FALSE(error.has_value()) << error.value();
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
TEST_P(ApiGuardDelegateTest, CurrentUserOwnerButNotMainLacrosProfile) {
// Don't set the current profile as the main profile.
profile()->SetIsMainProfile(false);
ASSERT_FALSE(profile()->IsMainProfile());
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("This extension is not run by the device owner", error.value());
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
TEST_P(ApiGuardDelegateTest, AppNotOpen) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
SetUserAsOwner();
#endif // IS_CHROMEOS_ASH
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("Companion app UI is not open or not secure", error.value());
}
TEST_P(ApiGuardDelegateTest, AppIsOpenButNotSecure) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
SetUserAsOwner();
#endif // IS_CHROMEOS_ASH
OpenAppUIUrlAndSetCertificateWithStatus(
/*cert_status=*/net::CERT_STATUS_INVALID);
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("Companion app UI is not open or not secure", error.value());
}
TEST_P(ApiGuardDelegateTest, ManufacturerNotAllowed) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
SetUserAsOwner();
#endif // IS_CHROMEOS_ASH
OpenAppUIUrlAndSetCertificateWithStatus(/*cert_status=*/net::OK);
// Make sure device manufacturer is not allowed.
SetDeviceManufacturer("NOT_ALLOWED");
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("This extension is not allowed to access the API on this device",
error.value());
}
TEST_P(ApiGuardDelegateTest, SkipManufacturerCheck) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
SetUserAsOwner();
#endif // IS_CHROMEOS_ASH
OpenAppUIUrlAndSetCertificateWithStatus(/*cert_status=*/net::OK);
// Append the switch to skip the manufacturer check.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kTelemetryExtensionSkipManufacturerCheckForTesting);
// Make sure device manufacturer is not allowed.
SetDeviceManufacturer("NOT_ALLOWED");
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
EXPECT_FALSE(error.has_value()) << error.value();
}
TEST_P(ApiGuardDelegateTest, NoError) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
SetUserAsOwner();
#endif // IS_CHROMEOS_ASH
OpenAppUIUrlAndSetCertificateWithStatus(/*cert_status=*/net::OK);
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
EXPECT_FALSE(error.has_value()) << error.value();
}
INSTANTIATE_TEST_SUITE_P(All,
ApiGuardDelegateTest,
testing::ValuesIn(kAllExtensionInfoTestParams));
class ApiGuardDelegateAffiliatedUserTest : public ApiGuardDelegateTest {
public:
ApiGuardDelegateAffiliatedUserTest() = default;
~ApiGuardDelegateAffiliatedUserTest() override = default;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
void SetUp() override {
ApiGuardDelegateTest::SetUp();
// Make sure the main user is affiliated.
auto init_params = crosapi::BrowserInitParams::New();
init_params->session_type = crosapi::SessionType::kPublicSession;
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params));
ASSERT_TRUE(policy::PolicyLoaderLacros::IsMainUserAffiliated());
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
protected:
#if BUILDFLAG(IS_CHROMEOS_ASH)
void LogIn(const std::string& email) override {
// Make sure the current user is affiliated.
const AccountId account_id = AccountId::FromUserEmail(email);
user_manager()->AddUserWithAffiliation(account_id, /*is_affiliated=*/true);
user_manager()->UserLoggedIn(
account_id,
user_manager::FakeUserManager::GetFakeUsernameHash(account_id),
/*browser_restart=*/false,
/*is_child=*/false);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
};
TEST_P(ApiGuardDelegateAffiliatedUserTest, ExtensionNotForceInstalled) {
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("This extension is not installed by the admin", error.value());
}
TEST_P(ApiGuardDelegateAffiliatedUserTest, AppNotOpen) {
{
extensions::ExtensionManagementPrefUpdater<
sync_preferences::TestingPrefServiceSyncable>
updater(profile()->GetTestingPrefService());
// Make sure the extension is marked as force-installed.
updater.SetIndividualExtensionAutoInstalled(
extension_id(), extension_urls::kChromeWebstoreUpdateURL,
/*forced=*/true);
}
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("Companion app UI is not open or not secure", error.value());
}
TEST_P(ApiGuardDelegateAffiliatedUserTest, AppIsOpenButNotSecure) {
{
extensions::ExtensionManagementPrefUpdater<
sync_preferences::TestingPrefServiceSyncable>
updater(profile()->GetTestingPrefService());
// Make sure the extension is marked as force-installed.
updater.SetIndividualExtensionAutoInstalled(
extension_id(), extension_urls::kChromeWebstoreUpdateURL,
/*forced=*/true);
}
OpenAppUIUrlAndSetCertificateWithStatus(
/*cert_status=*/net::CERT_STATUS_INVALID);
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("Companion app UI is not open or not secure", error.value());
}
TEST_P(ApiGuardDelegateAffiliatedUserTest, ManufacturerNotAllowed) {
{
extensions::ExtensionManagementPrefUpdater<
sync_preferences::TestingPrefServiceSyncable>
updater(profile()->GetTestingPrefService());
// Make sure the extension is marked as force-installed.
updater.SetIndividualExtensionAutoInstalled(
extension_id(), extension_urls::kChromeWebstoreUpdateURL,
/*forced=*/true);
}
OpenAppUIUrlAndSetCertificateWithStatus(/*cert_status=*/net::OK);
// Make sure device manufacturer is not allowed.
SetDeviceManufacturer("NOT_ALLOWED");
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("This extension is not allowed to access the API on this device",
error.value());
}
TEST_P(ApiGuardDelegateAffiliatedUserTest, NoError) {
{
extensions::ExtensionManagementPrefUpdater<
sync_preferences::TestingPrefServiceSyncable>
updater(profile()->GetTestingPrefService());
// Make sure the extension is marked as force-installed.
updater.SetIndividualExtensionAutoInstalled(
extension_id(), extension_urls::kChromeWebstoreUpdateURL,
/*forced=*/true);
}
OpenAppUIUrlAndSetCertificateWithStatus(/*cert_status=*/net::OK);
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
EXPECT_FALSE(error.has_value()) << error.value();
}
INSTANTIATE_TEST_SUITE_P(All,
ApiGuardDelegateAffiliatedUserTest,
testing::ValuesIn(kAllExtensionInfoTestParams));
// TODO(b/292227137): Migrate Shimless RMA app to LaCrOS.
#if BUILDFLAG(IS_CHROMEOS_ASH)
class WebContentsCloseWaiter : public content::WebContentsObserver {
public:
explicit WebContentsCloseWaiter(content::WebContents* contents);
WebContentsCloseWaiter(const WebContentsCloseWaiter&) = delete;
WebContentsCloseWaiter& operator=(const WebContentsCloseWaiter&) = delete;
void Wait() { ASSERT_TRUE(future_.Wait()) << "Web contents did not close."; }
private:
// content::WebContentsObserver overrides.
void WebContentsDestroyed() override;
base::test::TestFuture<void> future_;
};
WebContentsCloseWaiter::WebContentsCloseWaiter(content::WebContents* contents)
: content::WebContentsObserver(contents) {}
void WebContentsCloseWaiter::WebContentsDestroyed() {
future_.SetValue();
}
class ApiGuardDelegateShimlessRMAAppTest : public ApiGuardDelegateTest {
public:
ApiGuardDelegateShimlessRMAAppTest() = default;
~ApiGuardDelegateShimlessRMAAppTest() override = default;
void SetUp() override {
feature_list_.InitWithFeatures(
{
::ash::features::kShimlessRMA3pDiagnostics,
},
{});
chromeos_system_extension_info_ =
ScopedChromeOSSystemExtensionInfo::CreateForTesting();
// TODO(b/293560424): Remove this override after we add some valid IWA id to
// the allowlist.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
chromeos::switches::kTelemetryExtensionIwaIdOverrideForTesting,
"pt2jysa7yu326m2cbu5mce4rrajvguagronrsqwn5dhbaris6eaaaaic");
chromeos_system_extension_info_->ApplyCommandLineSwitchesForTesting();
// Above overrides need to be done before creating extensions.
ApiGuardDelegateTest::SetUp();
ash::Shell::Get()->session_controller()->SetSessionInfo(ash::SessionInfo{
.can_lock_screen = true,
.should_lock_screen_automatically = false,
.add_user_session_policy = ash::AddUserSessionPolicy::ALLOWED,
.state = session_manager::SessionState::RMA,
});
}
void TearDown() override {
if (ash::shimless_rma::ExternalAppDialog::GetWebContents()) {
WebContentsCloseWaiter waiter(
ash::shimless_rma::ExternalAppDialog::GetWebContents());
ash::shimless_rma::ExternalAppDialog::CloseForTesting();
waiter.Wait();
}
ApiGuardDelegateTest::TearDown();
}
protected:
void OpenShimlessRmaAppDialog() {
ash::shimless_rma::ExternalAppDialog::InitParams params;
params.context = profile();
params.app_name = "App Name";
params.content_url = GURL(app_ui_url());
ash::shimless_rma::ExternalAppDialog::Show(params);
// Wait for WebContents being created.
base::RunLoop().RunUntilIdle();
auto* content = ash::shimless_rma::ExternalAppDialog::GetWebContents();
CHECK(content);
web_app::CommitPendingIsolatedWebAppNavigation(content);
}
// BrowserWithTestWindowTest overrides.
std::string GetDefaultProfileName() override {
return ash::kShimlessRmaAppBrowserContextBaseName;
}
// Do nothing for special profile for shimless RMA App.
void LogIn(const std::string& email) override {}
void SwitchActiveUser(const std::string& email) override {}
void OnUserProfileCreated(const std::string& email,
Profile* profile) override {}
private:
base::test::ScopedFeatureList feature_list_;
std::unique_ptr<ScopedChromeOSSystemExtensionInfo>
chromeos_system_extension_info_;
};
TEST_P(ApiGuardDelegateShimlessRMAAppTest, IwaNotOpen) {
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("Companion app UI is not open or not secure", error.value());
}
TEST_P(ApiGuardDelegateShimlessRMAAppTest, ManufacturerNotAllowed) {
OpenShimlessRmaAppDialog();
// Make sure device manufacturer is not allowed.
SetDeviceManufacturer("NOT_ALLOWED");
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
ASSERT_TRUE(error.has_value());
EXPECT_EQ("This extension is not allowed to access the API on this device",
error.value());
}
TEST_P(ApiGuardDelegateShimlessRMAAppTest, NoError) {
OpenShimlessRmaAppDialog();
auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
base::test::TestFuture<std::optional<std::string>> future;
api_guard_delegate->CanAccessApi(profile(), extension(),
future.GetCallback());
ASSERT_TRUE(future.Wait());
std::optional<std::string> error = future.Get();
EXPECT_FALSE(error.has_value()) << error.value();
}
INSTANTIATE_TEST_SUITE_P(
IWA,
ApiGuardDelegateShimlessRMAAppTest,
testing::Values(ExtensionInfoTestParams(
/*extension_id=*/"gogonhoemckpdpadfnjnpgbjpbjnodgc",
/*app_ui_url=*/
"isolated-app://"
"pt2jysa7yu326m2cbu5mce4rrajvguagronrsqwn5dhbaris6eaaaaic",
/*matches_origin=*/
"isolated-app://"
"pt2jysa7yu326m2cbu5mce4rrajvguagronrsqwn5dhbaris6eaaaaic/*",
/*manufacturer=*/"HP")));
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace chromeos