Bug 1805860 - Add "storage-access" permission to dom::Permissions - r=anti-tracking-reviewers,webidl,saschanaz,pbz,smaug

Differential Revision: https://phabricator.services.mozilla.com/D182246
This commit is contained in:
Benjamin VanderSloot 2023-07-19 14:51:13 +00:00
Родитель 1ac439a64e
Коммит 035109eef7
10 изменённых файлов: 268 добавлений и 3 удалений

Просмотреть файл

@ -18,7 +18,8 @@ static const nsLiteralCString kPermissionTypes[] = {
"persistent-storage"_ns,
// "midi" is the only public permission but internally we have both "midi"
// and "midi-sysex" (and yes, this is confusing).
"midi"_ns
"midi"_ns,
"storage-access"_ns
// clang-format on
};
@ -39,6 +40,12 @@ Maybe<PermissionName> TypeToPermissionName(const nsACString& aType) {
return Some(PermissionName::Midi);
}
// "storage-access" permissions are also annoying and require a special case.
if (StringBeginsWith(aType, "3rdPartyStorage^"_ns) ||
StringBeginsWith(aType, "3rdPartyFrameStorage^"_ns)) {
return Some(PermissionName::Storage_access);
}
for (size_t i = 0; i < ArrayLength(kPermissionTypes); ++i) {
if (kPermissionTypes[i].Equals(aType)) {
return Some(static_cast<PermissionName>(i));

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/dom/PermissionStatus.h"
#include "mozilla/dom/PermissionsBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/StorageAccessPermissionStatus.h"
#include "mozilla/Components.h"
#include "nsIPermissionManager.h"
#include "PermissionUtils.h"
@ -61,6 +62,8 @@ CreatePermissionStatus(JSContext* aCx, JS::Handle<JSObject*> aPermission,
bool sysex = midiPerm.mSysex.WasPassed() && midiPerm.mSysex.Value();
return MidiPermissionStatus::Create(aWindow, sysex);
}
case PermissionName::Storage_access:
return StorageAccessPermissionStatus::Create(aWindow);
case PermissionName::Geolocation:
case PermissionName::Notifications:
case PermissionName::Push:

Просмотреть файл

@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/StorageAccessPermissionStatus.h"
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/PermissionStatus.h"
#include "mozilla/dom/PermissionStatusBinding.h"
namespace mozilla::dom {
// static
RefPtr<PermissionStatus::CreatePromise> StorageAccessPermissionStatus::Create(
nsPIDOMWindowInner* aWindow) {
RefPtr<PermissionStatus> status = new StorageAccessPermissionStatus(aWindow);
return status->Init()->Then(
GetMainThreadSerialEventTarget(), __func__,
[status](nsresult aOk) {
MOZ_ASSERT(NS_SUCCEEDED(aOk));
return MozPromise<RefPtr<PermissionStatus>, nsresult,
true>::CreateAndResolve(status, __func__);
},
[](nsresult aError) {
MOZ_ASSERT(NS_FAILED(aError));
return MozPromise<RefPtr<PermissionStatus>, nsresult,
true>::CreateAndReject(aError, __func__);
});
}
StorageAccessPermissionStatus::StorageAccessPermissionStatus(
nsPIDOMWindowInner* aWindow)
: PermissionStatus(aWindow, PermissionName::Storage_access) {}
RefPtr<PermissionStatus::SimplePromise>
StorageAccessPermissionStatus::UpdateState() {
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
if (NS_WARN_IF(!window)) {
return SimplePromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
WindowGlobalChild* wgc = window->GetWindowGlobalChild();
if (NS_WARN_IF(!wgc)) {
return SimplePromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
RefPtr<StorageAccessPermissionStatus> self(this);
return wgc->SendHasStorageAccessPermission()->Then(
GetMainThreadSerialEventTarget(), __func__,
[self](bool aGranted) {
if (aGranted) {
self->mState = PermissionState::Granted;
} else {
self->mState = PermissionState::Prompt;
}
return SimplePromise::CreateAndResolve(NS_OK, __func__);
},
[](mozilla::ipc::ResponseRejectReason aError) {
return SimplePromise::CreateAndResolve(NS_ERROR_FAILURE, __func__);
});
}
bool StorageAccessPermissionStatus::MaybeUpdatedBy(
nsIPermission* aPermission) const {
return false;
}
bool StorageAccessPermissionStatus::MaybeUpdatedByNotifyOnly(
nsPIDOMWindowInner* aInnerWindow) const {
nsPIDOMWindowInner* owner = GetOwner();
NS_ENSURE_TRUE(owner, false);
NS_ENSURE_TRUE(aInnerWindow, false);
return owner->WindowID() == aInnerWindow->WindowID();
}
} // namespace mozilla::dom

Просмотреть файл

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_StorageAccessPermissionStatus_h_
#define mozilla_dom_StorageAccessPermissionStatus_h_
#include "mozilla/dom/PermissionStatus.h"
namespace mozilla::dom {
class StorageAccessPermissionStatus final : public PermissionStatus {
public:
static RefPtr<CreatePromise> Create(nsPIDOMWindowInner* aWindow);
private:
explicit StorageAccessPermissionStatus(nsPIDOMWindowInner* aWindow);
RefPtr<SimplePromise> UpdateState() override;
bool MaybeUpdatedBy(nsIPermission* aPermission) const override;
bool MaybeUpdatedByNotifyOnly(
nsPIDOMWindowInner* aInnerWindow) const override;
};
} // namespace mozilla::dom
#endif // mozilla_dom_StorageAccessPermissionStatus_h_

Просмотреть файл

@ -11,6 +11,7 @@ EXPORTS.mozilla.dom += [
"MidiPermissionStatus.h",
"Permissions.h",
"PermissionStatus.h",
"StorageAccessPermissionStatus.h",
]
UNIFIED_SOURCES += [
@ -19,6 +20,7 @@ UNIFIED_SOURCES += [
"Permissions.cpp",
"PermissionStatus.cpp",
"PermissionUtils.cpp",
"StorageAccessPermissionStatus.cpp",
]
MOCHITEST_MANIFESTS += ["tests/mochitest.ini"]

Просмотреть файл

@ -0,0 +1,30 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Helper for Permissions API Test</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<script>
'use strict';
async function helper() {
let status = await navigator.permissions
.query({ name: "storage-access" });
status.onchange = () => {
status.onchange = null;
parent.postMessage(status.state, "*")
};
parent.postMessage("ready", "*");
}
</script>
</head>
<body onload="helper()">
</body>
</html>

Просмотреть файл

@ -1,6 +1,7 @@
[DEFAULT]
support-files =
file_empty.html
file_storage_access_notification_helper.html
prefs =
dom.security.featurePolicy.header.enabled=true
dom.security.featurePolicy.webidl.enabled=true
@ -9,3 +10,5 @@ prefs =
fail-if = xorigin
[test_permissions_api.html]
skip-if = xorigin # Hangs
[test_storage_access_notification.html]
skip-if = xorigin # Hangs

Просмотреть файл

@ -106,6 +106,13 @@
type: 'persistent-storage',
expected: 'denied',
},
{
id: 'query storage-access unknown',
top: UNKNOWN_ACTION,
name: 'storage-access',
type: '3rdPartyFrameStorage^https://example.org',
expected: 'prompt',
},
{
id: 'query navigation top prompt',
top: PROMPT_ACTION,
@ -134,6 +141,13 @@
type: 'persistent-storage',
expected: 'denied',
},
{
id: 'query storage-access top prompt',
top: PROMPT_ACTION,
name: 'storage-access',
type: '3rdPartyFrameStorage^https://example.org',
expected: 'prompt',
},
{
id: 'query navigation top denied',
top: DENY_ACTION,
@ -162,6 +176,13 @@
type: 'persistent-storage',
expected: 'denied',
},
{
id: 'query storage-access top denied',
top: DENY_ACTION,
name: 'storage-access',
type: '3rdPartyFrameStorage^https://example.org',
expected: 'prompt',
},
{
id: 'query navigation top granted',
top: ALLOW_ACTION,
@ -190,6 +211,13 @@
type: 'persistent-storage',
expected: 'denied',
},
{
id: 'query storage-access top granted',
top: ALLOW_ACTION,
name: 'storage-access',
type: '3rdPartyFrameStorage^https://example.org',
expected: 'granted',
},
{
id: 'query navigation top denied, iframe has allow attribute',
top: DENY_ACTION,
@ -222,7 +250,38 @@
type: 'geo',
expected: 'prompt',
},
{
id: 'query storage-access top denied, iframe has allow none attribute',
top: DENY_ACTION,
allow: "storage-access 'none'",
name: 'storage-access',
type: '3rdPartyFrameStorage^https://example.org',
expected: 'prompt',
},
{
id: 'query storage-access top granted, iframe has allow none attribute',
top: ALLOW_ACTION,
allow: "storage-access 'none'",
name: 'storage-access',
type: '3rdPartyFrameStorage^https://example.org',
expected: 'prompt',
},
{
id: 'query storage-access top prompt, iframe has allow none attribute',
top: PROMPT_ACTION,
allow: "storage-access 'none'",
name: 'storage-access',
type: '3rdPartyFrameStorage^https://example.org',
expected: 'prompt',
},
{
id: 'query storage-access top unknown, iframe has allow none attribute',
top: UNKNOWN_ACTION,
allow: "storage-access 'none'",
name: 'storage-access',
type: '3rdPartyFrameStorage^https://example.org',
expected: 'prompt',
},
];
SimpleTest.waitForExplicitFinish();

Просмотреть файл

@ -0,0 +1,50 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for Permissions API</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<script type="application/javascript">
'use strict';
SimpleTest.waitForExplicitFinish();
async function setPermission(type, allow) {
await SpecialPowers.popPermissions();
await SpecialPowers.pushPermissions(
[{ type, allow, context: document }]
);
}
const {
UNKNOWN_ACTION,
PROMPT_ACTION,
ALLOW_ACTION,
DENY_ACTION
} = SpecialPowers.Ci.nsIPermissionManager;
window.addEventListener(
"message",
(event) => {
if (event.data == "ready") {
setPermission("3rdPartyFrameStorage^https://example.org", ALLOW_ACTION);
} else {
is(event.data, "granted", "storage-access permission should change to granted after the permission is set");
SimpleTest.finish();
}
}
);
</script>
</head>
<body>
<iframe id="frame" src="https://example.org/tests/dom/permission/tests/file_storage_access_notification_helper.html"/>
</body>
</html>

Просмотреть файл

@ -12,7 +12,8 @@ enum PermissionName {
"notifications",
"push",
"persistent-storage",
"midi"
"midi",
"storage-access" // Defined in https://privacycg.github.io/storage-access/#permissions-integration
};
[GenerateInit]