diff options
Diffstat (limited to 'dom/permission/Permissions.cpp')
-rw-r--r-- | dom/permission/Permissions.cpp | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/dom/permission/Permissions.cpp b/dom/permission/Permissions.cpp new file mode 100644 index 000000000..ddbfc5ffe --- /dev/null +++ b/dom/permission/Permissions.cpp @@ -0,0 +1,181 @@ +/* -*- 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/PermissionsBinding.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/Services.h" +#include "nsIPermissionManager.h" +#include "PermissionUtils.h" + +namespace mozilla { +namespace 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() +{ +} + +JSObject* +Permissions::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +{ + return PermissionsBinding::Wrap(aCx, this, aGivenProto); +} + +namespace { + +already_AddRefed<PermissionStatus> +CreatePermissionStatus(JSContext* aCx, + JS::Handle<JSObject*> aPermission, + nsPIDOMWindowInner* aWindow, + ErrorResult& aRv) +{ + PermissionDescriptor permission; + JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aPermission)); + if (NS_WARN_IF(!permission.Init(aCx, value))) { + aRv.NoteJSContextException(aCx); + return nullptr; + } + + switch (permission.mName) { + case PermissionName::Geolocation: + case PermissionName::Notifications: + case PermissionName::Push: + return PermissionStatus::Create(aWindow, permission.mName, aRv); + + default: + MOZ_ASSERT_UNREACHABLE("Unhandled type"); + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); + return nullptr; + } +} + +} // namespace + +already_AddRefed<Promise> +Permissions::Query(JSContext* aCx, + JS::Handle<JSObject*> aPermission, + ErrorResult& aRv) +{ + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow); + if (!global) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + RefPtr<PermissionStatus> status = + CreatePermissionStatus(aCx, aPermission, mWindow, aRv); + if (NS_WARN_IF(aRv.Failed())) { + MOZ_ASSERT(!status); + return nullptr; + } + + MOZ_ASSERT(status); + RefPtr<Promise> promise = Promise::Create(global, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + promise->MaybeResolve(status); + return promise.forget(); +} + +/* static */ nsresult +Permissions::RemovePermission(nsIPrincipal* aPrincipal, const char* aPermissionType) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager(); + if (NS_WARN_IF(!permMgr)) { + return NS_ERROR_FAILURE; + } + + return permMgr->RemoveFromPrincipal(aPrincipal, aPermissionType); +} + +already_AddRefed<Promise> +Permissions::Revoke(JSContext* aCx, + JS::Handle<JSObject*> aPermission, + ErrorResult& aRv) +{ + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow); + if (!global) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + PermissionDescriptor permission; + JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aPermission)); + if (NS_WARN_IF(!permission.Init(aCx, value))) { + aRv.NoteJSContextException(aCx); + return nullptr; + } + + RefPtr<Promise> promise = Promise::Create(global, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + nsCOMPtr<nsIDocument> document = mWindow->GetExtantDoc(); + if (!document) { + promise->MaybeReject(NS_ERROR_UNEXPECTED); + return promise.forget(); + } + + nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager(); + if (NS_WARN_IF(!permMgr)) { + promise->MaybeReject(NS_ERROR_FAILURE); + return promise.forget(); + } + + const char* 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( + IPC::Principal(document->NodePrincipal()), nsDependentCString(permissionType), &rv); + } + + if (NS_WARN_IF(NS_FAILED(rv))) { + promise->MaybeReject(rv); + return promise.forget(); + } + + RefPtr<PermissionStatus> 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 dom +} // namespace mozilla |