Check for spoofed sender addresses, only display the address if so.
This adds a check for malware spoofing of RFC 822 mailbox addresses such as those found in Mailsploit, and if found only displays the email address part and not the mailbox name part. Part 1 of Mailsploit mitigation. * src/engine/rfc822/rfc822-mailbox-address.vala (MailboxAddress): Add new is_spoofed method to check if the mailbox address looks like it has been spoofed. Add is_distinct method to determine if the name and the label is the same. Do whitespace and non-printing character stripping when generating display versions of the mailbox address, rename methods to make it more obvious what they do and update call sites. Add unit tests to cover all this. * src/client/conversation-viewer/conversation-message.vala (ConversationMessage): Check name is distinct and is not valid before displaying it. Use new MailboxAddress methods for getting display versions of the address, to ensure we get the stripped versions of the addresses. * src/client/conversation-list/formatted-conversation-data.vala (ParticipantDisplay): Ensure full addresses are always HTML-markup escaped before displaying them as markup, to avoid dropping "<address>" values as invalid HTML. Always show the full address if an address is invalid. * src/engine/util/util-string.vala (reduce_whitespace): Strip not only whitespace but also non-printing characters. Add unit tests.
This commit is contained in:
parent
f6b4b5c9e8
commit
71e0e6835e
14 changed files with 369 additions and 108 deletions
|
|
@ -10,6 +10,11 @@ class Geary.RFC822.MailboxAddressTest : Gee.TestCase {
|
|||
public MailboxAddressTest() {
|
||||
base("Geary.RFC822.MailboxAddressTest");
|
||||
add_test("is_valid_address", is_valid_address);
|
||||
add_test("is_spoofed", is_spoofed);
|
||||
add_test("has_distinct_name", has_distinct_name);
|
||||
add_test("to_full_display", to_full_display);
|
||||
add_test("to_short_display", to_short_display);
|
||||
add_test("to_rfc822_string", to_rfc822_string);
|
||||
}
|
||||
|
||||
public void is_valid_address() {
|
||||
|
|
@ -30,4 +35,81 @@ class Geary.RFC822.MailboxAddressTest : Gee.TestCase {
|
|||
assert(Geary.RFC822.MailboxAddress.is_valid_address("") == false);
|
||||
}
|
||||
|
||||
public void is_spoofed() {
|
||||
assert(new MailboxAddress(null, "example@example.com").is_spoofed() == false);
|
||||
assert(new MailboxAddress("", "example@example.com").is_spoofed() == false);
|
||||
assert(new MailboxAddress("", "example@example.com").is_spoofed() == false);
|
||||
assert(new MailboxAddress("test", "example@example.com").is_spoofed() == false);
|
||||
assert(new MailboxAddress("test test", "example@example.com").is_spoofed() == false);
|
||||
assert(new MailboxAddress("test test", "example@example.com").is_spoofed() == false);
|
||||
assert(new MailboxAddress("test?", "example@example.com").is_spoofed() == false);
|
||||
|
||||
assert(new MailboxAddress("test@example.com", "example@example.com").is_spoofed() == true);
|
||||
assert(new MailboxAddress("test @ example . com", "example@example.com").is_spoofed() == true);
|
||||
assert(new MailboxAddress("\n", "example@example.com").is_spoofed() == true);
|
||||
assert(new MailboxAddress("\n", "example@example.com").is_spoofed() == true);
|
||||
assert(new MailboxAddress("test", "example@\nexample@example.com").is_spoofed() == true);
|
||||
assert(new MailboxAddress("test", "example@example@example.com").is_spoofed() == true);
|
||||
|
||||
try {
|
||||
assert(new MailboxAddress.from_rfc822_string("\"=?utf-8?b?dGVzdCIgPHBvdHVzQHdoaXRlaG91c2UuZ292Pg==?==?utf-8?Q?=00=0A?=\" <demo@mailsploit.com>")
|
||||
.is_spoofed() == true);
|
||||
} catch (Error err) {
|
||||
assert_no_error(err);
|
||||
}
|
||||
}
|
||||
|
||||
public void has_distinct_name() {
|
||||
assert(new MailboxAddress("example", "example@example.com").has_distinct_name() == true);
|
||||
|
||||
assert(new MailboxAddress("", "example@example.com").has_distinct_name() == false);
|
||||
assert(new MailboxAddress(" ", "example@example.com").has_distinct_name() == false);
|
||||
assert(new MailboxAddress("example@example.com", "example@example.com").has_distinct_name() == false);
|
||||
assert(new MailboxAddress(" example@example.com ", "example@example.com").has_distinct_name() == false);
|
||||
assert(new MailboxAddress(" example@example.com ", "example@example.com").has_distinct_name() == false);
|
||||
}
|
||||
|
||||
public void to_full_display() {
|
||||
assert(new MailboxAddress("", "example@example.com").to_full_display() ==
|
||||
"example@example.com");
|
||||
assert(new MailboxAddress("Test", "example@example.com").to_full_display() ==
|
||||
"Test <example@example.com>");
|
||||
assert(new MailboxAddress("example@example.com", "example@example.com").to_full_display() ==
|
||||
"example@example.com");
|
||||
assert(new MailboxAddress("Test", "example@example@example.com").to_full_display() ==
|
||||
"example@example@example.com");
|
||||
}
|
||||
|
||||
public void to_short_display() {
|
||||
assert(new MailboxAddress("", "example@example.com").to_short_display() ==
|
||||
"example@example.com");
|
||||
assert(new MailboxAddress("Test", "example@example.com").to_short_display() ==
|
||||
"Test");
|
||||
assert(new MailboxAddress("example@example.com", "example@example.com").to_short_display() ==
|
||||
"example@example.com");
|
||||
assert(new MailboxAddress("Test", "example@example@example.com").to_short_display() ==
|
||||
"example@example@example.com");
|
||||
}
|
||||
|
||||
public void to_rfc822_string() {
|
||||
assert(new MailboxAddress("", "example@example.com").to_rfc822_string() ==
|
||||
"example@example.com");
|
||||
assert(new MailboxAddress(" ", "example@example.com").to_rfc822_string() ==
|
||||
"example@example.com");
|
||||
assert(new MailboxAddress("test", "example@example.com").to_rfc822_string() ==
|
||||
"test <example@example.com>");
|
||||
assert(new MailboxAddress("test test", "example@example.com").to_rfc822_string() ==
|
||||
"test test <example@example.com>");
|
||||
assert(new MailboxAddress("example@example.com", "example@example.com").to_rfc822_string() ==
|
||||
"example@example.com");
|
||||
// Technically, per
|
||||
// https://tools.ietf.org/html/rfc5322#appendix-A.1.2 this
|
||||
// would be fine as just "test? <example@example.com>",
|
||||
// i.e. without the name being quoted, but I guess GMime is
|
||||
// just being conservative here?
|
||||
assert(new MailboxAddress("test?", "example@example.com").to_rfc822_string() ==
|
||||
"\"test?\" <example@example.com>");
|
||||
assert(new MailboxAddress(";", "example@example.com").to_rfc822_string() ==
|
||||
"\";\" <example@example.com>");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ https://app.foobar.com/xxxxxxxxxxxxx">https://app.foobar.com/xxxxxxxxxxx</a=
|
|||
></p></td></tr>
|
||||
</table></body></html>""";
|
||||
|
||||
public static string HTML_BODY1_EXPECTED = "Hi Kenneth, We xxxxx xxxx xx xxx xxx xx xxxx x xxxxxxxx xxxxxxxx. Thank you, XXXXXX XXXXXX You can reply directly to this message or click the following link: https://app.foobar.com/xxxxxxxxxxxxxxxx1641966deff6c48623aba You can change your email preferences at: https://app.foobar.com/xxxxxxxxxxx";
|
||||
public static string HTML_BODY1_EXPECTED = "Hi Kenneth, We xxxxx xxxx xx xxx xxx xx xxxx x xxxxxxxx xxxxxxxx. Thank you, XXXXXX XXXXXX You can reply directly to this message or click the following link: https://app.foobar.com/xxxxxxxxxxxxxxxx1641966deff6c48623aba You can change your email preferences at: https://app.foobar.com/xxxxxxxxxxx";
|
||||
|
||||
public static string HTML_BODY2_ENCODED = """<!DOCTYPE html>
|
||||
<!--2c2a1c66-0638-7c87-5057-bff8be4291eb_v180-->
|
||||
|
|
@ -618,5 +618,5 @@ x 133, 3000 Bern 6, Switzerland
|
|||
|
||||
""";
|
||||
|
||||
public static string HTML_BODY2_EXPECTED = "Buy It Now from US $1,750.00 to US $5,950.00. eBay Daccordi, Worldwide: 2 new matches today Daccordi 50th anniversary edition with... Buy it now: US $5,950.00 100% positive feedback Daccordi Griffe Campagnolo Croce D'Aune... Buy it now: US $1,750.00 100% positive feedback View all results Refine this search Disable emails for this search Email reference id: [#d9f42b5e860b4eabb98195c2888cba9e#] We don't check this mailbox, so please don't reply to this message. If you have a question, go to Help & Contact. ©2016 eBay Inc., eBay International AG Helvetiastrasse 15/17 - P.O. Box 133, 3000 Bern 6, Switzerland";
|
||||
public static string HTML_BODY2_EXPECTED = "Buy It Now from US $1,750.00 to US $5,950.00. eBay Daccordi, Worldwide: 2 new matches today Daccordi 50th anniversary edition with... Buy it now: US $5,950.00 100% positive feedback Daccordi Griffe Campagnolo Croce D'Aune... Buy it now: US $1,750.00 100% positive feedback View all results Refine this search Disable emails for this search Email reference id: [#d9f42b5e860b4eabb98195c2888cba9e#] We don't check this mailbox, so please don't reply to this message. If you have a question, go to Help & Contact. ©2016 eBay Inc., eBay International AG Helvetiastrasse 15/17 - P.O. Box 133, 3000 Bern 6, Switzerland";
|
||||
}
|
||||
|
|
|
|||
47
test/engine/util-string-test.vala
Normal file
47
test/engine/util-string-test.vala
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2018 Michael Gratton <mike@vee.net>
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
class Geary.String.Test : Gee.TestCase {
|
||||
|
||||
public Test() {
|
||||
base("Geary.String.Test");
|
||||
add_test("test_whitespace", test_whitespace);
|
||||
add_test("test_nonprinting", test_nonprinting);
|
||||
}
|
||||
|
||||
public void test_whitespace() {
|
||||
assert(reduce_whitespace("") == "");
|
||||
assert(reduce_whitespace(" ") == "");
|
||||
assert(reduce_whitespace(" ") == "");
|
||||
assert(reduce_whitespace(" ") == "");
|
||||
assert(reduce_whitespace("test") == "test");
|
||||
assert(reduce_whitespace("test ") == "test");
|
||||
assert(reduce_whitespace("test ") == "test");
|
||||
assert(reduce_whitespace("test\n") == "test");
|
||||
assert(reduce_whitespace("test\r") == "test");
|
||||
assert(reduce_whitespace("test\t") == "test");
|
||||
assert(reduce_whitespace(" test") == "test");
|
||||
assert(reduce_whitespace(" test") == "test");
|
||||
assert(reduce_whitespace("test test") == "test test");
|
||||
assert(reduce_whitespace("test test") == "test test");
|
||||
assert(reduce_whitespace("test\ntest") == "test test");
|
||||
assert(reduce_whitespace("test\n test") == "test test");
|
||||
assert(reduce_whitespace("test \ntest") == "test test");
|
||||
assert(reduce_whitespace("test \n test") == "test test");
|
||||
assert(reduce_whitespace("test\rtest") == "test test");
|
||||
assert(reduce_whitespace("test\ttest") == "test test");
|
||||
}
|
||||
|
||||
public void test_nonprinting() {
|
||||
assert(reduce_whitespace("\0") == ""); // NUL
|
||||
assert(reduce_whitespace("\u00A0") == ""); // ENQUIRY
|
||||
assert(reduce_whitespace("\u00A0") == ""); // NO-BREAK SPACE
|
||||
assert(reduce_whitespace("\u2003") == ""); // EM SPACE
|
||||
assert(reduce_whitespace("test\n") == "test");
|
||||
assert(reduce_whitespace("test\ntest") == "test test");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue