From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- dom/permission/MidiPermissionStatus.cpp | 34 +++ dom/permission/MidiPermissionStatus.h | 32 +++ dom/permission/PermissionObserver.cpp | 115 ++++++++ dom/permission/PermissionObserver.h | 45 ++++ dom/permission/PermissionStatus.cpp | 142 ++++++++++ dom/permission/PermissionStatus.h | 71 +++++ dom/permission/PermissionUtils.cpp | 65 +++++ dom/permission/PermissionUtils.h | 32 +++ dom/permission/Permissions.cpp | 182 +++++++++++++ dom/permission/Permissions.h | 54 ++++ dom/permission/moz.build | 28 ++ dom/permission/tests/file_empty.html | 2 + dom/permission/tests/mochitest.ini | 11 + dom/permission/tests/test_cross_origin_iframe.html | 251 +++++++++++++++++ dom/permission/tests/test_permissions_api.html | 298 +++++++++++++++++++++ 15 files changed, 1362 insertions(+) create mode 100644 dom/permission/MidiPermissionStatus.cpp create mode 100644 dom/permission/MidiPermissionStatus.h create mode 100644 dom/permission/PermissionObserver.cpp create mode 100644 dom/permission/PermissionObserver.h create mode 100644 dom/permission/PermissionStatus.cpp create mode 100644 dom/permission/PermissionStatus.h create mode 100644 dom/permission/PermissionUtils.cpp create mode 100644 dom/permission/PermissionUtils.h create mode 100644 dom/permission/Permissions.cpp create mode 100644 dom/permission/Permissions.h create mode 100644 dom/permission/moz.build create mode 100644 dom/permission/tests/file_empty.html create mode 100644 dom/permission/tests/mochitest.ini create mode 100644 dom/permission/tests/test_cross_origin_iframe.html create mode 100644 dom/permission/tests/test_permissions_api.html (limited to 'dom/permission') diff --git a/dom/permission/MidiPermissionStatus.cpp b/dom/permission/MidiPermissionStatus.cpp new file mode 100644 index 0000000000..9466989b24 --- /dev/null +++ b/dom/permission/MidiPermissionStatus.cpp @@ -0,0 +1,34 @@ +/* -*- 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/MidiPermissionStatus.h" + +#include "mozilla/dom/PermissionStatus.h" +#include "mozilla/Permission.h" + +namespace mozilla::dom { + +/* static */ +already_AddRefed MidiPermissionStatus::Create( + nsPIDOMWindowInner* aWindow, bool aSysex, ErrorResult& aRv) { + RefPtr status = new MidiPermissionStatus(aWindow, aSysex); + aRv = status->Init(); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return status.forget(); +} + +MidiPermissionStatus::MidiPermissionStatus(nsPIDOMWindowInner* aWindow, + bool aSysex) + : PermissionStatus(aWindow, PermissionName::Midi), mSysex(aSysex) {} + +nsLiteralCString MidiPermissionStatus::GetPermissionType() { + return mSysex ? "midi-sysex"_ns : "midi"_ns; +} + +} // namespace mozilla::dom diff --git a/dom/permission/MidiPermissionStatus.h b/dom/permission/MidiPermissionStatus.h new file mode 100644 index 0000000000..fd0d925c88 --- /dev/null +++ b/dom/permission/MidiPermissionStatus.h @@ -0,0 +1,32 @@ +/* -*- 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_MidiPermissionStatus_h_ +#define mozilla_dom_MidiPermissionStatus_h_ + +#include "mozilla/dom/PermissionStatus.h" + +namespace mozilla::dom { + +class MidiPermissionStatus final : public PermissionStatus { + public: + static already_AddRefed Create(nsPIDOMWindowInner* aWindow, + bool aSysex, + ErrorResult& aRv); + + private: + ~MidiPermissionStatus() {} + + MidiPermissionStatus(nsPIDOMWindowInner* aWindow, bool aSysex); + + virtual nsLiteralCString GetPermissionType() override; + + bool mSysex; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_MidiPermissionStatus_h_ diff --git a/dom/permission/PermissionObserver.cpp b/dom/permission/PermissionObserver.cpp new file mode 100644 index 0000000000..47e1a23918 --- /dev/null +++ b/dom/permission/PermissionObserver.cpp @@ -0,0 +1,115 @@ +/* -*- 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 "PermissionObserver.h" + +#include "mozilla/dom/PermissionStatus.h" +#include "mozilla/Services.h" +#include "mozilla/UniquePtr.h" +#include "nsIObserverService.h" +#include "nsIPermission.h" +#include "PermissionUtils.h" + +namespace mozilla::dom { + +namespace { +PermissionObserver* gInstance = nullptr; +} // namespace + +NS_IMPL_ISUPPORTS(PermissionObserver, nsIObserver, nsISupportsWeakReference) + +PermissionObserver::PermissionObserver() { MOZ_ASSERT(!gInstance); } + +PermissionObserver::~PermissionObserver() { + MOZ_ASSERT(mSinks.IsEmpty()); + MOZ_ASSERT(gInstance == this); + + gInstance = nullptr; +} + +/* static */ +already_AddRefed PermissionObserver::GetInstance() { + RefPtr instance = gInstance; + if (!instance) { + instance = new PermissionObserver(); + + nsCOMPtr obs = services::GetObserverService(); + if (NS_WARN_IF(!obs)) { + return nullptr; + } + + nsresult rv = obs->AddObserver(instance, "perm-changed", true); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + + gInstance = instance; + } + + return instance.forget(); +} + +void PermissionObserver::AddSink(PermissionStatus* aSink) { + MOZ_ASSERT(aSink); + MOZ_ASSERT(!mSinks.Contains(aSink)); + + mSinks.AppendElement(aSink); +} + +void PermissionObserver::RemoveSink(PermissionStatus* aSink) { + MOZ_ASSERT(aSink); + MOZ_ASSERT(mSinks.Contains(aSink)); + + mSinks.RemoveElement(aSink); +} + +void PermissionObserver::Notify(PermissionName aName, + nsIPrincipal& aPrincipal) { + for (auto* sink : mSinks) { + if (sink->mName != aName) { + continue; + } + + nsCOMPtr sinkPrincipal = sink->GetPrincipal(); + if (NS_WARN_IF(!sinkPrincipal) || !aPrincipal.Equals(sinkPrincipal)) { + continue; + } + + sink->PermissionChanged(); + } +} + +NS_IMETHODIMP +PermissionObserver::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) { + MOZ_ASSERT(!strcmp(aTopic, "perm-changed")); + + if (mSinks.IsEmpty()) { + return NS_OK; + } + + nsCOMPtr perm = do_QueryInterface(aSubject); + if (!perm) { + return NS_OK; + } + + nsCOMPtr principal; + perm->GetPrincipal(getter_AddRefs(principal)); + if (!principal) { + return NS_OK; + } + + nsAutoCString type; + perm->GetType(type); + Maybe permission = TypeToPermissionName(type); + if (permission) { + Notify(permission.value(), *principal); + } + + return NS_OK; +} + +} // namespace mozilla::dom diff --git a/dom/permission/PermissionObserver.h b/dom/permission/PermissionObserver.h new file mode 100644 index 0000000000..cc085cc51b --- /dev/null +++ b/dom/permission/PermissionObserver.h @@ -0,0 +1,45 @@ +/* -*- 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_PermissionObserver_h_ +#define mozilla_dom_PermissionObserver_h_ + +#include "mozilla/dom/PermissionsBinding.h" + +#include "nsIObserver.h" +#include "nsIPrincipal.h" +#include "nsTArray.h" +#include "nsWeakReference.h" + +namespace mozilla::dom { + +class PermissionStatus; + +// Singleton that watches for perm-changed notifications in order to notify +// PermissionStatus objects. +class PermissionObserver final : public nsIObserver, + public nsSupportsWeakReference { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + static already_AddRefed GetInstance(); + + void AddSink(PermissionStatus* aObs); + void RemoveSink(PermissionStatus* aObs); + + private: + PermissionObserver(); + virtual ~PermissionObserver(); + + void Notify(PermissionName aName, nsIPrincipal& aPrincipal); + + nsTArray mSinks; +}; + +} // namespace mozilla::dom + +#endif diff --git a/dom/permission/PermissionStatus.cpp b/dom/permission/PermissionStatus.cpp new file mode 100644 index 0000000000..81e69d361c --- /dev/null +++ b/dom/permission/PermissionStatus.cpp @@ -0,0 +1,142 @@ +/* -*- 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/PermissionStatus.h" +#include "mozilla/PermissionDelegateHandler.h" + +#include "mozilla/AsyncEventDispatcher.h" +#include "mozilla/Permission.h" +#include "mozilla/Services.h" +#include "nsIPermissionManager.h" +#include "PermissionObserver.h" +#include "PermissionUtils.h" + +namespace mozilla::dom { + +/* static */ +already_AddRefed PermissionStatus::Create( + nsPIDOMWindowInner* aWindow, PermissionName aName, ErrorResult& aRv) { + RefPtr status = new PermissionStatus(aWindow, aName); + aRv = status->Init(); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return status.forget(); +} + +PermissionStatus::PermissionStatus(nsPIDOMWindowInner* aWindow, + PermissionName aName) + : DOMEventTargetHelper(aWindow), + mName(aName), + mState(PermissionState::Denied) { + KeepAliveIfHasListenersFor(nsGkAtoms::onchange); +} + +nsresult PermissionStatus::Init() { + mObserver = PermissionObserver::GetInstance(); + if (NS_WARN_IF(!mObserver)) { + return NS_ERROR_FAILURE; + } + + mObserver->AddSink(this); + + nsresult rv = UpdateState(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +PermissionStatus::~PermissionStatus() { + if (mObserver) { + mObserver->RemoveSink(this); + } +} + +JSObject* PermissionStatus::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return PermissionStatus_Binding::Wrap(aCx, this, aGivenProto); +} + +nsLiteralCString PermissionStatus::GetPermissionType() { + return PermissionNameToType(mName); +} + +nsresult PermissionStatus::UpdateState() { + nsCOMPtr window = GetOwner(); + if (NS_WARN_IF(!window)) { + return NS_ERROR_FAILURE; + } + + RefPtr document = window->GetExtantDoc(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_FAILURE; + } + + uint32_t action = nsIPermissionManager::DENY_ACTION; + + PermissionDelegateHandler* permissionHandler = + document->GetPermissionDelegateHandler(); + if (NS_WARN_IF(!permissionHandler)) { + return NS_ERROR_FAILURE; + } + + nsresult rv = permissionHandler->GetPermissionForPermissionsAPI( + GetPermissionType(), &action); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mState = ActionToPermissionState(action); + return NS_OK; +} + +already_AddRefed PermissionStatus::GetPrincipal() const { + nsCOMPtr window = GetOwner(); + if (NS_WARN_IF(!window)) { + return nullptr; + } + + Document* doc = window->GetExtantDoc(); + if (NS_WARN_IF(!doc)) { + return nullptr; + } + + nsCOMPtr principal = + Permission::ClonePrincipalForPermission(doc->NodePrincipal()); + NS_ENSURE_TRUE(principal, nullptr); + + return principal.forget(); +} + +void PermissionStatus::PermissionChanged() { + nsCOMPtr window = GetOwner(); + if (NS_WARN_IF(!window) || !window->IsFullyActive()) { + return; + } + auto oldState = mState; + UpdateState(); + if (mState != oldState) { + RefPtr eventDispatcher = + new AsyncEventDispatcher(this, u"change"_ns, CanBubble::eNo); + eventDispatcher->PostDOMEvent(); + } +} + +void PermissionStatus::DisconnectFromOwner() { + IgnoreKeepAliveIfHasListenersFor(nsGkAtoms::onchange); + + if (mObserver) { + mObserver->RemoveSink(this); + mObserver = nullptr; + } + + DOMEventTargetHelper::DisconnectFromOwner(); +} + +} // namespace mozilla::dom diff --git a/dom/permission/PermissionStatus.h b/dom/permission/PermissionStatus.h new file mode 100644 index 0000000000..37b11d42e9 --- /dev/null +++ b/dom/permission/PermissionStatus.h @@ -0,0 +1,71 @@ +/* -*- 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_PermissionStatus_h_ +#define mozilla_dom_PermissionStatus_h_ + +#include "mozilla/dom/PermissionsBinding.h" +#include "mozilla/dom/PermissionStatusBinding.h" +#include "mozilla/DOMEventTargetHelper.h" + +namespace mozilla::dom { + +class PermissionObserver; + +class PermissionStatus : public DOMEventTargetHelper { + friend class PermissionObserver; + + public: + static already_AddRefed Create(nsPIDOMWindowInner* aWindow, + PermissionName aName, + ErrorResult& aRv); + + JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + PermissionState State() const { return mState; } + + IMPL_EVENT_HANDLER(change) + + void DisconnectFromOwner() override; + + PermissionName Name() const { return mName; } + + nsresult Init(); + + protected: + ~PermissionStatus(); + + PermissionStatus(nsPIDOMWindowInner* aWindow, PermissionName aName); + + /** + * This method returns the internal permission type, which should be equal to + * the permission name for all but the MIDI permission because of the SysEx + * support: internally, we have both "midi" and "midi-sysex" permission types + * but we only have a "midi" (public) permission name. + * + * Note: the `MidiPermissionDescriptor` descriptor has an optional `sysex` + * boolean, which is used to determine whether to return "midi" or + * "midi-sysex" for the MIDI permission. + */ + virtual nsLiteralCString GetPermissionType(); + + private: + nsresult UpdateState(); + + already_AddRefed GetPrincipal() const; + + void PermissionChanged(); + + PermissionName mName; + PermissionState mState; + + RefPtr mObserver; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_permissionstatus_h_ diff --git a/dom/permission/PermissionUtils.cpp b/dom/permission/PermissionUtils.cpp new file mode 100644 index 0000000000..51deceee8b --- /dev/null +++ b/dom/permission/PermissionUtils.cpp @@ -0,0 +1,65 @@ +/* -*- 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 "PermissionUtils.h" +#include "nsIPermissionManager.h" + +namespace mozilla::dom { + +static const nsLiteralCString kPermissionTypes[] = { + // clang-format off + "geo"_ns, + "desktop-notification"_ns, + // Alias `push` to `desktop-notification`. + "desktop-notification"_ns, + "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 + // clang-format on +}; + +const size_t kPermissionNameCount = PermissionNameValues::Count; + +static_assert(MOZ_ARRAY_LENGTH(kPermissionTypes) == kPermissionNameCount, + "kPermissionTypes and PermissionName count should match"); + +const nsLiteralCString& PermissionNameToType(PermissionName aName) { + MOZ_ASSERT((size_t)aName < ArrayLength(kPermissionTypes)); + return kPermissionTypes[static_cast(aName)]; +} + +Maybe TypeToPermissionName(const nsACString& aType) { + // Annoyingly, "midi-sysex" is an internal permission. The public permission + // name is "midi" so we have to special-case it here... + if (aType.Equals("midi-sysex"_ns)) { + return Some(PermissionName::Midi); + } + + for (size_t i = 0; i < ArrayLength(kPermissionTypes); ++i) { + if (kPermissionTypes[i].Equals(aType)) { + return Some(static_cast(i)); + } + } + + return Nothing(); +} + +PermissionState ActionToPermissionState(uint32_t aAction) { + switch (aAction) { + case nsIPermissionManager::ALLOW_ACTION: + return PermissionState::Granted; + + case nsIPermissionManager::DENY_ACTION: + return PermissionState::Denied; + + default: + case nsIPermissionManager::PROMPT_ACTION: + return PermissionState::Prompt; + } +} + +} // namespace mozilla::dom diff --git a/dom/permission/PermissionUtils.h b/dom/permission/PermissionUtils.h new file mode 100644 index 0000000000..18b176f7f6 --- /dev/null +++ b/dom/permission/PermissionUtils.h @@ -0,0 +1,32 @@ +/* -*- 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_PermissionUtils_h_ +#define mozilla_dom_PermissionUtils_h_ + +#include "mozilla/dom/PermissionsBinding.h" +#include "mozilla/dom/PermissionStatusBinding.h" +#include "mozilla/Maybe.h" + +namespace mozilla::dom { + +const nsLiteralCString& PermissionNameToType(PermissionName aName); + +/** + * Returns the permission name given a permission type. + * + * Note: the "midi" permission is implemented with two internal permissions + * ("midi" and "midi-sysex"). For this reason, when we pass "midi-sysex" to + * this function, it unconditionally returns the "midi" permission name, + * because that's the only public permission name. + */ +Maybe TypeToPermissionName(const nsACString& aType); + +PermissionState ActionToPermissionState(uint32_t aAction); + +} // namespace mozilla::dom + +#endif diff --git a/dom/permission/Permissions.cpp b/dom/permission/Permissions.cpp new file mode 100644 index 0000000000..571dec7630 --- /dev/null +++ b/dom/permission/Permissions.cpp @@ -0,0 +1,182 @@ +/* -*- 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/Permissions.h" + +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/Document.h" +#include "mozilla/dom/MidiPermissionStatus.h" +#include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/dom/PermissionStatus.h" +#include "mozilla/dom/PermissionsBinding.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/Components.h" +#include "nsIPermissionManager.h" +#include "PermissionUtils.h" + +namespace mozilla::dom { + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Permissions) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(Permissions) +NS_IMPL_CYCLE_COLLECTING_RELEASE(Permissions) + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Permissions, mWindow) + +Permissions::Permissions(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {} + +Permissions::~Permissions() = default; + +JSObject* Permissions::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return Permissions_Binding::Wrap(aCx, this, aGivenProto); +} + +namespace { + +already_AddRefed CreatePermissionStatus( + JSContext* aCx, JS::Handle aPermission, + nsPIDOMWindowInner* aWindow, ErrorResult& aRv) { + PermissionDescriptor permission; + JS::Rooted value(aCx, JS::ObjectOrNullValue(aPermission)); + if (NS_WARN_IF(!permission.Init(aCx, value))) { + aRv.NoteJSContextException(aCx); + return nullptr; + } + + switch (permission.mName) { + case PermissionName::Midi: { + MidiPermissionDescriptor midiPerm; + if (NS_WARN_IF(!midiPerm.Init(aCx, value))) { + aRv.NoteJSContextException(aCx); + return nullptr; + } + + bool sysex = midiPerm.mSysex.WasPassed() && midiPerm.mSysex.Value(); + return MidiPermissionStatus::Create(aWindow, sysex, aRv); + } + case PermissionName::Geolocation: + case PermissionName::Notifications: + case PermissionName::Push: + case PermissionName::Persistent_storage: + return PermissionStatus::Create(aWindow, permission.mName, aRv); + + default: + MOZ_ASSERT_UNREACHABLE("Unhandled type"); + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); + return nullptr; + } +} + +} // namespace + +already_AddRefed Permissions::Query(JSContext* aCx, + JS::Handle aPermission, + ErrorResult& aRv) { + if (!mWindow || !mWindow->IsFullyActive()) { + aRv.ThrowInvalidStateError("The document is not fully active."); + return nullptr; + } + + RefPtr status = + CreatePermissionStatus(aCx, aPermission, mWindow, aRv); + if (NS_WARN_IF(aRv.Failed())) { + MOZ_ASSERT(!status); + return nullptr; + } + + MOZ_ASSERT(status); + RefPtr promise = Promise::Create(mWindow->AsGlobal(), aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + promise->MaybeResolve(status); + return promise.forget(); +} + +/* static */ +nsresult Permissions::RemovePermission(nsIPrincipal* aPrincipal, + const nsACString& aPermissionType) { + MOZ_ASSERT(XRE_IsParentProcess()); + + nsCOMPtr permMgr = + components::PermissionManager::Service(); + if (NS_WARN_IF(!permMgr)) { + return NS_ERROR_FAILURE; + } + + return permMgr->RemoveFromPrincipal(aPrincipal, aPermissionType); +} + +already_AddRefed Permissions::Revoke(JSContext* aCx, + JS::Handle aPermission, + ErrorResult& aRv) { + if (!mWindow) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + PermissionDescriptor permission; + JS::Rooted value(aCx, JS::ObjectOrNullValue(aPermission)); + if (NS_WARN_IF(!permission.Init(aCx, value))) { + aRv.NoteJSContextException(aCx); + return nullptr; + } + + RefPtr promise = Promise::Create(mWindow->AsGlobal(), aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + nsCOMPtr document = mWindow->GetExtantDoc(); + if (!document) { + promise->MaybeReject(NS_ERROR_UNEXPECTED); + return promise.forget(); + } + + nsCOMPtr permMgr = + components::PermissionManager::Service(); + if (NS_WARN_IF(!permMgr)) { + promise->MaybeReject(NS_ERROR_FAILURE); + return promise.forget(); + } + + const nsLiteralCString& permissionType = + PermissionNameToType(permission.mName); + + nsresult rv; + if (XRE_IsParentProcess()) { + rv = RemovePermission(document->NodePrincipal(), permissionType); + } else { + // Permissions can't be removed from the content process. Send a message + // to the parent; `ContentParent::RecvRemovePermission` will call + // `RemovePermission`. + ContentChild::GetSingleton()->SendRemovePermission( + document->NodePrincipal(), permissionType, &rv); + } + + if (NS_WARN_IF(NS_FAILED(rv))) { + promise->MaybeReject(rv); + return promise.forget(); + } + + RefPtr status = + CreatePermissionStatus(aCx, aPermission, mWindow, aRv); + if (NS_WARN_IF(aRv.Failed())) { + MOZ_ASSERT(!status); + return nullptr; + } + + MOZ_ASSERT(status); + promise->MaybeResolve(status); + return promise.forget(); +} + +} // namespace mozilla::dom diff --git a/dom/permission/Permissions.h b/dom/permission/Permissions.h new file mode 100644 index 0000000000..f974fa49a9 --- /dev/null +++ b/dom/permission/Permissions.h @@ -0,0 +1,54 @@ +/* -*- 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_Permissions_h_ +#define mozilla_dom_Permissions_h_ + +#include "nsISupports.h" +#include "nsPIDOMWindow.h" +#include "nsWrapperCache.h" + +namespace mozilla { + +class ErrorResult; + +namespace dom { + +class Promise; + +class Permissions final : public nsISupports, public nsWrapperCache { + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Permissions) + + explicit Permissions(nsPIDOMWindowInner* aWindow); + + nsPIDOMWindowInner* GetParentObject() const { return mWindow; } + + JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + already_AddRefed Query(JSContext* aCx, + JS::Handle aPermission, + ErrorResult& aRv); + + static nsresult RemovePermission(nsIPrincipal* aPrincipal, + const nsACString& aPermissionType); + + already_AddRefed Revoke(JSContext* aCx, + JS::Handle aPermission, + ErrorResult& aRv); + + private: + ~Permissions(); + + nsCOMPtr mWindow; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_permissions_h_ diff --git a/dom/permission/moz.build b/dom/permission/moz.build new file mode 100644 index 0000000000..7e00baca04 --- /dev/null +++ b/dom/permission/moz.build @@ -0,0 +1,28 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +with Files("**"): + BUG_COMPONENT = ("Core", "DOM: Core & HTML") + +EXPORTS.mozilla.dom += [ + "MidiPermissionStatus.h", + "Permissions.h", + "PermissionStatus.h", +] + +UNIFIED_SOURCES += [ + "MidiPermissionStatus.cpp", + "PermissionObserver.cpp", + "Permissions.cpp", + "PermissionStatus.cpp", + "PermissionUtils.cpp", +] + +MOCHITEST_MANIFESTS += ["tests/mochitest.ini"] + +FINAL_LIBRARY = "xul" + +include("/ipc/chromium/chromium-config.mozbuild") diff --git a/dom/permission/tests/file_empty.html b/dom/permission/tests/file_empty.html new file mode 100644 index 0000000000..15648ec5aa --- /dev/null +++ b/dom/permission/tests/file_empty.html @@ -0,0 +1,2 @@ +

I'm just a support file

+

I get loaded to do permission testing.

diff --git a/dom/permission/tests/mochitest.ini b/dom/permission/tests/mochitest.ini new file mode 100644 index 0000000000..fb631736f6 --- /dev/null +++ b/dom/permission/tests/mochitest.ini @@ -0,0 +1,11 @@ +[DEFAULT] +support-files = + file_empty.html +prefs = + dom.security.featurePolicy.header.enabled=true + dom.security.featurePolicy.webidl.enabled=true + +[test_cross_origin_iframe.html] +fail-if = xorigin +[test_permissions_api.html] +skip-if = xorigin # Hangs diff --git a/dom/permission/tests/test_cross_origin_iframe.html b/dom/permission/tests/test_cross_origin_iframe.html new file mode 100644 index 0000000000..b024592e75 --- /dev/null +++ b/dom/permission/tests/test_cross_origin_iframe.html @@ -0,0 +1,251 @@ + + + + + + + Test for Permissions API + + + + + +

+  
+
+
+
diff --git a/dom/permission/tests/test_permissions_api.html b/dom/permission/tests/test_permissions_api.html
new file mode 100644
index 0000000000..bef0b56a03
--- /dev/null
+++ b/dom/permission/tests/test_permissions_api.html
@@ -0,0 +1,298 @@
+
+
+
+
+
+  
+  Test for Permissions API
+  
+  
+
+
+
+  

+  
+
+
+
-- 
cgit v1.2.3