Skip to content

Commit

Permalink
SAK-32068 Extract local part from BATV addresses. (sakaiproject#3740)
Browse files Browse the repository at this point in the history
Some mail systems protect FROM envelope addresses by signing them using BATV, this means that the FROM address can no longer be directly used to check who the sender is. This change strips out any private BATV signatures from the local part. We could try to be more generic and strip out more BATV possible tags but then we run the risk of stripping something we shouldn’t.

Doing it this was allows us to still do envelope time rejection but not reject BATV signed messages.

Supported formats are:

[email protected]
[email protected]
  • Loading branch information
buckett authored Jan 6, 2017
1 parent 0add841 commit 2ed17d5
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
package org.sakaiproject.mailarchive;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Just a tuple for a split email address.
* Just a tuple for a split email address, but it also remove any BATV checking from local part.
*/
public class SplitEmailAddress {

/**
* Pattern to get the local part out of a BATV modified from address.
* @see <a href="https://tools.ietf.org/html/draft-levine-smtp-batv-01">BATV RFC</a>
*/
private static final Pattern BATV_RFC = Pattern.compile("prvs=\\d\\d{3}[0-9A-F]{6}=(?<localpart>.+)",
Pattern.CASE_INSENSITIVE);
/**
* Pattern for Sub-Address syntax.
* @see <a href="https://www.agwa.name/projects/batv-tools/">Sub Addressing BATV</a>
*/
private static final Pattern BATV_SUB_ADDRESS = Pattern.compile("(?<localpart>.+)\\+prvs=\\d\\d{3}[0-9A-F]{6}",
Pattern.CASE_INSENSITIVE);

private final String local;
private final String domain;

Expand All @@ -28,8 +44,18 @@ public static SplitEmailAddress parse(String address) {
if (atPos < 1 || atPos == address.length() -1) {
throw new IllegalArgumentException("Can't find @ or it's at the start or end.");
}
String local = address.substring(0, atPos);
Matcher rfcMatcher = BATV_RFC.matcher(local);
if (rfcMatcher.matches()) {
local = rfcMatcher.group("localpart");
} else {
Matcher subMatcher = BATV_SUB_ADDRESS.matcher(local);
if (subMatcher.matches()) {
local = subMatcher.group("localpart");
}
}
return new SplitEmailAddress(
address.substring(0, atPos),
local,
address.substring(atPos+1).toLowerCase()
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,30 @@ public void testGood() {
assertEquals("example.com", email.getDomain());
}

@Test
public void testBATVGood() {
// Check that our batv parsing works.
SplitEmailAddress email = SplitEmailAddress.parse("[email protected]");
assertEquals("me", email.getLocal());
assertEquals("example.com", email.getDomain());
}

@Test
public void testBATVBad() {
// Check that our batv parsing is strict along the lines of the RFC
SplitEmailAddress email = SplitEmailAddress.parse("[email protected]");
assertEquals("prvs=aaaaaaaaaa=me", email.getLocal());
assertEquals("example.com", email.getDomain());
}

@Test
public void testBATVSubAddress() {
// Check that we also catch the subaddressing style.
SplitEmailAddress email = SplitEmailAddress.parse("[email protected]");
assertEquals("me", email.getLocal());
assertEquals("example.com", email.getDomain());
}

@Test(expected = IllegalArgumentException.class)
public void testNoAt() {
SplitEmailAddress email = SplitEmailAddress.parse("notavalidemail");
Expand Down

0 comments on commit 2ed17d5

Please sign in to comment.