зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1871135 - Add content analysis support to clipboard operations r=edgar,nika,masayuki,devtools-reviewers
When content analysis is on, pastes will be checked by the CA agent while tab input is blocked. The synchronous nsIClipboard.getData() method must block until the analysis result is received, so this requires doing a SpinEventLoopUntil. Differential Revision: https://phabricator.services.mozilla.com/D196997
This commit is contained in:
Родитель
068080982b
Коммит
5a2f92686a
|
@ -21,6 +21,7 @@
|
|||
#include "imgIContainer.h"
|
||||
#include "imgITools.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsGlobalWindowInner.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
@ -172,7 +173,15 @@ void DataTransferItem::FillInExternalData() {
|
|||
return;
|
||||
}
|
||||
|
||||
nsresult rv = clipboard->GetData(trans, mDataTransfer->ClipboardType());
|
||||
nsCOMPtr<nsIGlobalObject> global = mDataTransfer->GetGlobal();
|
||||
WindowContext* windowContext = nullptr;
|
||||
if (global) {
|
||||
const auto* innerWindow = global->GetAsInnerWindow();
|
||||
windowContext = innerWindow ? innerWindow->GetWindowContext() : nullptr;
|
||||
}
|
||||
MOZ_ASSERT(windowContext);
|
||||
nsresult rv = clipboard->GetData(trans, mDataTransfer->ClipboardType(),
|
||||
windowContext);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -197,6 +197,7 @@
|
|||
#include "nsICaptivePortalService.h"
|
||||
#include "nsICertOverrideService.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsIContentAnalysis.h"
|
||||
#include "nsIContentProcess.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsICookie.h"
|
||||
|
@ -3462,8 +3463,23 @@ static Result<nsCOMPtr<nsITransferable>, nsresult> CreateTransferable(
|
|||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvGetClipboard(
|
||||
nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
|
||||
const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
|
||||
IPCTransferableData* aTransferableData) {
|
||||
nsresult rv;
|
||||
// We expect content processes to always pass a non-null window so Content
|
||||
// Analysis can analyze it. (if Content Analysis is active)
|
||||
// There may be some cases when a window is closing, etc., in
|
||||
// which case returning no clipboard content should not be a problem.
|
||||
if (aRequestingWindowContext.IsDiscarded()) {
|
||||
NS_WARNING(
|
||||
"discarded window passed to RecvGetClipboard(); returning no clipboard "
|
||||
"content");
|
||||
return IPC_OK();
|
||||
}
|
||||
if (aRequestingWindowContext.IsNull()) {
|
||||
return IPC_FAIL(this, "passed null window to RecvGetClipboard()");
|
||||
}
|
||||
RefPtr<WindowGlobalParent> window = aRequestingWindowContext.get_canonical();
|
||||
// Retrieve clipboard
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -3478,7 +3494,7 @@ mozilla::ipc::IPCResult ContentParent::RecvGetClipboard(
|
|||
|
||||
// Get data from clipboard
|
||||
nsCOMPtr<nsITransferable> trans = result.unwrap();
|
||||
clipboard->GetData(trans, aWhichClipboard);
|
||||
clipboard->GetData(trans, aWhichClipboard, window);
|
||||
|
||||
nsContentUtils::TransferableToIPCTransferableData(
|
||||
trans, aTransferableData, true /* aInSyncMessage */, this);
|
||||
|
|
|
@ -955,6 +955,7 @@ class ContentParent final : public PContentParent,
|
|||
|
||||
mozilla::ipc::IPCResult RecvGetClipboard(
|
||||
nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
|
||||
const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
|
||||
IPCTransferableData* aTransferableData);
|
||||
|
||||
mozilla::ipc::IPCResult RecvEmptyClipboard(const int32_t& aWhichClipboard);
|
||||
|
|
|
@ -1220,7 +1220,10 @@ parent:
|
|||
|
||||
// Given a list of supported types, returns the clipboard data for the
|
||||
// first type that matches.
|
||||
sync GetClipboard(nsCString[] aTypes, int32_t aWhichClipboard)
|
||||
// aRequestingWindowContext is the window that is requesting the clipboard,
|
||||
// which is used for content analysis.
|
||||
sync GetClipboard(nsCString[] aTypes, int32_t aWhichClipboard,
|
||||
MaybeDiscardedWindowContext aRequestingWindowContext)
|
||||
returns (IPCTransferableData transferableData);
|
||||
|
||||
// Returns a list of formats supported by the clipboard
|
||||
|
|
|
@ -2323,7 +2323,12 @@ nsresult HTMLEditor::PasteInternal(int32_t aClipboardType) {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Get the Data from the clipboard
|
||||
rv = clipboard->GetData(transferable, aClipboardType);
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("No window context");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = clipboard->GetData(transferable, aClipboardType, windowContext);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsIClipboard::GetData() failed");
|
||||
return rv;
|
||||
|
@ -2357,7 +2362,8 @@ nsresult HTMLEditor::PasteInternal(int32_t aClipboardType) {
|
|||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"nsITransferable::AddDataFlavor(kHTMLContext) failed, but ignored");
|
||||
rvIgnored = clipboard->GetData(contextTransferable, aClipboardType);
|
||||
rvIgnored =
|
||||
clipboard->GetData(contextTransferable, aClipboardType, windowContext);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"nsIClipboard::GetData() failed, but ignored");
|
||||
nsCOMPtr<nsISupports> contextDataObj;
|
||||
|
@ -2387,7 +2393,9 @@ nsresult HTMLEditor::PasteInternal(int32_t aClipboardType) {
|
|||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"nsITransferable::AddDataFlavor(kHTMLInfo) failed, but ignored");
|
||||
clipboard->GetData(infoTransferable, aClipboardType);
|
||||
|
||||
rvIgnored =
|
||||
clipboard->GetData(infoTransferable, aClipboardType, windowContext);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"nsIClipboard::GetData() failed, but ignored");
|
||||
nsCOMPtr<nsISupports> infoDataObj;
|
||||
|
@ -2553,6 +2561,11 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
|||
NS_WARNING("Editor didn't have document, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("Editor didn't have document window context, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Result<nsCOMPtr<nsITransferable>, nsresult> maybeTransferable =
|
||||
EditorUtils::CreateTransferableForPlainText(*GetDocument());
|
||||
|
@ -2573,7 +2586,7 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
|||
}
|
||||
|
||||
// Get the Data from the clipboard
|
||||
rv = clipboard->GetData(transferable, aClipboardType);
|
||||
rv = clipboard->GetData(transferable, aClipboardType, windowContext);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsIClipboard::GetData() failed");
|
||||
return rv;
|
||||
|
@ -2817,6 +2830,12 @@ nsresult HTMLEditor::PasteAsPlaintextQuotation(int32_t aSelectionType) {
|
|||
}
|
||||
|
||||
RefPtr<Document> destdoc = GetDocument();
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("Editor didn't have document window context");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsILoadContext* loadContext = destdoc ? destdoc->GetLoadContext() : nullptr;
|
||||
DebugOnly<nsresult> rvIgnored = transferable->Init(loadContext);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
|
@ -2829,7 +2848,7 @@ nsresult HTMLEditor::PasteAsPlaintextQuotation(int32_t aSelectionType) {
|
|||
"nsITransferable::AddDataFlavor(kTextMime) failed, but ignored");
|
||||
|
||||
// Get the Data from the clipboard
|
||||
rvIgnored = clipboard->GetData(transferable, aSelectionType);
|
||||
rvIgnored = clipboard->GetData(transferable, aSelectionType, windowContext);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"nsIClipboard::GetData() failed, but ignored");
|
||||
|
||||
|
|
|
@ -599,8 +599,13 @@ nsresult TextEditor::HandlePasteAsQuotation(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("Editor didn't have document window context");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Get the Data from the clipboard
|
||||
clipboard->GetData(trans, aClipboardType);
|
||||
rv = clipboard->GetData(trans, aClipboardType, windowContext);
|
||||
|
||||
// Now we ask the transferable for the data
|
||||
// it still owns the data, we just have a pointer to it.
|
||||
|
|
|
@ -193,7 +193,13 @@ nsresult TextEditor::HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
|||
return NS_OK; // XXX Why?
|
||||
}
|
||||
// Get the Data from the clipboard.
|
||||
rv = clipboard->GetData(transferable, aClipboardType);
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("Editor didn't have document window context");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = clipboard->GetData(transferable, aClipboardType, windowContext);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsIClipboard::GetData() failed, but ignored");
|
||||
return NS_OK; // XXX Why?
|
||||
|
|
|
@ -128,8 +128,9 @@ ContentAnalysisRequest::GetFilePath(nsAString& aFilePath) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentAnalysisRequest::GetUrl(nsAString& aUrl) {
|
||||
aUrl = mUrl;
|
||||
ContentAnalysisRequest::GetUrl(nsIURI** aUrl) {
|
||||
NS_ENSURE_ARG_POINTER(aUrl);
|
||||
NS_IF_ADDREF(*aUrl = mUrl);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -196,8 +197,8 @@ nsresult ContentAnalysis::CreateContentAnalysisClient(nsCString&& aPipePathName,
|
|||
|
||||
ContentAnalysisRequest::ContentAnalysisRequest(
|
||||
AnalysisType aAnalysisType, nsString aString, bool aStringIsFilePath,
|
||||
nsCString aSha256Digest, nsString aUrl, OperationType aOperationType,
|
||||
dom::WindowGlobalParent* aWindowGlobalParent)
|
||||
nsCString aSha256Digest, nsCOMPtr<nsIURI> aUrl,
|
||||
OperationType aOperationType, dom::WindowGlobalParent* aWindowGlobalParent)
|
||||
: mAnalysisType(aAnalysisType),
|
||||
mUrl(std::move(aUrl)),
|
||||
mSha256Digest(std::move(aSha256Digest)),
|
||||
|
@ -296,11 +297,14 @@ static nsresult ConvertToProtobuf(
|
|||
|
||||
auto* requestData = aOut->mutable_request_data();
|
||||
|
||||
nsString url;
|
||||
rv = aIn->GetUrl(url);
|
||||
nsCOMPtr<nsIURI> url;
|
||||
rv = aIn->GetUrl(getter_AddRefs(url));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!url.IsEmpty()) {
|
||||
requestData->set_url(NS_ConvertUTF16toUTF8(url).get());
|
||||
nsCString urlString;
|
||||
rv = url->GetSpec(urlString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!urlString.IsEmpty()) {
|
||||
requestData->set_url(urlString.get());
|
||||
}
|
||||
|
||||
nsString email;
|
||||
|
@ -635,9 +639,12 @@ NS_IMETHODIMP ContentAnalysisResult::GetShouldAllowContent(
|
|||
bool* aShouldAllowContent) {
|
||||
if (mValue.is<NoContentAnalysisResult>()) {
|
||||
NoContentAnalysisResult result = mValue.as<NoContentAnalysisResult>();
|
||||
// Note that we allow content if we're unable to get it (for example, if
|
||||
// there's clipboard content that is not text or file)
|
||||
*aShouldAllowContent =
|
||||
result == NoContentAnalysisResult::AGENT_NOT_PRESENT ||
|
||||
result == NoContentAnalysisResult::NO_PARENT_BROWSER;
|
||||
result == NoContentAnalysisResult::NO_PARENT_BROWSER ||
|
||||
result == NoContentAnalysisResult::ERROR_COULD_NOT_GET_DATA;
|
||||
} else {
|
||||
*aShouldAllowContent =
|
||||
ShouldAllowAction(mValue.as<nsIContentAnalysisResponse::Action>());
|
||||
|
@ -997,8 +1004,7 @@ ContentAnalysis::AnalyzeContentRequestCallback(
|
|||
mozilla::services::GetObserverService();
|
||||
obsServ->NotifyObservers(aRequest, "dlp-request-made", nullptr);
|
||||
|
||||
rv = RunAnalyzeRequestTask(aRequest, aAutoAcknowledge, aCallback);
|
||||
return rv;
|
||||
return RunAnalyzeRequestTask(aRequest, aAutoAcknowledge, aCallback);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -31,7 +31,7 @@ class ContentAnalysisRequest final : public nsIContentAnalysisRequest {
|
|||
|
||||
ContentAnalysisRequest(AnalysisType aAnalysisType, nsString aString,
|
||||
bool aStringIsFilePath, nsCString aSha256Digest,
|
||||
nsString aUrl, OperationType aOperationType,
|
||||
nsCOMPtr<nsIURI> aUrl, OperationType aOperationType,
|
||||
dom::WindowGlobalParent* aWindowGlobalParent);
|
||||
static nsresult GetFileDigest(const nsAString& aFilePath,
|
||||
nsCString& aDigestString);
|
||||
|
@ -53,7 +53,7 @@ class ContentAnalysisRequest final : public nsIContentAnalysisRequest {
|
|||
|
||||
// The URL containing the file download/upload or to which web content is
|
||||
// being uploaded.
|
||||
nsString mUrl;
|
||||
nsCOMPtr<nsIURI> mUrl;
|
||||
|
||||
// Sha256 digest of file.
|
||||
nsCString mSha256Digest;
|
||||
|
|
|
@ -83,6 +83,15 @@ class ContentAnalysisResult : public nsIContentAnalysisResult {
|
|||
return FromNoResult(NoContentAnalysisResult::ERROR_INVALID_JSON_RESPONSE);
|
||||
}
|
||||
|
||||
static RefPtr<ContentAnalysisResult> FromContentAnalysisResponse(
|
||||
nsIContentAnalysisResponse* aResponse) {
|
||||
if (aResponse->GetShouldAllowContent()) {
|
||||
return FromAction(nsIContentAnalysisResponse::Action::eAllow);
|
||||
} else {
|
||||
return FromAction(nsIContentAnalysisResponse::Action::eBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
explicit ContentAnalysisResult(nsIContentAnalysisResponse::Action aAction)
|
||||
: mValue(aAction) {}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIURI;
|
||||
webidl WindowGlobalParent;
|
||||
|
||||
[scriptable, uuid(06e6a60f-3a2b-41fa-a63b-fea7a7f71649)]
|
||||
|
@ -132,7 +133,7 @@ interface nsIContentAnalysisRequest : nsISupports
|
|||
|
||||
// The URL containing the file download/upload or to which web content is
|
||||
// being uploaded.
|
||||
readonly attribute AString url;
|
||||
readonly attribute nsIURI url;
|
||||
|
||||
// Sha256 digest of file. Callers may pass in an empty string to have the
|
||||
// content analysis code calculate this.
|
||||
|
@ -172,7 +173,7 @@ interface nsIContentAnalysis : nsISupports
|
|||
* True if content analysis should be consulted. Must only be accessed from
|
||||
* the parent process's main thread.
|
||||
*/
|
||||
readonly attribute bool isActive;
|
||||
readonly attribute boolean isActive;
|
||||
|
||||
/**
|
||||
* True if content analysis might be active, and False if content analysis
|
||||
|
|
|
@ -159,7 +159,7 @@ function commonDialogOnLoad() {
|
|||
resources: [],
|
||||
analysisType: Ci.nsIContentAnalysisRequest.eBulkDataEntry,
|
||||
operationTypeForDisplay: Ci.nsIContentAnalysisRequest.eClipboard,
|
||||
url: args.owningBrowsingContext.currentURI.spec,
|
||||
url: args.owningBrowsingContext.currentURI,
|
||||
textContent: data,
|
||||
windowGlobalParent:
|
||||
args.owningBrowsingContext.currentWindowContext,
|
||||
|
|
|
@ -5,21 +5,27 @@
|
|||
|
||||
#include "nsBaseClipboard.h"
|
||||
|
||||
#include "ContentAnalysis.h"
|
||||
#include "mozilla/contentanalysis/ContentAnalysisIPCTypes.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/dom/WindowContext.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/MoveOnlyFunction.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/SpinEventLoopUntil.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/StaticPrefs_widget.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsIClipboardOwner.h"
|
||||
#include "nsIPromptService.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsError.h"
|
||||
#include "nsXPCOM.h"
|
||||
|
||||
|
@ -53,11 +59,13 @@ class UserConfirmationRequest final
|
|||
UserConfirmationRequest(int32_t aClipboardType,
|
||||
Document* aRequestingChromeDocument,
|
||||
nsIPrincipal* aRequestingPrincipal,
|
||||
nsBaseClipboard* aClipboard)
|
||||
nsBaseClipboard* aClipboard,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext)
|
||||
: mClipboardType(aClipboardType),
|
||||
mRequestingChromeDocument(aRequestingChromeDocument),
|
||||
mRequestingPrincipal(aRequestingPrincipal),
|
||||
mClipboard(aClipboard) {
|
||||
mClipboard(aClipboard),
|
||||
mRequestingWindowContext(aRequestingWindowContext) {
|
||||
MOZ_ASSERT(
|
||||
mClipboard->nsIClipboard::IsClipboardTypeSupported(aClipboardType));
|
||||
}
|
||||
|
@ -69,10 +77,13 @@ class UserConfirmationRequest final
|
|||
mozilla::ErrorResult& aRv) override;
|
||||
|
||||
bool IsEqual(int32_t aClipboardType, Document* aRequestingChromeDocument,
|
||||
nsIPrincipal* aRequestingPrincipal) const {
|
||||
nsIPrincipal* aRequestingPrincipal,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext) const {
|
||||
return ClipboardType() == aClipboardType &&
|
||||
RequestingChromeDocument() == aRequestingChromeDocument &&
|
||||
RequestingPrincipal()->Equals(aRequestingPrincipal);
|
||||
RequestingPrincipal()->Equals(aRequestingPrincipal) &&
|
||||
(mRequestingWindowContext && aRequestingWindowContext &&
|
||||
mRequestingWindowContext->Id() == aRequestingWindowContext->Id());
|
||||
}
|
||||
|
||||
int32_t ClipboardType() const { return mClipboardType; }
|
||||
|
@ -108,6 +119,7 @@ class UserConfirmationRequest final
|
|||
MOZ_ASSERT(!request->mFlavorList.IsEmpty());
|
||||
MOZ_ASSERT(request->mCallback);
|
||||
mClipboard->AsyncGetDataInternal(request->mFlavorList, mClipboardType,
|
||||
mRequestingWindowContext,
|
||||
request->mCallback);
|
||||
}
|
||||
}
|
||||
|
@ -123,6 +135,7 @@ class UserConfirmationRequest final
|
|||
RefPtr<Document> mRequestingChromeDocument;
|
||||
const nsCOMPtr<nsIPrincipal> mRequestingPrincipal;
|
||||
const RefPtr<nsBaseClipboard> mClipboard;
|
||||
const RefPtr<mozilla::dom::WindowContext> mRequestingWindowContext;
|
||||
// Track the pending read requests that wait for user confirmation.
|
||||
nsTArray<UniquePtr<ClipboardGetRequest>> mPendingClipboardGetRequests;
|
||||
};
|
||||
|
@ -287,6 +300,228 @@ NS_IMETHODIMP nsBaseClipboard::AsyncSetData(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class SafeContentAnalysisResultCallback final
|
||||
: public nsIContentAnalysisCallback {
|
||||
public:
|
||||
explicit SafeContentAnalysisResultCallback(
|
||||
std::function<void(RefPtr<nsIContentAnalysisResult>&&)> aResolver)
|
||||
: mResolver(std::move(aResolver)) {}
|
||||
void Callback(RefPtr<nsIContentAnalysisResult>&& aResult) {
|
||||
MOZ_ASSERT(mResolver, "Called SafeContentAnalysisResultCallback twice!");
|
||||
if (auto resolver = std::move(mResolver)) {
|
||||
resolver(std::move(aResult));
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ContentResult(nsIContentAnalysisResponse* aResponse) {
|
||||
using namespace mozilla::contentanalysis;
|
||||
RefPtr<ContentAnalysisResult> result =
|
||||
ContentAnalysisResult::FromContentAnalysisResponse(aResponse);
|
||||
Callback(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Error(nsresult aError) {
|
||||
using namespace mozilla::contentanalysis;
|
||||
Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::ERROR_OTHER));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
private:
|
||||
// Private destructor to force this to be allocated in a RefPtr, which is
|
||||
// necessary for safe usage.
|
||||
~SafeContentAnalysisResultCallback() {
|
||||
MOZ_ASSERT(!mResolver, "SafeContentAnalysisResultCallback never called!");
|
||||
}
|
||||
mozilla::MoveOnlyFunction<void(RefPtr<nsIContentAnalysisResult>&&)> mResolver;
|
||||
};
|
||||
NS_IMPL_ISUPPORTS(SafeContentAnalysisResultCallback,
|
||||
nsIContentAnalysisCallback);
|
||||
} // namespace
|
||||
|
||||
// Returning:
|
||||
// - true means a content analysis request was fired
|
||||
// - false means there is no text data in the transferable
|
||||
// - NoContentAnalysisResult means there was an error
|
||||
static mozilla::Result<bool, mozilla::contentanalysis::NoContentAnalysisResult>
|
||||
CheckClipboardContentAnalysisAsText(
|
||||
uint64_t aInnerWindowId, SafeContentAnalysisResultCallback* aResolver,
|
||||
nsIURI* aDocumentURI, nsIContentAnalysis* aContentAnalysis,
|
||||
nsITransferable* aTextTrans) {
|
||||
using namespace mozilla::contentanalysis;
|
||||
|
||||
nsCOMPtr<nsISupports> transferData;
|
||||
if (NS_FAILED(aTextTrans->GetTransferData(kTextMime,
|
||||
getter_AddRefs(transferData)))) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsISupportsString> textData = do_QueryInterface(transferData);
|
||||
if (MOZ_UNLIKELY(!textData)) {
|
||||
return false;
|
||||
}
|
||||
nsString text;
|
||||
if (NS_FAILED(textData->GetData(text))) {
|
||||
return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
|
||||
}
|
||||
RefPtr<mozilla::dom::WindowGlobalParent> window =
|
||||
mozilla::dom::WindowGlobalParent::GetByInnerWindowId(aInnerWindowId);
|
||||
if (!window) {
|
||||
// The window has gone away in the meantime
|
||||
return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
|
||||
}
|
||||
nsCOMPtr<nsIContentAnalysisRequest> contentAnalysisRequest =
|
||||
new ContentAnalysisRequest(
|
||||
nsIContentAnalysisRequest::AnalysisType::eBulkDataEntry,
|
||||
std::move(text), false, EmptyCString(), aDocumentURI,
|
||||
nsIContentAnalysisRequest::OperationType::eClipboard, window);
|
||||
nsresult rv = aContentAnalysis->AnalyzeContentRequestCallback(
|
||||
contentAnalysisRequest, /* aAutoAcknowledge */ true, aResolver);
|
||||
if (NS_FAILED(rv)) {
|
||||
return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returning:
|
||||
// - true means a content analysis request was fired
|
||||
// - false means there is no file data in the transferable
|
||||
// - NoContentAnalysisResult means there was an error
|
||||
static mozilla::Result<bool, mozilla::contentanalysis::NoContentAnalysisResult>
|
||||
CheckClipboardContentAnalysisAsFile(
|
||||
uint64_t aInnerWindowId, SafeContentAnalysisResultCallback* aResolver,
|
||||
nsIURI* aDocumentURI, nsIContentAnalysis* aContentAnalysis,
|
||||
nsITransferable* aFileTrans) {
|
||||
using namespace mozilla::contentanalysis;
|
||||
|
||||
nsCOMPtr<nsISupports> transferData;
|
||||
nsresult rv =
|
||||
aFileTrans->GetTransferData(kFileMime, getter_AddRefs(transferData));
|
||||
nsString filePath;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (nsCOMPtr<nsIFile> file = do_QueryInterface(transferData)) {
|
||||
rv = file->GetPath(filePath);
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("clipboard data had kFileMime but no nsIFile!");
|
||||
return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
|
||||
}
|
||||
}
|
||||
if (NS_FAILED(rv) || filePath.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
RefPtr<mozilla::dom::WindowGlobalParent> window =
|
||||
mozilla::dom::WindowGlobalParent::GetByInnerWindowId(aInnerWindowId);
|
||||
if (!window) {
|
||||
// The window has gone away in the meantime
|
||||
return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
|
||||
}
|
||||
// Let the content analysis code calculate the digest
|
||||
nsCOMPtr<nsIContentAnalysisRequest> contentAnalysisRequest =
|
||||
new ContentAnalysisRequest(
|
||||
nsIContentAnalysisRequest::AnalysisType::eBulkDataEntry,
|
||||
std::move(filePath), true, EmptyCString(), aDocumentURI,
|
||||
nsIContentAnalysisRequest::OperationType::eCustomDisplayString,
|
||||
window);
|
||||
rv = aContentAnalysis->AnalyzeContentRequestCallback(
|
||||
contentAnalysisRequest,
|
||||
/* aAutoAcknowledge */ true, aResolver);
|
||||
if (NS_FAILED(rv)) {
|
||||
return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void CheckClipboardContentAnalysis(
|
||||
mozilla::dom::WindowGlobalParent* aWindow, nsITransferable* aTransferable,
|
||||
SafeContentAnalysisResultCallback* aResolver) {
|
||||
using namespace mozilla::contentanalysis;
|
||||
|
||||
// Content analysis is only needed if an outside webpage has access to
|
||||
// the data. So, skip content analysis if there is:
|
||||
// - no associated window (for example, scripted clipboard read by system
|
||||
// code)
|
||||
// - the window is a chrome docshell
|
||||
// - the window is being rendered in the parent process (for example,
|
||||
// about:support and the like)
|
||||
if (!aWindow || aWindow->GetBrowsingContext()->IsChrome() ||
|
||||
aWindow->IsInProcess()) {
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::NO_PARENT_BROWSER));
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIContentAnalysis> contentAnalysis =
|
||||
mozilla::components::nsIContentAnalysis::Service();
|
||||
if (!contentAnalysis) {
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::ERROR_OTHER));
|
||||
return;
|
||||
}
|
||||
|
||||
bool contentAnalysisIsActive;
|
||||
nsresult rv = contentAnalysis->GetIsActive(&contentAnalysisIsActive);
|
||||
if (MOZ_LIKELY(NS_FAILED(rv) || !contentAnalysisIsActive)) {
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::AGENT_NOT_PRESENT));
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> currentURI = aWindow->Canonical()->GetDocumentURI();
|
||||
uint64_t innerWindowId = aWindow->InnerWindowId();
|
||||
nsTArray<nsCString> flavors;
|
||||
rv = aTransferable->FlavorsTransferableCanExport(flavors);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::ERROR_OTHER));
|
||||
return;
|
||||
}
|
||||
bool keepChecking = true;
|
||||
if (flavors.Contains(kFileMime)) {
|
||||
auto fileResult = CheckClipboardContentAnalysisAsFile(
|
||||
innerWindowId, aResolver, currentURI, contentAnalysis, aTransferable);
|
||||
|
||||
if (fileResult.isErr()) {
|
||||
aResolver->Callback(
|
||||
ContentAnalysisResult::FromNoResult(fileResult.unwrapErr()));
|
||||
return;
|
||||
}
|
||||
keepChecking = !fileResult.unwrap();
|
||||
}
|
||||
if (keepChecking) {
|
||||
// Failed to get the clipboard data as a file, so try as text
|
||||
auto textResult = CheckClipboardContentAnalysisAsText(
|
||||
innerWindowId, aResolver, currentURI, contentAnalysis, aTransferable);
|
||||
if (textResult.isErr()) {
|
||||
aResolver->Callback(
|
||||
ContentAnalysisResult::FromNoResult(textResult.unwrapErr()));
|
||||
return;
|
||||
}
|
||||
if (!textResult.unwrap()) {
|
||||
// Couldn't get file or text data from this
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::ERROR_COULD_NOT_GET_DATA));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool CheckClipboardContentAnalysisSync(
|
||||
mozilla::dom::WindowGlobalParent* aWindow,
|
||||
const nsCOMPtr<nsITransferable>& trans) {
|
||||
bool requestDone = false;
|
||||
RefPtr<nsIContentAnalysisResult> result;
|
||||
auto callback = mozilla::MakeRefPtr<SafeContentAnalysisResultCallback>(
|
||||
[&requestDone, &result](RefPtr<nsIContentAnalysisResult>&& aResult) {
|
||||
result = std::move(aResult);
|
||||
requestDone = true;
|
||||
});
|
||||
CheckClipboardContentAnalysis(aWindow, trans, callback);
|
||||
mozilla::SpinEventLoopUntil("CheckClipboardContentAnalysisSync"_ns,
|
||||
[&requestDone]() -> bool { return requestDone; });
|
||||
return result->GetShouldAllowContent();
|
||||
}
|
||||
|
||||
nsBaseClipboard::nsBaseClipboard(const ClipboardCapabilities& aClipboardCaps)
|
||||
: mClipboardCaps(aClipboardCaps) {
|
||||
using mozilla::MakeUnique;
|
||||
|
@ -392,8 +627,9 @@ nsresult nsBaseClipboard::GetDataFromClipboardCache(
|
|||
/**
|
||||
* Gets the transferable object from system clipboard.
|
||||
*/
|
||||
NS_IMETHODIMP nsBaseClipboard::GetData(nsITransferable* aTransferable,
|
||||
int32_t aWhichClipboard) {
|
||||
NS_IMETHODIMP nsBaseClipboard::GetData(
|
||||
nsITransferable* aTransferable, int32_t aWhichClipboard,
|
||||
mozilla::dom::WindowContext* aWindowContext) {
|
||||
MOZ_CLIPBOARD_LOG("%s: clipboard=%d", __FUNCTION__, aWhichClipboard);
|
||||
|
||||
if (!aTransferable) {
|
||||
|
@ -414,19 +650,33 @@ NS_IMETHODIMP nsBaseClipboard::GetData(nsITransferable* aTransferable,
|
|||
if (NS_SUCCEEDED(
|
||||
GetDataFromClipboardCache(aTransferable, aWhichClipboard))) {
|
||||
// maybe try to fill in more types? Is there a point?
|
||||
if (!CheckClipboardContentAnalysisSync(aWindowContext->Canonical(),
|
||||
aTransferable)) {
|
||||
aTransferable->ClearAllData();
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// at this point we can't satisfy the request from cache data so let's look
|
||||
// for things other people put on the system clipboard
|
||||
}
|
||||
|
||||
return GetNativeClipboardData(aTransferable, aWhichClipboard);
|
||||
nsresult rv = GetNativeClipboardData(aTransferable, aWhichClipboard);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (!CheckClipboardContentAnalysisSync(aWindowContext->Canonical(),
|
||||
aTransferable)) {
|
||||
aTransferable->ClearAllData();
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsBaseClipboard::MaybeRetryGetAvailableFlavors(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
|
||||
nsIAsyncClipboardGetCallback* aCallback, int32_t aRetryCount) {
|
||||
nsIAsyncClipboardGetCallback* aCallback, int32_t aRetryCount,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext) {
|
||||
// Note we have to get the clipboard sequence number first before the actual
|
||||
// read. This is to use it to verify the clipboard data is still the one we
|
||||
// try to read, instead of the later state.
|
||||
|
@ -443,8 +693,9 @@ void nsBaseClipboard::MaybeRetryGetAvailableFlavors(
|
|||
AsyncHasNativeClipboardDataMatchingFlavors(
|
||||
aFlavorList, aWhichClipboard,
|
||||
[self = RefPtr{this}, callback = nsCOMPtr{aCallback}, aWhichClipboard,
|
||||
aRetryCount, flavorList = aFlavorList.Clone(),
|
||||
sequenceNumber](auto aFlavorsOrError) {
|
||||
aRetryCount, flavorList = aFlavorList.Clone(), sequenceNumber,
|
||||
requestingWindowContext =
|
||||
RefPtr{aRequestingWindowContext}](auto aFlavorsOrError) {
|
||||
if (aFlavorsOrError.isErr()) {
|
||||
MOZ_CLIPBOARD_LOG(
|
||||
"%s: unable to get available flavors for clipboard %d.",
|
||||
|
@ -467,7 +718,8 @@ void nsBaseClipboard::MaybeRetryGetAvailableFlavors(
|
|||
auto asyncGetClipboardData =
|
||||
mozilla::MakeRefPtr<AsyncGetClipboardData>(
|
||||
aWhichClipboard, sequenceNumber,
|
||||
std::move(aFlavorsOrError.unwrap()), false, self);
|
||||
std::move(aFlavorsOrError.unwrap()), false, self,
|
||||
requestingWindowContext);
|
||||
callback->OnSuccess(asyncGetClipboardData);
|
||||
return;
|
||||
}
|
||||
|
@ -478,7 +730,8 @@ void nsBaseClipboard::MaybeRetryGetAvailableFlavors(
|
|||
"doesn't match, retry (%d) ..",
|
||||
__FUNCTION__, aWhichClipboard, aRetryCount);
|
||||
self->MaybeRetryGetAvailableFlavors(flavorList, aWhichClipboard,
|
||||
callback, aRetryCount - 1);
|
||||
callback, aRetryCount - 1,
|
||||
requestingWindowContext);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -510,7 +763,8 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetData(
|
|||
dom_events_testing_asyncClipboard_DoNotUseDirectly() ||
|
||||
nsContentUtils::PrincipalHasPermission(*aRequestingPrincipal,
|
||||
nsGkAtoms::clipboardRead)) {
|
||||
AsyncGetDataInternal(aFlavorList, aWhichClipboard, aCallback);
|
||||
AsyncGetDataInternal(aFlavorList, aWhichClipboard, aRequestingWindowContext,
|
||||
aCallback);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -524,7 +778,8 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetData(
|
|||
if (aRequestingPrincipal->Subsumes(principal)) {
|
||||
MOZ_CLIPBOARD_LOG("%s: native clipboard data is from same-origin page.",
|
||||
__FUNCTION__);
|
||||
AsyncGetDataInternal(aFlavorList, aWhichClipboard, aCallback);
|
||||
AsyncGetDataInternal(aFlavorList, aWhichClipboard,
|
||||
aRequestingWindowContext, aCallback);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -544,6 +799,7 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetData(
|
|||
|
||||
void nsBaseClipboard::AsyncGetDataInternal(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aClipboardType,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext,
|
||||
nsIAsyncClipboardGetCallback* aCallback) {
|
||||
MOZ_ASSERT(nsIClipboard::IsClipboardTypeSupported(aClipboardType));
|
||||
|
||||
|
@ -576,7 +832,7 @@ void nsBaseClipboard::AsyncGetDataInternal(
|
|||
// be found in cache?
|
||||
auto asyncGetClipboardData = mozilla::MakeRefPtr<AsyncGetClipboardData>(
|
||||
aClipboardType, clipboardCache->GetSequenceNumber(),
|
||||
std::move(results), true, this);
|
||||
std::move(results), true, this, aRequestingWindowContext);
|
||||
aCallback->OnSuccess(asyncGetClipboardData);
|
||||
return;
|
||||
}
|
||||
|
@ -587,7 +843,8 @@ void nsBaseClipboard::AsyncGetDataInternal(
|
|||
}
|
||||
|
||||
MaybeRetryGetAvailableFlavors(aFlavorList, aClipboardType, aCallback,
|
||||
kGetAvailableFlavorsRetryCount);
|
||||
kGetAvailableFlavorsRetryCount,
|
||||
aRequestingWindowContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBaseClipboard::EmptyClipboard(int32_t aWhichClipboard) {
|
||||
|
@ -790,8 +1047,8 @@ void nsBaseClipboard::RequestUserConfirmation(
|
|||
// If there is a pending user confirmation request, check if we could reuse
|
||||
// it. If not, reject the request.
|
||||
if (sUserConfirmationRequest) {
|
||||
if (sUserConfirmationRequest->IsEqual(aClipboardType, chromeDoc,
|
||||
aRequestingPrincipal)) {
|
||||
if (sUserConfirmationRequest->IsEqual(
|
||||
aClipboardType, chromeDoc, aRequestingPrincipal, aWindowContext)) {
|
||||
sUserConfirmationRequest->AddClipboardGetRequest(aFlavorList, aCallback);
|
||||
return;
|
||||
}
|
||||
|
@ -816,7 +1073,7 @@ void nsBaseClipboard::RequestUserConfirmation(
|
|||
}
|
||||
|
||||
sUserConfirmationRequest = new UserConfirmationRequest(
|
||||
aClipboardType, chromeDoc, aRequestingPrincipal, this);
|
||||
aClipboardType, chromeDoc, aRequestingPrincipal, this, aWindowContext);
|
||||
sUserConfirmationRequest->AddClipboardGetRequest(aFlavorList, aCallback);
|
||||
promise->AppendNativeHandler(sUserConfirmationRequest);
|
||||
}
|
||||
|
@ -827,12 +1084,14 @@ NS_IMPL_ISUPPORTS(nsBaseClipboard::AsyncGetClipboardData,
|
|||
nsBaseClipboard::AsyncGetClipboardData::AsyncGetClipboardData(
|
||||
int32_t aClipboardType, int32_t aSequenceNumber,
|
||||
nsTArray<nsCString>&& aFlavors, bool aFromCache,
|
||||
nsBaseClipboard* aClipboard)
|
||||
nsBaseClipboard* aClipboard,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext)
|
||||
: mClipboardType(aClipboardType),
|
||||
mSequenceNumber(aSequenceNumber),
|
||||
mFlavors(std::move(aFlavors)),
|
||||
mFromCache(aFromCache),
|
||||
mClipboard(aClipboard) {
|
||||
mClipboard(aClipboard),
|
||||
mRequestingWindowContext(aRequestingWindowContext) {
|
||||
MOZ_ASSERT(mClipboard);
|
||||
MOZ_ASSERT(
|
||||
mClipboard->nsIClipboard::IsClipboardTypeSupported(mClipboardType));
|
||||
|
@ -879,6 +1138,19 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetClipboardData::GetData(
|
|||
|
||||
MOZ_ASSERT(mClipboard);
|
||||
|
||||
auto contentAnalysisCallback =
|
||||
mozilla::MakeRefPtr<SafeContentAnalysisResultCallback>(
|
||||
[transferable = nsCOMPtr{aTransferable},
|
||||
callback = nsCOMPtr{aCallback}](
|
||||
RefPtr<nsIContentAnalysisResult>&& aResult) {
|
||||
if (aResult->GetShouldAllowContent()) {
|
||||
callback->OnComplete(NS_OK);
|
||||
} else {
|
||||
transferable->ClearAllData();
|
||||
callback->OnComplete(NS_ERROR_CONTENT_BLOCKED);
|
||||
}
|
||||
});
|
||||
|
||||
if (mFromCache) {
|
||||
const auto* clipboardCache =
|
||||
mClipboard->GetClipboardCacheIfValid(mClipboardType);
|
||||
|
@ -888,7 +1160,8 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetClipboardData::GetData(
|
|||
MOZ_DIAGNOSTIC_ASSERT(clipboardCache->GetSequenceNumber() ==
|
||||
mSequenceNumber);
|
||||
if (NS_SUCCEEDED(clipboardCache->GetData(aTransferable))) {
|
||||
aCallback->OnComplete(NS_OK);
|
||||
CheckClipboardContentAnalysis(mRequestingWindowContext->Canonical(),
|
||||
aTransferable, contentAnalysisCallback);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -900,10 +1173,23 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetClipboardData::GetData(
|
|||
// valid after we get the result.
|
||||
mClipboard->AsyncGetNativeClipboardData(
|
||||
aTransferable, mClipboardType,
|
||||
[callback = nsCOMPtr{aCallback}, self = RefPtr{this}](nsresult aResult) {
|
||||
[callback = nsCOMPtr{aCallback}, self = RefPtr{this},
|
||||
transferable = nsCOMPtr{aTransferable},
|
||||
contentAnalysisCallback =
|
||||
std::move(contentAnalysisCallback)](nsresult aResult) mutable {
|
||||
if (NS_FAILED(aResult)) {
|
||||
callback->OnComplete(aResult);
|
||||
return;
|
||||
}
|
||||
// `IsValid()` checks the clipboard sequence number to ensure the data
|
||||
// we are requesting is still valid.
|
||||
callback->OnComplete(self->IsValid() ? aResult : NS_ERROR_FAILURE);
|
||||
if (!self->IsValid()) {
|
||||
callback->OnComplete(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
CheckClipboardContentAnalysis(
|
||||
self->mRequestingWindowContext->Canonical(), transferable,
|
||||
contentAnalysisCallback);
|
||||
});
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -47,8 +47,9 @@ class nsBaseClipboard : public nsIClipboard {
|
|||
NS_IMETHOD AsyncSetData(int32_t aWhichClipboard,
|
||||
nsIAsyncClipboardRequestCallback* aCallback,
|
||||
nsIAsyncSetClipboardData** _retval) override final;
|
||||
NS_IMETHOD GetData(nsITransferable* aTransferable,
|
||||
int32_t aWhichClipboard) override final;
|
||||
NS_IMETHOD GetData(
|
||||
nsITransferable* aTransferable, int32_t aWhichClipboard,
|
||||
mozilla::dom::WindowContext* aWindowContext) override final;
|
||||
NS_IMETHOD AsyncGetData(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext,
|
||||
|
@ -61,9 +62,10 @@ class nsBaseClipboard : public nsIClipboard {
|
|||
NS_IMETHOD IsClipboardTypeSupported(int32_t aWhichClipboard,
|
||||
bool* aRetval) override final;
|
||||
|
||||
void AsyncGetDataInternal(const nsTArray<nsCString>& aFlavorList,
|
||||
int32_t aClipboardType,
|
||||
nsIAsyncClipboardGetCallback* aCallback);
|
||||
void AsyncGetDataInternal(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aClipboardType,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext,
|
||||
nsIAsyncClipboardGetCallback* aCallback);
|
||||
|
||||
using GetDataCallback = mozilla::MoveOnlyFunction<void(nsresult)>;
|
||||
using HasMatchingFlavorsCallback = mozilla::MoveOnlyFunction<void(
|
||||
|
@ -124,9 +126,11 @@ class nsBaseClipboard : public nsIClipboard {
|
|||
|
||||
class AsyncGetClipboardData final : public nsIAsyncGetClipboardData {
|
||||
public:
|
||||
AsyncGetClipboardData(int32_t aClipboardType, int32_t aSequenceNumber,
|
||||
nsTArray<nsCString>&& aFlavors, bool aFromCache,
|
||||
nsBaseClipboard* aClipboard);
|
||||
AsyncGetClipboardData(
|
||||
int32_t aClipboardType, int32_t aSequenceNumber,
|
||||
nsTArray<nsCString>&& aFlavors, bool aFromCache,
|
||||
nsBaseClipboard* aClipboard,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIASYNCGETCLIPBOARDDATA
|
||||
|
@ -147,6 +151,8 @@ class nsBaseClipboard : public nsIClipboard {
|
|||
const bool mFromCache;
|
||||
// This is also used to indicate whether this request is still valid.
|
||||
RefPtr<nsBaseClipboard> mClipboard;
|
||||
// The requesting window, which is used for Content Analysis purposes.
|
||||
RefPtr<mozilla::dom::WindowContext> mRequestingWindowContext;
|
||||
};
|
||||
|
||||
class ClipboardCache final {
|
||||
|
@ -180,10 +186,10 @@ class nsBaseClipboard : public nsIClipboard {
|
|||
int32_t mSequenceNumber = -1;
|
||||
};
|
||||
|
||||
void MaybeRetryGetAvailableFlavors(const nsTArray<nsCString>& aFlavorList,
|
||||
int32_t aWhichClipboard,
|
||||
nsIAsyncClipboardGetCallback* aCallback,
|
||||
int32_t aRetryCount);
|
||||
void MaybeRetryGetAvailableFlavors(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
|
||||
nsIAsyncClipboardGetCallback* aCallback, int32_t aRetryCount,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext);
|
||||
|
||||
// Return clipboard cache if the cached data is valid, otherwise clear the
|
||||
// cached data and returns null.
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/net/CookieJarSettings.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsBaseClipboard.h"
|
||||
|
@ -57,13 +58,20 @@ NS_IMETHODIMP nsClipboardProxy::AsyncSetData(
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsClipboardProxy::GetData(nsITransferable* aTransferable,
|
||||
int32_t aWhichClipboard) {
|
||||
int32_t aWhichClipboard,
|
||||
mozilla::dom::WindowContext* aWindowContext) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aWindowContext && aWindowContext->IsInProcess(),
|
||||
"content clipboard reads must be associated with an "
|
||||
"in-process WindowContext");
|
||||
if (aWindowContext->IsDiscarded()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
nsTArray<nsCString> types;
|
||||
aTransferable->FlavorsTransferableCanImport(types);
|
||||
|
||||
IPCTransferableData transferable;
|
||||
ContentChild::GetSingleton()->SendGetClipboard(types, aWhichClipboard,
|
||||
&transferable);
|
||||
aWindowContext, &transferable);
|
||||
return nsContentUtils::IPCTransferableDataToTransferable(
|
||||
transferable, false /* aAddDataFlavor */, aTransferable,
|
||||
false /* aFilterUnknownFlavors */);
|
||||
|
|
|
@ -145,14 +145,20 @@ interface nsIClipboard : nsISupports
|
|||
*
|
||||
* @param aTransferable The transferable
|
||||
* @param aWhichClipboard Specifies the clipboard to which this operation applies.
|
||||
* @param aRequestingWindowContext [optional]
|
||||
* The window context window that is requesting the clipboard, which is
|
||||
* used for content analysis. Passing null means that the content is
|
||||
* exempt from content analysis. (for example, scripted clipboard read by
|
||||
* system code) This parameter should not be null when calling this from a
|
||||
* content process.
|
||||
* @result NS_OK if no errors
|
||||
*/
|
||||
|
||||
void getData ( in nsITransferable aTransferable, in long aWhichClipboard ) ;
|
||||
void getData ( in nsITransferable aTransferable, in long aWhichClipboard, [optional] in WindowContext aRequestingWindowContext) ;
|
||||
|
||||
/**
|
||||
* Requests getting data asynchronously from the native clipboard. This does
|
||||
* not actually retreive the data, but returns a nsIAsyncGetClipboardData
|
||||
* not actually retrieve the data, but returns a nsIAsyncGetClipboardData
|
||||
* contains current avaiable data formats. If the native clipboard is
|
||||
* updated, either by us or other application, the existing
|
||||
* nsIAsyncGetClipboardData becomes invalid.
|
||||
|
|
|
@ -168,6 +168,11 @@ interface nsITransferable : nsISupports
|
|||
*/
|
||||
void setTransferData(in string aFlavor, in nsISupports aData);
|
||||
|
||||
/**
|
||||
* Removes the data from all flavors.
|
||||
*/
|
||||
void clearAllData();
|
||||
|
||||
/**
|
||||
* Add the data flavor, indicating that this transferable
|
||||
* can receive this type of flavor
|
||||
|
|
|
@ -110,6 +110,14 @@ void DataStruct::GetData(nsISupports** aData) {
|
|||
data.forget(aData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void DataStruct::ClearData() {
|
||||
if (mCacheFD) {
|
||||
PR_Close(mCacheFD);
|
||||
}
|
||||
mData = nullptr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
nsresult DataStruct::WriteCache(void* aData, uint32_t aDataLen) {
|
||||
MOZ_ASSERT(aData && aDataLen);
|
||||
|
@ -366,6 +374,14 @@ nsTransferable::SetTransferData(const char* aFlavor, nsISupports* aData) {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTransferable::ClearAllData() {
|
||||
for (auto& entry : mDataArray) {
|
||||
entry.ClearData();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// AddDataFlavor
|
||||
//
|
||||
|
|
|
@ -33,6 +33,7 @@ struct DataStruct {
|
|||
const nsCString& GetFlavor() const { return mFlavor; }
|
||||
void SetData(nsISupports* aData, bool aIsPrivateData);
|
||||
void GetData(nsISupports** aData);
|
||||
void ClearData();
|
||||
bool IsDataAvailable() const { return mData || mCacheFD; }
|
||||
|
||||
protected:
|
||||
|
|
|
@ -717,25 +717,19 @@ nsFilePicker::CheckContentAnalysisService() {
|
|||
__func__);
|
||||
}
|
||||
|
||||
RefPtr<nsIURI> uri = mBrowsingContext->Canonical()->GetCurrentURI();
|
||||
nsCString uriCString;
|
||||
rv = uri->GetSpec(uriCString);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nsFilePicker::ContentAnalysisResponse::CreateAndReject(rv, __func__);
|
||||
}
|
||||
nsString uriString = NS_ConvertUTF8toUTF16(uriCString);
|
||||
nsCOMPtr<nsIURI> uri = mBrowsingContext->Canonical()->GetCurrentURI();
|
||||
|
||||
auto processOneItem = [self = RefPtr{this},
|
||||
contentAnalysis = std::move(contentAnalysis),
|
||||
uriString = std::move(uriString)](
|
||||
const mozilla::PathString& aItem) {
|
||||
uri =
|
||||
std::move(uri)](const mozilla::PathString& aItem) {
|
||||
nsCString emptyDigestString;
|
||||
auto* windowGlobal =
|
||||
self->mBrowsingContext->Canonical()->GetCurrentWindowGlobal();
|
||||
nsCOMPtr<nsIContentAnalysisRequest> contentAnalysisRequest(
|
||||
new mozilla::contentanalysis::ContentAnalysisRequest(
|
||||
nsIContentAnalysisRequest::AnalysisType::eFileAttached, aItem, true,
|
||||
std::move(emptyDigestString), uriString,
|
||||
std::move(emptyDigestString), uri,
|
||||
nsIContentAnalysisRequest::OperationType::eCustomDisplayString,
|
||||
windowGlobal));
|
||||
|
||||
|
@ -750,7 +744,8 @@ nsFilePicker::CheckContentAnalysisService() {
|
|||
[promise](nsresult aError) { promise->Reject(aError, __func__); });
|
||||
|
||||
nsresult rv = contentAnalysis->AnalyzeContentRequestCallback(
|
||||
contentAnalysisRequest, true, contentAnalysisCallback);
|
||||
contentAnalysisRequest, /* aAutoAcknowledge */ true,
|
||||
contentAnalysisCallback);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
promise->Reject(rv, __func__);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче