diff --git a/core/src/main/java/google/registry/model/eppcommon/Address.java b/core/src/main/java/google/registry/model/eppcommon/Address.java index ddb98101ca0..95502d2cdcf 100644 --- a/core/src/main/java/google/registry/model/eppcommon/Address.java +++ b/core/src/main/java/google/registry/model/eppcommon/Address.java @@ -49,6 +49,10 @@ * also matches the "addrType" type from Mark and Signed Mark Objects Mapping. * + *

The lengths of the fields are limited to match the constraints defined in XSD schemas like + * {@code rde-registrar.xsd}. Specifically, {@code zip} is limited to 16 characters and {@code + * city}, {@code state}, and each {@code street} line are limited to 255 characters. + * * @see google.registry.model.mark.MarkAddress * @see google.registry.model.registrar.RegistrarAddress */ @@ -169,11 +173,20 @@ public void validateState() { street == null || (!street.isEmpty() && street.size() <= 3), "Street address must have [1-3] lines: %s", street); - //noinspection ConstantConditions + if (street != null) { + checkArgument( + street.stream().noneMatch(String::isEmpty), + "Street address cannot contain empty string: %s", + street); + checkArgument( + street.stream().allMatch(s -> s.length() <= 255), + "Street address lines cannot be longer than 255 characters"); + } checkArgument( - street == null || street.stream().noneMatch(String::isEmpty), - "Street address cannot contain empty string: %s", - street); + city == null || city.length() <= 255, "City cannot be longer than 255 characters"); + checkArgument( + state == null || state.length() <= 255, "State cannot be longer than 255 characters"); + checkArgument(zip == null || zip.length() <= 16, "Zip cannot be longer than 16 characters"); checkArgument( countryCode == null || countryCode.length() == 2, "Country code should be a 2 character string"); @@ -196,9 +209,9 @@ public T build() { public Builder setStreet(ImmutableList street) { getInstance().street = street; - getInstance().streetLine1 = street.get(0); - getInstance().streetLine2 = street.size() >= 2 ? street.get(1) : null; - getInstance().streetLine3 = street.size() == 3 ? street.get(2) : null; + getInstance().streetLine1 = (street != null && street.size() >= 1) ? street.get(0) : null; + getInstance().streetLine2 = (street != null && street.size() >= 2) ? street.get(1) : null; + getInstance().streetLine3 = (street != null && street.size() == 3) ? street.get(2) : null; return this; } diff --git a/core/src/test/java/google/registry/model/eppcommon/AddressTest.java b/core/src/test/java/google/registry/model/eppcommon/AddressTest.java index f9c92818c98..6aa7446cb12 100644 --- a/core/src/test/java/google/registry/model/eppcommon/AddressTest.java +++ b/core/src/test/java/google/registry/model/eppcommon/AddressTest.java @@ -109,6 +109,32 @@ void testFailure_emptyStreetLine() { assertThrows(IllegalArgumentException.class, () -> createAddress("line1", "", "line3")); } + @Test + void testFailure_streetLineTooLong() { + assertThrows(IllegalArgumentException.class, () -> createAddress("a".repeat(256))); + } + + @Test + void testFailure_cityTooLong() { + assertThrows( + IllegalArgumentException.class, + () -> createAddress("line1").asBuilder().setCity("a".repeat(256)).build()); + } + + @Test + void testFailure_stateTooLong() { + assertThrows( + IllegalArgumentException.class, + () -> createAddress("line1").asBuilder().setState("a".repeat(256)).build()); + } + + @Test + void testFailure_zipTooLong() { + assertThrows( + IllegalArgumentException.class, + () -> createAddress("line1").asBuilder().setZip("12345678901234567").build()); + } + @Test void testSuccess_pojoToAndFromXml() throws Exception { JAXBContext jaxbContext = JAXBContext.newInstance(TestEntity.class); diff --git a/core/src/test/java/google/registry/ui/server/console/settings/RdapRegistrarFieldsActionTest.java b/core/src/test/java/google/registry/ui/server/console/settings/RdapRegistrarFieldsActionTest.java index c3284b379e4..5b260d50916 100644 --- a/core/src/test/java/google/registry/ui/server/console/settings/RdapRegistrarFieldsActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/settings/RdapRegistrarFieldsActionTest.java @@ -19,6 +19,7 @@ import static google.registry.testing.DatabaseHelper.loadSingleton; import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN; import static jakarta.servlet.http.HttpServletResponse.SC_OK; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableList; @@ -67,7 +68,8 @@ public class RdapRegistrarFieldsActionTest extends ConsoleActionBaseTestCase { "url", "\"http://my.fake.url\"", "localizedAddress", - "{\"street\": [\"123 Example Boulevard\"], \"city\": \"Williamsburg\", \"state\":" + "{\"street\": [\"123 Example Boulevard\"], \"city\":" + + " \"Williamsburg\", \"state\":" + " \"NY\", \"zip\": \"11201\", \"countryCode\": \"US\"}")); @Test @@ -132,6 +134,17 @@ void testFailure_noAccessToRegistrar() throws Exception { assertThat(DatabaseHelper.loadByEntity(newRegistrar)).isEqualTo(newRegistrar); } + @Test + void testFailure_zipTooLong() throws Exception { + uiRegistrarMap.put( + "localizedAddress", + "{\"street\": [\"123 Fake St\"], \"city\": \"Fakeville\", \"state\":" + + " \"NL\", \"zip\": \"12345678901234567\", \"countryCode\": \"CA\"}"); + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, this::createAction); + assertThat(exception).hasMessageThat().contains("Zip cannot be longer than 16 characters"); + } + private RdapRegistrarFieldsAction createAction() throws IOException { return createAction(fteUser); }