blob: 90bb1f31cc786e0bfe6c9bf16f4cb85653149566 [file] [log] [blame]
// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_API_H_
#include <optional>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/scoped_refptr.h"
#include "base/values.h"
#include "chrome/browser/extensions/chrome_extension_function_details.h"
#include "chrome/browser/extensions/window_controller.h"
#include "chrome/common/extensions/api/tabs.h"
#include "components/safe_browsing/buildflags.h"
#include "components/translate/core/browser/translate_driver.h"
#include "components/zoom/zoom_controller.h"
#include "content/public/browser/web_contents_observer.h"
#include "extensions/browser/api/execute_code_function.h"
#include "extensions/browser/api/web_contents_capture_client.h"
#include "extensions/browser/extension_function.h"
#include "extensions/common/extension_resource.h"
#include "extensions/common/user_script.h"
#include "ui/base/mojom/window_show_state.mojom-forward.h"
#include "url/gurl.h"
#if BUILDFLAG(FULL_SAFE_BROWSING)
#include "chrome/browser/safe_browsing/extension_telemetry/tabs_api_signal.h"
#endif
class BrowserWindowInterface;
class GURL;
class SkBitmap;
class TabStripModel;
namespace base {
class TaskRunner;
}
namespace content {
class WebContents;
}
namespace ui {
class ListSelectionModel;
}
namespace user_prefs {
class PrefRegistrySyncable;
}
namespace extensions {
namespace api::windows {
enum class WindowState;
}
// This namespace includes a collection of conceptually-internal helper methods
// and constants that are currently here because they are used by both
// tabs_api.cc and tabs_api_non_android.cc. Eventually, they should only be
// used by tabs_api.cc, and we can move them to an anonymous namespace in
// tabs_api.cc.
// TODO(devlin): Do that. ^^
namespace tabs_internal {
inline constexpr char kMissingLockWindowFullscreenPrivatePermission[] =
"Cannot lock window to fullscreen or close a locked fullscreen window "
"without lockWindowFullscreenPrivate manifest permission";
// A helper class to extract popular properties from different arguments.
template <typename T>
class ApiParameterExtractor {
public:
explicit ApiParameterExtractor(std::optional<T>& params) : params_(*params) {}
~ApiParameterExtractor() = default;
bool populate_tabs() {
if (params_->query_options && params_->query_options->populate) {
return *params_->query_options->populate;
}
return false;
}
WindowController::TypeFilter type_filters() {
if (params_->query_options && params_->query_options->window_types) {
return WindowController::GetFilterFromWindowTypes(
*params_->query_options->window_types);
}
return WindowController::kNoWindowFilter;
}
private:
raw_ref<T> params_;
};
// Returns true if the given `extension` has API access to the locked
// fullscreen permission.
bool ExtensionHasLockedFullscreenPermission(const Extension* extension);
// Helper method to generate a new tab object for the given `contents`,
// appropriately scrubbed of data for the given `extension`.
api::tabs::Tab CreateTabObjectHelper(content::WebContents* contents,
const Extension* extension,
mojom::ContextType context,
BrowserWindowInterface* browser,
int tab_index);
// Retrieves the tab associated with the given `tab_id`, populating
// `contents_out`, `window_out`, and `index_out` with the result. If the tab
// isn't found and `error_out` is non-null, populates `error_out` with an
// appropriate error.
// Returns true if the tab was found.
bool GetTabById(int tab_id,
content::BrowserContext* context,
bool include_incognito,
WindowController** window_out,
content::WebContents** contents_out,
int* index_out,
std::string* error_out);
#if BUILDFLAG(FULL_SAFE_BROWSING)
// Notifies the safe browsing telemetry service of a relevant extension action.
void NotifyExtensionTelemetry(Profile* profile,
const Extension* extension,
safe_browsing::TabsApiInfo::ApiMethod api_method,
const std::string& current_url,
const std::string& new_url,
const std::optional<StackTrace>& js_callstack);
#endif
// Gets the WebContents for `tab_id` if it is specified. Otherwise get the
// WebContents for the active tab in the `function`'s current window.
// Returns nullptr and fills `error` if failed.
content::WebContents* GetTabsAPIDefaultWebContents(ExtensionFunction* function,
int tab_id,
std::string* error);
// Converts the given `state` to the mojom::WindowShowState equivalent.
ui::mojom::WindowShowState ConvertToWindowShowState(
api::windows::WindowState state);
// Returns whether the given `bounds` intersect with at least 50% of all the
// displays.
bool WindowBoundsIntersectDisplays(const gfx::Rect& bounds);
} // namespace tabs_internal
// Converts a ZoomMode to its ZoomSettings representation.
void ZoomModeToZoomSettings(zoom::ZoomController::ZoomMode zoom_mode,
api::tabs::ZoomSettings* zoom_settings);
// Windows
class WindowsGetFunction : public ExtensionFunction {
~WindowsGetFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("windows.get", WINDOWS_GET)
};
class WindowsGetCurrentFunction : public ExtensionFunction {
~WindowsGetCurrentFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("windows.getCurrent", WINDOWS_GETCURRENT)
};
class WindowsGetLastFocusedFunction : public ExtensionFunction {
~WindowsGetLastFocusedFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("windows.getLastFocused", WINDOWS_GETLASTFOCUSED)
};
class WindowsGetAllFunction : public ExtensionFunction {
~WindowsGetAllFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("windows.getAll", WINDOWS_GETALL)
};
class WindowsCreateFunction : public ExtensionFunction {
~WindowsCreateFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("windows.create", WINDOWS_CREATE)
};
class WindowsUpdateFunction : public ExtensionFunction {
~WindowsUpdateFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("windows.update", WINDOWS_UPDATE)
};
class WindowsRemoveFunction : public ExtensionFunction {
~WindowsRemoveFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("windows.remove", WINDOWS_REMOVE)
};
// Tabs
class TabsGetFunction : public ExtensionFunction {
~TabsGetFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.get", TABS_GET)
};
class TabsGetCurrentFunction : public ExtensionFunction {
~TabsGetCurrentFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.getCurrent", TABS_GETCURRENT)
};
class TabsGetSelectedFunction : public ExtensionFunction {
~TabsGetSelectedFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.getSelected", TABS_GETSELECTED)
};
class TabsGetAllInWindowFunction : public ExtensionFunction {
~TabsGetAllInWindowFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.getAllInWindow", TABS_GETALLINWINDOW)
};
class TabsQueryFunction : public ExtensionFunction {
~TabsQueryFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.query", TABS_QUERY)
};
class TabsCreateFunction : public ExtensionFunction {
~TabsCreateFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.create", TABS_CREATE)
};
class TabsDuplicateFunction : public ExtensionFunction {
~TabsDuplicateFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.duplicate", TABS_DUPLICATE)
};
class TabsHighlightFunction : public ExtensionFunction {
~TabsHighlightFunction() override = default;
ResponseAction Run() override;
bool HighlightTab(TabStripModel* tabstrip,
ui::ListSelectionModel* selection,
std::optional<size_t>* active_index,
int index,
std::string* error);
DECLARE_EXTENSION_FUNCTION("tabs.highlight", TABS_HIGHLIGHT)
};
class TabsUpdateFunction : public ExtensionFunction {
public:
TabsUpdateFunction();
protected:
~TabsUpdateFunction() override = default;
bool UpdateURL(const std::string& url,
int tab_id,
std::string* error);
ResponseValue GetResult();
raw_ptr<content::WebContents, DanglingUntriaged> web_contents_;
private:
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.update", TABS_UPDATE)
};
class TabsMoveFunction : public ExtensionFunction {
~TabsMoveFunction() override = default;
ResponseAction Run() override;
bool MoveTab(int tab_id,
int* new_index,
base::Value::List& tab_values,
const std::optional<int>& window_id,
std::string* error);
DECLARE_EXTENSION_FUNCTION("tabs.move", TABS_MOVE)
};
class TabsReloadFunction : public ExtensionFunction {
~TabsReloadFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.reload", TABS_RELOAD)
};
class TabsRemoveFunction : public ExtensionFunction {
public:
TabsRemoveFunction();
void TabDestroyed();
private:
~TabsRemoveFunction() override;
ResponseAction Run() override;
bool RemoveTab(int tab_id, std::string* error);
int remaining_tabs_count_ = 0;
bool triggered_all_tab_removals_ = false;
class WebContentsDestroyedObserver;
std::vector<std::unique_ptr<WebContentsDestroyedObserver>>
web_contents_destroyed_observers_;
DECLARE_EXTENSION_FUNCTION("tabs.remove", TABS_REMOVE)
};
class TabsGroupFunction : public ExtensionFunction {
~TabsGroupFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.group", TABS_GROUP)
};
class TabsUngroupFunction : public ExtensionFunction {
~TabsUngroupFunction() override = default;
ResponseAction Run() override;
bool UngroupTab(int tab_id, std::string* error);
DECLARE_EXTENSION_FUNCTION("tabs.ungroup", TABS_UNGROUP)
};
class TabsDetectLanguageFunction
: public ExtensionFunction,
public content::WebContentsObserver,
public translate::TranslateDriver::LanguageDetectionObserver {
private:
~TabsDetectLanguageFunction() override = default;
ResponseAction Run() override;
// content::WebContentsObserver:
void NavigationEntryCommitted(
const content::LoadCommittedDetails& load_details) override;
void WebContentsDestroyed() override;
// translate::TranslateDriver::LanguageDetectionObserver:
void OnTranslateDriverDestroyed(translate::TranslateDriver* driver) override;
void OnLanguageDetermined(
const translate::LanguageDetectionDetails& details) override;
// Resolves the API call with the detected `language`.
void RespondWithLanguage(const std::string& language);
// Indicates if this instance is observing the tabs' WebContents and the
// ContentTranslateDriver, in which case the observers must be unregistered.
bool is_observing_ = false;
DECLARE_EXTENSION_FUNCTION("tabs.detectLanguage", TABS_DETECTLANGUAGE)
};
class TabsCaptureVisibleTabFunction :
public extensions::WebContentsCaptureClient,
public ExtensionFunction {
public:
TabsCaptureVisibleTabFunction();
TabsCaptureVisibleTabFunction(const TabsCaptureVisibleTabFunction&) = delete;
TabsCaptureVisibleTabFunction& operator=(
const TabsCaptureVisibleTabFunction&) = delete;
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
static void set_disable_throttling_for_tests(
bool disable_throttling_for_test) {
disable_throttling_for_test_ = disable_throttling_for_test;
}
// ExtensionFunction implementation.
ResponseAction Run() override;
void GetQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) const override;
bool ShouldSkipQuotaLimiting() const override;
protected:
~TabsCaptureVisibleTabFunction() override = default;
private:
ChromeExtensionFunctionDetails chrome_details_;
content::WebContents* GetWebContentsForID(int window_id, std::string* error);
// extensions::WebContentsCaptureClient:
ScreenshotAccess GetScreenshotAccess(
content::WebContents* web_contents) const override;
bool ClientAllowsTransparency() override;
void OnCaptureSuccess(const SkBitmap& bitmap) override;
void OnCaptureFailure(CaptureResult result) override;
void EncodeBitmapOnWorkerThread(
scoped_refptr<base::TaskRunner> reply_task_runner,
const SkBitmap& bitmap);
void OnBitmapEncodedOnUIThread(std::optional<std::string> base64_result);
private:
DECLARE_EXTENSION_FUNCTION("tabs.captureVisibleTab", TABS_CAPTUREVISIBLETAB)
static std::string CaptureResultToErrorMessage(CaptureResult result);
static bool disable_throttling_for_test_;
};
// Implement API calls tabs.executeScript, tabs.insertCSS, and tabs.removeCSS.
class ExecuteCodeInTabFunction : public ExecuteCodeFunction {
public:
ExecuteCodeInTabFunction();
protected:
~ExecuteCodeInTabFunction() override;
// Initializes `execute_tab_id_` and `details_`.
InitResult Init() override;
bool ShouldInsertCSS() const override;
bool ShouldRemoveCSS() const override;
bool CanExecuteScriptOnPage(std::string* error) override;
ScriptExecutor* GetScriptExecutor(std::string* error) override;
bool IsWebView() const override;
int GetRootFrameId() const override;
const GURL& GetWebViewSrc() const override;
private:
const ChromeExtensionFunctionDetails chrome_details_{this};
// Id of tab which executes code.
int execute_tab_id_ = -1;
};
class TabsExecuteScriptFunction : public ExecuteCodeInTabFunction {
private:
~TabsExecuteScriptFunction() override = default;
DECLARE_EXTENSION_FUNCTION("tabs.executeScript", TABS_EXECUTESCRIPT)
};
class TabsInsertCSSFunction : public ExecuteCodeInTabFunction {
private:
~TabsInsertCSSFunction() override = default;
bool ShouldInsertCSS() const override;
DECLARE_EXTENSION_FUNCTION("tabs.insertCSS", TABS_INSERTCSS)
};
// TODO(https://crrev.com/c/608854): When a file URL is passed, this will do
// more work than needed: since the key is created based on the file URL in
// that case, we don't actually need to
//
// a) load the file or
// b) localize it
//
// ... hence, it could just go straight to the ScriptExecutor.
class TabsRemoveCSSFunction : public ExecuteCodeInTabFunction {
private:
~TabsRemoveCSSFunction() override = default;
bool ShouldRemoveCSS() const override;
DECLARE_EXTENSION_FUNCTION("tabs.removeCSS", TABS_REMOVECSS)
};
class TabsSetZoomFunction : public ExtensionFunction {
private:
~TabsSetZoomFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.setZoom", TABS_SETZOOM)
};
class TabsGetZoomFunction : public ExtensionFunction {
private:
~TabsGetZoomFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.getZoom", TABS_GETZOOM)
};
class TabsSetZoomSettingsFunction : public ExtensionFunction {
private:
~TabsSetZoomSettingsFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.setZoomSettings", TABS_SETZOOMSETTINGS)
};
class TabsGetZoomSettingsFunction : public ExtensionFunction {
private:
~TabsGetZoomSettingsFunction() override = default;
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("tabs.getZoomSettings", TABS_GETZOOMSETTINGS)
};
class TabsDiscardFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("tabs.discard", TABS_DISCARD)
TabsDiscardFunction();
TabsDiscardFunction(const TabsDiscardFunction&) = delete;
TabsDiscardFunction& operator=(const TabsDiscardFunction&) = delete;
private:
~TabsDiscardFunction() override;
// ExtensionFunction:
ExtensionFunction::ResponseAction Run() override;
};
class TabsGoForwardFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("tabs.goForward", TABS_GOFORWARD)
TabsGoForwardFunction() = default;
TabsGoForwardFunction(const TabsGoForwardFunction&) = delete;
TabsGoForwardFunction& operator=(const TabsGoForwardFunction&) = delete;
private:
~TabsGoForwardFunction() override = default;
// ExtensionFunction:
ExtensionFunction::ResponseAction Run() override;
};
class TabsGoBackFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("tabs.goBack", TABS_GOBACK)
TabsGoBackFunction() = default;
TabsGoBackFunction(const TabsGoBackFunction&) = delete;
TabsGoBackFunction& operator=(const TabsGoBackFunction&) = delete;
private:
~TabsGoBackFunction() override = default;
// ExtensionFunction:
ExtensionFunction::ResponseAction Run() override;
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_API_H_