Add diff logic and send daily Spec11 emails with new threats

For each registrar, the daily email will only include threats that did not appear
in the prior run's email.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=228889972
This commit is contained in:
gbrodman 2019-01-11 08:59:28 -08:00 committed by Ben McIlwain
parent a80a44cd06
commit f017798162
15 changed files with 529 additions and 160 deletions

View file

@ -15,13 +15,23 @@
package google.registry.reporting.spec11;
import static com.google.common.base.Throwables.getRootCause;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.io.Resources.getResource;
import google.registry.beam.spec11.ThreatMatch;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.template.soy.SoyFileSet;
import com.google.template.soy.parseinfo.SoyTemplateInfo;
import com.google.template.soy.tofu.SoyTofu;
import com.google.template.soy.tofu.SoyTofu.Renderer;
import google.registry.config.RegistryConfig.Config;
import google.registry.reporting.spec11.soy.Spec11EmailSoyInfo;
import google.registry.util.Retrier;
import google.registry.util.SendEmailService;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
@ -32,11 +42,22 @@ import org.joda.time.LocalDate;
/** Provides e-mail functionality for Spec11 tasks, such as sending Spec11 reports to registrars. */
public class Spec11EmailUtils {
private static final SoyTofu SOY_SAUCE =
SoyFileSet.builder()
.add(
getResource(
Spec11EmailSoyInfo.getInstance().getClass(),
Spec11EmailSoyInfo.getInstance().getFileName()))
.build()
.compileToTofu();
private final SendEmailService emailService;
private final LocalDate date;
private final String outgoingEmailAddress;
private final String alertRecipientAddress;
private final String spec11ReplyToAddress;
private final ImmutableList<String> spec11WebResources;
private final String registryName;
private final Retrier retrier;
@Inject
@ -46,12 +67,16 @@ public class Spec11EmailUtils {
@Config("gSuiteOutgoingEmailAddress") String outgoingEmailAddress,
@Config("alertRecipientEmailAddress") String alertRecipientAddress,
@Config("spec11ReplyToEmailAddress") String spec11ReplyToAddress,
@Config("spec11WebResources") ImmutableList<String> spec11WebResources,
@Config("registryName") String registryName,
Retrier retrier) {
this.emailService = emailService;
this.date = date;
this.outgoingEmailAddress = outgoingEmailAddress;
this.alertRecipientAddress = alertRecipientAddress;
this.spec11ReplyToAddress = spec11ReplyToAddress;
this.spec11WebResources = spec11WebResources;
this.registryName = registryName;
this.retrier = retrier;
}
@ -60,14 +85,14 @@ public class Spec11EmailUtils {
* appropriate address.
*/
void emailSpec11Reports(
String spec11EmailBodyTemplate,
SoyTemplateInfo soyTemplateInfo,
String subject,
List<RegistrarThreatMatches> registrarThreatMatchesList) {
Set<RegistrarThreatMatches> registrarThreatMatchesSet) {
try {
retrier.callWithRetry(
() -> {
for (RegistrarThreatMatches registrarThreatMatches : registrarThreatMatchesList) {
emailRegistrar(spec11EmailBodyTemplate, subject, registrarThreatMatches);
for (RegistrarThreatMatches registrarThreatMatches : registrarThreatMatchesSet) {
emailRegistrar(soyTemplateInfo, subject, registrarThreatMatches);
}
},
IOException.class,
@ -85,28 +110,45 @@ public class Spec11EmailUtils {
}
private void emailRegistrar(
String spec11EmailBodyTemplate, String subject, RegistrarThreatMatches registrarThreatMatches)
SoyTemplateInfo soyTemplateInfo,
String subject,
RegistrarThreatMatches registrarThreatMatches)
throws MessagingException {
String registrarEmail = registrarThreatMatches.registrarEmailAddress();
StringBuilder threatList = new StringBuilder();
for (ThreatMatch threatMatch : registrarThreatMatches.threatMatches()) {
threatList.append(
String.format(
"%s - %s\n", threatMatch.fullyQualifiedDomainName(), threatMatch.threatType()));
}
String body =
spec11EmailBodyTemplate
.replace("{REPLY_TO_EMAIL}", spec11ReplyToAddress)
.replace("{LIST_OF_THREATS}", threatList.toString());
Message msg = emailService.createMessage();
msg.setSubject(subject);
msg.setText(body);
String content = getContent(soyTemplateInfo, registrarThreatMatches);
msg.setContent(content, "text/html");
msg.setHeader("Content-Type", "text/html");
msg.setFrom(new InternetAddress(outgoingEmailAddress));
msg.addRecipient(RecipientType.TO, new InternetAddress(registrarEmail));
msg.addRecipient(
RecipientType.TO, new InternetAddress(registrarThreatMatches.registrarEmailAddress()));
msg.addRecipient(RecipientType.BCC, new InternetAddress(spec11ReplyToAddress));
emailService.sendMessage(msg);
}
private String getContent(
SoyTemplateInfo soyTemplateInfo, RegistrarThreatMatches registrarThreatMatches) {
Renderer renderer = SOY_SAUCE.newRenderer(soyTemplateInfo);
// Soy templates require that data be in raw map/list form.
List<Map<String, String>> threatMatchMap =
registrarThreatMatches.threatMatches().stream()
.map(
threatMatch ->
ImmutableMap.of(
"fullyQualifiedDomainName", threatMatch.fullyQualifiedDomainName(),
"threatType", threatMatch.threatType()))
.collect(toImmutableList());
Map<String, Object> data =
ImmutableMap.of(
"registry", registryName,
"replyToEmail", spec11ReplyToAddress,
"threats", threatMatchMap,
"resources", spec11WebResources);
renderer.setData(data);
return renderer.render();
}
/** Sends an e-mail indicating the state of the spec11 pipeline, with a given subject and body. */
void sendAlertEmail(String subject, String body) {
try {