chromium/chrome/browser/extensions/window_open_apitest.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stddef.h>

#include "base/path_service.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/result_codes.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/process_manager.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/base_window.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/extensions/window_controller.h"
#include "chrome/browser/extensions/window_controller_list.h"
#include "chrome/browser/ui/browser_command_controller.h"
#include "chromeos/ui/base/window_pin_type.h"
#include "ui/aura/window.h"
#endif

#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/ui/lacros/window_properties.h"
#else
#include "chrome/browser/ui/chromeos/window_pin_util.h"
#endif

OpenURLParams;
Referrer;
WebContents;

namespace aura {
class Window;
}

namespace extensions {

class WindowOpenApiTest : public ExtensionApiTest {};

bool WaitForTabsPopupsApps(Browser* browser,
                           int num_tabs,
                           int num_popups,
                           int num_app_popups) {}

IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, BrowserIsApp) {}

IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, WindowOpenPopupDefault) {}

IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, WindowOpenPopupIframe) {}

IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, WindowOpenPopupLarge) {}

IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, WindowOpenPopupSmall) {}

IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, PopupBlockingExtension) {}

IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, PopupBlockingHostedApp) {}

IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, WindowArgumentsOverflow) {}

IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, WindowOpener) {}

// Ensure that the width and height properties of a window opened with
// chrome.windows.create match the creation parameters. See crbug.com/173831.
IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, WindowOpenSized) {}

// Tests that an extension page can call window.open to an extension URL and
// the new window has extension privileges.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenExtension) {}

// Tests that if an extension page calls window.open to an invalid extension
// URL, the browser doesn't crash.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenInvalidExtension) {}

// Tests that calling window.open from the newtab page to an extension URL
// gives the new window extension privileges - even though the opening page
// does not have extension privileges, we break the script connection, so
// there is no privilege leak.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenNoPrivileges) {}

// Tests that calling window.open for an extension URL from a non-HTTP or HTTPS
// URL on a new tab cannot access non-web-accessible resources.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest,
                       WindowOpenInaccessibleResourceFromDataURL) {}

// Test that navigating to an extension URL is allowed on chrome://.
// See https://crbug.com/662602.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest,
                       NavigateToInaccessibleResourceFromChromeURL) {}

#if BUILDFLAG(IS_CHROMEOS)

namespace {

aura::Window* GetCurrentWindow() {
  extensions::WindowController* controller = nullptr;
  for (extensions::WindowController* iter :
       extensions::WindowControllerList::GetInstance()->windows()) {
    if (iter->window()->IsActive()) {
      controller = iter;
      break;
    }
  }

#if BUILDFLAG(IS_CHROMEOS_LACROS)
  if (!controller || !controller->window())
    return nullptr;
#else
  EXPECT_TRUE(controller);
#endif
  return controller->window()->GetNativeWindow();
}

chromeos::WindowPinType GetCurrentWindowPinType() {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
  chromeos::WindowPinType type =
      GetCurrentWindow()->GetProperty(lacros::kWindowPinTypeKey);
#else
  chromeos::WindowPinType type = GetWindowPinType(GetCurrentWindow());
#endif
  return type;
}

// Disabling this test temporarily - Ash needs to be built to make this test
// work. Will enable after this landed.
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
void SetCurrentWindowPinType(chromeos::WindowPinType type) {
  if (type == chromeos::WindowPinType::kNone) {
    UnpinWindow(GetCurrentWindow());
  } else {
    PinWindow(GetCurrentWindow(), /*trusted=*/true);
  }
}
#endif

}  // namespace

// Disabling this test temporarily - Ash needs to be built to make this test
// work. Will enable after this landed.
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, OpenLockedFullscreenWindow) {
  ASSERT_TRUE(RunExtensionTest("locked_fullscreen/with_permission",
                               {.custom_arg = "openLockedFullscreenWindow"}))
      << message_;

  // Make sure the newly created window is "trusted pinned" (which means that
  // it's in locked fullscreen mode).
  EXPECT_EQ(chromeos::WindowPinType::kTrustedPinned, GetCurrentWindowPinType());
}
#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)

// Disabled on Lacros due to flaky. crbug.com/1254453
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_UpdateWindowToLockedFullscreen
#else
#define MAYBE_UpdateWindowToLockedFullscreen
#endif
IN_PROC_BROWSER_TEST_F(WindowOpenApiTest,
                       MAYBE_UpdateWindowToLockedFullscreen) {
  ASSERT_TRUE(
      RunExtensionTest("locked_fullscreen/with_permission",
                       {.custom_arg = "updateWindowToLockedFullscreen"}))
      << message_;

  // Make sure the current window is put into the "trusted pinned" state.
  EXPECT_EQ(chromeos::WindowPinType::kTrustedPinned, GetCurrentWindowPinType());
}

// Disabling this test temporarily - Ash needs to be built to make this test
// work. Will enable after this landed.
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, RemoveLockedFullscreenFromWindow) {
  // After locking the window, do a LockedFullscreenStateChanged so the
  // command_controller state catches up as well.
  SetCurrentWindowPinType(chromeos::WindowPinType::kTrustedPinned);
  browser()->command_controller()->LockedFullscreenStateChanged();

  ASSERT_TRUE(
      RunExtensionTest("locked_fullscreen/with_permission",
                       {.custom_arg = "removeLockedFullscreenFromWindow"}))
      << message_;

  // Make sure the current window is removed from locked-fullscreen state.
  EXPECT_EQ(chromeos::WindowPinType::kNone, GetCurrentWindowPinType());
}
#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)

// Make sure that commands disabling code works in locked fullscreen mode.
IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, VerifyCommandsInLockedFullscreen) {
  // IDC_EXIT is always enabled in regular mode so it's a perfect candidate for
  // testing.
  EXPECT_TRUE(browser()->command_controller()->IsCommandEnabled(IDC_EXIT));
  ASSERT_TRUE(
      RunExtensionTest("locked_fullscreen/with_permission",
                       {.custom_arg = "updateWindowToLockedFullscreen"}))
      << message_;

  // IDC_EXIT should always be disabled in locked fullscreen.
  EXPECT_FALSE(browser()->command_controller()->IsCommandEnabled(IDC_EXIT));

  // Some other disabled commands.
  EXPECT_FALSE(browser()->command_controller()->IsCommandEnabled(IDC_FIND));
  EXPECT_FALSE(
      browser()->command_controller()->IsCommandEnabled(IDC_ZOOM_PLUS));

  // Verify some allowlisted commands.
  EXPECT_TRUE(browser()->command_controller()->IsCommandEnabled(IDC_COPY));
  EXPECT_TRUE(browser()->command_controller()->IsCommandEnabled(IDC_PASTE));
}

IN_PROC_BROWSER_TEST_F(WindowOpenApiTest,
                       OpenLockedFullscreenWindowWithoutPermission) {
  ASSERT_TRUE(RunExtensionTest("locked_fullscreen/without_permission",
                               {.custom_arg = "openLockedFullscreenWindow"}))
      << message_;

  // Make sure no new windows get created (so only the one created by default
  // exists) since the call to chrome.windows.create fails on the javascript
  // side.
  EXPECT_EQ(1u,
            extensions::WindowControllerList::GetInstance()->windows().size());
}

// Disabled on Lacros due to flaky. crbug.com/1254453
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_UpdateWindowToLockedFullscreenWithoutPermission
#else
#define MAYBE_UpdateWindowToLockedFullscreenWithoutPermission
#endif
IN_PROC_BROWSER_TEST_F(WindowOpenApiTest,
                       MAYBE_UpdateWindowToLockedFullscreenWithoutPermission) {
  ASSERT_TRUE(
      RunExtensionTest("locked_fullscreen/without_permission",
                       {.custom_arg = "updateWindowToLockedFullscreen"}))
      << message_;

  // chrome.windows.update call fails since this extension doesn't have the
  // correct permission and hence the current window has NONE as WindowPinType.
  EXPECT_EQ(chromeos::WindowPinType::kNone, GetCurrentWindowPinType());
}

// Disabling this test temporarily - Ash needs to be built to make this test
// work. Will enable after this landed.
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
IN_PROC_BROWSER_TEST_F(WindowOpenApiTest,
                       RemoveLockedFullscreenFromWindowWithoutPermission) {
  SetCurrentWindowPinType(chromeos::WindowPinType::kTrustedPinned);
  browser()->command_controller()->LockedFullscreenStateChanged();

  ASSERT_TRUE(
      RunExtensionTest("locked_fullscreen/without_permission",
                       {.custom_arg = "removeLockedFullscreenFromWindow"}))
      << message_;

  // The current window is still locked-fullscreen.
  EXPECT_EQ(chromeos::WindowPinType::kTrustedPinned, GetCurrentWindowPinType());
}
#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
#endif  // BUILDFLAG(IS_CHROMEOS)

#if !BUILDFLAG(IS_CHROMEOS)
// Loading an extension requiring the 'lockWindowFullscreenPrivate' permission
// on non Chrome OS platforms should always fail since the API is available only
// on Chrome OS.
IN_PROC_BROWSER_TEST_F(WindowOpenApiTest,
                       OpenLockedFullscreenWindowNonChromeOS) {}
#endif

}  // namespace extensions