#include "extensions/browser/api/storage/storage_utils.h"
#include "base/types/cxx23_to_underlying.h"
#include "base/values.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_util.h"
#include "extensions/browser/process_map.h"
#include "extensions/common/mojom/api_permission_id.mojom-shared.h"
#include "extensions/common/permissions/permissions_data.h"
namespace extensions::storage_utils {
namespace {
constexpr PrefMap kPrefSessionStorageAccessLevel = {
"storage_session_access_level", PrefType::kInteger,
PrefScope::kExtensionSpecific};
constexpr PrefMap kPrefLocalStorageAccessLevel = {
"storage_local_access_level", PrefType::kInteger,
PrefScope::kExtensionSpecific};
constexpr PrefMap kPrefSyncStorageAccessLevel = {"storage_sync_access_level",
PrefType::kInteger,
PrefScope::kExtensionSpecific};
constexpr PrefMap kPrefManagedStorageAccessLevel = {
"storage_managed_access_level", PrefType::kInteger,
PrefScope::kExtensionSpecific};
const PrefMap* GetPrefMapForStorageArea(StorageAreaNamespace storage_area) {
switch (storage_area) {
case StorageAreaNamespace::kSession:
return &kPrefSessionStorageAccessLevel;
case StorageAreaNamespace::kLocal:
return &kPrefLocalStorageAccessLevel;
case StorageAreaNamespace::kSync:
return &kPrefSyncStorageAccessLevel;
case StorageAreaNamespace::kManaged:
return &kPrefManagedStorageAccessLevel;
case StorageAreaNamespace::kInvalid:
NOTREACHED();
}
}
}
api::storage::AccessLevel GetAccessLevelForArea(
const ExtensionId& extension_id,
content::BrowserContext& browser_context,
StorageAreaNamespace storage_area) {
ExtensionPrefs* prefs = ExtensionPrefs::Get(&browser_context);
const PrefMap* pref_map = GetPrefMapForStorageArea(storage_area);
int stored_access_level_int = 0;
if (pref_map && prefs->ReadPrefAsInteger(extension_id, *pref_map,
&stored_access_level_int)) {
if (stored_access_level_int > 0 &&
stored_access_level_int <=
base::to_underlying(api::storage::AccessLevel::kMaxValue)) {
return static_cast<api::storage::AccessLevel>(stored_access_level_int);
}
}
switch (storage_area) {
case StorageAreaNamespace::kSession:
return api::storage::AccessLevel::kTrustedContexts;
case StorageAreaNamespace::kLocal:
case StorageAreaNamespace::kSync:
case StorageAreaNamespace::kManaged:
return api::storage::AccessLevel::kTrustedAndUntrustedContexts;
case StorageAreaNamespace::kInvalid:
NOTREACHED();
}
}
void SetAccessLevelForArea(const ExtensionId& extension_id,
content::BrowserContext& browser_context,
StorageAreaNamespace storage_area,
api::storage::AccessLevel access_level) {
ExtensionPrefs* prefs = ExtensionPrefs::Get(&browser_context);
const PrefMap* pref_map = GetPrefMapForStorageArea(storage_area);
prefs->SetIntegerPref(extension_id, *pref_map,
base::to_underlying(access_level));
}
base::Value ValueChangeToValue(
std::vector<SessionStorageManager::ValueChange> changes) {
base::Value::Dict changes_value;
for (auto& change : changes) {
base::Value::Dict change_value;
if (change.old_value.has_value()) {
change_value.Set("oldValue", std::move(change.old_value.value()));
}
if (change.new_value) {
change_value.Set("newValue", change.new_value->Clone());
}
changes_value.Set(change.key, std::move(change_value));
}
return base::Value(std::move(changes_value));
}
bool CanRendererAccessExtensionStorage(
content::BrowserContext& browser_context,
const Extension& extension,
std::optional<StorageAreaNamespace> storage_area,
content::RenderFrameHost* render_frame_host,
content::RenderProcessHost& render_process_host) {
if (!extension.permissions_data()->HasAPIPermission(
mojom::APIPermissionID::kStorage)) {
return false;
}
if (storage_area == StorageAreaNamespace::kSession) {
if (extension.manifest_version() < 3) {
return false;
}
api::storage::AccessLevel access_level =
GetAccessLevelForArea(extension.id(), browser_context, *storage_area);
if (access_level == api::storage::AccessLevel::kTrustedContexts) {
ProcessMap* process_map = ProcessMap::Get(&browser_context);
return process_map->IsPrivilegedExtensionProcess(
extension, render_process_host.GetDeprecatedID());
}
}
return util::CanRendererActOnBehalfOfExtension(
extension.id(), render_frame_host, render_process_host,
false);
}
}