forked from mirrors/gecko-dev
Bug 1888259 - Show a notification when a Content Analysis request is denied for lack of an agent connection r=dlp-reviewers,fluent-reviewers,handyman
Note that this also covers the case when the connection initially succeeds but then the agent goes away - we hope to handle this better in bug 1888293. This also shows a message if the signature verification fails. Differential Revision: https://phabricator.services.mozilla.com/D206024
This commit is contained in:
parent
e5eba44e91
commit
2bd7572f35
5 changed files with 126 additions and 16 deletions
|
|
@ -243,7 +243,7 @@ export const ContentAnalysis = {
|
|||
},
|
||||
|
||||
// nsIObserver
|
||||
async observe(aSubj, aTopic) {
|
||||
async observe(aSubj, aTopic, _aData) {
|
||||
switch (aTopic) {
|
||||
case "quit-application-requested": {
|
||||
let pendingRequests =
|
||||
|
|
@ -345,7 +345,7 @@ export const ContentAnalysis = {
|
|||
});
|
||||
}
|
||||
break;
|
||||
case "dlp-response":
|
||||
case "dlp-response": {
|
||||
const request = aSubj.QueryInterface(Ci.nsIContentAnalysisResponse);
|
||||
// Cancels timer or slow message UI,
|
||||
// if present, and possibly presents the CA verdict.
|
||||
|
|
@ -379,12 +379,14 @@ export const ContentAnalysis = {
|
|||
windowAndResourceNameOrOperationType.resourceNameOrOperationType,
|
||||
windowAndResourceNameOrOperationType.browsingContext,
|
||||
request.requestToken,
|
||||
responseResult
|
||||
responseResult,
|
||||
request.cancelError
|
||||
);
|
||||
this._showAnotherPendingDialog(
|
||||
windowAndResourceNameOrOperationType.browsingContext
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -662,7 +664,8 @@ export const ContentAnalysis = {
|
|||
aResourceNameOrOperationType,
|
||||
aBrowsingContext,
|
||||
aRequestToken,
|
||||
aCAResult
|
||||
aCAResult,
|
||||
aRequestCancelError
|
||||
) {
|
||||
let message = null;
|
||||
let timeoutMs = 0;
|
||||
|
|
@ -683,7 +686,7 @@ export const ContentAnalysis = {
|
|||
);
|
||||
timeoutMs = this._RESULT_NOTIFICATION_FAST_TIMEOUT_MS;
|
||||
break;
|
||||
case Ci.nsIContentAnalysisResponse.eWarn:
|
||||
case Ci.nsIContentAnalysisResponse.eWarn: {
|
||||
const result = await Services.prompt.asyncConfirmEx(
|
||||
aBrowsingContext,
|
||||
Ci.nsIPromptService.MODAL_TYPE_TAB,
|
||||
|
|
@ -711,6 +714,7 @@ export const ContentAnalysis = {
|
|||
const allow = result.get("buttonNumClicked") === 0;
|
||||
lazy.gContentAnalysis.respondToWarnDialog(aRequestToken, allow);
|
||||
return null;
|
||||
}
|
||||
case Ci.nsIContentAnalysisResponse.eBlock:
|
||||
if (!lazy.showBlockedResult) {
|
||||
// Don't show anything
|
||||
|
|
@ -724,13 +728,51 @@ export const ContentAnalysis = {
|
|||
timeoutMs = this._RESULT_NOTIFICATION_TIMEOUT_MS;
|
||||
break;
|
||||
case Ci.nsIContentAnalysisResponse.eUnspecified:
|
||||
message = await this.l10n.formatValue("contentanalysis-error-message", {
|
||||
content: this._getResourceNameFromNameOrOperationType(
|
||||
aResourceNameOrOperationType
|
||||
),
|
||||
});
|
||||
message = await this.l10n.formatValue(
|
||||
"contentanalysis-unspecified-error-message",
|
||||
{
|
||||
agent: lazy.agentName,
|
||||
content: this._getResourceNameFromNameOrOperationType(
|
||||
aResourceNameOrOperationType
|
||||
),
|
||||
}
|
||||
);
|
||||
timeoutMs = this._RESULT_NOTIFICATION_TIMEOUT_MS;
|
||||
break;
|
||||
case Ci.nsIContentAnalysisResponse.eCanceled:
|
||||
{
|
||||
let messageId;
|
||||
switch (aRequestCancelError) {
|
||||
case Ci.nsIContentAnalysisResponse.eUserInitiated:
|
||||
console.error(
|
||||
"Got unexpected cancel response with eUserInitiated"
|
||||
);
|
||||
return null;
|
||||
case Ci.nsIContentAnalysisResponse.eNoAgent:
|
||||
messageId = "contentanalysis-no-agent-connected-message";
|
||||
break;
|
||||
case Ci.nsIContentAnalysisResponse.eInvalidAgentSignature:
|
||||
messageId = "contentanalysis-invalid-agent-signature-message";
|
||||
break;
|
||||
case Ci.nsIContentAnalysisResponse.eErrorOther:
|
||||
messageId = "contentanalysis-unspecified-error-message";
|
||||
break;
|
||||
default:
|
||||
console.error(
|
||||
"Unexpected CA cancelError value: " + aRequestCancelError
|
||||
);
|
||||
messageId = "contentanalysis-unspecified-error-message";
|
||||
break;
|
||||
}
|
||||
message = await this.l10n.formatValue(messageId, {
|
||||
agent: lazy.agentName,
|
||||
content: this._getResourceNameFromNameOrOperationType(
|
||||
aResourceNameOrOperationType
|
||||
),
|
||||
});
|
||||
timeoutMs = this._RESULT_NOTIFICATION_TIMEOUT_MS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unexpected CA result value: " + aCAResult);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -612,6 +612,12 @@ ContentAnalysisResponse::GetAction(Action* aAction) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentAnalysisResponse::GetCancelError(CancelError* aCancelError) {
|
||||
*aCancelError = mCancelError;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void LogAcknowledgement(
|
||||
content_analysis::sdk::ContentAnalysisAcknowledgement* aPbAck) {
|
||||
if (!static_cast<LogModule*>(gContentAnalysisLog)
|
||||
|
|
@ -643,6 +649,10 @@ void ContentAnalysisResponse::SetOwner(RefPtr<ContentAnalysis> aOwner) {
|
|||
mOwner = std::move(aOwner);
|
||||
}
|
||||
|
||||
void ContentAnalysisResponse::SetCancelError(CancelError aCancelError) {
|
||||
mCancelError = aCancelError;
|
||||
}
|
||||
|
||||
void ContentAnalysisResponse::ResolveWarnAction(bool aAllowContent) {
|
||||
MOZ_ASSERT(mAction == Action::eWarn);
|
||||
mAction = aAllowContent ? Action::eAllow : Action::eBlock;
|
||||
|
|
@ -955,6 +965,20 @@ nsresult ContentAnalysis::CancelWithError(nsCString aRequestToken,
|
|||
: nsIContentAnalysisResponse::Action::eCanceled,
|
||||
aRequestToken);
|
||||
response->SetOwner(owner);
|
||||
nsIContentAnalysisResponse::CancelError cancelError;
|
||||
switch (aResult) {
|
||||
case NS_ERROR_NOT_AVAILABLE:
|
||||
cancelError = nsIContentAnalysisResponse::CancelError::eNoAgent;
|
||||
break;
|
||||
case NS_ERROR_INVALID_SIGNATURE:
|
||||
cancelError =
|
||||
nsIContentAnalysisResponse::CancelError::eInvalidAgentSignature;
|
||||
break;
|
||||
default:
|
||||
cancelError = nsIContentAnalysisResponse::CancelError::eErrorOther;
|
||||
break;
|
||||
}
|
||||
response->SetCancelError(cancelError);
|
||||
obsServ->NotifyObservers(response, "dlp-response", nullptr);
|
||||
nsMainThreadPtrHandle<nsIContentAnalysisCallback> callbackHolder;
|
||||
{
|
||||
|
|
@ -1236,8 +1260,28 @@ NS_IMETHODIMP
|
|||
ContentAnalysis::AnalyzeContentRequestCallback(
|
||||
nsIContentAnalysisRequest* aRequest, bool aAutoAcknowledge,
|
||||
nsIContentAnalysisCallback* aCallback) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_ARG(aRequest);
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
nsresult rv = AnalyzeContentRequestCallbackPrivate(aRequest, aAutoAcknowledge,
|
||||
aCallback);
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCString requestToken;
|
||||
nsresult requestTokenRv = aRequest->GetRequestToken(requestToken);
|
||||
NS_ENSURE_SUCCESS(requestTokenRv, requestTokenRv);
|
||||
CancelWithError(requestToken, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult ContentAnalysis::AnalyzeContentRequestCallbackPrivate(
|
||||
nsIContentAnalysisRequest* aRequest, bool aAutoAcknowledge,
|
||||
nsIContentAnalysisCallback* aCallback) {
|
||||
// Make sure we send the notification first, so if we later return
|
||||
// an error the JS will handle it correctly.
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
mozilla::services::GetObserverService();
|
||||
obsServ->NotifyObservers(aRequest, "dlp-request-made", nullptr);
|
||||
|
||||
bool isActive;
|
||||
nsresult rv = GetIsActive(&isActive);
|
||||
|
|
@ -1246,10 +1290,6 @@ ContentAnalysis::AnalyzeContentRequestCallback(
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
mozilla::services::GetObserverService();
|
||||
obsServ->NotifyObservers(aRequest, "dlp-request-made", nullptr);
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// since we're on the main thread, don't need to synchronize this
|
||||
int64_t requestCount = ++mRequestCount;
|
||||
|
|
|
|||
|
|
@ -135,6 +135,10 @@ class ContentAnalysis final : public nsIContentAnalysis {
|
|||
nsresult CreateContentAnalysisClient(nsCString&& aPipePathName,
|
||||
nsString&& aClientSignatureSetting,
|
||||
bool aIsPerUser);
|
||||
nsresult AnalyzeContentRequestCallbackPrivate(
|
||||
nsIContentAnalysisRequest* aRequest, bool aAutoAcknowledge,
|
||||
nsIContentAnalysisCallback* aCallback);
|
||||
|
||||
nsresult RunAnalyzeRequestTask(
|
||||
const RefPtr<nsIContentAnalysisRequest>& aRequest, bool aAutoAcknowledge,
|
||||
int64_t aRequestCount,
|
||||
|
|
@ -219,6 +223,7 @@ class ContentAnalysisResponse final : public nsIContentAnalysisResponse {
|
|||
|
||||
void SetOwner(RefPtr<ContentAnalysis> aOwner);
|
||||
void DoNotAcknowledge() { mDoNotAcknowledge = true; }
|
||||
void SetCancelError(CancelError aCancelError);
|
||||
|
||||
private:
|
||||
~ContentAnalysisResponse() = default;
|
||||
|
|
@ -239,7 +244,11 @@ class ContentAnalysisResponse final : public nsIContentAnalysisResponse {
|
|||
// Identifier for the corresponding nsIContentAnalysisRequest
|
||||
nsCString mRequestToken;
|
||||
|
||||
// ContentAnalysis (or, more precisely, it's Client object) must outlive
|
||||
// If mAction is eCanceled, this is the error explaining why the request was
|
||||
// canceled, or eUserInitiated if the user canceled it.
|
||||
CancelError mCancelError = CancelError::eUserInitiated;
|
||||
|
||||
// ContentAnalysis (or, more precisely, its Client object) must outlive
|
||||
// the transaction.
|
||||
RefPtr<ContentAnalysis> mOwner;
|
||||
|
||||
|
|
|
|||
|
|
@ -52,8 +52,18 @@ interface nsIContentAnalysisResponse : nsISupports
|
|||
eCanceled = 1001,
|
||||
};
|
||||
|
||||
cenum CancelError : 32 {
|
||||
eUserInitiated = 0,
|
||||
eNoAgent = 1,
|
||||
eInvalidAgentSignature = 2,
|
||||
eErrorOther = 3,
|
||||
};
|
||||
|
||||
[infallible] readonly attribute nsIContentAnalysisResponse_Action action;
|
||||
[infallible] readonly attribute boolean shouldAllowContent;
|
||||
// If action is eCanceled, this is the error explaining why the request was canceled,
|
||||
// or eUserInitiated if the user canceled it.
|
||||
[infallible] readonly attribute nsIContentAnalysisResponse_CancelError cancelError;
|
||||
|
||||
// Identifier for the corresponding nsIContentAnalysisRequest
|
||||
readonly attribute ACString requestToken;
|
||||
|
|
|
|||
|
|
@ -42,8 +42,17 @@ contentanalysis-genericresponse-message = Content Analysis responded with { $res
|
|||
# $content - Description of the content being blocked, such as "clipboard" or "aFile.txt"
|
||||
contentanalysis-block-message = Your organization uses data-loss prevention software that has blocked this content: { $content }.
|
||||
# Variables:
|
||||
# $agent - The name of the DLP agent doing the analysis
|
||||
# $content - Description of the content being blocked, such as "clipboard" or "aFile.txt"
|
||||
contentanalysis-error-message = An error occurred in communicating with the data-loss prevention software. Transfer denied for resource: { $content }.
|
||||
contentanalysis-unspecified-error-message = An error occurred in communicating with { $agent }. Transfer denied for resource: { $content }.
|
||||
# Variables:
|
||||
# $agent - The name of the DLP agent doing the analysis
|
||||
# $content - Description of the content being blocked, such as "clipboard" or "aFile.txt"
|
||||
contentanalysis-no-agent-connected-message = Unable to connect to { $agent }. Transfer denied for resource: { $content }.
|
||||
# Variables:
|
||||
# $agent - The name of the DLP agent doing the analysis
|
||||
# $content - Description of the content being blocked, such as "clipboard" or "aFile.txt"
|
||||
contentanalysis-invalid-agent-signature-message = Failed signature verification for { $agent }. Transfer denied for resource: { $content }.
|
||||
|
||||
contentanalysis-inprogress-quit-title = Quit { -brand-shorter-name }?
|
||||
contentanalysis-inprogress-quit-message = Several actions are in progress. If you quit { -brand-shorter-name }, these actions will not be completed.
|
||||
|
|
|
|||
Loading…
Reference in a new issue