From 2aa4a82499d4becd2284cdb482213d541b8804dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 16:29:10 +0200 Subject: Adding upstream version 86.0.1. Signed-off-by: Daniel Baumann --- dom/events/Clipboard.cpp | 216 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 dom/events/Clipboard.cpp (limited to 'dom/events/Clipboard.cpp') diff --git a/dom/events/Clipboard.cpp b/dom/events/Clipboard.cpp new file mode 100644 index 0000000000..1f9efdc2cf --- /dev/null +++ b/dom/events/Clipboard.cpp @@ -0,0 +1,216 @@ +/* -*- 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/AbstractThread.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/dom/Clipboard.h" +#include "mozilla/dom/ClipboardBinding.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/DataTransfer.h" +#include "mozilla/dom/DataTransferItemList.h" +#include "mozilla/dom/DataTransferItem.h" +#include "mozilla/dom/Document.h" +#include "mozilla/StaticPrefs_dom.h" +#include "nsIClipboard.h" +#include "nsComponentManagerUtils.h" +#include "nsContentUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsITransferable.h" +#include "nsArrayUtils.h" + +static mozilla::LazyLogModule gClipboardLog("Clipboard"); + +namespace mozilla::dom { + +Clipboard::Clipboard(nsPIDOMWindowInner* aWindow) + : DOMEventTargetHelper(aWindow) {} + +Clipboard::~Clipboard() = default; + +already_AddRefed Clipboard::ReadHelper( + nsIPrincipal& aSubjectPrincipal, ClipboardReadType aClipboardReadType, + ErrorResult& aRv) { + // Create a new promise + RefPtr p = dom::Promise::Create(GetOwnerGlobal(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + // We want to disable security check for automated tests that have the pref + // dom.events.testing.asyncClipboard set to true + if (!IsTestingPrefEnabled() && + !nsContentUtils::PrincipalHasPermission(aSubjectPrincipal, + nsGkAtoms::clipboardRead)) { + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("Clipboard, ReadHelper, " + "Don't have permissions for reading\n")); + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + // Want isExternal = true in order to use the data transfer object to perform + // a read + RefPtr dataTransfer = new DataTransfer( + this, ePaste, /* is external */ true, nsIClipboard::kGlobalClipboard); + + // Create a new runnable + RefPtr r = NS_NewRunnableFunction( + "Clipboard::Read", + [p, dataTransfer, &aSubjectPrincipal, aClipboardReadType]() { + IgnoredErrorResult ier; + switch (aClipboardReadType) { + case eRead: + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("Clipboard, ReadHelper, read case\n")); + dataTransfer->FillAllExternalData(); + // If there are items on the clipboard, data transfer will contain + // those, else, data transfer will be empty and we will be resolving + // with an empty data transfer + p->MaybeResolve(dataTransfer); + break; + case eReadText: + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("Clipboard, ReadHelper, read text case\n")); + nsAutoString str; + dataTransfer->GetData(NS_LITERAL_STRING_FROM_CSTRING(kTextMime), + str, aSubjectPrincipal, ier); + // Either resolve with a string extracted from data transfer item + // or resolve with an empty string if nothing was found + p->MaybeResolve(str); + break; + } + }); + // Dispatch the runnable + GetParentObject()->Dispatch(TaskCategory::Other, r.forget()); + return p.forget(); +} + +already_AddRefed Clipboard::Read(nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) { + return ReadHelper(aSubjectPrincipal, eRead, aRv); +} + +already_AddRefed Clipboard::ReadText(nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) { + return ReadHelper(aSubjectPrincipal, eReadText, aRv); +} + +already_AddRefed Clipboard::Write(DataTransfer& aData, + nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) { + // Create a promise + RefPtr p = dom::Promise::Create(GetOwnerGlobal(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + nsPIDOMWindowInner* owner = GetOwner(); + Document* doc = owner ? owner->GetDoc() : nullptr; + + // We want to disable security check for automated tests that have the pref + // dom.events.testing.asyncClipboard set to true + if (!IsTestingPrefEnabled() && + !nsContentUtils::IsCutCopyAllowed(doc, aSubjectPrincipal)) { + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("Clipboard, Write, Not allowed to write to clipboard\n")); + p->MaybeRejectWithNotAllowedError( + "Clipboard write was blocked due to lack of user activation."); + return p.forget(); + } + + // Get the clipboard service + nsCOMPtr clipboard( + do_GetService("@mozilla.org/widget/clipboard;1")); + if (!clipboard) { + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + nsILoadContext* context = doc ? doc->GetLoadContext() : nullptr; + if (!context) { + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + // Get the transferable + RefPtr transferable = aData.GetTransferable(0, context); + if (!transferable) { + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + // Create a runnable + RefPtr r = NS_NewRunnableFunction( + "Clipboard::Write", [transferable, p, clipboard]() { + nsresult rv = + clipboard->SetData(transferable, + /* owner of the transferable */ nullptr, + nsIClipboard::kGlobalClipboard); + if (NS_FAILED(rv)) { + p->MaybeRejectWithUndefined(); + return; + } + p->MaybeResolveWithUndefined(); + return; + }); + // Dispatch the runnable + GetParentObject()->Dispatch(TaskCategory::Other, r.forget()); + return p.forget(); +} + +already_AddRefed Clipboard::WriteText(const nsAString& aData, + nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) { + // We create a data transfer with text/plain format so that + // we can reuse Clipboard::Write(...) member function + RefPtr dataTransfer = new DataTransfer(this, eCopy, + /* is external */ true, + /* clipboard type */ -1); + dataTransfer->SetData(NS_LITERAL_STRING_FROM_CSTRING(kTextMime), aData, + aSubjectPrincipal, aRv); + return Write(*dataTransfer, aSubjectPrincipal, aRv); +} + +JSObject* Clipboard::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return Clipboard_Binding::Wrap(aCx, this, aGivenProto); +} + +/* static */ +LogModule* Clipboard::GetClipboardLog() { return gClipboardLog; } + +/* static */ +bool Clipboard::ReadTextEnabled(JSContext* aCx, JSObject* aGlobal) { + nsIPrincipal* prin = nsContentUtils::SubjectPrincipal(aCx); + return IsTestingPrefEnabled() || prin->GetIsAddonOrExpandedAddonPrincipal() || + prin->IsSystemPrincipal(); +} + +/* static */ +bool Clipboard::IsTestingPrefEnabled() { + bool clipboardTestingEnabled = + StaticPrefs::dom_events_testing_asyncClipboard_DoNotUseDirectly(); + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("Clipboard, Is testing enabled? %d\n", clipboardTestingEnabled)); + return clipboardTestingEnabled; +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(Clipboard) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Clipboard, + DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Clipboard, DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Clipboard) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(Clipboard, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(Clipboard, DOMEventTargetHelper) + +} // namespace mozilla::dom -- cgit v1.2.3