blob: aaebeed2be11e366655c30253b51fa2dcc06bbc2 [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.
#include "chrome/browser/extensions/api/developer_private/developer_private_api.h"
#include "base/lazy_instance.h"
#include "chrome/browser/extensions/api/developer_private/extension_info_generator.h"
#include "chrome/browser/extensions/commands/command_service.h"
#include "chrome/browser/extensions/error_console/error_console_factory.h"
#include "chrome/browser/extensions/extension_management.h"
#include "extensions/browser/event_router_factory.h"
#include "extensions/browser/extension_prefs_factory.h"
#include "extensions/browser/extension_registry_factory.h"
#include "extensions/browser/extension_system_provider.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/permissions_manager.h"
#include "extensions/browser/process_manager_factory.h"
#include "extensions/browser/warning_service_factory.h"
#include "ui/base/clipboard/file_info.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "chrome/browser/extensions/sync/account_extension_tracker.h"
#include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h"
#include "extensions/browser/app_window/app_window_registry.h"
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
namespace extensions {
namespace developer = api::developer_private;
static base::LazyInstance<BrowserContextKeyedAPIFactory<DeveloperPrivateAPI>>::
DestructorAtExit g_developer_private_api_factory =
LAZY_INSTANCE_INITIALIZER;
class DeveloperPrivateAPI::WebContentsTracker
: public content::WebContentsObserver {
public:
WebContentsTracker(base::WeakPtr<DeveloperPrivateAPI> api,
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents), api_(api) {}
WebContentsTracker(const WebContentsTracker&) = delete;
WebContentsTracker& operator=(const WebContentsTracker&) = delete;
private:
~WebContentsTracker() override = default;
void WebContentsDestroyed() override {
if (api_)
api_->web_contents_data_.erase(web_contents());
delete this;
}
base::WeakPtr<DeveloperPrivateAPI> api_;
};
DeveloperPrivateAPI::WebContentsData::WebContentsData() = default;
DeveloperPrivateAPI::WebContentsData::~WebContentsData() = default;
DeveloperPrivateAPI::WebContentsData::WebContentsData(WebContentsData&& other) =
default;
// static
BrowserContextKeyedAPIFactory<DeveloperPrivateAPI>*
DeveloperPrivateAPI::GetFactoryInstance() {
return g_developer_private_api_factory.Pointer();
}
template <>
void BrowserContextKeyedAPIFactory<
DeveloperPrivateAPI>::DeclareFactoryDependencies() {
// Keep this in sync with observers DeveloperPrivateEventRouterShared
// implements.
DependsOn(ExtensionRegistryFactory::GetInstance());
DependsOn(ErrorConsoleFactory::GetInstance());
DependsOn(ProcessManagerFactory::GetInstance());
DependsOn(WarningServiceFactory::GetInstance());
DependsOn(ExtensionPrefsFactory::GetInstance());
DependsOn(EventRouterFactory::GetInstance());
DependsOn(PermissionsManager::GetFactory());
DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
DependsOn(ExtensionManagementFactory::GetInstance());
DependsOn(CommandService::GetFactoryInstance());
#if BUILDFLAG(ENABLE_EXTENSIONS)
DependsOn(AppWindowRegistry::Factory::GetInstance());
DependsOn(ToolbarActionsModelFactory::GetInstance());
DependsOn(AccountExtensionTracker::GetFactory());
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
}
// static
DeveloperPrivateAPI* DeveloperPrivateAPI::Get(
content::BrowserContext* context) {
return GetFactoryInstance()->Get(context);
}
DeveloperPrivateAPI::DeveloperPrivateAPI(content::BrowserContext* context)
: profile_(Profile::FromBrowserContext(context)) {
RegisterNotifications();
}
DeveloperPrivateAPI::UnpackedRetryId DeveloperPrivateAPI::AddUnpackedPath(
content::WebContents* web_contents,
const base::FilePath& path) {
DCHECK(web_contents);
last_unpacked_directory_ = path;
WebContentsData* data = GetOrCreateWebContentsData(web_contents);
IdToPathMap& paths = data->allowed_unpacked_paths;
auto existing =
std::ranges::find(paths, path, &IdToPathMap::value_type::second);
if (existing != paths.end())
return existing->first;
UnpackedRetryId id = base::Uuid::GenerateRandomV4().AsLowercaseString();
paths[id] = path;
return id;
}
base::FilePath DeveloperPrivateAPI::GetUnpackedPath(
content::WebContents* web_contents,
const UnpackedRetryId& id) const {
const WebContentsData* data = GetWebContentsData(web_contents);
if (!data)
return base::FilePath();
const IdToPathMap& paths = data->allowed_unpacked_paths;
auto path_iter = paths.find(id);
if (path_iter == paths.end())
return base::FilePath();
return path_iter->second;
}
void DeveloperPrivateAPI::SetDraggedFile(content::WebContents* web_contents,
const ui::FileInfo& dragged_file) {
WebContentsData* data = GetOrCreateWebContentsData(web_contents);
data->dragged_file = dragged_file;
}
ui::FileInfo DeveloperPrivateAPI::GetDraggedFile(
content::WebContents* web_contents) const {
const WebContentsData* data = GetWebContentsData(web_contents);
return data ? data->dragged_file : ui::FileInfo();
}
void DeveloperPrivateAPI::RegisterNotifications() {
EventRouter::Get(profile_)->RegisterObserver(
this, developer::OnItemStateChanged::kEventName);
EventRouter::Get(profile_)->RegisterObserver(
this, developer::OnUserSiteSettingsChanged::kEventName);
}
const DeveloperPrivateAPI::WebContentsData*
DeveloperPrivateAPI::GetWebContentsData(
content::WebContents* web_contents) const {
auto iter = web_contents_data_.find(web_contents);
return iter == web_contents_data_.end() ? nullptr : &iter->second;
}
DeveloperPrivateAPI::WebContentsData*
DeveloperPrivateAPI::GetOrCreateWebContentsData(
content::WebContents* web_contents) {
auto iter = web_contents_data_.find(web_contents);
if (iter != web_contents_data_.end())
return &iter->second;
// This is the first we've added this WebContents. Track its lifetime so we
// can clean up the paths when it is destroyed.
// WebContentsTracker manages its own lifetime.
new WebContentsTracker(weak_factory_.GetWeakPtr(), web_contents);
return &web_contents_data_[web_contents];
}
DeveloperPrivateAPI::~DeveloperPrivateAPI() = default;
void DeveloperPrivateAPI::Shutdown() {}
void DeveloperPrivateAPI::OnListenerAdded(
const EventListenerInfo& details) {
if (!developer_private_event_router_) {
developer_private_event_router_ =
std::make_unique<DeveloperPrivateEventRouter>(profile_);
}
developer_private_event_router_->AddExtensionId(details.extension_id);
}
void DeveloperPrivateAPI::OnListenerRemoved(
const EventListenerInfo& details) {
if (!EventRouter::Get(profile_)->HasEventListener(
developer::OnItemStateChanged::kEventName) &&
!EventRouter::Get(profile_)->HasEventListener(
developer::OnUserSiteSettingsChanged::kEventName)) {
developer_private_event_router_.reset(nullptr);
} else {
developer_private_event_router_->RemoveExtensionId(details.extension_id);
}
}
} // namespace extensions