Bug 764987 - "Allow extensions to add exposed protocols in nsMsgContentPolicy". r=rkent
This commit is contained in:
Родитель
aa70bcfac0
Коммит
1afa917a01
|
@ -22,6 +22,7 @@ XPIDL_SOURCES += [
|
|||
'nsIMsgAccountManager.idl',
|
||||
'nsIMsgAsyncPrompter.idl',
|
||||
'nsIMsgBiffManager.idl',
|
||||
'nsIMsgContentPolicy.idl',
|
||||
'nsIMsgCopyService.idl',
|
||||
'nsIMsgCopyServiceListener.idl',
|
||||
'nsIMsgCustomColumnHandler.idl',
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(c29b2fd3-64d0-4083-a096-c20a9b847a99)]
|
||||
|
||||
/**
|
||||
* This interface provide functions which help extension developers
|
||||
* add their customized schema to the exposed protocls of nsMsgContentPolicy.
|
||||
* By default, a list of existing protocols (such as imap and nntp)
|
||||
* are allowed to process urls locally, while non-matching urls are required
|
||||
* to be processed as external.
|
||||
* This interface allows additional protocols to be added to
|
||||
* the list of protocols that are processed locally.
|
||||
* Typically this would be used in cases where a new messaging protocol
|
||||
* is being added by an extension.
|
||||
*/
|
||||
interface nsIMsgContentPolicy : nsISupports {
|
||||
/**
|
||||
* Add the specific aScheme to nsMsgContentPolicy's exposed protocols.
|
||||
*
|
||||
* @param aScheme scheme who will be added to nsMsgContentPolicy's exposed protocols
|
||||
*/
|
||||
void addExposedProtocol(in ACString aScheme);
|
||||
|
||||
/**
|
||||
* Remove the specific aScheme from nsMsgContentPolicy's exposed protocols.
|
||||
*
|
||||
* @param aScheme scheme who will be removed from nsMsgContentPolicy's exposed protocols
|
||||
*/
|
||||
void removeExposedProtocol(in ACString aScheme);
|
||||
};
|
||||
|
|
@ -33,18 +33,19 @@ static const char kTrustedDomains[] = "mail.trusteddomains";
|
|||
using namespace mozilla::mailnews;
|
||||
|
||||
// Per message headder flags to keep track of whether the user is allowing remote
|
||||
// content for a particular message.
|
||||
// content for a particular message.
|
||||
// if you change or add more values to these constants, be sure to modify
|
||||
// the corresponding definitions in mailWindowOverlay.js
|
||||
#define kNoRemoteContentPolicy 0
|
||||
#define kBlockRemoteContent 1
|
||||
#define kAllowRemoteContent 2
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMsgContentPolicy,
|
||||
nsIContentPolicy,
|
||||
nsIWebProgressListener,
|
||||
nsIObserver,
|
||||
nsISupportsWeakReference)
|
||||
NS_IMPL_ISUPPORTS(nsMsgContentPolicy,
|
||||
nsIContentPolicy,
|
||||
nsIWebProgressListener,
|
||||
nsIMsgContentPolicy,
|
||||
nsIObserver,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
nsMsgContentPolicy::nsMsgContentPolicy()
|
||||
{
|
||||
|
@ -87,7 +88,7 @@ nsresult nsMsgContentPolicy::Init()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @returns true if the sender referenced by aMsgHdr is explicitly allowed to
|
||||
* load remote images according to the PermissionManager
|
||||
*/
|
||||
|
@ -102,7 +103,7 @@ nsMsgContentPolicy::ShouldAcceptRemoteContentForSender(nsIMsgDBHdr *aMsgHdr)
|
|||
nsresult rv = aMsgHdr->GetAuthor(getter_Copies(author));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
nsCString emailAddress;
|
||||
nsCString emailAddress;
|
||||
ExtractEmail(EncodedHeader(author), emailAddress);
|
||||
if (emailAddress.IsEmpty())
|
||||
return false;
|
||||
|
@ -134,7 +135,7 @@ bool nsMsgContentPolicy::IsTrustedDomain(nsIURI * aContentLocation)
|
|||
nsAutoCString host;
|
||||
nsresult rv = aContentLocation->GetHost(host);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !mTrustedMailDomains.IsEmpty())
|
||||
if (NS_SUCCEEDED(rv) && !mTrustedMailDomains.IsEmpty())
|
||||
trustedDomain = MsgHostDomainIsTrusted(host, mTrustedMailDomains);
|
||||
|
||||
return trustedDomain;
|
||||
|
@ -193,14 +194,14 @@ nsMsgContentPolicy::ShouldLoad(uint32_t aContentType,
|
|||
case nsIContentPolicy::TYPE_DOCUMENT:
|
||||
// At this point, we have no intention of supporting a different JS
|
||||
// setting on a subdocument, so we don't worry about TYPE_SUBDOCUMENT here.
|
||||
|
||||
|
||||
// If the timing were right, we'd enable JavaScript on the docshell
|
||||
// for non mailnews URIs here. However, at this point, the
|
||||
// old document may still be around, so we can't do any enabling just yet.
|
||||
// Instead, we apply the policy in nsIWebProgressListener::OnLocationChange.
|
||||
// old document may still be around, so we can't do any enabling just yet.
|
||||
// Instead, we apply the policy in nsIWebProgressListener::OnLocationChange.
|
||||
// For now, we explicitly disable JavaScript in order to be safe rather than
|
||||
// sorry, because OnLocationChange isn't guaranteed to necessarily be called
|
||||
// soon enough to disable it in time (though bz says it _should_ be called
|
||||
// soon enough to disable it in time (though bz says it _should_ be called
|
||||
// soon enough "in all sane cases").
|
||||
rv = SetDisableItemsOnMailNewsUrlDocshells(aContentLocation,
|
||||
aRequestingContext);
|
||||
|
@ -221,7 +222,7 @@ nsMsgContentPolicy::ShouldLoad(uint32_t aContentType,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// NOTE: Not using NS_ENSURE_ARG_POINTER because this is a legitimate case
|
||||
// that can happen. Also keep in mind that the default policy used for a
|
||||
// failure code is ACCEPT.
|
||||
|
@ -237,7 +238,7 @@ nsMsgContentPolicy::ShouldLoad(uint32_t aContentType,
|
|||
if (IsSafeRequestingLocation(aRequestingLocation))
|
||||
return rv;
|
||||
|
||||
// Now default to reject so early returns via NS_ENSURE_SUCCESS
|
||||
// Now default to reject so early returns via NS_ENSURE_SUCCESS
|
||||
// cause content to be rejected.
|
||||
*aDecision = nsIContentPolicy::REJECT_REQUEST;
|
||||
|
||||
|
@ -250,7 +251,7 @@ nsMsgContentPolicy::ShouldLoad(uint32_t aContentType,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// never load unexposed protocols except for http, https and file.
|
||||
// never load unexposed protocols except for http, https and file.
|
||||
// Protocols like ftp are always blocked.
|
||||
if (ShouldBlockUnexposedProtocol(aContentLocation))
|
||||
return NS_OK;
|
||||
|
@ -390,6 +391,10 @@ nsMsgContentPolicy::IsExposedProtocol(nsIURI *aContentLocation)
|
|||
MsgLowerCaseEqualsLiteral(contentScheme, "about"))
|
||||
return true;
|
||||
|
||||
// check if customized exposed scheme
|
||||
if (mCustomExposedProtocols.Contains(contentScheme))
|
||||
return true;
|
||||
|
||||
bool isData;
|
||||
bool isChrome;
|
||||
bool isRes;
|
||||
|
@ -468,7 +473,7 @@ nsMsgContentPolicy::ShouldAcceptRemoteContentForMsgHdr(nsIMsgDBHdr *aMsgHdr,
|
|||
// kNoRemoteContentPolicy means we have never set a value on the message
|
||||
if (result == nsIContentPolicy::REJECT_REQUEST && !remoteContentPolicy)
|
||||
aMsgHdr->SetUint32Property("remoteContentPolicy", kBlockRemoteContent);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -498,7 +503,7 @@ private:
|
|||
nsCOMPtr<nsIURI> mContentURI;
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* This function is used to determine if we allow content for a remote message.
|
||||
* If we reject loading remote content, then we'll inform the message window
|
||||
* that this message has remote content (and hence we are not loading it).
|
||||
|
@ -548,7 +553,7 @@ nsMsgContentPolicy::ShouldAcceptContentForPotentialMsg(nsIURI *aOriginatorLocati
|
|||
if (*aDecision == nsIContentPolicy::REJECT_REQUEST)
|
||||
{
|
||||
nsCOMPtr<nsIMsgWindow> msgWindow;
|
||||
(void)mailnewsUrl->GetMsgWindow(getter_AddRefs(msgWindow));
|
||||
(void)mailnewsUrl->GetMsgWindow(getter_AddRefs(msgWindow));
|
||||
if (msgWindow)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
|
@ -561,9 +566,9 @@ nsMsgContentPolicy::ShouldAcceptContentForPotentialMsg(nsIURI *aOriginatorLocati
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Content policy logic for compose windows
|
||||
*
|
||||
*
|
||||
*/
|
||||
void nsMsgContentPolicy::ComposeShouldLoad(nsIMsgCompose *aMsgCompose,
|
||||
nsISupports *aRequestingContext,
|
||||
|
@ -601,7 +606,7 @@ void nsMsgContentPolicy::ComposeShouldLoad(nsIMsgCompose *aMsgCompose,
|
|||
// images that are a part of the quoted content to load. Fortunately, after
|
||||
// the quoted message has been inserted into the document, mail compose
|
||||
// flags remote content elements that came from the original message with a
|
||||
// moz-do-not-send attribute.
|
||||
// moz-do-not-send attribute.
|
||||
if (*aDecision == nsIContentPolicy::REJECT_REQUEST)
|
||||
{
|
||||
bool insertingQuotedContent = true;
|
||||
|
@ -613,7 +618,7 @@ void nsMsgContentPolicy::ComposeShouldLoad(nsIMsgCompose *aMsgCompose,
|
|||
if (element)
|
||||
{
|
||||
bool doNotSendAttrib;
|
||||
if (NS_SUCCEEDED(element->HasAttribute(NS_LITERAL_STRING("moz-do-not-send"), &doNotSendAttrib)) &&
|
||||
if (NS_SUCCEEDED(element->HasAttribute(NS_LITERAL_STRING("moz-do-not-send"), &doNotSendAttrib)) &&
|
||||
!doNotSendAttrib)
|
||||
*aDecision = nsIContentPolicy::ACCEPT;
|
||||
}
|
||||
|
@ -655,8 +660,8 @@ nsresult nsMsgContentPolicy::SetDisableItemsOnMailNewsUrlDocshells(
|
|||
// ShouldProcess, and if it's possible for this to be null when called from
|
||||
// ShouldLoad, but not in the corresponding ShouldProcess call,
|
||||
// we need to re-think the assumptions underlying this code.
|
||||
|
||||
// If there's no docshell to get to, there's nowhere for the JavaScript to
|
||||
|
||||
// If there's no docshell to get to, there's nowhere for the JavaScript to
|
||||
// run, so we're already safe and don't need to disable anything.
|
||||
if (!aRequestingContext) {
|
||||
return NS_OK;
|
||||
|
@ -681,7 +686,7 @@ nsresult nsMsgContentPolicy::SetDisableItemsOnMailNewsUrlDocshells(
|
|||
rv = flOwner->GetFrameLoader(getter_AddRefs(frameLoader));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(frameLoader, NS_ERROR_INVALID_POINTER);
|
||||
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
rv = frameLoader->GetDocShell(getter_AddRefs(docShell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -749,7 +754,7 @@ nsMsgContentPolicy::GetRootDocShellForContext(nsISupports *aRequestingContext,
|
|||
* Navigates up the docshell tree from aRequestingContext and finds the
|
||||
* highest parent with the same type docshell as aRequestingContext, then
|
||||
* returns the URI associated with that docshell.
|
||||
*/
|
||||
*/
|
||||
nsresult
|
||||
nsMsgContentPolicy::GetOriginatingURIForContext(nsISupports *aRequestingContext,
|
||||
nsIURI **aURI)
|
||||
|
@ -783,7 +788,7 @@ nsMsgContentPolicy::ShouldProcess(uint32_t aContentType,
|
|||
{
|
||||
// XXX Returning ACCEPT is presumably only a reasonable thing to do if we
|
||||
// think that ShouldLoad is going to catch all possible cases (i.e. that
|
||||
// everything we use to make decisions is going to be available at
|
||||
// everything we use to make decisions is going to be available at
|
||||
// ShouldLoad time, and not only become available in time for ShouldProcess).
|
||||
// Do we think that's actually the case?
|
||||
*aDecision = nsIContentPolicy::ACCEPT;
|
||||
|
@ -792,7 +797,7 @@ nsMsgContentPolicy::ShouldProcess(uint32_t aContentType,
|
|||
|
||||
NS_IMETHODIMP nsMsgContentPolicy::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData)
|
||||
{
|
||||
if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic))
|
||||
if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic))
|
||||
{
|
||||
NS_LossyConvertUTF16toASCII pref(aData);
|
||||
|
||||
|
@ -810,11 +815,11 @@ NS_IMETHODIMP nsMsgContentPolicy::Observe(nsISupports *aSubject, const char *aTo
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* We implement the nsIWebProgressListener interface in order to enforce
|
||||
* settings at onLocationChange time.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
NS_IMETHODIMP
|
||||
nsMsgContentPolicy::OnStateChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest, uint32_t aStateFlags,
|
||||
nsresult aStatus)
|
||||
|
@ -833,7 +838,7 @@ nsMsgContentPolicy::OnProgressChange(nsIWebProgress *aWebProgress,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NS_IMETHODIMP
|
||||
nsMsgContentPolicy::OnLocationChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest, nsIURI *aLocation,
|
||||
uint32_t aFlags)
|
||||
|
@ -841,11 +846,11 @@ nsMsgContentPolicy::OnLocationChange(nsIWebProgress *aWebProgress,
|
|||
nsresult rv;
|
||||
|
||||
// If anything goes wrong and/or there's no docshell associated with this
|
||||
// request, just give up. The behavior ends up being "don't consider
|
||||
// request, just give up. The behavior ends up being "don't consider
|
||||
// re-enabling JS on the docshell", which is the safe thing to do (and if
|
||||
// the problem was that there's no docshell, that means that there was
|
||||
// the problem was that there's no docshell, that means that there was
|
||||
// nowhere for any JavaScript to run, so we're already safe
|
||||
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_OK;
|
||||
|
@ -860,7 +865,7 @@ nsMsgContentPolicy::OnLocationChange(nsIWebProgress *aWebProgress,
|
|||
" do not point to the same docshell");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
nsCOMPtr<nsIMsgMessageUrl> messageUrl = do_QueryInterface(aLocation, &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -900,3 +905,27 @@ nsMsgContentPolicy::OnSecurityChange(nsIWebProgress *aWebProgress,
|
|||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of nsIMsgContentPolicy
|
||||
*
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsMsgContentPolicy::AddExposedProtocol(const nsACString &aScheme)
|
||||
{
|
||||
if (mCustomExposedProtocols.Contains(nsCString(aScheme)))
|
||||
return NS_OK;
|
||||
|
||||
mCustomExposedProtocols.AppendElement(aScheme);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgContentPolicy::RemoveExposedProtocol(const nsACString &aScheme)
|
||||
{
|
||||
mCustomExposedProtocols.RemoveElement(nsCString(aScheme));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "nsIMsgCompose.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIMsgContentPolicy.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
/* DBFCFDF0-4489-4faa-8122-190FD1EFA16C */
|
||||
#define NS_MSGCONTENTPOLICY_CID \
|
||||
|
@ -35,6 +37,7 @@ class nsIDocShell;
|
|||
class nsMsgContentPolicy : public nsIContentPolicy,
|
||||
public nsIObserver,
|
||||
public nsIWebProgressListener,
|
||||
public nsIMsgContentPolicy,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
|
@ -46,6 +49,7 @@ public:
|
|||
NS_DECL_NSICONTENTPOLICY
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
NS_DECL_NSIMSGCONTENTPOLICY
|
||||
|
||||
protected:
|
||||
virtual ~nsMsgContentPolicy();
|
||||
|
@ -79,6 +83,8 @@ protected:
|
|||
nsIURI **aURI);
|
||||
nsresult SetDisableItemsOnMailNewsUrlDocshells(nsIURI *aContentLocation,
|
||||
nsISupports *aRequestingContext);
|
||||
|
||||
nsTArray<nsCString> mCustomExposedProtocols;
|
||||
};
|
||||
|
||||
#endif // _nsMsgContentPolicy_H_
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* Test suite for nsIMsgContentPolicy to check we could add/remove customized protocol to
|
||||
* nsMsgContentPolicy.
|
||||
*/
|
||||
|
||||
function makeURI(aURL) {
|
||||
var ioService = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
return ioService.newURI(aURL, null, null);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
var content_policy = Cc["@mozilla.org/messenger/content-policy;1"]
|
||||
.getService(Ci.nsIContentPolicy);
|
||||
|
||||
Assert.ok(content_policy);
|
||||
|
||||
var msg_content_policy = content_policy.QueryInterface(Ci.nsIMsgContentPolicy);
|
||||
|
||||
Assert.ok(msg_content_policy);
|
||||
|
||||
var req_uri = makeURI("custom-scheme://custom_url/1.emal");
|
||||
Assert.ok(req_uri);
|
||||
|
||||
var content_uri = makeURI("custom-scheme://custom_content_url/1.jsp");
|
||||
Assert.ok(content_uri);
|
||||
|
||||
var decision = content_policy.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
|
||||
content_uri,
|
||||
req_uri,
|
||||
null,
|
||||
"img/jpeg",
|
||||
null);
|
||||
Assert.notEqual(decision,
|
||||
Ci.nsIContentPolicy.ACCEPT,
|
||||
"customized protocol should not load");
|
||||
|
||||
msg_content_policy.addExposedProtocol("custom-scheme");
|
||||
|
||||
decision = content_policy.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
|
||||
content_uri,
|
||||
req_uri,
|
||||
null,
|
||||
"img/jpeg",
|
||||
null);
|
||||
Assert.equal(decision,
|
||||
Ci.nsIContentPolicy.ACCEPT,
|
||||
"customized protocol should load");
|
||||
|
||||
msg_content_policy.removeExposedProtocol("custom-scheme");
|
||||
|
||||
decision = content_policy.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
|
||||
content_uri,
|
||||
req_uri,
|
||||
null,
|
||||
"img/jpeg",
|
||||
null);
|
||||
Assert.notEqual(decision,
|
||||
Ci.nsIContentPolicy.ACCEPT,
|
||||
"customized protocol should not load");
|
||||
};
|
||||
|
|
@ -43,6 +43,7 @@ support-files = nodelist_test.xml data/*
|
|||
# Not yet working for non-Mac OS
|
||||
skip-if = os != 'mac'
|
||||
|
||||
[test_nsIMsgContentPolicy.js]
|
||||
[test_nsIMsgFolder.js]
|
||||
[test_nsIMsgFolderListener.js]
|
||||
[test_nsIMsgFolderListenerLocal.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче