DocumentStorageAccess.cpp [plain text]
#include "config.h"
#include "DocumentStorageAccess.h"
#if ENABLE(RESOURCE_LOAD_STATISTICS)
#include "Chrome.h"
#include "ChromeClient.h"
#include "Document.h"
#include "EventLoop.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "JSDOMPromiseDeferred.h"
#include "Page.h"
#include "RegistrableDomain.h"
#include "SecurityOrigin.h"
#include "Settings.h"
#include "UserGestureIndicator.h"
namespace WebCore {
DocumentStorageAccess::DocumentStorageAccess(Document& document)
: m_document(document)
{
}
DocumentStorageAccess::~DocumentStorageAccess() = default;
DocumentStorageAccess* DocumentStorageAccess::from(Document& document)
{
auto* supplement = static_cast<DocumentStorageAccess*>(Supplement<Document>::from(&document, supplementName()));
if (!supplement) {
auto newSupplement = makeUnique<DocumentStorageAccess>(document);
supplement = newSupplement.get();
provideTo(&document, supplementName(), WTFMove(newSupplement));
}
return supplement;
}
const char* DocumentStorageAccess::supplementName()
{
return "DocumentStorageAccess";
}
void DocumentStorageAccess::hasStorageAccess(Document& document, Ref<DeferredPromise>&& promise)
{
DocumentStorageAccess::from(document)->hasStorageAccess(WTFMove(promise));
}
void DocumentStorageAccess::requestStorageAccess(Document& document, Ref<DeferredPromise>&& promise)
{
DocumentStorageAccess::from(document)->requestStorageAccess(WTFMove(promise));
}
void DocumentStorageAccess::hasStorageAccess(Ref<DeferredPromise>&& promise)
{
ASSERT(m_document.settings().storageAccessAPIEnabled());
auto* frame = m_document.frame();
if (frame && hasFrameSpecificStorageAccess()) {
promise->resolve<IDLBoolean>(true);
return;
}
if (!frame || m_document.securityOrigin().isUnique()) {
promise->resolve<IDLBoolean>(false);
return;
}
if (frame->isMainFrame()) {
promise->resolve<IDLBoolean>(true);
return;
}
auto& securityOrigin = m_document.securityOrigin();
auto& topSecurityOrigin = m_document.topDocument().securityOrigin();
if (securityOrigin.equal(&topSecurityOrigin)) {
promise->resolve<IDLBoolean>(true);
return;
}
auto* page = frame->page();
if (!page) {
promise->reject();
return;
}
auto subFrameDomain = RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host());
auto topFrameDomain = RegistrableDomain::uncheckedCreateFromHost(topSecurityOrigin.host());
page->chrome().client().hasStorageAccess(WTFMove(subFrameDomain), WTFMove(topFrameDomain), *frame, [weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (bool hasAccess) {
if (!weakThis)
return;
promise->resolve<IDLBoolean>(hasAccess);
});
}
void DocumentStorageAccess::requestStorageAccess(Ref<DeferredPromise>&& promise)
{
ASSERT(m_document.settings().storageAccessAPIEnabled());
auto* frame = m_document.frame();
if (frame && hasFrameSpecificStorageAccess()) {
promise->resolve();
return;
}
if (!frame || m_document.securityOrigin().isUnique() || !isAllowedToRequestFrameSpecificStorageAccess()) {
promise->reject();
return;
}
if (frame->isMainFrame()) {
promise->resolve();
return;
}
auto& topDocument = m_document.topDocument();
auto& topSecurityOrigin = topDocument.securityOrigin();
auto& securityOrigin = m_document.securityOrigin();
if (securityOrigin.equal(&topSecurityOrigin)) {
promise->resolve();
return;
}
if (m_document.sandboxFlags() != SandboxNone && m_document.isSandboxed(SandboxStorageAccessByUserActivation)) {
promise->reject();
return;
}
if (&topDocument != m_document.parentDocument()) {
promise->reject();
return;
}
if (!UserGestureIndicator::processingUserGesture()) {
promise->reject();
return;
}
auto* page = frame->page();
if (!page) {
promise->reject();
return;
}
auto subFrameDomain = RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host());
auto topFrameDomain = RegistrableDomain::uncheckedCreateFromHost(topSecurityOrigin.host());
page->chrome().client().requestStorageAccess(WTFMove(subFrameDomain), WTFMove(topFrameDomain), *frame, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (StorageAccessWasGranted wasGranted, StorageAccessPromptWasShown promptWasShown) mutable {
if (!weakThis)
return;
bool shouldPreserveUserGesture = wasGranted == StorageAccessWasGranted::Yes || promptWasShown == StorageAccessPromptWasShown::No;
if (shouldPreserveUserGesture) {
m_document.eventLoop().queueMicrotask([this, weakThis = makeWeakPtr(*weakThis)] {
if (weakThis)
enableTemporaryTimeUserGesture();
});
}
if (wasGranted == StorageAccessWasGranted::Yes)
promise->resolve();
else {
if (promptWasShown == StorageAccessPromptWasShown::Yes)
setWasExplicitlyDeniedFrameSpecificStorageAccess();
promise->reject();
}
if (shouldPreserveUserGesture) {
m_document.eventLoop().queueMicrotask([this, weakThis = makeWeakPtr(*weakThis)] {
if (weakThis)
consumeTemporaryTimeUserGesture();
});
}
});
}
void DocumentStorageAccess::enableTemporaryTimeUserGesture()
{
m_temporaryUserGesture = makeUnique<UserGestureIndicator>(ProcessingUserGesture, &m_document);
}
void DocumentStorageAccess::consumeTemporaryTimeUserGesture()
{
m_temporaryUserGesture = nullptr;
}
bool DocumentStorageAccess::hasFrameSpecificStorageAccess() const
{
auto* frame = m_document.frame();
return frame && frame->loader().client().hasFrameSpecificStorageAccess();
}
}
#endif // ENABLE(RESOURCE_LOAD_STATISTICS)