blob: cd982521c3a339f3b79e56f275106974ce3bd12f [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/web_applications/isolation_prefs_utils.h"
#include <memory>
#include "base/values.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_prefs_utils.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"
#include "services/preferences/public/cpp/dictionary_value_update.h"
#include "services/preferences/public/cpp/scoped_pref_update.h"
#include "url/origin.h"
namespace web_app {
// The stored preferences managed by this file look like:
// "web_apps": {
// ... other fields managed by web_app_prefs_utils ...
//
// "isolation_state": {
// "<origin>": {
// "storage_isolation_key": "abc123",
// },
// },
// }
namespace {
const char kStorageIsolationKey[] = "storage_isolation_key";
// Creates a copy of the given origin but without a port set. This is a
// temporary hack meant to work around the fact that we key app isolation state
// on the app's origin, but StoragePartitions are looked up based on sites.
// Removing the port does not convert an origin into a site, but the actual
// origin to site logic is private to //content and this is good enough to
// allow testing in the short term.
// TODO(crbug.com/1212263): Remove this function.
url::Origin RemovePort(const url::Origin& origin) {
return url::Origin::CreateFromNormalizedTuple(origin.scheme(), origin.host(),
/*port=*/0);
}
} // namespace
void IsolationPrefsUtilsRegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(::prefs::kWebAppsIsolationState);
}
void RecordOrRemoveAppIsolationState(PrefService* pref_service,
const WebApp& web_app) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
url::Origin origin = RemovePort(url::Origin::Create(web_app.scope()));
prefs::ScopedDictionaryPrefUpdate update(pref_service,
prefs::kWebAppsIsolationState);
if (web_app.IsStorageIsolated()) {
std::unique_ptr<prefs::DictionaryValueUpdate> origin_isolation_update;
if (!update->GetDictionaryWithoutPathExpansion(origin.Serialize(),
&origin_isolation_update)) {
origin_isolation_update = update->SetDictionaryWithoutPathExpansion(
origin.Serialize(), std::make_unique<base::DictionaryValue>());
}
origin_isolation_update->SetString(kStorageIsolationKey, web_app.app_id());
} else {
update->RemoveWithoutPathExpansion(origin.Serialize(), nullptr);
}
}
void RemoveAppIsolationState(PrefService* pref_service,
const url::Origin& origin) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
prefs::ScopedDictionaryPrefUpdate update(pref_service,
prefs::kWebAppsIsolationState);
update->RemoveWithoutPathExpansion(RemovePort(origin).Serialize(), nullptr);
}
const std::string* GetStorageIsolationKey(PrefService* pref_service,
const url::Origin& origin) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const base::Value* isolation_prefs =
pref_service->GetDictionary(prefs::kWebAppsIsolationState);
if (!isolation_prefs)
return nullptr;
const base::Value* origin_prefs =
isolation_prefs->FindDictKey(RemovePort(origin).Serialize());
if (!origin_prefs)
return nullptr;
return origin_prefs->FindStringKey(kStorageIsolationKey);
}
} // namespace web_app