Add BCC capabilities to the Spec11 reports (#418)

* Add BCC capabilities to the Spec11 reports
This commit is contained in:
gbrodman 2019-12-18 17:08:06 -05:00 committed by GitHub
parent bfd61ef867
commit 25d43511f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 75 additions and 31 deletions

View file

@ -917,6 +917,20 @@ public final class RegistryConfig {
return parseEmailAddress(config.misc.spec11OutgoingEmailAddress); return parseEmailAddress(config.misc.spec11OutgoingEmailAddress);
} }
/**
* Returns the email addresses to which we will BCC Spec11 emails.
*
* @see google.registry.reporting.spec11.Spec11EmailUtils
*/
@Provides
@Config("spec11BccEmailAddresses")
public static ImmutableList<InternetAddress> provideSpec11BccEmailAddresses(
RegistryConfigSettings config) {
return config.misc.spec11BccEmailAddresses.stream()
.map(RegistryConfig::parseEmailAddress)
.collect(toImmutableList());
}
/** /**
* Returns the name of the registry, for use in spec 11 emails. * Returns the name of the registry, for use in spec 11 emails.
* *

View file

@ -193,6 +193,7 @@ public class RegistryConfigSettings {
public String sheetExportId; public String sheetExportId;
public String alertRecipientEmailAddress; public String alertRecipientEmailAddress;
public String spec11OutgoingEmailAddress; public String spec11OutgoingEmailAddress;
public List<String> spec11BccEmailAddresses;
public int asyncDeleteDelaySeconds; public int asyncDeleteDelaySeconds;
public int transientFailureRetries; public int transientFailureRetries;
} }

View file

@ -389,6 +389,11 @@ misc:
# to be a deliverable email address to handle replies from registrars as well. # to be a deliverable email address to handle replies from registrars as well.
spec11OutgoingEmailAddress: abuse@example.com spec11OutgoingEmailAddress: abuse@example.com
# Addresses to which we will BCC all Spec11 email reports, in case one
# wishes to examine the output.
spec11BccEmailAddresses:
- abuse@example.com
# How long to delay processing of asynchronous deletions. This should always # How long to delay processing of asynchronous deletions. This should always
# be longer than eppResourceCachingSeconds, to prevent deleted contacts or # be longer than eppResourceCachingSeconds, to prevent deleted contacts or
# hosts from being used on domains. # hosts from being used on domains.

View file

@ -58,6 +58,7 @@ public class Spec11EmailUtils {
private final SendEmailService emailService; private final SendEmailService emailService;
private final InternetAddress outgoingEmailAddress; private final InternetAddress outgoingEmailAddress;
private final ImmutableList<InternetAddress> spec11BccEmailAddresses;
private final InternetAddress alertRecipientAddress; private final InternetAddress alertRecipientAddress;
private final ImmutableList<String> spec11WebResources; private final ImmutableList<String> spec11WebResources;
private final String registryName; private final String registryName;
@ -67,10 +68,12 @@ public class Spec11EmailUtils {
SendEmailService emailService, SendEmailService emailService,
@Config("alertRecipientEmailAddress") InternetAddress alertRecipientAddress, @Config("alertRecipientEmailAddress") InternetAddress alertRecipientAddress,
@Config("spec11OutgoingEmailAddress") InternetAddress spec11OutgoingEmailAddress, @Config("spec11OutgoingEmailAddress") InternetAddress spec11OutgoingEmailAddress,
@Config("spec11BccEmailAddresses") ImmutableList<InternetAddress> spec11BccEmailAddresses,
@Config("spec11WebResources") ImmutableList<String> spec11WebResources, @Config("spec11WebResources") ImmutableList<String> spec11WebResources,
@Config("registryName") String registryName) { @Config("registryName") String registryName) {
this.emailService = emailService; this.emailService = emailService;
this.outgoingEmailAddress = spec11OutgoingEmailAddress; this.outgoingEmailAddress = spec11OutgoingEmailAddress;
this.spec11BccEmailAddresses = spec11BccEmailAddresses;
this.alertRecipientAddress = alertRecipientAddress; this.alertRecipientAddress = alertRecipientAddress;
this.spec11WebResources = spec11WebResources; this.spec11WebResources = spec11WebResources;
this.registryName = registryName; this.registryName = registryName;
@ -125,11 +128,18 @@ public class Spec11EmailUtils {
private RegistrarThreatMatches filterOutNonPublishedMatches( private RegistrarThreatMatches filterOutNonPublishedMatches(
RegistrarThreatMatches registrarThreatMatches) { RegistrarThreatMatches registrarThreatMatches) {
ImmutableList<ThreatMatch> filteredMatches = registrarThreatMatches.threatMatches().stream() ImmutableList<ThreatMatch> filteredMatches =
.filter(threatMatch -> registrarThreatMatches.threatMatches().stream()
ofy().load().type(DomainBase.class).filter("fullyQualifiedDomainName", .filter(
threatMatch.fullyQualifiedDomainName()).first().now().shouldPublishToDns() threatMatch ->
).collect(toImmutableList()); ofy()
.load()
.type(DomainBase.class)
.filter("fullyQualifiedDomainName", threatMatch.fullyQualifiedDomainName())
.first()
.now()
.shouldPublishToDns())
.collect(toImmutableList());
return RegistrarThreatMatches.create(registrarThreatMatches.clientId(), filteredMatches); return RegistrarThreatMatches.create(registrarThreatMatches.clientId(), filteredMatches);
} }
@ -146,7 +156,7 @@ public class Spec11EmailUtils {
.setContentType(MediaType.HTML_UTF_8) .setContentType(MediaType.HTML_UTF_8)
.setFrom(outgoingEmailAddress) .setFrom(outgoingEmailAddress)
.addRecipient(getEmailAddressForRegistrar(registrarThreatMatches.clientId())) .addRecipient(getEmailAddressForRegistrar(registrarThreatMatches.clientId()))
.setBcc(outgoingEmailAddress) .setBccs(spec11BccEmailAddresses)
.build()); .build());
} }

View file

@ -118,6 +118,8 @@ public class Spec11EmailUtilsTest {
emailService, emailService,
new InternetAddress("my-receiver@test.com"), new InternetAddress("my-receiver@test.com"),
new InternetAddress("abuse@test.com"), new InternetAddress("abuse@test.com"),
ImmutableList.of(
new InternetAddress("abuse@test.com"), new InternetAddress("bcc@test.com")),
FAKE_RESOURCES, FAKE_RESOURCES,
"Super Cool Registry"); "Super Cool Registry");
@ -142,7 +144,7 @@ public class Spec11EmailUtilsTest {
capturedContents.get(0), capturedContents.get(0),
"abuse@test.com", "abuse@test.com",
"the.registrar@example.com", "the.registrar@example.com",
Optional.of("abuse@test.com"), ImmutableList.of("abuse@test.com", "bcc@test.com"),
"Super Cool Registry Monthly Threat Detector [2018-07-15]", "Super Cool Registry Monthly Threat Detector [2018-07-15]",
String.format(MONTHLY_EMAIL_FORMAT, "<tr><td>a.com</td><td>MALWARE</td></tr>"), String.format(MONTHLY_EMAIL_FORMAT, "<tr><td>a.com</td><td>MALWARE</td></tr>"),
Optional.of(MediaType.HTML_UTF_8)); Optional.of(MediaType.HTML_UTF_8));
@ -150,7 +152,7 @@ public class Spec11EmailUtilsTest {
capturedContents.get(1), capturedContents.get(1),
"abuse@test.com", "abuse@test.com",
"new.registrar@example.com", "new.registrar@example.com",
Optional.of("abuse@test.com"), ImmutableList.of("abuse@test.com", "bcc@test.com"),
"Super Cool Registry Monthly Threat Detector [2018-07-15]", "Super Cool Registry Monthly Threat Detector [2018-07-15]",
String.format( String.format(
MONTHLY_EMAIL_FORMAT, MONTHLY_EMAIL_FORMAT,
@ -160,7 +162,7 @@ public class Spec11EmailUtilsTest {
capturedContents.get(2), capturedContents.get(2),
"abuse@test.com", "abuse@test.com",
"my-receiver@test.com", "my-receiver@test.com",
Optional.empty(), ImmutableList.of(),
"Spec11 Pipeline Success 2018-07-15", "Spec11 Pipeline Success 2018-07-15",
"Spec11 reporting completed successfully.", "Spec11 reporting completed successfully.",
Optional.empty()); Optional.empty());
@ -180,7 +182,7 @@ public class Spec11EmailUtilsTest {
capturedMessages.get(0), capturedMessages.get(0),
"abuse@test.com", "abuse@test.com",
"the.registrar@example.com", "the.registrar@example.com",
Optional.of("abuse@test.com"), ImmutableList.of("abuse@test.com", "bcc@test.com"),
"Super Cool Registry Daily Threat Detector [2018-07-15]", "Super Cool Registry Daily Threat Detector [2018-07-15]",
String.format(DAILY_EMAIL_FORMAT, "<tr><td>a.com</td><td>MALWARE</td></tr>"), String.format(DAILY_EMAIL_FORMAT, "<tr><td>a.com</td><td>MALWARE</td></tr>"),
Optional.of(MediaType.HTML_UTF_8)); Optional.of(MediaType.HTML_UTF_8));
@ -188,7 +190,7 @@ public class Spec11EmailUtilsTest {
capturedMessages.get(1), capturedMessages.get(1),
"abuse@test.com", "abuse@test.com",
"new.registrar@example.com", "new.registrar@example.com",
Optional.of("abuse@test.com"), ImmutableList.of("abuse@test.com", "bcc@test.com"),
"Super Cool Registry Daily Threat Detector [2018-07-15]", "Super Cool Registry Daily Threat Detector [2018-07-15]",
String.format( String.format(
DAILY_EMAIL_FORMAT, DAILY_EMAIL_FORMAT,
@ -198,7 +200,7 @@ public class Spec11EmailUtilsTest {
capturedMessages.get(2), capturedMessages.get(2),
"abuse@test.com", "abuse@test.com",
"my-receiver@test.com", "my-receiver@test.com",
Optional.empty(), ImmutableList.of(),
"Spec11 Pipeline Success 2018-07-15", "Spec11 Pipeline Success 2018-07-15",
"Spec11 reporting completed successfully.", "Spec11 reporting completed successfully.",
Optional.empty()); Optional.empty());
@ -225,7 +227,7 @@ public class Spec11EmailUtilsTest {
capturedContents.get(0), capturedContents.get(0),
"abuse@test.com", "abuse@test.com",
"new.registrar@example.com", "new.registrar@example.com",
Optional.of("abuse@test.com"), ImmutableList.of("abuse@test.com", "bcc@test.com"),
"Super Cool Registry Monthly Threat Detector [2018-07-15]", "Super Cool Registry Monthly Threat Detector [2018-07-15]",
String.format(MONTHLY_EMAIL_FORMAT, "<tr><td>c.com</td><td>MALWARE</td></tr>"), String.format(MONTHLY_EMAIL_FORMAT, "<tr><td>c.com</td><td>MALWARE</td></tr>"),
Optional.of(MediaType.HTML_UTF_8)); Optional.of(MediaType.HTML_UTF_8));
@ -233,7 +235,7 @@ public class Spec11EmailUtilsTest {
capturedContents.get(1), capturedContents.get(1),
"abuse@test.com", "abuse@test.com",
"my-receiver@test.com", "my-receiver@test.com",
Optional.empty(), ImmutableList.of(),
"Spec11 Pipeline Success 2018-07-15", "Spec11 Pipeline Success 2018-07-15",
"Spec11 reporting completed successfully.", "Spec11 reporting completed successfully.",
Optional.empty()); Optional.empty());
@ -270,7 +272,7 @@ public class Spec11EmailUtilsTest {
capturedMessages.get(0), capturedMessages.get(0),
"abuse@test.com", "abuse@test.com",
"the.registrar@example.com", "the.registrar@example.com",
Optional.of("abuse@test.com"), ImmutableList.of("abuse@test.com", "bcc@test.com"),
"Super Cool Registry Monthly Threat Detector [2018-07-15]", "Super Cool Registry Monthly Threat Detector [2018-07-15]",
String.format(MONTHLY_EMAIL_FORMAT, "<tr><td>a.com</td><td>MALWARE</td></tr>"), String.format(MONTHLY_EMAIL_FORMAT, "<tr><td>a.com</td><td>MALWARE</td></tr>"),
Optional.of(MediaType.HTML_UTF_8)); Optional.of(MediaType.HTML_UTF_8));
@ -278,7 +280,7 @@ public class Spec11EmailUtilsTest {
capturedMessages.get(1), capturedMessages.get(1),
"abuse@test.com", "abuse@test.com",
"new.registrar@example.com", "new.registrar@example.com",
Optional.of("abuse@test.com"), ImmutableList.of("abuse@test.com", "bcc@test.com"),
"Super Cool Registry Monthly Threat Detector [2018-07-15]", "Super Cool Registry Monthly Threat Detector [2018-07-15]",
String.format( String.format(
MONTHLY_EMAIL_FORMAT, MONTHLY_EMAIL_FORMAT,
@ -288,7 +290,7 @@ public class Spec11EmailUtilsTest {
capturedMessages.get(2), capturedMessages.get(2),
"abuse@test.com", "abuse@test.com",
"my-receiver@test.com", "my-receiver@test.com",
Optional.empty(), ImmutableList.of(),
"Spec11 Emailing Failure 2018-07-15", "Spec11 Emailing Failure 2018-07-15",
"Emailing Spec11 reports failed due to expected", "Emailing Spec11 reports failed due to expected",
Optional.empty()); Optional.empty());
@ -302,7 +304,7 @@ public class Spec11EmailUtilsTest {
contentCaptor.getValue(), contentCaptor.getValue(),
"abuse@test.com", "abuse@test.com",
"my-receiver@test.com", "my-receiver@test.com",
Optional.empty(), ImmutableList.of(),
"Spec11 Pipeline Alert: 2018-07", "Spec11 Pipeline Alert: 2018-07",
"Alert!", "Alert!",
Optional.empty()); Optional.empty());
@ -351,7 +353,7 @@ public class Spec11EmailUtilsTest {
EmailMessage message, EmailMessage message,
String from, String from,
String recipient, String recipient,
Optional<String> replyTo, ImmutableList<String> bccs,
String subject, String subject,
String body, String body,
Optional<MediaType> contentType) Optional<MediaType> contentType)
@ -363,8 +365,8 @@ public class Spec11EmailUtilsTest {
.setSubject(subject) .setSubject(subject)
.setBody(body); .setBody(body);
if (replyTo.isPresent()) { for (String bcc : bccs) {
expectedContentBuilder.setBcc(new InternetAddress(replyTo.get())); expectedContentBuilder.addBcc(new InternetAddress(bcc));
} }
contentType.ifPresent(expectedContentBuilder::setContentType); contentType.ifPresent(expectedContentBuilder::setContentType);
assertThat(message).isEqualTo(expectedContentBuilder.build()); assertThat(message).isEqualTo(expectedContentBuilder.build());

View file

@ -29,7 +29,7 @@ public abstract class EmailMessage {
public abstract String body(); public abstract String body();
public abstract ImmutableList<InternetAddress> recipients(); public abstract ImmutableList<InternetAddress> recipients();
public abstract InternetAddress from(); public abstract InternetAddress from();
public abstract Optional<InternetAddress> bcc(); public abstract ImmutableList<InternetAddress> bccs();
public abstract Optional<MediaType> contentType(); public abstract Optional<MediaType> contentType();
public abstract Optional<Attachment> attachment(); public abstract Optional<Attachment> attachment();
@ -55,17 +55,23 @@ public abstract class EmailMessage {
public abstract Builder setBody(String body); public abstract Builder setBody(String body);
public abstract Builder setRecipients(Collection<InternetAddress> recipients); public abstract Builder setRecipients(Collection<InternetAddress> recipients);
public abstract Builder setFrom(InternetAddress from); public abstract Builder setFrom(InternetAddress from);
public abstract Builder setBcc(InternetAddress bcc); public abstract Builder setBccs(Collection<InternetAddress> bccs);
public abstract Builder setContentType(MediaType contentType); public abstract Builder setContentType(MediaType contentType);
public abstract Builder setAttachment(Attachment attachment); public abstract Builder setAttachment(Attachment attachment);
abstract ImmutableList.Builder<InternetAddress> recipientsBuilder(); abstract ImmutableList.Builder<InternetAddress> recipientsBuilder();
abstract ImmutableList.Builder<InternetAddress> bccsBuilder();
public Builder addRecipient(InternetAddress value) { public Builder addRecipient(InternetAddress value) {
recipientsBuilder().add(value); recipientsBuilder().add(value);
return this; return this;
} }
public Builder addBcc(InternetAddress bcc) {
bccsBuilder().add(bcc);
return this;
}
public abstract EmailMessage build(); public abstract EmailMessage build();
} }

View file

@ -78,8 +78,8 @@ public class SendEmailService {
attachmentPart.setFileName(attachment.filename()); attachmentPart.setFileName(attachment.filename());
multipart.addBodyPart(attachmentPart); multipart.addBodyPart(attachmentPart);
} }
if (emailMessage.bcc().isPresent()) { for (InternetAddress bcc : emailMessage.bccs()) {
msg.addRecipient(RecipientType.BCC, emailMessage.bcc().get()); msg.addRecipient(RecipientType.BCC, bcc);
} }
msg.setContent(multipart); msg.setContent(multipart);
msg.saveChanges(); msg.saveChanges();

View file

@ -21,6 +21,7 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableList;
import com.google.common.net.MediaType; import com.google.common.net.MediaType;
import google.registry.testing.FakeClock; import google.registry.testing.FakeClock;
import google.registry.testing.FakeSleeper; import google.registry.testing.FakeSleeper;
@ -44,8 +45,7 @@ import org.mockito.junit.MockitoRule;
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class SendEmailServiceTest { public class SendEmailServiceTest {
@Rule @Rule public final MockitoRule mocks = MockitoJUnit.rule();
public final MockitoRule mocks = MockitoJUnit.rule();
private final Retrier retrier = new Retrier(new FakeSleeper(new FakeClock()), 2); private final Retrier retrier = new Retrier(new FakeSleeper(new FakeClock()), 2);
private final TransportEmailSender wrapper = mock(TransportEmailSender.class); private final TransportEmailSender wrapper = mock(TransportEmailSender.class);
@ -74,12 +74,19 @@ public class SendEmailServiceTest {
@Test @Test
public void testSuccess_bcc() throws Exception { public void testSuccess_bcc() throws Exception {
EmailMessage content = createBuilder().setBcc(new InternetAddress("bcc@example.com")).build(); EmailMessage content =
createBuilder()
.setBccs(
ImmutableList.of(
new InternetAddress("bcc@example.com"),
new InternetAddress("bcc2@example.com")))
.build();
sendEmailService.sendEmail(content); sendEmailService.sendEmail(content);
Message message = getMessage(); Message message = getMessage();
assertThat(message.getRecipients(RecipientType.BCC)) assertThat(message.getRecipients(RecipientType.BCC))
.asList() .asList()
.containsExactly(new InternetAddress("bcc@example.com")); .containsExactly(
new InternetAddress("bcc@example.com"), new InternetAddress("bcc2@example.com"));
} }
@Test @Test
@ -87,8 +94,7 @@ public class SendEmailServiceTest {
EmailMessage content = createBuilder().setContentType(MediaType.HTML_UTF_8).build(); EmailMessage content = createBuilder().setContentType(MediaType.HTML_UTF_8).build();
sendEmailService.sendEmail(content); sendEmailService.sendEmail(content);
Message message = getMessage(); Message message = getMessage();
assertThat(getInternalContent(message).getContentType()) assertThat(getInternalContent(message).getContentType()).isEqualTo("text/html; charset=utf-8");
.isEqualTo("text/html; charset=utf-8");
} }
@Test @Test