Bug 296758 Adding phishing detection to mailnews

p=me r=mnyromyr sr=bienvenu a=asa


git-svn-id: svn://10.0.0.236/trunk@177340 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bugzilla%arlen.demon.co.uk
2005-08-08 18:29:12 +00:00
parent fccf294891
commit ab3519a637
22 changed files with 599 additions and 109 deletions

View File

@@ -210,6 +210,8 @@ var DefaultController =
case "cmd_markAsJunk":
case "cmd_markAsNotJunk":
case "cmd_recalculateJunkScore":
case "cmd_markAsShowRemote":
case "cmd_markAsNotPhish":
case "cmd_applyFilters":
case "cmd_runJunkControls":
case "cmd_deleteJunk":
@@ -322,12 +324,16 @@ var DefaultController =
case "cmd_markAsFlagged":
case "button_file":
case "cmd_file":
return (GetNumSelectedMessages() > 0 );
return (GetNumSelectedMessages() > 0);
case "cmd_markAsJunk":
case "cmd_markAsNotJunk":
case "cmd_recalculateJunkScore":
// can't do news on junk yet.
return (GetNumSelectedMessages() > 0 && !isNewsURI(GetFirstSelectedMessage()));
case "cmd_markAsShowRemote":
return (GetNumSelectedMessages() > 0 && checkMsgHdrPropertyIsNot("remoteContentPolicy", kAllowRemoteContent));
case "cmd_markAsNotPhish":
return (GetNumSelectedMessages() > 0 && checkMsgHdrPropertyIsNot("notAPhishMessage", kNotAPhishMessage));
case "cmd_applyFilters":
if (gDBView)
gDBView.getCommandStatus(nsMsgViewCommandType.applyFilters, enabled, checkStatus);
@@ -633,6 +639,12 @@ var DefaultController =
case "cmd_recalculateJunkScore":
analyzeMessagesForJunk();
return;
case "cmd_markAsShowRemote":
LoadMsgWithRemoteContent();
return;
case "cmd_markAsNotPhish":
MsgIsNotAScam();
return;
case "cmd_applyFilters":
MsgApplyFilters(null);
return;

View File

@@ -84,6 +84,7 @@
<script type="application/x-javascript" src="chrome://messenger/content/messengerdnd.js"/>
<script type="application/x-javascript" src="chrome://messenger/content/accountUtils.js"/>
<script type="application/x-javascript" src="chrome://messenger/content/mail-offline.js"/>
<script type="application/x-javascript" src="chrome://messenger/content/phishingDetector.js"/>
<script type="application/x-javascript" src="chrome://communicator/content/contentAreaClick.js"/>
<script type="application/x-javascript" src="chrome://global/content/nsTransferable.js"/>
<script type="application/x-javascript" src="chrome://global/content/nsDragAndDrop.js"/>
@@ -184,14 +185,14 @@
</splitter>
<vbox id="messagepanebox" flex="2" minheight="100" height="200" minwidth="100" width="200" persist="collapsed height width" class="window-focusborder" focusring="false">
<hbox id="junkBar"/>
<deck id="msgNotificationBar"/>
<hbox id="msgHeaderView"/>
<browser id="messagepane" name="messagepane" height="0" flex="1"
context="messagePaneContext" minwidth="1" minheight="1"
disablesecurity="true" disablehistory="true" autofind="false"
type="content-primary" onclick="messagePaneOnClick(event);"/>
type="content-primary" onclick="return messagePaneOnClick(event);"/>
</vbox>
</box>

View File

@@ -228,16 +228,15 @@ function messagePaneOnClick(event)
// if this is stand alone mail (no browser)
// or this isn't a simple left click, do nothing, and let the normal code execute
if (event.button != 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
{
contentAreaClick(event);
return;
}
return contentAreaClick(event);
// try to determine the href for what you are clicking on.
// for example, it might be "" if you aren't left clicking on a link
var href = hrefForClickEvent(event);
if (!href)
return;
var ceParams = {event: event, href: "", linkNode: null};
hrefAndLinkNodeForClickEvent(ceParams);
var href = ceParams.href;
if (!href)
return true;
// we know that http://, https://, ftp://, file://, chrome://,
// resource://, about:, and gopher:// (as if),
@@ -248,7 +247,7 @@ function messagePaneOnClick(event)
// and let the normal code handle it
var needABrowser = /(^http(s)?:|^ftp:|^file:|^gopher:|^chrome:|^resource:|^about:)/i;
if (href.search(needABrowser) == -1)
return;
return true;
// however, if the protocol should not be loaded internally, then we should
// not put up a new browser window. we should just let the usual processing
@@ -258,7 +257,7 @@ function messagePaneOnClick(event)
extProtService = extProtService.QueryInterface(Components.interfaces.nsIExternalProtocolService);
var scheme = href.substring(0, href.indexOf(":"));
if (!extProtService.isExposedProtocol(scheme))
return;
return true;
}
catch (ex) {} // ignore errors, and just assume that we can proceed.
@@ -270,7 +269,11 @@ function messagePaneOnClick(event)
// we want to preventDefault, so that in
// nsGenericHTMLElement::HandleDOMEventForAnchors(), we don't try to handle the click again
event.preventDefault();
if (isPhishingURL(ceParams.linkNode, false))
return false;
openTopBrowserWith(href);
return true;
}
function AddDataSources()
@@ -529,30 +532,32 @@ function StopUrls()
msgWindow.StopUrls();
}
function loadStartPage() {
try {
// collapse the junk bar
SetUpJunkBar(null);
function loadStartPage()
{
try
{
gMessageNotificationBar.clearMsgNotifications();
var startpageenabled = pref.getBoolPref("mailnews.start_page.enabled");
if (startpageenabled) {
var startpage = pref.getComplexValue("mailnews.start_page.url",
Components.interfaces.nsIPrefLocalizedString).data;
if (startpage != "") {
// first, clear out the charset setting.
messenger.setDisplayCharset("");
GetMessagePaneFrame().location.href = startpage;
//dump("start message pane with: " + startpage + "\n");
ClearMessageSelection();
}
}
}
catch (ex) {
dump("Error loading start page.\n");
return;
var startpageenabled = pref.getBoolPref("mailnews.start_page.enabled");
if (startpageenabled)
{
var startpage = pref.getComplexValue("mailnews.start_page.url",
Components.interfaces.nsIPrefLocalizedString).data;
if (startpage)
{
// first, clear out the charset setting.
messenger.setDisplayCharset("");
GetMessagePaneFrame().location.href = startpage;
//dump("start message pane with: " + startpage + "\n");
ClearMessageSelection();
}
}
}
catch (ex)
{
dump("Error loading start page.\n");
return;
}
}
// Display AccountCentral page when users clicks on the Account Folder.

View File

@@ -27,6 +27,7 @@
* Jan Varga <varga@ku.sk>
* Seth Spitzer <sspitzer@netscape.com>
* David Bienvenu <bienvenu@netscape.com>
* Ian Neal <bugzilla@arlen.demon.co.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@@ -53,6 +54,22 @@ const kClassicMailLayout = 0;
const kWideMailLayout = 1;
const kVerticalMailLayout = 2;
// Per message header flags to keep track of whether the user is allowing remote
// content for a particular message.
// if you change or add more values to these constants, be sure to modify
// the corresponding definitions in nsMsgContentPolicy.cpp
const kNoRemoteContentPolicy = 0;
const kBlockRemoteContent = 1;
const kAllowRemoteContent = 2;
const kIsAPhishMessage = 0;
const kNotAPhishMessage = 1;
const kMsgNotificationNoStatus = 0;
const kMsgNotificationJunkBar = 1;
const kMsgNotificationRemoteImages = 2;
const kMsgNotificationPhishingBar = 3;
var gMessengerBundle;
var gPromptService;
var gOfflinePromptsBundle;
@@ -2049,40 +2066,143 @@ function HandleJunkStatusChanged(folder)
var loadedMessage = GetLoadedMessage();
if (loadedMessage && (!(/type=x-message-display/.test(loadedMessage))) && IsCurrentLoadedFolder(folder))
{
var messageURI = GetLoadedMessage();
// if multiple message are selected
// and we change the junk status
// we don't want to show the junk bar
// (since the message pane is blank)
if (messageURI && (GetNumSelectedMessages() == 1))
SetUpJunkBar(messenger.messageServiceFromURI(messageURI).messageURIToMsgHdr(messageURI));
else
SetUpJunkBar(null);
// if multiple message are selected and we change the junk status
// we don't want to show the junk bar (since the message pane is blank)
var msgHdr = null;
if (GetNumSelectedMessages() == 1)
msgHdr = messenger.messageServiceFromURI(loadedMessage).messageURIToMsgHdr(loadedMessage);
gMessageNotificationBar.setJunkMsg(msgHdr);
}
}
function SetUpJunkBar(aMsgHdr)
var gMessageNotificationBar =
{
// XXX todo
// should this happen on the start, or at the end?
// if at the end, we might keep the "this message is junk" up for a while, until a big message is loaded
// or do we need to wait until here, to make sure the message is fully analyzed
// what about almost hiding it on the start, and then showing here?
mBarStatus: 0,
// flag bit values for mBarStatus, indexed by kMsgNotificationXXX
mBarFlagValues: [
0, // kMsgNotificationNoStatus
1, // 1 << (kMsgNotificationJunkBar - 1)
2, // 1 << (kMsgNotificationRemoteImages - 1)
4 // 1 << (kMsgNotificationPhishingBar - 1)
],
var isJunk = false;
mMsgNotificationBar: document.getElementById('msgNotificationBar'),
setJunkMsg: function(aMsgHdr)
{
var isJunk = false;
var isCurrentlyNotJunk = this.mMsgNotificationBar.selectedIndex != kMsgNotificationJunkBar;
if (aMsgHdr) {
var junkScore = aMsgHdr.getStringProperty("junkscore");
isJunk = ((junkScore != "") && (junkScore != "0"));
if (aMsgHdr)
{
var junkScore = aMsgHdr.getStringProperty("junkscore");
isJunk = ((junkScore != "") && (junkScore != "0"));
}
this.updateMsgNotificationBar (kMsgNotificationJunkBar, isJunk);
goUpdateCommand('button_junk');
},
setRemoteContentMsg: function(aMsgHdr)
{
var blockRemote = aMsgHdr &&
aMsgHdr.getUint32Property("remoteContentPolicy") == kBlockRemoteContent;
this.updateMsgNotificationBar(kMsgNotificationRemoteImages, blockRemote);
},
// aUrl is the nsIURI for the message currently loaded in the message pane
setPhishingMsg: function(aUrl)
{
// if we've explicitly marked this message as not being an email scam, then don't
// bother checking it with the phishing detector.
var phishingMsg = false;
if (!checkMsgHdrPropertyIsNot("notAPhishMessage", kIsAPhishMessage))
phishingMsg = isMsgEmailScam(aUrl);
this.updateMsgNotificationBar(kMsgNotificationPhishingBar, phishingMsg);
},
clearMsgNotifications: function()
{
this.updateMsgNotificationBar(kMsgNotificationNoStatus, true);
},
// private method used to set our message notification deck to the correct value...
updateMsgNotificationBar: function(aIndex, aSet)
{
var chunk = this.mBarFlagValues[aIndex];
var status = aSet ? this.mBarStatus | chunk : this.mBarStatus & ~chunk;
this.mBarStatus = status;
// the junk message takes precedence over the phishing message
// which takes precedence over the remote content message
if (status & this.mBarFlagValues[kMsgNotificationJunkBar])
aIndex = kMsgNotificationJunkBar;
else if (status & this.mBarFlagValues[kMsgNotificationPhishingBar])
aIndex = kMsgNotificationPhishingBar;
else if (status & this.mBarFlagValues[kMsgNotificationRemoteImages])
aIndex = kMsgNotificationRemoteImages;
else
aIndex = kMsgNotificationNoStatus;
if (status == kMsgNotificationNoStatus)
this.mMsgNotificationBar.setAttribute('collapsed', true);
else
this.mMsgNotificationBar.removeAttribute('collapsed');
this.mMsgNotificationBar.selectedIndex = aIndex;
}
var junkBar = document.getElementById("junkBar");
if (isJunk)
junkBar.removeAttribute("collapsed");
else
junkBar.setAttribute("collapsed","true");
goUpdateCommand('button_junk');
};
function LoadMsgWithRemoteContent()
{
// we want to get the msg hdr for the currently selected message
// change the "remoteContentBar" property on it
// then reload the message
setMsgHdrPropertyAndReload("remoteContentPolicy", kAllowRemoteContent);
}
function MsgIsNotAScam()
{
// we want to get the msg hdr for the currently selected message
// change the "isPhishingMsg" property on it
// then reload the message
setMsgHdrPropertyAndReload("notAPhishMessage", kNotAPhishMessage);
}
function setMsgHdrPropertyAndReload(aProperty, aValue)
{
// we want to get the msg hdr for the currently selected message
// change the appropiate property on it then reload the message
var msgURI = GetLoadedMessage();
if (msgURI && !(/type=x-message-display/.test(msgURI)))
{
var msgHdr = messenger.messageServiceFromURI(msgURI).messageURIToMsgHdr(msgURI);
if (msgHdr)
{
msgHdr.setUint32Property(aProperty, aValue);
MsgReload();
}
}
}
function checkMsgHdrPropertyIsNot(aProperty, aValue)
{
// we want to get the msg hdr for the currently selected message,
// get the appropiate property on it and then test against value.
var msgURI = GetLoadedMessage();
if (msgURI && !(/type=x-message-display/.test(msgURI)))
{
var msgHdr = messenger.messageServiceFromURI(msgURI).messageURIToMsgHdr(msgURI);
return (msgHdr && msgHdr.getUint32Property(aProperty) != aValue);
}
return false;
}
function MarkCurrentMessageAsRead()
@@ -2099,6 +2219,11 @@ function ClearPendingReadTimer()
}
}
function OnMsgParsed(aUrl)
{
gMessageNotificationBar.setPhishingMsg(aUrl);
}
function OnMsgLoaded(aUrl)
{
if (!aUrl)
@@ -2117,14 +2242,11 @@ function OnMsgLoaded(aUrl)
// SetNextMessageAfterDelete() when the operation completes (bug 243532).
gNextMessageViewIndexAfterDelete = -2;
if (/type=x-message-display/.test(msgURI))
SetUpJunkBar(null);
else
{
if (!(/type=x-message-display/.test(msgURI)))
msgHdr = messenger.messageServiceFromURI(msgURI).messageURIToMsgHdr(msgURI);
SetUpJunkBar(msgHdr);
}
gMessageNotificationBar.setJunkMsg(msgHdr);
// we just finished loading a message. set a timer to actually mark the message as read after n seconds
// where n can be configured by the user.
var markReadOnADelay = gPrefBranch.getBoolPref("mailnews.mark_message_read.delay");
@@ -2324,5 +2446,3 @@ function OpenOrFocusWindow(args, windowType, chromeURL)
else
window.openDialog(chromeURL, "", "chrome,resizable,status,centerscreen,dialog=no", args);
}

View File

@@ -280,6 +280,8 @@
<command id="cmd_markAsJunk" oncommand="goDoCommand('cmd_markAsJunk'); event.preventBubble()" disabled="true"/>
<command id="cmd_markAsNotJunk" oncommand="goDoCommand('cmd_markAsNotJunk'); event.preventBubble()" disabled="true"/>
<command id="cmd_recalculateJunkScore" oncommand="goDoCommand('cmd_recalculateJunkScore');" disabled="true"/>
<command id="cmd_markAsShowRemote" oncommand="goDoCommand('cmd_markAsShowRemote'); event.preventBubble()" disabled="true"/>
<command id="cmd_markAsNotPhish" oncommand="goDoCommand('cmd_markAsNotPhish'); event.preventBubble()" disabled="true"/>
</commandset>
<commandset id="mailLabelMenuItems"
@@ -328,6 +330,10 @@
<key id="key_markJunk" key="&markAsJunkCmd.key;" oncommand="goDoCommand('cmd_markAsJunk');"/>
<key id="key_markNotJunk" key="&markAsNotJunkCmd.key;" oncommand="goDoCommand('cmd_markAsNotJunk');"
modifiers="shift"/>
<key id="key_markShowRemote" key="&markAsShowRemoteCmd.key;" oncommand="goDoCommand('cmd_markAsShowRemote');"
modifiers="shift"/>
<key id="key_markNotPhish" key="&markAsNotPhishCmd.key;" oncommand="goDoCommand('cmd_markAsNotPhish');"
modifiers="shift"/>
<key id="key_markAllRead" key="&markAllReadCmd.key;" oncommand="goDoCommand('cmd_markAllRead');" modifiers="accel, shift"/>
<key id="key_markThreadAsRead" key="&markThreadAsReadCmd.key;" oncommand="goDoCommand('cmd_markThreadAsRead')"/>
<key id="key_markReadByDate" key="&markReadByDateCmd.key;" oncommand="goDoCommand('cmd_markReadByDate')"/>
@@ -633,6 +639,12 @@
<menuitem label="&recalculateJunkScoreCmd.label;"
accesskey="&recalculateJunkScoreCmd.accesskey;"
command="cmd_recalculateJunkScore"/>
<menuitem label="&markAsShowRemoteCmd.label;"
accesskey="&markAsShowRemoteCmd.accesskey;"
command="cmd_markAsShowRemote"/>
<menuitem label="&markAsNotPhishCmd.label;"
accesskey="&markAsNotPhishCmd.accesskey;"
command="cmd_markAsNotPhish"/>
</menupopup>
</menu>
<menuseparator/>
@@ -977,6 +989,12 @@
<menuitem label="&recalculateJunkScoreCmd.label;"
accesskey="&recalculateJunkScoreCmd.accesskey;"
command="cmd_recalculateJunkScore"/>
<menuitem label="&markAsShowRemoteCmd.label;"
accesskey="&markAsShowRemoteCmd.accesskey;"
command="cmd_markAsShowRemote"/>
<menuitem label="&markAsNotPhishCmd.label;"
accesskey="&markAsNotPhishCmd.accesskey;"
command="cmd_markAsNotPhish"/>
</menupopup>
</menu>
<menuseparator id="messagePaneContext-sep-labels-2"/>
@@ -1610,6 +1628,14 @@
<menuitem label="&recalculateJunkScoreCmd.label;"
accesskey="&recalculateJunkScoreCmd.accesskey;"
command="cmd_recalculateJunkScore"/>
<menuitem label="&markAsShowRemoteCmd.label;"
key="key_markShowRemote"
accesskey="&markAsShowRemoteCmd.accesskey;"
command="cmd_markAsShowRemote"/>
<menuitem label="&markAsNotPhishCmd.label;"
key="key_markNotPhish"
accesskey="&markAsNotPhishCmd.accesskey;"
command="cmd_markAsNotPhish"/>
</menupopup>
</menu>
<menuseparator/>
@@ -1827,13 +1853,34 @@
accesskey="&advancedButton.accesskey;"/>
</hbox>
<hbox id="junkBar" collapsed="true" align="center">
<image id="junkBarImage"/>
<label id="junkBarMessage" value="&junkBarMessage.label;"/>
<spacer flex="1"/>
<button label="&junkInfoButton.label;" oncommand="MsgJunkMailInfo(false)"/>
<button label="&junkBarButton.label;" oncommand="JunkSelectedMessages(false)"/>
</hbox>
<!-- The msgNotificationBar appears on top of the message and displays
information like: junk, contains remote images, or is a suspected phishing URL
-->
<deck id="msgNotificationBar" selectedIndex="0" collapsed="true">
<hbox id="msgNotificationNoStatus"/>
<hbox id="junkBar" class="msgNotificationBar" align="center">
<image id="junkBarImage"/>
<description flex="1" class="msgNotificationBarText">&junkBarMessage.label;</description>
<spacer flex="1"/>
<button label="&junkInfoButton.label;" oncommand="MsgJunkMailInfo(false)"/>
<button label="&junkBarButton.label;" oncommand="JunkSelectedMessages(false);"/>
</hbox>
<hbox id="remoteContentBar" class="msgNotificationBar" align="center">
<image id="remoteContentImage"/>
<description flex="1" class="msgNotificationBarText">&remoteContentMessage.label;</description>
<spacer flex="1"/>
<button label="&loadRemoteContentButton.label;" oncommand="LoadMsgWithRemoteContent();"/>
</hbox>
<hbox id="phishingBar" class="msgNotificationBar" align="center">
<image id="phishingBarImage"/>
<description flex="1" class="msgNotificationBarText">&phishingBarMessage.label;</description>
<spacer flex="1"/>
<button label="&removePhishingBarButton.label;" oncommand="MsgIsNotAScam();"/>
</hbox>
</deck>
<statusbar class="chromeclass-status" id="status-bar">
<statusbarpanel id="component-bar"/>

View File

@@ -655,6 +655,8 @@ var MessageWindowController =
case "cmd_markAsJunk":
case "cmd_markAsNotJunk":
case "cmd_recalculateJunkScore":
case "cmd_markAsShowRemote":
case "cmd_markAsNotPhish":
case "cmd_applyFilters":
case "cmd_runJunkControls":
case "cmd_deleteJunk":
@@ -753,6 +755,10 @@ var MessageWindowController =
case "button_file":
case "cmd_file":
return (gCurrentMessageUri != null);
case "cmd_markAsShowRemote":
return (GetNumSelectedMessages() > 0 && checkMsgHdrPropertyIsNot("remoteContentPolicy", kAllowRemoteContent));
case "cmd_markAsNotPhish":
return (GetNumSelectedMessages() > 0 && checkMsgHdrPropertyIsNot("notAPhishMessage", kNotAPhishMessage));
case "cmd_printSetup":
return true;
case "cmd_getNewMessages":
@@ -921,6 +927,12 @@ var MessageWindowController =
case "cmd_recalculateJunkScore":
analyzeMessagesForJunk();
return;
case "cmd_markAsShowRemote":
LoadMsgWithRemoteContent();
return;
case "cmd_markAsNotPhish":
MsgIsNotAScam();
return;
case "cmd_label0":
gDBView.doCommand(nsMsgViewCommandType.label0);
return;

View File

@@ -76,6 +76,7 @@
<script type="application/x-javascript" src="chrome://messenger/content/messageWindow.js"/>
<script type="application/x-javascript" src="chrome://messenger/content/accountUtils.js"/>
<script type="application/x-javascript" src="chrome://messenger/content/mailContextMenus.js"/>
<script type="application/x-javascript" src="chrome://messenger/content/phishingDetector.js"/>
<script type="application/x-javascript" src="chrome://communicator/content/contentAreaClick.js"/>
<script type="application/x-javascript" src="chrome://global/content/nsTransferable.js"/>
<script type="application/x-javascript" src="chrome://global/content/nsDragAndDrop.js"/>
@@ -147,7 +148,7 @@
ondragdrop="nsDragAndDrop.drop(event, messagepaneObserver);"
ondragexit="nsDragAndDrop.dragExit(event, messagepaneObserver);">
<hbox id="junkBar"/>
<deck id="msgNotificationBar"/>
<hbox id="msgHeaderView"/>
@@ -155,7 +156,7 @@
<browser id="messagepane" context="messagePaneContext"
style="height: 0px; min-height: 1px" flex="1" name="messagepane"
disablesecurity="true" disablehistory="true" type="content-primary"
src="about:blank" onclick="messagePaneOnClick(event);" autofind="false"/>
src="about:blank" onclick="return messagePaneOnClick(event);" autofind="false"/>
</vbox>
</vbox>

View File

@@ -84,6 +84,7 @@
<script type="application/x-javascript" src="chrome://messenger/content/messengerdnd.js"/>
<script type="application/x-javascript" src="chrome://messenger/content/accountUtils.js"/>
<script type="application/x-javascript" src="chrome://messenger/content/mail-offline.js"/>
<script type="application/x-javascript" src="chrome://messenger/content/phishingDetector.js"/>
<script type="application/x-javascript" src="chrome://communicator/content/contentAreaClick.js"/>
<script type="application/x-javascript" src="chrome://global/content/nsTransferable.js"/>
<script type="application/x-javascript" src="chrome://global/content/nsDragAndDrop.js"/>
@@ -182,14 +183,14 @@
</splitter>
<vbox id="messagepanebox" flex="2" minheight="100" height="200" minwidth="100" width="200" persist="collapsed height width" class="window-focusborder" focusring="false">
<hbox id="junkBar"/>
<deck id="msgNotificationBar"/>
<hbox id="msgHeaderView"/>
<browser id="messagepane" name="messagepane" height="0" flex="1"
context="messagePaneContext" minwidth="1" minheight="1"
disablesecurity="true" disablehistory="true" autofind="false"
type="content-primary" onclick="messagePaneOnClick(event);"/>
type="content-primary" onclick="return messagePaneOnClick(event);"/>
</vbox>
</box>
</box>

View File

@@ -293,6 +293,7 @@ var messageHeaderSink = {
gBuildAttachmentPopupForCurrentMsg = true;
ClearAttachmentList();
ClearEditMessageButton();
gMessageNotificationBar.clearMsgNotifications();
for (var index in gMessageListeners)
gMessageListeners[index].onStartHeaders();
@@ -443,6 +444,7 @@ var messageHeaderSink = {
onEndMsgDownload: function(url)
{
OnMsgParsed(url);
},
onEndMsgHeaders: function(url)
@@ -452,6 +454,7 @@ var messageHeaderSink = {
onMsgHasRemoteContent: function(aMsgHdr)
{
gMessageNotificationBar.setRemoteContentMsg(aMsgHdr);
},
mSecurityInfo : null,

View File

@@ -1130,11 +1130,10 @@ function ClearMessagePane()
gCurrentDisplayedMessage = null;
if (GetMessagePaneFrame().location.href != "about:blank")
GetMessagePaneFrame().location.href = "about:blank";
// hide the message header view AND the message pane...
HideMessageHeaderPane();
// hide the junk bar
SetUpJunkBar(null);
gMessageNotificationBar.clearMsgNotifications();
}
}

View File

@@ -0,0 +1,239 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Thunderbird Phishing Dectector
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@mozilla.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ****** */
// Dependencies:
// gPrefBranch, gBrandBundle, gMessengerBundle should already be defined
// gatherTextUnder from utilityOverlay.js
const kPhishingNotSuspicious = 0;
const kPhishingWithIPAddress = 1;
const kPhishingWithMismatchedHosts = 2;
//////////////////////////////////////////////////////////////////////////////
// isEmailScam --> examines the message currently loaded in the message pane
// and returns true if we think that message is an e-mail scam.
// Assumes the message has been completely loaded in the message pane (i.e. OnMsgParsed has fired)
// aUrl: nsIURI object for the msg we want to examine...
//////////////////////////////////////////////////////////////////////////////
function isMsgEmailScam(aUrl)
{
var isEmailScam = false;
if (!aUrl || !gPrefBranch.getBoolPref("mail.phishing.detection.enabled"))
return isEmailScam;
// Ignore nntp and RSS messages
var folder = aUrl.folder;
if (folder.server.type == 'nntp' || folder.server.type == 'rss')
return isEmailScam;
// loop through all of the link nodes in the message's DOM, looking for phishing URLs...
var msgDocument = document.getElementById('messagepane').contentDocument;
// examine all anchor tags...
var anchorNodes = msgDocument.getElementsByTagName("a");
for (var index = 0; index < anchorNodes.length && !isEmailScam; index++)
isEmailScam = isPhishingURL(anchorNodes[index], true);
// if an e-mail contains a non-addressbook form element, then assume the message is
// a phishing attack. Legitimate sites should not be using forms inside of e-mail
if (!isEmailScam)
{
var forms = msgDocument.getElementsByTagName("form");
for (var i = 0; i < forms.length && !isEmailScam; i++)
isEmailScam = forms[i].action.search("addbook") != 0;
}
// we'll add more checks here as our detector matures....
return isEmailScam;
}
//////////////////////////////////////////////////////////////////////////////
// isPhishingURL --> examines the passed in linkNode and returns true if we think
// the URL is an email scam.
// aLinkNode: the link node to examine
// aSilentMode: don't prompt the user to confirm
//////////////////////////////////////////////////////////////////////////////
function isPhishingURL(aLinkNode, aSilentMode)
{
if (!gPrefBranch.getBoolPref("mail.phishing.detection.enabled"))
return false;
var phishingType = kPhishingNotSuspicious;
var href = aLinkNode.href;
if (!href)
return false;
var linkTextURL = {};
var unobscuredHostName = {};
var isPhishingURL = false;
var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
hrefURL = ioService.newURI(href, null, null);
// only check for phishing urls if the url is an http or https link.
// this prevents us from flagging imap and other internally handled urls
if (hrefURL.schemeIs('http') || hrefURL.schemeIs('https'))
{
unobscuredHostName.value = hrefURL.host;
if (hostNameIsIPAddress(hrefURL.host, unobscuredHostName))
phishingType = kPhishingWithIPAddress;
else if (misMatchedHostWithLinkText(aLinkNode, hrefURL, linkTextURL))
phishingType = kPhishingWithMismatchedHosts;
isPhishingURL = phishingType != kPhishingNotSuspicious;
if (!aSilentMode && isPhishingURL) // allow the user to override the decision
isPhishingURL = confirmSuspiciousURL(phishingType, unobscuredHostName.value);
}
return isPhishingURL;
}
//////////////////////////////////////////////////////////////////////////////
// helper methods in support of isPhishingURL
//////////////////////////////////////////////////////////////////////////////
function misMatchedHostWithLinkText(aLinkNode, aHrefURL, aLinkTextURL)
{
var linkNodeText = gatherTextUnder(aLinkNode);
// only worry about http and https urls
if (linkNodeText)
{
// does the link text look like a http url?
if (linkNodeText.search(/(^http:|^https:)/) != -1)
{
var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
linkTextURL = ioService.newURI(linkNodeText, null, null);
aLinkTextURL.value = linkTextURL;
return aHrefURL.host != linkTextURL.host;
}
}
return false;
}
// returns true if the hostName is an IP address
// if the host name is an obscured IP address, returns the unobscured host
function hostNameIsIPAddress(aHostName, aUnobscuredHostName)
{
// TODO: Add Support for IPv6
var index;
// scammers frequently obscure the IP address by encoding each component as octal, hex
// or in some cases a mix match of each. The IP address could also be represented as a DWORD.
// break the IP address down into individual components.
var ipComponents = aHostName.split(".");
// if we didn't find at least 4 parts to our IP address it either isn't a numerical IP
// or it is encoded as a dword
if (ipComponents.length < 4)
{
// Convert to a binary to test for possible DWORD.
var binaryDword = parseInt(aHostName).toString(2);
if (isNaN(binaryDword))
return false;
// convert the dword into its component IP parts.
ipComponents =
[
(aHostName >> 24) & 255,
(aHostName >> 16) & 255,
(aHostName >> 8) & 255,
(aHostName & 255)
];
}
else
{
for (index = 0; index < ipComponents.length; index++)
{
// by leaving the radix parameter blank, we can handle IP addresses
// where one component is hex, another is octal, etc.
ipComponents[index] = parseInt(ipComponents[index]);
}
}
// make sure each part of the IP address is in fact a number
for (index = 0; index < ipComponents.length; index++)
if (isNaN(ipComponents[index])) // if any part of the IP address is not a number, then we can safely return
return false;
// only set aUnobscuredHostName if we are looking at an IPv4 host name
var hostName = ipComponents.join(".");
if (isIPv4HostName(hostName))
{
aUnobscuredHostName.value = hostName;
return true;
}
return false;
}
function isIPv4HostName(aHostName)
{
var ipv4HostRegExp = new RegExp(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/); // IPv4
// treat 0.0.0.0 as an invalid IP address
return ipv4HostRegExp.test(aHostName) && aHostName != '0.0.0.0';
}
// returns true if the user confirms the URL is a scam
function confirmSuspiciousURL(aPhishingType, aSuspiciousHostName)
{
var brandShortName = gBrandBundle.getString("brandShortName");
var titleMsg = gMessengerBundle.getString("confirmPhishingTitle");
var dialogMsg = null;
switch (aPhishingType)
{
case kPhishingWithIPAddress:
case kPhishingWithMismatchedHosts:
dialogMsg = gMessengerBundle.getFormattedString("confirmPhishingUrl" + aPhishingType, [brandShortName, aSuspiciousHostName], 2);
break;
default:
return false;
}
const nsIPS = Components.interfaces.nsIPromptService;
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(nsIPS);
var buttons = nsIPS.STD_YES_NO_BUTTONS + nsIPS.BUTTON_POS_1_DEFAULT;
return promptService.confirmEx(window, titleMsg, dialogMsg, buttons, "", "", "", "", {}); /* the yes button is in position 0 */
}

View File

@@ -437,6 +437,12 @@
<!ENTITY markAsNotJunkCmd.key "j">
<!ENTITY recalculateJunkScoreCmd.label "Run Junk Mail Controls">
<!ENTITY recalculateJunkScoreCmd.accesskey "C">
<!ENTITY markAsShowRemoteCmd.label "Show Remote Content">
<!ENTITY markAsShowRemoteCmd.accesskey "e">
<!ENTITY markAsShowRemoteCmd.key "r">
<!ENTITY markAsNotPhishCmd.label "As Not Scam">
<!ENTITY markAsNotPhishCmd.accesskey "S">
<!ENTITY markAsNotPhishCmd.key "p">
<!ENTITY openMessageWindowCmd.label "Open Message">
<!ENTITY openMessageWindowCmd.accesskey "O">
<!ENTITY openMessageWindowCmd.key "o">
@@ -585,8 +591,15 @@
<!ENTITY deleteJunk.label "Delete Mail Marked as Junk in Folder">
<!ENTITY deleteJunk.accesskey "e">
<!-- junk bar -->
<!ENTITY junkBarMessage.label "&brandShortName; thinks this message is junk mail">
<!-- Junk Bar -->
<!ENTITY junkBarMessage.label "&brandShortName; thinks this message is junk.">
<!ENTITY junkBarButton.label "This is Not Junk">
<!ENTITY junkInfoButton.label "?">
<!-- Remote Content Bar -->
<!ENTITY remoteContentMessage.label "To protect your privacy, &brandShortName; has blocked remote content in this message.">
<!ENTITY loadRemoteContentButton.label "Show Remote Content">
<!-- Phishing Bar -->
<!ENTITY phishingBarMessage.label "&brandShortName; thinks this message might be an email scam.">
<!ENTITY removePhishingBarButton.label "Not a Scam">

View File

@@ -365,3 +365,9 @@ alertNoSearchFoldersSelected=You must choose at least one folder to search for t
# LOCALIZATION NOTES(????ByteAbbreviation): Do not translate %d below, it is the size of the message/folder
kiloByteAbbreviation=%dKB
megaByteAbbreviation=%dMB
# Warnings to alert users about phishing urls
confirmPhishingTitle=Email Scam Alert
#LOCALIZATION NOTE %1$S is the brand name, %2$S is the host name of the url being visited
confirmPhishingUrl1=%1$S thinks this site is suspicious! It may be trying to impersonate the web page you want to visit. Most legitimate sites use names instead of numbers. Are you sure you want to visit %2$S?
confirmPhishingUrl2=%1$S thinks this site is suspicious! It may be trying to impersonate the web page you want to visit. Are you sure you want to visit %2$S?

View File

@@ -143,6 +143,7 @@ messenger.jar:
content/messenger/junkMail.xul (base/resources/content/junkMail.xul)
content/messenger/junkMail.js (base/resources/content/junkMail.js)
* content/messenger/junkMailInfo.xul (base/resources/content/junkMailInfo.xul)
content/messenger/phishingDetector.js (base/resources/content/phishingDetector.js)
content/messenger/SearchDialog.xul (base/search/resources/content/SearchDialog.xul)
content/messenger/ABSearchDialog.xul (base/search/resources/content/ABSearchDialog.xul)
content/messenger/SearchDialog.js (base/search/resources/content/SearchDialog.js)

View File

@@ -518,6 +518,7 @@ pref("news.cancel.confirm",true);
pref("news.cancel.alert_on_success",true);
pref("mail.SpellCheckBeforeSend",false);
pref("mail.spellcheck.inline",true);
pref("mail.phishing.detection.enabled", true); // enable / disable phishing detection for link clicks
pref("mail.warn_on_send_accel_key", true);
pref("mail.enable_autocomplete",true);
pref("mailnews.html_domains","");

View File

@@ -429,6 +429,7 @@ classic.jar:
skin/classic/messenger/icons/message-news-new-attach-off.gif (messenger/icons/message-news-new-attach-off.gif)
skin/classic/messenger/icons/message-news-new-offl.gif (messenger/icons/message-news-new-offl.gif)
skin/classic/messenger/icons/message-news-offl.gif (messenger/icons/message-news-offl.gif)
skin/classic/messenger/icons/remote-blocked.png (messenger/icons/remote-blocked.png)
skin/classic/messenger/icons/server-local.gif (messenger/icons/server-local.gif)
skin/classic/messenger/icons/server-local-new.gif (messenger/icons/server-local-new.gif)
skin/classic/messenger/icons/server-mail.gif (messenger/icons/server-mail.gif)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -242,21 +242,30 @@
-moz-image-region: rect(21px 88px 42px 66px) !important;
}
#junkBarImage {
list-style-image: url("chrome://messenger/skin/icons/junkBar.gif");
/* ::::: message notification bar style rules ::::: */
.msgNotificationBar {
border-bottom: 1px solid;
-moz-border-bottom-colors: #000000;
-moz-appearance: toolbox;
background-color: #C7BC8F;
color: black;
}
#junkBarMessage {
.msgNotificationBarText {
font-weight: bold;
}
#junkBar {
border-bottom: 1px solid;
-moz-border-bottom-colors: #000000;
background-color: #C7BC8F;
#junkBarImage {
list-style-image: url("chrome://messenger/skin/icons/junkBar.gif");
}
#junkIcon {
margin-left: 0.5ex;
list-style-image: url("chrome://messenger/skin/icons/folder-junk.gif");
}
#remoteContentImage {
list-style-image: url("chrome://messenger/skin/icons/remote-blocked.png");
padding: 3px;
}

View File

@@ -396,6 +396,7 @@ modern.jar:
skin/modern/messenger/icons/message-news-offl.gif (messenger/icons/message-news-offl.gif)
skin/modern/messenger/icons/readcol-read.gif (messenger/icons/readcol-read.gif)
skin/modern/messenger/icons/readcol-unread.gif (messenger/icons/readcol-unread.gif)
skin/modern/messenger/icons/remote-blocked.png (messenger/icons/remote-blocked.png)
skin/modern/messenger/icons/server-local-new.gif (messenger/icons/server-local-new.gif)
skin/modern/messenger/icons/server-local.gif (messenger/icons/server-local.gif)
skin/modern/messenger/icons/server-mail-new.gif (messenger/icons/server-mail-new.gif)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -254,22 +254,30 @@
-moz-image-region: rect(68px 199px 101px 150px) !important;
}
#junkBarImage {
list-style-image: url("chrome://messenger/skin/icons/junkBar.gif");
/* ::::: message notification bar style rules ::::: */
.msgNotificationBar {
border-bottom: 1px solid;
-moz-border-bottom-colors: #000000;
-moz-appearance: toolbox;
background-color: #C7BC8F;
color: black;
}
#junkBarMessage {
.msgNotificationBarText {
font-weight: bold;
}
#junkBar {
border-bottom: 1px solid;
-moz-border-bottom-colors: #000000;
background-color: #C7BC8F;
#junkBarImage {
list-style-image: url("chrome://messenger/skin/icons/junkBar.gif");
}
#junkIcon {
margin-left: 0.3ex;
list-style-image: url("chrome://messenger/skin/icons/message-junk-other.gif");
}
#remoteContentImage {
list-style-image: url("chrome://messenger/skin/icons/remote-blocked.png");
padding: 3px;
}

View File

@@ -110,10 +110,12 @@
}
}
function hrefForClickEvent(event)
function hrefAndLinkNodeForClickEvent(aParams)
{
var event = aParams.event;
var target = event.target;
var linkNode;
var href = aParams.href;
var linkNode = aParams.linkNode;
var isKeyPress = (event.type == "keypress");
@@ -142,7 +144,7 @@
if (linkNode && !linkNode.hasAttribute("href"))
linkNode = null;
}
var href;
if (linkNode) {
href = linkNode.href;
} else {
@@ -155,11 +157,13 @@
}
linkNode = linkNode.parentNode;
}
if (href && href != "") {
if (href) {
href = makeURLAbsolute(linkNode.baseURI, href);
}
}
return href;
aParams.href = href;
aParams.linkNode = linkNode;
}
// Called whenever the user clicks in the content area,
@@ -172,7 +176,9 @@
}
var isKeyPress = (event.type == "keypress");
var href = hrefForClickEvent(event);
var ceParams = {event: event, href: "", linkNode: null};
hrefAndLinkNodeForClickEvent(ceParams);
var href = ceParams.href;
if (href) {
if (isKeyPress) {
openNewTabWith(href, true, event.shiftKey);
@@ -180,6 +186,10 @@
}
else {
handleLinkClick(event, href, null);
// if in mailnews block the link left click if we determine
// that this URL is phishy (i.e. a potential email scam)
if ("gMessengerBundle" in this && !event.button)
return !isPhishingURL(ceParams.linkNode, false);
}
return true;
}
@@ -362,11 +372,11 @@
} // for
}
function makeURLAbsolute( base, url )
function makeURLAbsolute(base, url)
{
// Construct nsIURL.
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
.getService(Components.interfaces.nsIIOService);
var baseURI = ioService.newURI(base, null, null);
return ioService.newURI(baseURI.resolve(url), null, null).spec;