Migrate EPP/Email from Soy to JAXB/FreeMarker (#3038)

- Replace deprecated Soy templates for EPP XML with JAXB models and a refined Fluent DSL.
- Migrate Spec11 and administrative emails to FreeMarker with HTML auto-escaping.
- Remove Soy compiler, Gradle tasks, and library dependencies.
- Address PR feedback regarding shadowing, version locking, and security warnings.
- Enhance tests with comprehensive XML equality assertions using Java 15 text blocks.
- Improve Javadocs and maintain strict temporal consistency using java.time.

FreeMarker replaces Soy for email templating, providing native HTML auto-escaping and allowing the removal of the complex 'soyToJava' compilation step from the build process. This significantly simplifies the build system and reduces maintenance overhead. For EPP XML, migrating to JAXB allows tool-generated commands to use the same model classes as the server-side EPP flows. This ensures that tool-generated XML is always schema-compliant and eliminates the risk of divergence between tool templates and actual server-side implementation. This unified approach provides compile-time type safety and improves developer ergonomics via a refined fluent DSL.

The base ImmutableObject class now provides a public clone() override that correctly resets the cached hashCode to null. This centralizes the custom cloning logic previously handled by a static helper and ensures that all subclasses—including the newly added JAXB models—satisfy CodeQL security requirements without needing redundant per-class overrides. The legacy static clone(T) helper has been updated to delegate to this instance method to maintain compatibility and architectural consistency.
This commit is contained in:
Ben McIlwain
2026-05-22 19:33:47 +00:00
committed by GitHub
parent b3fc57c7f7
commit 53b92d602e
104 changed files with 2521 additions and 1982 deletions
@@ -85,10 +85,9 @@ public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource
return refreshedResource;
}
private ResourceCommand.SingleResourceCommand getResourceCommand() throws Exception {
return (ResourceCommand.SingleResourceCommand)
((ResourceCommandWrapper) eppLoader.getEpp().getCommandWrapper().getCommand())
.getResourceCommand();
private ResourceCommand getResourceCommand() throws Exception {
return ((ResourceCommandWrapper) eppLoader.getEpp().getCommandWrapper().getCommand())
.getResourceCommand();
}
protected String getUniqueIdFromCommand() throws Exception {
@@ -15,7 +15,7 @@
package google.registry.model.domain;
import static google.registry.testing.DatabaseHelper.persistActiveHost;
import static org.junit.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.flows.FlowUtils;
import google.registry.flows.domain.DomainFlowUtils.RegistrantProhibitedException;
@@ -14,57 +14,177 @@
package google.registry.model.eppinput;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.testing.TestDataHelper.loadBytes;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static google.registry.xml.XmlTestUtils.assertXmlEquals;
import static java.nio.charset.StandardCharsets.UTF_8;
import google.registry.model.domain.DomainTest;
import google.registry.model.eppinput.EppInput.InnerCommand;
import google.registry.model.eppinput.EppInput.Login;
import google.registry.xml.XmlException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import google.registry.model.domain.DomainCommand;
import google.registry.model.eppcommon.EppXmlTransformer;
import google.registry.model.eppcommon.StatusValue;
import google.registry.xml.ValidationMode;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link EppInput}. */
/** Unit tests for {@link EppInput} builders and marshaling. */
class EppInputTest {
@Test
void testUnmarshalling_domainCheck() throws Exception {
EppInput input =
unmarshal(EppInput.class, loadBytes(DomainTest.class, "domain_check.xml").read());
assertThat(input.getCommandWrapper().getClTrid()).hasValue("ABC-12345");
assertThat(input.getCommandType()).isEqualTo("check");
assertThat(input.getResourceType()).hasValue("domain");
assertThat(input.getSingleTargetId()).isEmpty();
assertThat(input.getTargetIds()).containsExactly("example.com", "example.net", "example.org");
void testBuilder_emptyExtensions_omitsExtensionTag() throws Exception {
EppInput eppInput =
new EppInput.Builder()
.setCommandWrapper(
new EppInput.CommandWrapper.Builder()
.setCommand(
new EppInput.Create.Builder()
.setResourceCommand(
new DomainCommand.Create.Builder()
.setDomainName("example.tld")
.build())
.build())
.setExtensions(ImmutableList.of())
.setClTrid("RegistryTool")
.build())
.build();
String xml =
new String(EppXmlTransformer.marshalInput(eppInput, ValidationMode.LENIENT), UTF_8);
assertXmlEquals(
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
</domain:create>
</create>
<clTRID>RegistryTool</clTRID>
</command>
</epp>
""",
xml);
}
@Test
void testUnmarshalling_login() throws Exception {
EppInput input = unmarshal(EppInput.class, loadBytes(getClass(), "login_valid.xml").read());
assertThat(input.getCommandWrapper().getClTrid()).hasValue("ABC-12345");
assertThat(input.getCommandType()).isEqualTo("login");
assertThat(input.getResourceType()).isEmpty();
assertThat(input.getSingleTargetId()).isEmpty();
assertThat(input.getTargetIds()).isEmpty();
InnerCommand command = input.getCommandWrapper().getCommand();
assertThat(command).isInstanceOf(Login.class);
Login loginCommand = (Login) command;
assertThat(loginCommand.clientId).isEqualTo("NewRegistrar");
assertThat(loginCommand.password).isEqualTo("foo-BAR2");
assertThat(loginCommand.newPassword).isNull();
assertThat(loginCommand.options.version).isEqualTo("1.0");
assertThat(loginCommand.options.language).isEqualTo("en");
assertThat(loginCommand.services.objectServices)
.containsExactly("urn:ietf:params:xml:ns:host-1.0", "urn:ietf:params:xml:ns:domain-1.0");
assertThat(loginCommand.services.serviceExtensions)
.containsExactly("urn:ietf:params:xml:ns:launch-1.0", "urn:ietf:params:xml:ns:rgp-1.0");
void testBuilder_nullExtensions_omitsExtensionTag() throws Exception {
EppInput eppInput =
new EppInput.Builder()
.setCommandWrapper(
new EppInput.CommandWrapper.Builder()
.setCommand(
new EppInput.Create.Builder()
.setResourceCommand(
new DomainCommand.Create.Builder()
.setDomainName("example.tld")
.build())
.build())
.setExtensions(null)
.setClTrid("RegistryTool")
.build())
.build();
String xml =
new String(EppXmlTransformer.marshalInput(eppInput, ValidationMode.LENIENT), UTF_8);
assertXmlEquals(
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
</domain:create>
</create>
<clTRID>RegistryTool</clTRID>
</command>
</epp>
""",
xml);
}
@Test
void testUnmarshalling_loginTagInWrongCase_throws() {
assertThrows(
XmlException.class,
() -> unmarshal(EppInput.class, loadBytes(getClass(), "login_wrong_case.xml").read()));
void testBuilder_domainUpdate_emptyAddRemove_omitsInnerTags() throws Exception {
EppInput eppInput =
new EppInput.Builder()
.setCommandWrapper(
new EppInput.CommandWrapper.Builder()
.setCommand(
new EppInput.Update.Builder()
.setResourceCommand(
new DomainCommand.Update.Builder()
.setTargetId("example.tld")
.setInnerAdd(
new DomainCommand.Update.DomainAddRemove.Builder().build())
.setInnerRemove(
new DomainCommand.Update.DomainAddRemove.Builder().build())
.build())
.build())
.setClTrid("RegistryTool")
.build())
.build();
String xml =
new String(EppXmlTransformer.marshalInput(eppInput, ValidationMode.LENIENT), UTF_8);
assertXmlEquals(
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<update>
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:add/>
<domain:rem/>
</domain:update>
</update>
<clTRID>RegistryTool</clTRID>
</command>
</epp>
""",
xml);
}
@Test
void testBuilder_domainUpdate_withStatuses() throws Exception {
EppInput eppInput =
new EppInput.Builder()
.setCommandWrapper(
new EppInput.CommandWrapper.Builder()
.setCommand(
new EppInput.Update.Builder()
.setResourceCommand(
new DomainCommand.Update.Builder()
.setTargetId("example.tld")
.setInnerAdd(
new DomainCommand.Update.DomainAddRemove.Builder()
.setStatusValues(
ImmutableSet.of(StatusValue.CLIENT_HOLD))
.build())
.build())
.build())
.setClTrid("RegistryTool")
.build())
.build();
String xml =
new String(EppXmlTransformer.marshalInput(eppInput, ValidationMode.LENIENT), UTF_8);
assertXmlEquals(
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<update>
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:add>
<domain:status s="clientHold"/>
</domain:add>
</domain:update>
</update>
<clTRID>RegistryTool</clTRID>
</command>
</epp>
""",
xml);
}
}
@@ -37,7 +37,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.MediaType;
import google.registry.beam.spec11.ThreatMatch;
import google.registry.reporting.spec11.soy.Spec11EmailSoyInfo;
import google.registry.reporting.spec11.Spec11EmailUtils.Spec11EmailTemplate;
import google.registry.testing.FakeResponse;
import java.io.IOException;
import java.time.LocalDate;
@@ -76,7 +76,6 @@ class PublishSpec11ReportActionTest {
expectedJob = new Job();
when(get.execute()).thenReturn(expectedJob);
emailUtils = mock(Spec11EmailUtils.class);
parser = mock(Spec11RegistrarThreatMatchesParser.class);
response = new FakeResponse();
parser = mock(Spec11RegistrarThreatMatchesParser.class);
publishAction =
@@ -113,7 +112,7 @@ class PublishSpec11ReportActionTest {
verify(emailUtils)
.emailSpec11Reports(
secondOfMonth,
Spec11EmailSoyInfo.MONTHLY_SPEC_11_EMAIL,
Spec11EmailTemplate.MONTHLY,
"Super Cool Registry Monthly Threat Detector [2018-06-02]",
sampleThreatMatches());
verifyNoMoreInteractions(emailUtils);
@@ -163,7 +162,7 @@ class PublishSpec11ReportActionTest {
verify(emailUtils)
.emailSpec11Reports(
date,
Spec11EmailSoyInfo.DAILY_SPEC_11_EMAIL,
Spec11EmailTemplate.DAILY,
"Super Cool Registry Daily Threat Detector [2018-06-05]",
sampleThreatMatches());
verifyNoMoreInteractions(emailUtils);
@@ -196,7 +195,7 @@ class PublishSpec11ReportActionTest {
verify(emailUtils)
.emailSpec11Reports(
date,
Spec11EmailSoyInfo.DAILY_SPEC_11_EMAIL,
Spec11EmailTemplate.DAILY,
"Super Cool Registry Daily Threat Detector [2018-06-05]",
expectedMatchSet);
verifyNoMoreInteractions(emailUtils);
@@ -214,7 +213,7 @@ class PublishSpec11ReportActionTest {
verify(emailUtils)
.emailSpec11Reports(
date,
Spec11EmailSoyInfo.DAILY_SPEC_11_EMAIL,
Spec11EmailTemplate.DAILY,
"Super Cool Registry Daily Threat Detector [2018-06-05]",
ImmutableSet.of());
verifyNoMoreInteractions(emailUtils);
@@ -23,6 +23,7 @@ import static google.registry.reporting.spec11.Spec11RegistrarThreatMatchesParse
import static google.registry.reporting.spec11.Spec11RegistrarThreatMatchesParserTest.sampleThreatMatches;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadByEntity;
import static google.registry.testing.DatabaseHelper.newDomain;
import static google.registry.testing.DatabaseHelper.persistActiveHost;
import static google.registry.testing.DatabaseHelper.persistResource;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -39,10 +40,10 @@ import google.registry.model.domain.Domain;
import google.registry.model.host.Host;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.reporting.spec11.soy.Spec11EmailSoyInfo;
import google.registry.testing.DatabaseHelper;
import google.registry.reporting.spec11.Spec11EmailUtils.Spec11EmailTemplate;
import google.registry.util.EmailMessage;
import google.registry.util.Sleeper;
import google.registry.util.TemplateRenderer;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.InternetAddress;
import java.time.Duration;
@@ -64,40 +65,80 @@ class Spec11EmailUtilsTest {
private static final ImmutableList<String> FAKE_RESOURCES = ImmutableList.of("foo");
private static final String DAILY_EMAIL_FORMAT =
"Dear registrar partner,<p>Super Cool Registry conducts a daily analysis of all domains"
+ " registered in its TLDs to identify potential security concerns. On 2018-07-15, the"
+ " following domains that your registrar manages were flagged for potential security"
+ " concerns:</p><table><tr><th>Domain Name</th><th>Threat Type</th></tr>%s"
+ "</table><p><b>Please communicate these findings to the registrant and work with the"
+ " registrant to mitigate any security issues and have the domains delisted.</b></p>"
+ "Some helpful resources for getting off a blocked list include:"
+ "<ul><li>foo</li></ul><p>If you believe that any of the domains were reported in"
+ " error, or are still receiving reports for issues that have been remediated, please"
+ " <a href=\"https://safebrowsing.google.com/safebrowsing/report_error/?hl=en\">submit"
+ " a request</a> to have the site reviewed.</p><p>You will continue to receive daily"
+ " notices when new domains managed by your registrar are flagged for abuse, as well as"
+ " a monthly summary of all of your domains under management that remain flagged for"
+ " abuse.</p><p>If you would like to change the email to which these notices are sent"
+ " please update your abuse contact using your registrar portal account.</p><p>If you"
+ " have any questions regarding this notice, please contact abuse@test.com.</p>";
"""
<p>Dear registrar partner,</p>
<p>Super Cool Registry conducts a daily analysis of all domains registered in its TLDs to
identify potential security concerns. On 2018-07-15, the following domains that your
registrar manages were flagged for potential security concerns:</p>
<table>
<tr>
<th>Domain Name</th>
<th>Threat Type</th>
</tr>
%s</table>
<p><b>Please communicate these findings to the registrant and work with the
registrant to mitigate any security issues and have the domains delisted.</b></p>
<p>Some helpful resources for getting off a blocked list include:</p>
<ul>
<li>foo</li>
</ul>
<p>If you believe that any of the domains were reported in error, or are still receiving
reports for issues that have been remediated,
please <a href="https://safebrowsing.google.com/safebrowsing/report_error/?hl=en">submit
a request</a> to have the site reviewed.</p>
<p>You will continue to receive daily notices when new domains managed by your registrar
are flagged for abuse, as well as a monthly summary of all of your domains under management
that remain flagged for abuse.</p>
<p>If you would like to change the email to which these notices are sent, please update your
abuse contact using your registrar portal account.</p>
<p>If you have any questions regarding this notice, please contact abuse@test.com.</p>
""";
private static final String MONTHLY_EMAIL_FORMAT =
"Dear registrar partner,<p>Super Cool Registry previously notified you when the following"
+ " domains managed by your registrar were flagged for potential security"
+ " concerns.</p><p>The following domains that you manage continue to be flagged by our"
+ " analysis for potential security concerns. This may be because the registrants have"
+ " not completed the requisite steps to mitigate the potential security abuse and/or"
+ " have it reviewed and delisted.</p><table><tr><th>Domain Name</th><th>Threat"
+ " Type</th></tr>%s</table><p>Please work with the registrant to mitigate any security"
+ " issues and have the domains delisted. If you believe that any of the domains were"
+ " reported in error, or are still receiving reports for issues that have been"
+ " remediated, please <a"
+ " href=\"https://safebrowsing.google.com/safebrowsing/report_error/?hl=en\">submit a"
+ " request</a> to have the site reviewed.</p>Some helpful resources for getting off a"
+ " blocked list include:<ul><li>foo</li></ul><p>You will continue to receive a monthly"
+ " summary of all domains managed by your registrar that remain on our lists of"
+ " potential security threats. You will also receive a daily notice when any new"
+ " domains are added to these lists.</p><p>If you have any questions regarding this"
+ " notice, please contact abuse@test.com.</p>";
"""
<p>Dear registrar partner,</p>
<p>Super Cool Registry previously notified you when the following domains managed by your
registrar were flagged for potential security concerns.</p>
<p>The following domains that you manage continue to be flagged by our analysis for
potential security concerns. This may be because the registrants have not completed the
requisite steps to mitigate the potential security abuse and/or have it reviewed and
delisted.</p>
<table>
<tr>
<th>Domain Name</th>
<th>Threat Type</th>
</tr>
%s</table>
<p>Please work with the registrant to mitigate any security issues and have the
domains delisted. If you believe that any of the domains were reported in error, or are
still receiving reports for issues that have been remediated,
please <a href="https://safebrowsing.google.com/safebrowsing/report_error/?hl=en">submit a
request</a> to have the site reviewed.</p>
<p>Some helpful resources for getting off a blocked list include:</p>
<ul>
<li>foo</li>
</ul>
<p>You will continue to receive a monthly summary of all domains managed by your registrar
that remain on our lists of potential security threats. You will also receive a daily
notice when any new domains are added to these lists.</p>
<p>If you have any questions regarding this notice, please contact abuse@test.com.</p>
""";
@RegisterExtension
final JpaIntegrationTestExtension jpa =
@@ -120,6 +161,7 @@ class Spec11EmailUtilsTest {
new Spec11EmailUtils(
gmailClient,
sleeper,
new TemplateRenderer(),
emailThrottleDuration,
new InternetAddress("my-receiver@test.com"),
new InternetAddress("abuse@test.com"),
@@ -139,7 +181,7 @@ class Spec11EmailUtilsTest {
void testSuccess_sleepsBetweenSending() throws Exception {
emailUtils.emailSpec11Reports(
date,
Spec11EmailSoyInfo.MONTHLY_SPEC_11_EMAIL,
Spec11EmailTemplate.MONTHLY,
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
sampleThreatMatches());
// We inspect individual parameters because Message doesn't implement equals().
@@ -152,7 +194,7 @@ class Spec11EmailUtilsTest {
void testSuccess_emailMonthlySpec11Reports() throws Exception {
emailUtils.emailSpec11Reports(
date,
Spec11EmailSoyInfo.MONTHLY_SPEC_11_EMAIL,
Spec11EmailTemplate.MONTHLY,
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
sampleThreatMatches());
// We inspect individual parameters because Message doesn't implement equals().
@@ -163,7 +205,14 @@ class Spec11EmailUtilsTest {
"the.registrar@example.com",
ImmutableList.of("abuse@test.com", "bcc@test.com"),
"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));
validateMessage(
capturedContents.get(1),
@@ -172,7 +221,16 @@ class Spec11EmailUtilsTest {
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
String.format(
MONTHLY_EMAIL_FORMAT,
"<tr><td>b[.]com</td><td>MALWARE</td></tr><tr><td>c[.]com</td><td>MALWARE</td></tr>"),
"""
<tr>
<td>b[.]com</td>
<td>MALWARE</td>
</tr>
<tr>
<td>c[.]com</td>
<td>MALWARE</td>
</tr>
"""),
Optional.of(MediaType.HTML_UTF_8));
validateMessage(
capturedContents.get(2),
@@ -187,7 +245,7 @@ class Spec11EmailUtilsTest {
void testSuccess_emailDailySpec11Reports() throws Exception {
emailUtils.emailSpec11Reports(
date,
Spec11EmailSoyInfo.DAILY_SPEC_11_EMAIL,
Spec11EmailTemplate.DAILY,
"Super Cool Registry Daily Threat Detector [2018-07-15]",
sampleThreatMatches());
// We inspect individual parameters because Message doesn't implement equals().
@@ -198,7 +256,14 @@ class Spec11EmailUtilsTest {
"the.registrar@example.com",
ImmutableList.of("abuse@test.com", "bcc@test.com"),
"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));
validateMessage(
capturedMessages.get(1),
@@ -207,7 +272,16 @@ class Spec11EmailUtilsTest {
"Super Cool Registry Daily Threat Detector [2018-07-15]",
String.format(
DAILY_EMAIL_FORMAT,
"<tr><td>b[.]com</td><td>MALWARE</td></tr><tr><td>c[.]com</td><td>MALWARE</td></tr>"),
"""
<tr>
<td>b[.]com</td>
<td>MALWARE</td>
</tr>
<tr>
<td>c[.]com</td>
<td>MALWARE</td>
</tr>
"""),
Optional.of(MediaType.HTML_UTF_8));
validateMessage(
capturedMessages.get(2),
@@ -225,7 +299,7 @@ class Spec11EmailUtilsTest {
persistResource(loadByEntity(bDomain).asBuilder().addStatusValue(CLIENT_HOLD).build());
emailUtils.emailSpec11Reports(
date,
Spec11EmailSoyInfo.MONTHLY_SPEC_11_EMAIL,
Spec11EmailTemplate.MONTHLY,
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
sampleThreatMatches());
// We inspect individual parameters because Message doesn't implement equals().
@@ -236,7 +310,14 @@ class Spec11EmailUtilsTest {
"new.registrar@example.com",
ImmutableList.of("abuse@test.com", "bcc@test.com"),
"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));
validateMessage(
capturedContents.get(1),
@@ -252,11 +333,13 @@ class Spec11EmailUtilsTest {
// Create an inactive domain and an active domain with the same name.
persistResource(loadByEntity(aDomain).asBuilder().addStatusValue(SERVER_HOLD).build());
Host host = persistActiveHost("ns1.example.com");
aDomain = persistResource(aDomain.asBuilder().setNameservers(host.createVKey()).build());
aDomain =
persistResource(
aDomain.asBuilder().setNameservers(ImmutableSet.of(host.createVKey())).build());
emailUtils.emailSpec11Reports(
date,
Spec11EmailSoyInfo.MONTHLY_SPEC_11_EMAIL,
Spec11EmailTemplate.MONTHLY,
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
sampleThreatMatches());
// We inspect individual parameters because Message doesn't implement equals().
@@ -267,7 +350,14 @@ class Spec11EmailUtilsTest {
"the.registrar@example.com",
ImmutableList.of("abuse@test.com", "bcc@test.com"),
"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));
validateMessage(
capturedContents.get(1),
@@ -276,7 +366,16 @@ class Spec11EmailUtilsTest {
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
String.format(
MONTHLY_EMAIL_FORMAT,
"<tr><td>b[.]com</td><td>MALWARE</td></tr><tr><td>c[.]com</td><td>MALWARE</td></tr>"),
"""
<tr>
<td>b[.]com</td>
<td>MALWARE</td>
</tr>
<tr>
<td>c[.]com</td>
<td>MALWARE</td>
</tr>
"""),
Optional.of(MediaType.HTML_UTF_8));
validateMessage(
capturedContents.get(2),
@@ -304,7 +403,7 @@ class Spec11EmailUtilsTest {
() ->
emailUtils.emailSpec11Reports(
date,
Spec11EmailSoyInfo.MONTHLY_SPEC_11_EMAIL,
Spec11EmailTemplate.MONTHLY,
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
ImmutableSet.copyOf(matches)));
assertThat(thrown)
@@ -319,7 +418,14 @@ class Spec11EmailUtilsTest {
"the.registrar@example.com",
ImmutableList.of("abuse@test.com", "bcc@test.com"),
"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));
validateMessage(
capturedMessages.get(1),
@@ -328,7 +434,16 @@ class Spec11EmailUtilsTest {
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
String.format(
MONTHLY_EMAIL_FORMAT,
"<tr><td>b[.]com</td><td>MALWARE</td></tr><tr><td>c[.]com</td><td>MALWARE</td></tr>"),
"""
<tr>
<td>b[.]com</td>
<td>MALWARE</td>
</tr>
<tr>
<td>c[.]com</td>
<td>MALWARE</td>
</tr>
"""),
Optional.of(MediaType.HTML_UTF_8));
validateMessage(
capturedMessages.get(2),
@@ -363,7 +478,7 @@ class Spec11EmailUtilsTest {
.build());
emailUtils.emailSpec11Reports(
date,
Spec11EmailSoyInfo.MONTHLY_SPEC_11_EMAIL,
Spec11EmailTemplate.MONTHLY,
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
sampleThreatMatches());
verify(gmailClient, times(3)).sendEmail(contentCaptor.capture());
@@ -379,7 +494,7 @@ class Spec11EmailUtilsTest {
() ->
emailUtils.emailSpec11Reports(
date,
Spec11EmailSoyInfo.MONTHLY_SPEC_11_EMAIL,
Spec11EmailTemplate.MONTHLY,
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
ImmutableSet.of(
RegistrarThreatMatches.create(
@@ -409,12 +524,13 @@ class Spec11EmailUtilsTest {
expectedContentBuilder.addBcc(new InternetAddress(bcc));
}
contentType.ifPresent(expectedContentBuilder::setContentType);
assertThat(message.body()).isEqualTo(body);
assertThat(message).isEqualTo(expectedContentBuilder.build());
}
private static Domain persistDomainWithHost(String domainName, Host host) {
return persistResource(
DatabaseHelper.newDomain(domainName)
newDomain(domainName)
.asBuilder()
.setNameservers(ImmutableSet.of(host.createVKey()))
.build());
@@ -1,13 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">jd1234</domain:contact>
<domain:contact type="tech">jd1234</domain:contact>
<domain:authInfo>
<domain:pw>abcdefghijklmnop</domain:pw>
</domain:authInfo>
@@ -1,13 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>premium.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">jd1234</domain:contact>
<domain:contact type="tech">jd1234</domain:contact>
<domain:authInfo>
<domain:pw>abcdefghijklmnop</domain:pw>
</domain:authInfo>
@@ -1,13 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">jd1234</domain:contact>
<domain:contact type="tech">jd1234</domain:contact>
<domain:authInfo>
<domain:pw>abcdefghijklmnop</domain:pw>
</domain:authInfo>
@@ -1,13 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">jd1234</domain:contact>
<domain:contact type="tech">jd1234</domain:contact>
<domain:authInfo>
<domain:pw>abcdefghijklmnop</domain:pw>
</domain:authInfo>
@@ -1,13 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">jd1234</domain:contact>
<domain:contact type="tech">jd1234</domain:contact>
<domain:authInfo>
<domain:pw>abcdefghijklmnop</domain:pw>
</domain:authInfo>
@@ -1,13 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">jd1234</domain:contact>
<domain:contact type="tech">jd1234</domain:contact>
<domain:authInfo>
<domain:pw>foo</domain:pw>
</domain:authInfo>
@@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>palladium.tld</domain:name>
<domain:period unit="y">1</domain:period>
<domain:authInfo>
@@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>parajiumu.baar</domain:name>
<domain:period unit="y">3</domain:period>
<domain:authInfo>
@@ -5,13 +5,12 @@
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:add>
<domain:status s="serverHold" lang="en"></domain:status>
<domain:status s="serverRenewProhibited" lang="en"></domain:status>
<domain:status s="serverTransferProhibited" lang="en"></domain:status>
<domain:status s="serverDeleteProhibited" lang="en"></domain:status>
<domain:status s="serverUpdateProhibited" lang="en"></domain:status>
<domain:status s="serverHold"></domain:status>
<domain:status s="serverRenewProhibited"></domain:status>
<domain:status s="serverTransferProhibited"></domain:status>
<domain:status s="serverDeleteProhibited"></domain:status>
<domain:status s="serverUpdateProhibited"></domain:status>
</domain:add>
<domain:rem></domain:rem>
</domain:update>
</update>
<extension>
@@ -5,9 +5,8 @@
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:add>
<domain:status s="serverRenewProhibited" lang="en"></domain:status>
<domain:status s="serverRenewProhibited"></domain:status>
</domain:add>
<domain:rem></domain:rem>
</domain:update>
</update>
<extension>
@@ -5,9 +5,8 @@
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:add>
<domain:status s="serverRenewProhibited" lang="en"></domain:status>
<domain:status s="serverRenewProhibited"></domain:status>
</domain:add>
<domain:rem></domain:rem>
</domain:update>
</update>
<extension>
@@ -4,13 +4,12 @@
<update>
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:add></domain:add>
<domain:rem>
<domain:status s="serverHold" lang="en"></domain:status>
<domain:status s="serverRenewProhibited" lang="en"></domain:status>
<domain:status s="serverTransferProhibited" lang="en"></domain:status>
<domain:status s="serverDeleteProhibited" lang="en"></domain:status>
<domain:status s="serverUpdateProhibited" lang="en"></domain:status>
<domain:status s="serverHold"></domain:status>
<domain:status s="serverRenewProhibited"></domain:status>
<domain:status s="serverTransferProhibited"></domain:status>
<domain:status s="serverDeleteProhibited"></domain:status>
<domain:status s="serverUpdateProhibited"></domain:status>
</domain:rem>
</domain:update>
</update>
@@ -4,9 +4,8 @@
<update>
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:add></domain:add>
<domain:rem>
<domain:status s="serverRenewProhibited" lang="en"></domain:status>
<domain:status s="serverRenewProhibited"></domain:status>
</domain:rem>
</domain:update>
</update>
@@ -131,7 +131,7 @@
<rdeHeader:count uri="urn:ietf:params:xml:ns:rdeDomain-1.0">0</rdeHeader:count>
<rdeHeader:count uri="urn:ietf:params:xml:ns:rdeHost-1.0">1</rdeHeader:count>
<rdeHeader:count uri="urn:ietf:params:xml:ns:rdeRegistrar-1.0">2</rdeHeader:count>
<rdeHeader:count uri="urn:ietf:params:xml:ns:rdeIDN-1.0">4</rdeHeader:count>
<rdeHeader:count uri="urn:ietf:params:xml:ns:rdeIDN-1.0">3</rdeHeader:count>
</rdeHeader:header>
</rde:contents>