forked from mirrors/gecko-dev
Bug 1888713 - move Content Analysis clipboard code into the Content Analysis code r=dlp-reviewers,handyman
Got [[ https://treeherder.mozilla.org/jobs?repo=try&revision=e6b8fb3ed7af5b1bd665e376a5917d196327b2d2 | good try builds here ]]. Differential Revision: https://phabricator.services.mozilla.com/D207784
This commit is contained in:
parent
b3f3e9a04a
commit
acb7118ea3
4 changed files with 279 additions and 273 deletions
|
|
@ -17,9 +17,11 @@
|
|||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/SpinEventLoopUntil.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
#include "nsAppRunner.h"
|
||||
#include "nsBaseClipboard.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsIFile.h"
|
||||
|
|
@ -28,6 +30,8 @@
|
|||
#include "nsIOutputStream.h"
|
||||
#include "nsIPrintSettings.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
|
|
@ -1697,6 +1701,220 @@ ContentAnalysis::PrintToPDFToDetermineIfPrintAllowed(
|
|||
}
|
||||
#endif
|
||||
|
||||
NS_IMPL_ISUPPORTS(ContentAnalysis::SafeContentAnalysisResultCallback,
|
||||
nsIContentAnalysisCallback);
|
||||
|
||||
// - true means a content analysis request was fired
|
||||
// - false means there is no text data in the transferable
|
||||
// - NoContentAnalysisResult means there was an error
|
||||
using ClipboardContentAnalysisResult =
|
||||
mozilla::Result<bool, mozilla::contentanalysis::NoContentAnalysisResult>;
|
||||
|
||||
NS_IMETHODIMP ContentAnalysis::SafeContentAnalysisResultCallback::ContentResult(
|
||||
nsIContentAnalysisResponse* aResponse) {
|
||||
RefPtr<ContentAnalysisResult> result =
|
||||
ContentAnalysisResult::FromContentAnalysisResponse(aResponse);
|
||||
Callback(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ContentAnalysis::SafeContentAnalysisResultCallback::Error(
|
||||
nsresult aError) {
|
||||
Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ClipboardContentAnalysisResult CheckClipboardContentAnalysisAsText(
|
||||
uint64_t aInnerWindowId,
|
||||
ContentAnalysis::SafeContentAnalysisResultCallback* aResolver,
|
||||
nsIURI* aDocumentURI, nsIContentAnalysis* aContentAnalysis,
|
||||
nsITransferable* aTextTrans) {
|
||||
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::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
if (text.IsEmpty()) {
|
||||
// Content Analysis doesn't expect to analyze an empty string.
|
||||
// Just approve it.
|
||||
return true;
|
||||
}
|
||||
RefPtr<mozilla::dom::WindowGlobalParent> window =
|
||||
mozilla::dom::WindowGlobalParent::GetByInnerWindowId(aInnerWindowId);
|
||||
if (!window) {
|
||||
// The window has gone away in the meantime
|
||||
return mozilla::Err(NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
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::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ClipboardContentAnalysisResult CheckClipboardContentAnalysisAsFile(
|
||||
uint64_t aInnerWindowId,
|
||||
ContentAnalysis::SafeContentAnalysisResultCallback* aResolver,
|
||||
nsIURI* aDocumentURI, nsIContentAnalysis* aContentAnalysis,
|
||||
nsITransferable* aFileTrans) {
|
||||
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::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
}
|
||||
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::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
// 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::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContentAnalysis::CheckClipboardContentAnalysis(
|
||||
nsBaseClipboard* aClipboard, mozilla::dom::WindowGlobalParent* aWindow,
|
||||
nsITransferable* aTransferable, int32_t aClipboardType,
|
||||
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::
|
||||
ALLOW_DUE_TO_CONTEXT_EXEMPT_FROM_CONTENT_ANALYSIS));
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIContentAnalysis> contentAnalysis =
|
||||
mozilla::components::nsIContentAnalysis::Service();
|
||||
if (!contentAnalysis) {
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
bool contentAnalysisIsActive;
|
||||
nsresult rv = contentAnalysis->GetIsActive(&contentAnalysisIsActive);
|
||||
if (MOZ_LIKELY(NS_FAILED(rv) || !contentAnalysisIsActive)) {
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::ALLOW_DUE_TO_CONTENT_ANALYSIS_NOT_ACTIVE));
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t innerWindowId = aWindow->InnerWindowId();
|
||||
if (mozilla::StaticPrefs::
|
||||
browser_contentanalysis_bypass_for_same_tab_operations()) {
|
||||
mozilla::Maybe<uint64_t> cacheInnerWindowId =
|
||||
aClipboard->GetClipboardCacheInnerWindowId(aClipboardType);
|
||||
if (cacheInnerWindowId.isSome() && *cacheInnerWindowId == innerWindowId) {
|
||||
// If the same page copied this data to the clipboard (and the above
|
||||
// preference is set) we can skip content analysis and immediately allow
|
||||
// this.
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::ALLOW_DUE_TO_SAME_TAB_SOURCE));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> currentURI = aWindow->Canonical()->GetDocumentURI();
|
||||
nsTArray<nsCString> flavors;
|
||||
rv = aTransferable->FlavorsTransferableCanExport(flavors);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR));
|
||||
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::ALLOW_DUE_TO_COULD_NOT_GET_DATA));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ContentAnalysis::CheckClipboardContentAnalysisSync(
|
||||
nsBaseClipboard* aClipboard, mozilla::dom::WindowGlobalParent* aWindow,
|
||||
const nsCOMPtr<nsITransferable>& trans, int32_t aClipboardType) {
|
||||
bool requestDone = false;
|
||||
RefPtr<nsIContentAnalysisResult> result;
|
||||
auto callback = mozilla::MakeRefPtr<SafeContentAnalysisResultCallback>(
|
||||
[&requestDone, &result](RefPtr<nsIContentAnalysisResult>&& aResult) {
|
||||
result = std::move(aResult);
|
||||
requestDone = true;
|
||||
});
|
||||
CheckClipboardContentAnalysis(aClipboard, aWindow, trans, aClipboardType,
|
||||
callback);
|
||||
mozilla::SpinEventLoopUntil("CheckClipboardContentAnalysisSync"_ns,
|
||||
[&requestDone]() -> bool { return requestDone; });
|
||||
return result->GetShouldAllowContent();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentAnalysisResponse::Acknowledge(
|
||||
nsIContentAnalysisAcknowledgement* aAcknowledgement) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#define mozilla_contentanalysis_h
|
||||
|
||||
#include "mozilla/DataMutex.h"
|
||||
#include "mozilla/MoveOnlyFunction.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/MaybeDiscarded.h"
|
||||
|
|
@ -24,6 +25,7 @@
|
|||
# include <windows.h>
|
||||
#endif // XP_WIN
|
||||
|
||||
class nsBaseClipboard;
|
||||
class nsIPrincipal;
|
||||
class nsIPrintSettings;
|
||||
class ContentAnalysisTest;
|
||||
|
|
@ -149,6 +151,7 @@ class ContentAnalysis final : public nsIContentAnalysis {
|
|||
nsCString GetUserActionId();
|
||||
void SetLastResult(nsresult aLastResult) { mLastResult = aLastResult; }
|
||||
|
||||
#if defined(XP_WIN)
|
||||
struct PrintAllowedResult final {
|
||||
bool mAllowed;
|
||||
dom::MaybeDiscarded<dom::BrowsingContext>
|
||||
|
|
@ -175,13 +178,42 @@ class ContentAnalysis final : public nsIContentAnalysis {
|
|||
};
|
||||
using PrintAllowedPromise =
|
||||
MozPromise<PrintAllowedResult, PrintAllowedError, true>;
|
||||
#if defined(XP_WIN)
|
||||
MOZ_CAN_RUN_SCRIPT static RefPtr<PrintAllowedPromise>
|
||||
PrintToPDFToDetermineIfPrintAllowed(
|
||||
dom::CanonicalBrowsingContext* aBrowsingContext,
|
||||
nsIPrintSettings* aPrintSettings);
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
class SafeContentAnalysisResultCallback final
|
||||
: public nsIContentAnalysisCallback {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSICONTENTANALYSISCALLBACK
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
~SafeContentAnalysisResultCallback() {
|
||||
MOZ_ASSERT(!mResolver, "SafeContentAnalysisResultCallback never called!");
|
||||
}
|
||||
mozilla::MoveOnlyFunction<void(RefPtr<nsIContentAnalysisResult>&&)>
|
||||
mResolver;
|
||||
};
|
||||
static bool CheckClipboardContentAnalysisSync(
|
||||
nsBaseClipboard* aClipboard, mozilla::dom::WindowGlobalParent* aWindow,
|
||||
const nsCOMPtr<nsITransferable>& trans, int32_t aClipboardType);
|
||||
static void CheckClipboardContentAnalysis(
|
||||
nsBaseClipboard* aClipboard, mozilla::dom::WindowGlobalParent* aWindow,
|
||||
nsITransferable* aTransferable, int32_t aClipboardType,
|
||||
SafeContentAnalysisResultCallback* aResolver);
|
||||
|
||||
private:
|
||||
~ContentAnalysis();
|
||||
// Remove unneeded copy constructor/assignment
|
||||
|
|
@ -210,7 +242,6 @@ class ContentAnalysis final : public nsIContentAnalysis {
|
|||
const std::shared_ptr<content_analysis::sdk::Client>& aClient);
|
||||
void IssueResponse(RefPtr<ContentAnalysisResponse>& response);
|
||||
bool LastRequestSucceeded();
|
||||
|
||||
// Did the URL filter completely handle the request or do we need to check
|
||||
// with the agent.
|
||||
enum UrlFilterResult { eCheck, eDeny, eAllow };
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "ContentAnalysis.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/contentanalysis/ContentAnalysisIPCTypes.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
|
|
@ -19,14 +18,12 @@
|
|||
#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"
|
||||
|
||||
|
|
@ -319,203 +316,6 @@ NS_IMETHODIMP nsBaseClipboard::AsyncSetData(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsBaseClipboard::SafeContentAnalysisResultCallback,
|
||||
nsIContentAnalysisCallback);
|
||||
|
||||
nsBaseClipboard::ClipboardContentAnalysisResult
|
||||
nsBaseClipboard::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::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
if (text.IsEmpty()) {
|
||||
// Content Analysis doesn't expect to analyze an empty string.
|
||||
// Just approve it.
|
||||
return true;
|
||||
}
|
||||
RefPtr<mozilla::dom::WindowGlobalParent> window =
|
||||
mozilla::dom::WindowGlobalParent::GetByInnerWindowId(aInnerWindowId);
|
||||
if (!window) {
|
||||
// The window has gone away in the meantime
|
||||
return mozilla::Err(NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
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::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsBaseClipboard::ClipboardContentAnalysisResult
|
||||
nsBaseClipboard::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::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
}
|
||||
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::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
// 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::DENY_DUE_TO_OTHER_ERROR);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void nsBaseClipboard::CheckClipboardContentAnalysis(
|
||||
mozilla::dom::WindowGlobalParent* aWindow, nsITransferable* aTransferable,
|
||||
int32_t aClipboardType, 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::
|
||||
ALLOW_DUE_TO_CONTEXT_EXEMPT_FROM_CONTENT_ANALYSIS));
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIContentAnalysis> contentAnalysis =
|
||||
mozilla::components::nsIContentAnalysis::Service();
|
||||
if (!contentAnalysis) {
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
bool contentAnalysisIsActive;
|
||||
nsresult rv = contentAnalysis->GetIsActive(&contentAnalysisIsActive);
|
||||
if (MOZ_LIKELY(NS_FAILED(rv) || !contentAnalysisIsActive)) {
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::ALLOW_DUE_TO_CONTENT_ANALYSIS_NOT_ACTIVE));
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t innerWindowId = aWindow->InnerWindowId();
|
||||
if (mozilla::StaticPrefs::
|
||||
browser_contentanalysis_bypass_for_same_tab_operations()) {
|
||||
const auto* clipboardCache = GetClipboardCacheIfValid(aClipboardType);
|
||||
if (clipboardCache) {
|
||||
if (clipboardCache->GetInnerWindowId().isSome() &&
|
||||
*(clipboardCache->GetInnerWindowId()) == innerWindowId) {
|
||||
// If the same page copied this data to the clipboard (and the above
|
||||
// preference is set) we can skip content analysis and immediately allow
|
||||
// this.
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::ALLOW_DUE_TO_SAME_TAB_SOURCE));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> currentURI = aWindow->Canonical()->GetDocumentURI();
|
||||
nsTArray<nsCString> flavors;
|
||||
rv = aTransferable->FlavorsTransferableCanExport(flavors);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aResolver->Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR));
|
||||
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::ALLOW_DUE_TO_COULD_NOT_GET_DATA));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool nsBaseClipboard::CheckClipboardContentAnalysisSync(
|
||||
mozilla::dom::WindowGlobalParent* aWindow,
|
||||
const nsCOMPtr<nsITransferable>& trans, int32_t aClipboardType) {
|
||||
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, aClipboardType, callback);
|
||||
mozilla::SpinEventLoopUntil("CheckClipboardContentAnalysisSync"_ns,
|
||||
[&requestDone]() -> bool { return requestDone; });
|
||||
return result->GetShouldAllowContent();
|
||||
}
|
||||
|
||||
nsBaseClipboard::nsBaseClipboard(const ClipboardCapabilities& aClipboardCaps)
|
||||
: mClipboardCaps(aClipboardCaps) {
|
||||
using mozilla::MakeUnique;
|
||||
|
|
@ -645,8 +445,10 @@ NS_IMETHODIMP nsBaseClipboard::GetData(
|
|||
if (NS_SUCCEEDED(
|
||||
GetDataFromClipboardCache(aTransferable, aWhichClipboard))) {
|
||||
// maybe try to fill in more types? Is there a point?
|
||||
if (!CheckClipboardContentAnalysisSync(aWindowContext->Canonical(),
|
||||
aTransferable, aWhichClipboard)) {
|
||||
if (!mozilla::contentanalysis::ContentAnalysis::
|
||||
CheckClipboardContentAnalysisSync(
|
||||
this, aWindowContext->Canonical(), aTransferable,
|
||||
aWhichClipboard)) {
|
||||
aTransferable->ClearAllData();
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
|
@ -660,8 +462,9 @@ NS_IMETHODIMP nsBaseClipboard::GetData(
|
|||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (!CheckClipboardContentAnalysisSync(aWindowContext->Canonical(),
|
||||
aTransferable, aWhichClipboard)) {
|
||||
if (!mozilla::contentanalysis::ContentAnalysis::
|
||||
CheckClipboardContentAnalysisSync(this, aWindowContext->Canonical(),
|
||||
aTransferable, aWhichClipboard)) {
|
||||
aTransferable->ClearAllData();
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
|
@ -1202,7 +1005,8 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetClipboardData::GetData(
|
|||
MOZ_ASSERT(mClipboard);
|
||||
|
||||
auto contentAnalysisCallback =
|
||||
mozilla::MakeRefPtr<SafeContentAnalysisResultCallback>(
|
||||
mozilla::MakeRefPtr<mozilla::contentanalysis::ContentAnalysis::
|
||||
SafeContentAnalysisResultCallback>(
|
||||
[transferable = nsCOMPtr{aTransferable},
|
||||
callback = nsCOMPtr{aCallback}](
|
||||
RefPtr<nsIContentAnalysisResult>&& aResult) {
|
||||
|
|
@ -1223,7 +1027,8 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetClipboardData::GetData(
|
|||
MOZ_DIAGNOSTIC_ASSERT(clipboardCache->GetSequenceNumber() ==
|
||||
mSequenceNumber);
|
||||
if (NS_SUCCEEDED(clipboardCache->GetData(aTransferable))) {
|
||||
mClipboard->CheckClipboardContentAnalysis(
|
||||
mozilla::contentanalysis::ContentAnalysis::CheckClipboardContentAnalysis(
|
||||
mClipboard,
|
||||
mRequestingWindowContext ? mRequestingWindowContext->Canonical()
|
||||
: nullptr,
|
||||
aTransferable, mClipboardType, contentAnalysisCallback);
|
||||
|
|
@ -1252,11 +1057,13 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetClipboardData::GetData(
|
|||
callback->OnComplete(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
self->mClipboard->CheckClipboardContentAnalysis(
|
||||
self->mRequestingWindowContext
|
||||
? self->mRequestingWindowContext->Canonical()
|
||||
: nullptr,
|
||||
transferable, self->mClipboardType, contentAnalysisCallback);
|
||||
mozilla::contentanalysis::ContentAnalysis::
|
||||
CheckClipboardContentAnalysis(
|
||||
self->mClipboard,
|
||||
self->mRequestingWindowContext
|
||||
? self->mRequestingWindowContext->Canonical()
|
||||
: nullptr,
|
||||
transferable, self->mClipboardType, contentAnalysisCallback);
|
||||
});
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
@ -1294,6 +1101,13 @@ bool nsBaseClipboard::AsyncGetClipboardData::IsValid() {
|
|||
return true;
|
||||
}
|
||||
|
||||
mozilla::Maybe<uint64_t> nsBaseClipboard::GetClipboardCacheInnerWindowId(
|
||||
int32_t aClipboardType) {
|
||||
auto* clipboardCache = GetClipboardCacheIfValid(aClipboardType);
|
||||
return clipboardCache ? clipboardCache->GetInnerWindowId()
|
||||
: mozilla::Nothing();
|
||||
}
|
||||
|
||||
nsBaseClipboard::ClipboardCache* nsBaseClipboard::GetClipboardCacheIfValid(
|
||||
int32_t aClipboardType) {
|
||||
MOZ_ASSERT(nsIClipboard::IsClipboardTypeSupported(aClipboardType));
|
||||
|
|
|
|||
|
|
@ -6,13 +6,11 @@
|
|||
#ifndef nsBaseClipboard_h__
|
||||
#define nsBaseClipboard_h__
|
||||
|
||||
#include "mozilla/contentanalysis/ContentAnalysisIPCTypes.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/MoveOnlyFunction.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsIContentAnalysis.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
|
|
@ -80,6 +78,9 @@ class nsBaseClipboard : public nsIClipboard {
|
|||
using HasMatchingFlavorsCallback = mozilla::MoveOnlyFunction<void(
|
||||
mozilla::Result<nsTArray<nsCString>, nsresult>)>;
|
||||
|
||||
mozilla::Maybe<uint64_t> GetClipboardCacheInnerWindowId(
|
||||
int32_t aClipboardType);
|
||||
|
||||
protected:
|
||||
virtual ~nsBaseClipboard();
|
||||
|
||||
|
|
@ -201,44 +202,6 @@ class nsBaseClipboard : public nsIClipboard {
|
|||
mozilla::Maybe<uint64_t> mInnerWindowId;
|
||||
};
|
||||
|
||||
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) override {
|
||||
using namespace mozilla::contentanalysis;
|
||||
RefPtr<ContentAnalysisResult> result =
|
||||
ContentAnalysisResult::FromContentAnalysisResponse(aResponse);
|
||||
Callback(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Error(nsresult aError) override {
|
||||
using namespace mozilla::contentanalysis;
|
||||
Callback(ContentAnalysisResult::FromNoResult(
|
||||
NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
private:
|
||||
~SafeContentAnalysisResultCallback() {
|
||||
MOZ_ASSERT(!mResolver, "SafeContentAnalysisResultCallback never called!");
|
||||
}
|
||||
mozilla::MoveOnlyFunction<void(RefPtr<nsIContentAnalysisResult>&&)>
|
||||
mResolver;
|
||||
};
|
||||
|
||||
void MaybeRetryGetAvailableFlavors(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
|
||||
nsIAsyncClipboardGetCallback* aCallback, int32_t aRetryCount,
|
||||
|
|
@ -252,26 +215,6 @@ class nsBaseClipboard : public nsIClipboard {
|
|||
int32_t aClipboardType);
|
||||
nsresult GetDataFromClipboardCache(nsITransferable* aTransferable,
|
||||
int32_t aClipboardType);
|
||||
bool CheckClipboardContentAnalysisSync(
|
||||
mozilla::dom::WindowGlobalParent* aWindow,
|
||||
const nsCOMPtr<nsITransferable>& trans, int32_t aClipboardType);
|
||||
void CheckClipboardContentAnalysis(
|
||||
mozilla::dom::WindowGlobalParent* aWindow, nsITransferable* aTransferable,
|
||||
int32_t aClipboardType, SafeContentAnalysisResultCallback* aResolver);
|
||||
// - true means a content analysis request was fired
|
||||
// - false means there is no text data in the transferable
|
||||
// - NoContentAnalysisResult means there was an error
|
||||
using ClipboardContentAnalysisResult =
|
||||
mozilla::Result<bool, mozilla::contentanalysis::NoContentAnalysisResult>;
|
||||
ClipboardContentAnalysisResult CheckClipboardContentAnalysisAsText(
|
||||
uint64_t aInnerWindowId, SafeContentAnalysisResultCallback* aResolver,
|
||||
nsIURI* aDocumentURI, nsIContentAnalysis* aContentAnalysis,
|
||||
nsITransferable* aTextTrans);
|
||||
ClipboardContentAnalysisResult CheckClipboardContentAnalysisAsFile(
|
||||
uint64_t aInnerWindowId, SafeContentAnalysisResultCallback* aResolver,
|
||||
nsIURI* aDocumentURI, nsIContentAnalysis* aContentAnalysis,
|
||||
nsITransferable* aFileTrans);
|
||||
|
||||
void RequestUserConfirmation(int32_t aClipboardType,
|
||||
const nsTArray<nsCString>& aFlavorList,
|
||||
mozilla::dom::WindowContext* aWindowContext,
|
||||
|
|
|
|||
Loading…
Reference in a new issue