mirror of
https://github.com/google/nomulus.git
synced 2025-08-03 16:32:11 +02:00
mv com/google/domain/registry google/registry
This change renames directories in preparation for the great package rename. The repository is now in a broken state because the code itself hasn't been updated. However this should ensure that git correctly preserves history for each file.
This commit is contained in:
parent
a41677aea1
commit
5012893c1d
2396 changed files with 0 additions and 0 deletions
23
javatests/google/registry/ui/server/BUILD
Normal file
23
javatests/google/registry/ui/server/BUILD
Normal file
|
@ -0,0 +1,23 @@
|
|||
package(default_visibility = ["//java/com/google/domain/registry:registry_project"])
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "server",
|
||||
srcs = glob(["*.java"]),
|
||||
deps = [
|
||||
"//java/com/google/domain/registry/ui/forms",
|
||||
"//java/com/google/domain/registry/ui/server",
|
||||
"//javatests/com/google/domain/registry/testing",
|
||||
"//third_party/java/hamcrest",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":server"],
|
||||
)
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
import com.google.domain.registry.testing.CertificateSamples;
|
||||
import com.google.domain.registry.ui.forms.FormFieldException;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link RegistrarFormFields}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class RegistrarFormFieldsTest {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void testValidCertificate_doesntThrowError() {
|
||||
assertThat(RegistrarFormFields.CLIENT_CERTIFICATE_FIELD.convert(CertificateSamples.SAMPLE_CERT))
|
||||
.hasValue(CertificateSamples.SAMPLE_CERT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadCertificate_throwsFfe() {
|
||||
thrown.expect(equalTo(
|
||||
new FormFieldException("Invalid X.509 PEM certificate")
|
||||
.propagate("clientCertificate")));
|
||||
RegistrarFormFields.CLIENT_CERTIFICATE_FIELD.convert("palfun");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidCertificateHash_doesntThrowError() {
|
||||
assertThat(
|
||||
RegistrarFormFields.CLIENT_CERTIFICATE_HASH_FIELD.convert(
|
||||
CertificateSamples.SAMPLE_CERT_HASH))
|
||||
.hasValue(CertificateSamples.SAMPLE_CERT_HASH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadCertificateHash_throwsFfe() {
|
||||
thrown.expect(equalTo(
|
||||
new FormFieldException("Field must contain a base64 value.")
|
||||
.propagate("clientCertificateHash")));
|
||||
RegistrarFormFields.CLIENT_CERTIFICATE_HASH_FIELD.convert("~~~");
|
||||
}
|
||||
}
|
27
javatests/google/registry/ui/server/api/BUILD
Normal file
27
javatests/google/registry/ui/server/api/BUILD
Normal file
|
@ -0,0 +1,27 @@
|
|||
package(default_visibility = ["//java/com/google/domain/registry:registry_project"])
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "api",
|
||||
srcs = glob(["*.java"]),
|
||||
deps = [
|
||||
"//java/com/google/common/collect",
|
||||
"//java/com/google/domain/registry/model",
|
||||
"//java/com/google/domain/registry/ui/server/api",
|
||||
"//javatests/com/google/domain/registry/testing",
|
||||
"//third_party/java/appengine:appengine-api-testonly",
|
||||
"//third_party/java/json_simple",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/mockito",
|
||||
"//third_party/java/servlet/servlet_api",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":api"],
|
||||
)
|
193
javatests/google/registry/ui/server/api/CheckApiServletTest.java
Normal file
193
javatests/google/registry/ui/server/api/CheckApiServletTest.java
Normal file
|
@ -0,0 +1,193 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server.api;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistReservedList;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.model.registry.Registry;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/** Tests for {@link CheckApiServlet}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CheckApiServletTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Mock HttpServletRequest req;
|
||||
@Mock HttpServletResponse rsp;
|
||||
|
||||
private final StringWriter writer = new StringWriter();
|
||||
|
||||
private final CheckApiServlet servlet = new CheckApiServlet();
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
createTld("example");
|
||||
persistResource(
|
||||
Registry.get("example")
|
||||
.asBuilder()
|
||||
.setReservedLists(persistReservedList("example-reserved", "foo,FULLY_BLOCKED"))
|
||||
.build());
|
||||
when(rsp.getWriter()).thenReturn(new PrintWriter(writer));
|
||||
}
|
||||
|
||||
private void doTest(Map<String, ?> expected) throws Exception {
|
||||
servlet.doGet(req, rsp);
|
||||
assertThat(JSONValue.parse(writer.toString())).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nullDomain() throws Exception {
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "error",
|
||||
"reason", "Must supply a valid second level domain name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_emptyDomain() throws Exception {
|
||||
when(req.getParameter("domain")).thenReturn("");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "error",
|
||||
"reason", "Must supply a valid second level domain name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_invalidDomain() throws Exception {
|
||||
when(req.getParameter("domain")).thenReturn("@#$%^");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "error",
|
||||
"reason", "Must supply a valid second level domain name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_singlePartDomain() throws Exception {
|
||||
when(req.getParameter("domain")).thenReturn("foo");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "error",
|
||||
"reason", "Must supply a valid second level domain name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonExistentTld() throws Exception {
|
||||
when(req.getParameter("domain")).thenReturn("foo.bar");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "error",
|
||||
"reason", "Domain name is under tld bar which doesn't exist"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unauthorizedTld() throws Exception {
|
||||
createTld("foo");
|
||||
persistResource(
|
||||
Registrar.loadByClientId("TheRegistrar")
|
||||
.asBuilder()
|
||||
.setAllowedTlds(ImmutableSet.of("foo"))
|
||||
.build());
|
||||
when(req.getParameter("domain")).thenReturn("timmy.example");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "error",
|
||||
"reason", "Registrar is not authorized to access the TLD example"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_availableStandard() throws Exception {
|
||||
when(req.getParameter("domain")).thenReturn("somedomain.example");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "success",
|
||||
"available", true,
|
||||
"tier", "standard"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_availableCapital() throws Exception {
|
||||
when(req.getParameter("domain")).thenReturn("SOMEDOMAIN.EXAMPLE");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "success",
|
||||
"available", true,
|
||||
"tier", "standard"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_availableUnicode() throws Exception {
|
||||
when(req.getParameter("domain")).thenReturn("ééé.example");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "success",
|
||||
"available", true,
|
||||
"tier", "standard"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_availablePunycode() throws Exception {
|
||||
when(req.getParameter("domain")).thenReturn("xn--9caaa.example");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "success",
|
||||
"available", true,
|
||||
"tier", "standard"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_availablePremium() throws Exception {
|
||||
when(req.getParameter("domain")).thenReturn("rich.example");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "success",
|
||||
"available", true,
|
||||
"tier", "premium"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_alreadyRegistered() throws Exception {
|
||||
persistActiveDomain("somedomain.example");
|
||||
when(req.getParameter("domain")).thenReturn("somedomain.example");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "success",
|
||||
"available", false,
|
||||
"reason", "In use"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_reserved() throws Exception {
|
||||
when(req.getParameter("domain")).thenReturn("foo.example");
|
||||
doTest(ImmutableMap.of(
|
||||
"status", "success",
|
||||
"available", false,
|
||||
"reason", "Reserved"));
|
||||
}
|
||||
}
|
43
javatests/google/registry/ui/server/registrar/BUILD
Normal file
43
javatests/google/registry/ui/server/registrar/BUILD
Normal file
|
@ -0,0 +1,43 @@
|
|||
package(default_visibility = ["//java/com/google/domain/registry:registry_project"])
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "registrar",
|
||||
srcs = glob(["*.java"]),
|
||||
resources = glob(["testdata/*"]),
|
||||
deps = [
|
||||
"//java/com/google/common/base",
|
||||
"//java/com/google/common/collect",
|
||||
"//java/com/google/common/io",
|
||||
"//java/com/google/common/net",
|
||||
"//java/com/google/common/testing",
|
||||
"//java/com/google/domain/registry/braintree",
|
||||
"//java/com/google/domain/registry/config",
|
||||
"//java/com/google/domain/registry/export/sheet",
|
||||
"//java/com/google/domain/registry/model",
|
||||
"//java/com/google/domain/registry/security",
|
||||
"//java/com/google/domain/registry/ui/server/registrar",
|
||||
"//java/com/google/domain/registry/ui/soy/registrar:soy_java_wrappers",
|
||||
"//java/com/google/domain/registry/util",
|
||||
"//javatests/com/google/domain/registry/security",
|
||||
"//javatests/com/google/domain/registry/testing",
|
||||
"//third_party/java/appengine:appengine-api-testonly",
|
||||
"//third_party/java/braintree",
|
||||
"//third_party/java/joda_money",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/json_simple",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/mockito",
|
||||
"//third_party/java/objectify:objectify-v4_1",
|
||||
"//third_party/java/servlet/servlet_api",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":registrar"],
|
||||
)
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server.registrar;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.appengine.api.users.UserServiceFactory;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeResponse;
|
||||
import com.google.domain.registry.testing.UserInfo;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/** Unit tests for {@link ConsoleUiAction}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ConsoleUiActionTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngineRule = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withUserService(UserInfo.create("marla.singer@example.com", "12345"))
|
||||
.build();
|
||||
|
||||
@Mock
|
||||
private SessionUtils sessionUtils;
|
||||
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private final ConsoleUiAction action = new ConsoleUiAction();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
action.enabled = true;
|
||||
action.response = response;
|
||||
action.sessionUtils = sessionUtils;
|
||||
action.userService = UserServiceFactory.getUserService();
|
||||
when(sessionUtils.checkRegistrarConsoleLogin(any(HttpServletRequest.class))).thenReturn(true);
|
||||
when(sessionUtils.getRegistrarClientId(any(HttpServletRequest.class)))
|
||||
.thenReturn("TheRegistrar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webPage_disallowsIframe() throws Exception {
|
||||
action.run();
|
||||
assertThat(response.getHeaders()).containsEntry("X-Frame-Options", "SAMEORIGIN");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webPage_setsHtmlUtf8ContentType() throws Exception {
|
||||
action.run();
|
||||
assertThat(response.getContentType()).isEqualTo(MediaType.HTML_UTF_8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webPage_containsUserNickname() throws Exception {
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("marla.singer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userHasAccessAsTheRegistrar_showsRegistrarConsole() throws Exception {
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Registrar Console");
|
||||
assertThat(response.getPayload()).contains("reg-content-and-footer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consoleDisabled_showsDisabledPage() throws Exception {
|
||||
action.enabled = false;
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("<h1>Console is disabled</h1>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userDoesntHaveAccessToAnyRegistrar_showsWhoAreYouPage() throws Exception {
|
||||
when(sessionUtils.checkRegistrarConsoleLogin(any(HttpServletRequest.class))).thenReturn(false);
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("<h1>You need permission</h1>");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server.registrar;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.security.JsonHttpTestUtils.createJsonPayload;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.model.registrar.RegistrarContact;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.DatastoreHelper;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Unit tests for contact_settings.js use of {@link RegistrarServlet}.
|
||||
*
|
||||
* <p>The default read and session validation tests are handled by the
|
||||
* superclass.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ContactSettingsTest extends RegistrarServletTestCase {
|
||||
|
||||
@Test
|
||||
public void testPost_readContacts_success() throws Exception {
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "read",
|
||||
"args", ImmutableMap.of())));
|
||||
servlet.service(req, rsp);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, ?>> results = (List<Map<String, ?>>) json.get().get("results");
|
||||
assertThat(results.get(0).get("contacts"))
|
||||
.isEqualTo(Registrar.loadByClientId(CLIENT_ID).toJsonMap().get("contacts"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_loadSaveRegistrar_success() throws Exception {
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", Registrar.loadByClientId(CLIENT_ID).toJsonMap())));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "SUCCESS");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_updateContacts_success() throws Exception {
|
||||
// Remove all the contacts but the first by updating with list of
|
||||
// just it.
|
||||
Map<String, /* @Nullable */ Object> adminContact1 = new HashMap<>();
|
||||
adminContact1.put("name", "contact1");
|
||||
adminContact1.put("emailAddress", "contact1@email.com");
|
||||
adminContact1.put("phoneNumber", "+1.2125650001");
|
||||
// Have to keep ADMIN or else expect FormException for at-least-one.
|
||||
adminContact1.put("types", "ADMIN");
|
||||
|
||||
Registrar registrar = Registrar.loadByClientId(CLIENT_ID);
|
||||
Map<String, Object> regMap = registrar.toJsonMap();
|
||||
regMap.put("contacts", ImmutableList.of(adminContact1));
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", regMap)));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "SUCCESS");
|
||||
|
||||
RegistrarContact newContact = new RegistrarContact.Builder()
|
||||
.setParent(registrar)
|
||||
.setName((String) adminContact1.get("name"))
|
||||
.setEmailAddress((String) adminContact1.get("emailAddress"))
|
||||
.setPhoneNumber((String) adminContact1.get("phoneNumber"))
|
||||
.setTypes(ImmutableList.of(RegistrarContact.Type.ADMIN))
|
||||
.build();
|
||||
assertThat(Registrar.loadByClientId(CLIENT_ID).getContacts())
|
||||
.containsExactlyElementsIn(ImmutableSet.of(newContact));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_updateContacts_requiredTypes_error() throws Exception {
|
||||
Map<String, Object> reqJson = Registrar.loadByClientId(CLIENT_ID).toJsonMap();
|
||||
reqJson.put("contacts",
|
||||
ImmutableList.of(AppEngineRule.makeRegistrarContact2()
|
||||
.asBuilder()
|
||||
.setTypes(ImmutableList.<RegistrarContact.Type>of())
|
||||
.build().toJsonMap()));
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", reqJson)));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "ERROR");
|
||||
assertThat(json.get()).containsEntry("message", "Must have at least one "
|
||||
+ RegistrarContact.Type.ADMIN.getDisplayName() + " contact");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_updateContacts_requireTechPhone_error() throws Exception {
|
||||
// First make the contact a tech contact as well.
|
||||
Registrar registrar = Registrar.loadByClientId(CLIENT_ID);
|
||||
RegistrarContact rc = AppEngineRule.makeRegistrarContact2()
|
||||
.asBuilder()
|
||||
.setTypes(ImmutableSet.of(RegistrarContact.Type.ADMIN, RegistrarContact.Type.TECH))
|
||||
.build();
|
||||
// Lest we anger the timestamp inversion bug.
|
||||
DatastoreHelper.persistResource(registrar);
|
||||
DatastoreHelper.persistSimpleGlobalResources(ImmutableSet.of(rc));
|
||||
|
||||
// Now try to remove the phone number.
|
||||
rc = rc.asBuilder().setPhoneNumber(null).build();
|
||||
Map<String, Object> reqJson = registrar.toJsonMap();
|
||||
reqJson.put("contacts", ImmutableList.of(rc.toJsonMap()));
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", reqJson)));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "ERROR");
|
||||
assertThat(json.get()).containsEntry("message", "At least one "
|
||||
+ RegistrarContact.Type.TECH.getDisplayName() + " contact must have a phone number");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,446 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server.registrar;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.ReflectiveFieldExtractor.extractField;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
|
||||
import com.braintreegateway.BraintreeGateway;
|
||||
import com.braintreegateway.Result;
|
||||
import com.braintreegateway.Transaction;
|
||||
import com.braintreegateway.Transaction.GatewayRejectionReason;
|
||||
import com.braintreegateway.TransactionGateway;
|
||||
import com.braintreegateway.TransactionRequest;
|
||||
import com.braintreegateway.ValidationError;
|
||||
import com.braintreegateway.ValidationErrorCode;
|
||||
import com.braintreegateway.ValidationErrors;
|
||||
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/** Tests for {@link RegistrarPaymentAction}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RegistrarPaymentActionTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||
|
||||
@Mock
|
||||
private BraintreeGateway braintreeGateway;
|
||||
|
||||
@Mock
|
||||
private TransactionGateway transactionGateway;
|
||||
|
||||
@Mock
|
||||
private Result<Transaction> result;
|
||||
|
||||
@Mock
|
||||
private Transaction transaction;
|
||||
|
||||
@Mock
|
||||
private ValidationErrors validationErrors;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<TransactionRequest> transactionRequestCaptor;
|
||||
|
||||
private final RegistrarPaymentAction paymentAction = new RegistrarPaymentAction();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
paymentAction.registrar = Registrar.loadByClientId("TheRegistrar");
|
||||
paymentAction.accountIds =
|
||||
ImmutableMap.of(
|
||||
CurrencyUnit.USD, "merchant-account-usd",
|
||||
CurrencyUnit.JPY, "merchant-account-jpy");
|
||||
paymentAction.braintreeGateway = braintreeGateway;
|
||||
when(braintreeGateway.transaction()).thenReturn(transactionGateway);
|
||||
when(transactionGateway.sale(any(TransactionRequest.class))).thenReturn(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrencyIsUsd_usesAmericanMerchantAccount() throws Exception {
|
||||
when(result.isSuccess()).thenReturn(true);
|
||||
when(result.getTarget()).thenReturn(transaction);
|
||||
when(transaction.getId()).thenReturn("omg-im-an-id");
|
||||
when(transaction.getAmount()).thenReturn(BigDecimal.valueOf(123.4));
|
||||
when(transaction.getCurrencyIsoCode()).thenReturn("USD");
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", " 123.4 ",
|
||||
"currency", "USD",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "SUCCESS",
|
||||
"message", "Payment processed successfully",
|
||||
"results", asList(
|
||||
ImmutableMap.of(
|
||||
"id", "omg-im-an-id",
|
||||
"formattedAmount", "$123.40")));
|
||||
verify(transactionGateway).sale(transactionRequestCaptor.capture());
|
||||
TransactionRequest transactionRequest = transactionRequestCaptor.getAllValues().get(0);
|
||||
assertThat(extractField(BigDecimal.class, transactionRequest, "amount"))
|
||||
.isEqualTo(BigDecimal.valueOf(123.4).setScale(2));
|
||||
assertThat(extractField(String.class, transactionRequest, "merchantAccountId"))
|
||||
.isEqualTo("merchant-account-usd");
|
||||
assertThat(extractField(String.class, transactionRequest, "customerId"))
|
||||
.isEqualTo("TheRegistrar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrencyIsJpy_usesJapaneseMerchantAccount() throws Exception {
|
||||
when(result.isSuccess()).thenReturn(true);
|
||||
when(result.getTarget()).thenReturn(transaction);
|
||||
when(transaction.getId()).thenReturn("omg-im-an-id");
|
||||
when(transaction.getAmount()).thenReturn(BigDecimal.valueOf(123));
|
||||
when(transaction.getCurrencyIsoCode()).thenReturn("JPY");
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "JPY",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "SUCCESS",
|
||||
"message", "Payment processed successfully",
|
||||
"results", asList(
|
||||
ImmutableMap.of(
|
||||
"id", "omg-im-an-id",
|
||||
"formattedAmount", "JPY 123")));
|
||||
verify(transactionGateway).sale(transactionRequestCaptor.capture());
|
||||
TransactionRequest transactionRequest = transactionRequestCaptor.getAllValues().get(0);
|
||||
assertThat(extractField(BigDecimal.class, transactionRequest, "amount"))
|
||||
.isEqualTo(BigDecimal.valueOf(123));
|
||||
assertThat(extractField(String.class, transactionRequest, "merchantAccountId"))
|
||||
.isEqualTo("merchant-account-jpy");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAmountNotPresent_returnsErrorOnAmountField() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"currency", "JPY",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "This field is required.",
|
||||
"field", "amount",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAmountNotNumber_returnsErrorOnAmountField() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "abc",
|
||||
"currency", "JPY",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Invalid number.",
|
||||
"field", "amount",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNegativeAmount_returnsErrorOnAmountField() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "-10",
|
||||
"currency", "JPY",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Must be a positive number.",
|
||||
"field", "amount",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroAmount_returnsErrorOnAmountField() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "0",
|
||||
"currency", "JPY",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Must be a positive number.",
|
||||
"field", "amount",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAmountHasMorePrecisionThanUsdCurrencyAllows_returnsError() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123.456",
|
||||
"currency", "USD",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Scale of amount 123.456 is greater than the scale of the currency USD",
|
||||
"field", "amount",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAmountHasMorePrecisionThanJpyCurrencyAllows_returnsError() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "1.1",
|
||||
"currency", "JPY",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Scale of amount 1.1 is greater than the scale of the currency JPY",
|
||||
"field", "amount",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrencyValidButNotSupported_returnsErrorOnCurrencyField() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "EUR",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Unsupported currency.",
|
||||
"field", "currency",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrencyBogus_returnsErrorOnCurrencyField() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "rm -rf /etc/passwd",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Invalid currency code.",
|
||||
"field", "currency",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrencyCodeNotAssigned_returnsErrorOnCurrencyField() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "ZZZ",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Unknown ISO currency code.",
|
||||
"field", "currency",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrencyMissing_returnsErrorOnCurrencyField() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"paymentMethodNonce", "omg")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "This field is required.",
|
||||
"field", "currency",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaymentMethodMissing_returnsErrorOnPaymentMethodField() throws Exception {
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "JPY")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "This field is required.",
|
||||
"field", "paymentMethodNonce",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessorDeclined_returnsErrorResponse() throws Exception {
|
||||
when(result.isSuccess()).thenReturn(false);
|
||||
when(result.getTransaction()).thenReturn(transaction);
|
||||
when(transaction.getStatus()).thenReturn(Transaction.Status.PROCESSOR_DECLINED);
|
||||
when(transaction.getProcessorResponseText())
|
||||
.thenReturn("You don't know the power of the dark side");
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "USD",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Payment declined: You don't know the power of the dark side",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayRejectedDueToCvv_returnsErrorResponse() throws Exception {
|
||||
when(result.isSuccess()).thenReturn(false);
|
||||
when(result.getTransaction()).thenReturn(transaction);
|
||||
when(transaction.getStatus()).thenReturn(Transaction.Status.GATEWAY_REJECTED);
|
||||
when(transaction.getGatewayRejectionReason()).thenReturn(GatewayRejectionReason.CVV);
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "USD",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Payment rejected: Invalid CVV code.",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayRejectedDueToAddress_returnsErrorResponse() throws Exception {
|
||||
when(result.isSuccess()).thenReturn(false);
|
||||
when(result.getTransaction()).thenReturn(transaction);
|
||||
when(transaction.getStatus()).thenReturn(Transaction.Status.GATEWAY_REJECTED);
|
||||
when(transaction.getGatewayRejectionReason()).thenReturn(GatewayRejectionReason.AVS);
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "USD",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Payment rejected: Invalid address.",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettlementDeclined_returnsErrorResponse() throws Exception {
|
||||
when(result.isSuccess()).thenReturn(false);
|
||||
when(result.getTransaction()).thenReturn(transaction);
|
||||
when(transaction.getStatus()).thenReturn(Transaction.Status.SETTLEMENT_DECLINED);
|
||||
when(transaction.getProcessorSettlementResponseText())
|
||||
.thenReturn("mine eyes have seen the glory of the coming of the borg");
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "USD",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Payment declined: mine eyes have seen the glory of the coming of the borg",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasTransactionObjectWithWeirdStatus_returnsErrorResponse() throws Exception {
|
||||
when(result.isSuccess()).thenReturn(false);
|
||||
when(result.getTransaction()).thenReturn(transaction);
|
||||
when(transaction.getStatus()).thenReturn(Transaction.Status.UNRECOGNIZED);
|
||||
when(transaction.getProcessorResponseText())
|
||||
.thenReturn("he is preempting the instance where the deadlocked shards are stored");
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "USD",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Payment failure: "
|
||||
+ "he is preempting the instance where the deadlocked shards are stored",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailedWithWeirdStatusButNoHelpfulText_usesWeirdStatusAsMsg() throws Exception {
|
||||
when(result.isSuccess()).thenReturn(false);
|
||||
when(result.getTransaction()).thenReturn(transaction);
|
||||
when(transaction.getStatus()).thenReturn(Transaction.Status.FAILED);
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "USD",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Payment failure: FAILED",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteValidationError_showsErrorOnlyOnFirstFormField() throws Exception {
|
||||
when(result.isSuccess()).thenReturn(false);
|
||||
when(result.getErrors()).thenReturn(validationErrors);
|
||||
when(validationErrors.getAllDeepValidationErrors())
|
||||
.thenReturn(asList(
|
||||
new ValidationError(
|
||||
"amount",
|
||||
ValidationErrorCode.TRANSACTION_SETTLEMENT_AMOUNT_IS_LESS_THAN_SERVICE_FEE_AMOUNT,
|
||||
"Gimmeh moar moneys"),
|
||||
new ValidationError(
|
||||
"fax",
|
||||
ValidationErrorCode.CUSTOMER_FAX_IS_TOO_LONG,
|
||||
"Fax is too long")));
|
||||
assertThat(
|
||||
paymentAction.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"amount", "123",
|
||||
"currency", "USD",
|
||||
"paymentMethodNonce", "abc-123")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "Gimmeh moar moneys",
|
||||
"field", "amount",
|
||||
"results", asList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server.registrar;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.braintree.BraintreeRegistrarSyncer;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
|
||||
import com.braintreegateway.BraintreeGateway;
|
||||
import com.braintreegateway.ClientTokenGateway;
|
||||
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/** Tests for {@link RegistrarPaymentSetupAction}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RegistrarPaymentSetupActionTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Mock
|
||||
private BraintreeGateway braintreeGateway;
|
||||
|
||||
@Mock
|
||||
private ClientTokenGateway clientTokenGateway;
|
||||
|
||||
@Mock
|
||||
private BraintreeRegistrarSyncer customerSyncer;
|
||||
|
||||
private final RegistrarPaymentSetupAction action = new RegistrarPaymentSetupAction();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
action.braintreeGateway = braintreeGateway;
|
||||
action.customerSyncer = customerSyncer;
|
||||
action.registrar =
|
||||
Registrar.loadByClientId("TheRegistrar").asBuilder()
|
||||
.setBillingMethod(Registrar.BillingMethod.BRAINTREE)
|
||||
.build();
|
||||
when(braintreeGateway.clientToken()).thenReturn(clientTokenGateway);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTokenGeneration() throws Exception {
|
||||
action.brainframe = "/doodle";
|
||||
action.accountIds =
|
||||
ImmutableMap.of(
|
||||
CurrencyUnit.USD, "sorrow",
|
||||
CurrencyUnit.JPY, "torment");
|
||||
String blanketsOfSadness = "our hearts are beating, but no one is breathing";
|
||||
when(clientTokenGateway.generate()).thenReturn(blanketsOfSadness);
|
||||
assertThat(action.handleJsonRequest(ImmutableMap.<String, Object>of()))
|
||||
.containsExactly(
|
||||
"status", "SUCCESS",
|
||||
"message", "Success",
|
||||
"results", asList(
|
||||
ImmutableMap.of(
|
||||
"token", blanketsOfSadness,
|
||||
"currencies", asList("USD", "JPY"),
|
||||
"brainframe", "/doodle")));
|
||||
verify(customerSyncer).sync(eq(action.registrar));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonEmptyRequestObject_returnsError() throws Exception {
|
||||
assertThat(action.handleJsonRequest(ImmutableMap.of("oh", "no")))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "JSON request object must be empty",
|
||||
"results", asList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotOnCreditCardBillingTerms_showsErrorPage() throws Exception {
|
||||
action.registrar =
|
||||
Registrar.loadByClientId("TheRegistrar").asBuilder()
|
||||
.setBillingMethod(Registrar.BillingMethod.EXTERNAL)
|
||||
.build();
|
||||
assertThat(action.handleJsonRequest(ImmutableMap.<String, Object>of()))
|
||||
.containsExactly(
|
||||
"status", "ERROR",
|
||||
"message", "not-using-cc-billing",
|
||||
"results", asList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server.registrar;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.security.JsonHttpTestUtils.createJsonPayload;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static com.google.domain.registry.util.ResourceUtils.readResourceUtf8;
|
||||
import static java.util.Arrays.asList;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.export.sheet.SyncRegistrarsSheetAction;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
/** Tests for {@link RegistrarServlet}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RegistrarServletTest extends RegistrarServletTestCase {
|
||||
|
||||
@Test
|
||||
public void testSuccess_updateRegistrarInfo_andSendsNotificationEmail() throws Exception {
|
||||
String jsonPostData = readResourceUtf8(getClass(), "testdata/update_registrar.json");
|
||||
String expectedEmailBody = readResourceUtf8(getClass(), "testdata/update_registrar_email.txt");
|
||||
when(req.getReader()).thenReturn(createJsonPayload(jsonPostData));
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).setStatus(SC_OK);
|
||||
verify(emailService).createMessage();
|
||||
verify(emailService).sendMessage(message);
|
||||
assertThat(message.getAllRecipients()).asList().containsExactly(
|
||||
new InternetAddress("notification@test.example"),
|
||||
new InternetAddress("notification2@test.example"));
|
||||
assertThat(message.getContent()).isEqualTo(expectedEmailBody);
|
||||
assertTasksEnqueued("sheet", new TaskMatcher()
|
||||
.url(SyncRegistrarsSheetAction.PATH)
|
||||
.method("GET")
|
||||
.header("Host", "backend.hostname"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_updateRegistrarInfo_duplicateContacts() throws Exception {
|
||||
String jsonPostData =
|
||||
readResourceUtf8(getClass(), "testdata/update_registrar_duplicate_contacts.json");
|
||||
when(req.getReader()).thenReturn(createJsonPayload(jsonPostData));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "ERROR");
|
||||
assertThat((String) json.get().get("message")).startsWith("One email address");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead_missingXsrfToken_failure() throws Exception {
|
||||
when(req.getHeader(eq("X-CSRF-Token"))).thenReturn("");
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(403, "Invalid X-CSRF-Token");
|
||||
assertNoTasksEnqueued("sheet");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead_invalidXsrfToken_failure() throws Exception {
|
||||
when(req.getHeader(eq("X-CSRF-Token"))).thenReturn("humbug");
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(403, "Invalid X-CSRF-Token");
|
||||
assertNoTasksEnqueued("sheet");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead_notLoggedIn_failure() throws Exception {
|
||||
when(sessionUtils.isLoggedIn()).thenReturn(false);
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "ERROR");
|
||||
assertThat(json.get()).containsEntry("message", "Not logged in");
|
||||
assertNoTasksEnqueued("sheet");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead_notAuthorized_failure() throws Exception {
|
||||
when(sessionUtils.checkRegistrarConsoleLogin(req)).thenReturn(false);
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "ERROR");
|
||||
assertThat((String) json.get().get("message")).startsWith("Not authorized");
|
||||
assertNoTasksEnqueued("sheet");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead_emptyPayload_failure() throws Exception {
|
||||
when(req.getReader()).thenReturn(createJsonPayload(""));
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(400, "Malformed JSON");
|
||||
assertNoTasksEnqueued("sheet");
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the default read test for the registrar settings servlets.
|
||||
*/
|
||||
@Test
|
||||
public void testRead_authorized_returnsRegistrarJson() throws Exception {
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "SUCCESS");
|
||||
assertThat(json.get()).containsEntry("results", asList(
|
||||
Registrar.loadByClientId(CLIENT_ID).toJsonMap()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead_authorized_nilClientId_failure() throws Exception {
|
||||
String nilClientId = "doesnotexist";
|
||||
when(sessionUtils.getRegistrarClientId(req)).thenReturn(nilClientId);
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(404, "No registrar exists with the given client id: " + nilClientId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate_emptyJsonObject_errorEmailFieldRequired() throws Exception {
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", ImmutableMap.of())));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "ERROR");
|
||||
assertThat(json.get()).containsEntry("field", "emailAddress");
|
||||
assertThat(json.get()).containsEntry("message", "This field is required.");
|
||||
assertNoTasksEnqueued("sheet");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate_badEmail_errorEmailField() throws Exception {
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", ImmutableMap.of(
|
||||
"emailAddress", "lolcat"))));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "ERROR");
|
||||
assertThat(json.get()).containsEntry("field", "emailAddress");
|
||||
assertThat(json.get()).containsEntry("message", "Please enter a valid email address.");
|
||||
assertNoTasksEnqueued("sheet");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_nonAsciiCharacters_getsAngry() throws Exception {
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", ImmutableMap.of(
|
||||
"emailAddress", "ヘ(◕。◕ヘ)@example.com"))));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "ERROR");
|
||||
assertThat(json.get()).containsEntry("field", "emailAddress");
|
||||
assertThat(json.get()).containsEntry("message", "Please only use ASCII-US characters.");
|
||||
assertNoTasksEnqueued("sheet");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server.registrar;
|
||||
|
||||
import static com.google.domain.registry.security.JsonHttpTestUtils.createJsonPayload;
|
||||
import static com.google.domain.registry.security.JsonHttpTestUtils.createJsonResponseSupplier;
|
||||
import static com.google.domain.registry.security.XsrfTokenManager.generateToken;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.appengine.api.modules.ModulesService;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.export.sheet.SyncRegistrarsSheetAction;
|
||||
import com.google.domain.registry.model.ofy.Ofy;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.util.SendEmailService;
|
||||
import com.google.domain.registry.util.SendEmailUtils;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.mail.Message;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/** Base class for tests using {@link RegistrarServlet}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RegistrarServletTestCase {
|
||||
|
||||
static final String CLIENT_ID = "TheRegistrar";
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Mock
|
||||
HttpServletRequest req;
|
||||
|
||||
@Mock
|
||||
HttpServletResponse rsp;
|
||||
|
||||
@Mock
|
||||
SessionUtils sessionUtils;
|
||||
|
||||
@Mock
|
||||
SendEmailService emailService;
|
||||
|
||||
@Mock
|
||||
ModulesService modulesService;
|
||||
|
||||
Message message;
|
||||
|
||||
final RegistrarServlet servlet = new RegistrarServlet();
|
||||
final StringWriter writer = new StringWriter();
|
||||
final Supplier<Map<String, Object>> json = createJsonResponseSupplier(writer);
|
||||
final FakeClock clock = new FakeClock(DateTime.parse("2014-01-01T00:00:00Z"));
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
inject.setStaticField(ResourceServlet.class, "sessionUtils", sessionUtils);
|
||||
inject.setStaticField(SendEmailUtils.class, "emailService", emailService);
|
||||
inject.setStaticField(SyncRegistrarsSheetAction.class, "modulesService", modulesService);
|
||||
message = new MimeMessage(Session.getDefaultInstance(new Properties(), null));
|
||||
when(emailService.createMessage()).thenReturn(message);
|
||||
when(req.getMethod()).thenReturn("POST");
|
||||
when(rsp.getWriter()).thenReturn(new PrintWriter(writer));
|
||||
when(req.getContentType()).thenReturn("application/json");
|
||||
when(req.getHeader(eq("X-CSRF-Token"))).thenReturn(generateToken("console"));
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of("op", "read")));
|
||||
when(sessionUtils.isLoggedIn()).thenReturn(true);
|
||||
when(sessionUtils.redirectIfNotLoggedIn(req, rsp)).thenReturn(true);
|
||||
when(sessionUtils.checkRegistrarConsoleLogin(req)).thenReturn(true);
|
||||
when(sessionUtils.getRegistrarClientId(req)).thenReturn(CLIENT_ID);
|
||||
when(modulesService.getVersionHostname("backend", null)).thenReturn("backend.hostname");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server.registrar;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.security.JsonHttpTestUtils.createJsonPayload;
|
||||
import static com.google.domain.registry.testing.CertificateSamples.SAMPLE_CERT;
|
||||
import static com.google.domain.registry.testing.CertificateSamples.SAMPLE_CERT2;
|
||||
import static com.google.domain.registry.testing.CertificateSamples.SAMPLE_CERT2_HASH;
|
||||
import static com.google.domain.registry.testing.CertificateSamples.SAMPLE_CERT_HASH;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.config.RegistryEnvironment;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Unit tests for security_settings.js use of {@link RegistrarServlet}.
|
||||
*
|
||||
* <p>The default read and session validation tests are handled by the
|
||||
* superclass.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SecuritySettingsTest extends RegistrarServletTestCase {
|
||||
|
||||
@Test
|
||||
public void testPost_updateCert_success() throws Exception {
|
||||
Registrar modified = Registrar.loadByClientId(CLIENT_ID).asBuilder()
|
||||
.setClientCertificate(SAMPLE_CERT, clock.nowUtc())
|
||||
.build();
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", modified.toJsonMap())));
|
||||
servlet.service(req, rsp);
|
||||
// Empty whoisServer and referralUrl fields should be set to defaults by server.
|
||||
modified = modified.asBuilder()
|
||||
.setWhoisServer(RegistryEnvironment.get().config().getRegistrarDefaultWhoisServer())
|
||||
.setReferralUrl(
|
||||
RegistryEnvironment.get().config().getRegistrarDefaultReferralUrl().toString())
|
||||
.build();
|
||||
assertThat(json.get()).containsEntry("status", "SUCCESS");
|
||||
assertThat(json.get()).containsEntry("results", asList(modified.toJsonMap()));
|
||||
assertThat(Registrar.loadByClientId(CLIENT_ID)).isEqualTo(modified);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_updateCert_failure() throws Exception {
|
||||
Map<String, Object> reqJson = Registrar.loadByClientId(CLIENT_ID).toJsonMap();
|
||||
reqJson.put("clientCertificate", "BLAH");
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", reqJson)));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "ERROR");
|
||||
assertThat(json.get()).containsEntry("message", "Invalid X.509 PEM certificate");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangeCertificates() throws Exception {
|
||||
Map<String, Object> jsonMap = Registrar.loadByClientId(CLIENT_ID).toJsonMap();
|
||||
jsonMap.put("clientCertificate", SAMPLE_CERT);
|
||||
jsonMap.put("failoverClientCertificate", null);
|
||||
when(req.getReader()).thenReturn(
|
||||
createJsonPayload(ImmutableMap.of("op", "update", "args", jsonMap)));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "SUCCESS");
|
||||
Registrar registrar = Registrar.loadByClientId(CLIENT_ID);
|
||||
assertThat(registrar.getClientCertificate()).isEqualTo(SAMPLE_CERT);
|
||||
assertThat(registrar.getClientCertificateHash()).isEqualTo(SAMPLE_CERT_HASH);
|
||||
assertThat(registrar.getFailoverClientCertificate()).isNull();
|
||||
assertThat(registrar.getFailoverClientCertificateHash()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangeFailoverCertificate() throws Exception {
|
||||
Map<String, Object> jsonMap = Registrar.loadByClientId(CLIENT_ID).toJsonMap();
|
||||
jsonMap.put("failoverClientCertificate", SAMPLE_CERT2);
|
||||
when(req.getReader()).thenReturn(
|
||||
createJsonPayload(ImmutableMap.of("op", "update", "args", jsonMap)));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "SUCCESS");
|
||||
Registrar registrar = Registrar.loadByClientId(CLIENT_ID);
|
||||
assertThat(registrar.getFailoverClientCertificate()).isEqualTo(SAMPLE_CERT2);
|
||||
assertThat(registrar.getFailoverClientCertificateHash()).isEqualTo(SAMPLE_CERT2_HASH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyOrNullCertificate_doesNotClearOutCurrentOne() throws Exception {
|
||||
persistResource(
|
||||
Registrar.loadByClientId(CLIENT_ID).asBuilder()
|
||||
.setClientCertificate(SAMPLE_CERT, START_OF_TIME)
|
||||
.setFailoverClientCertificate(SAMPLE_CERT2, START_OF_TIME)
|
||||
.build());
|
||||
Map<String, Object> jsonMap = Registrar.loadByClientId(CLIENT_ID).toJsonMap();
|
||||
jsonMap.put("clientCertificate", null);
|
||||
jsonMap.put("failoverClientCertificate", "");
|
||||
when(req.getReader()).thenReturn(
|
||||
createJsonPayload(ImmutableMap.of("op", "update", "args", jsonMap)));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get()).containsEntry("status", "SUCCESS");
|
||||
Registrar registrar = Registrar.loadByClientId(CLIENT_ID);
|
||||
assertThat(registrar.getClientCertificate()).isEqualTo(SAMPLE_CERT);
|
||||
assertThat(registrar.getClientCertificateHash()).isEqualTo(SAMPLE_CERT_HASH);
|
||||
assertThat(registrar.getFailoverClientCertificate()).isEqualTo(SAMPLE_CERT2);
|
||||
assertThat(registrar.getFailoverClientCertificateHash()).isEqualTo(SAMPLE_CERT2_HASH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToJsonMap_containsCertificate() throws Exception {
|
||||
Map<String, Object> jsonMap = Registrar.loadByClientId(CLIENT_ID).asBuilder()
|
||||
.setClientCertificate(SAMPLE_CERT2, START_OF_TIME)
|
||||
.build()
|
||||
.toJsonMap();
|
||||
assertThat(jsonMap).containsEntry("clientCertificate", SAMPLE_CERT2);
|
||||
assertThat(jsonMap).containsEntry("clientCertificateHash", SAMPLE_CERT2_HASH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToJsonMap_containsFailoverCertificate() throws Exception {
|
||||
Map<String, Object> jsonMap = Registrar.loadByClientId(CLIENT_ID).asBuilder()
|
||||
.setFailoverClientCertificate(SAMPLE_CERT2, START_OF_TIME)
|
||||
.build()
|
||||
.toJsonMap();
|
||||
assertThat(jsonMap).containsEntry("failoverClientCertificate", SAMPLE_CERT2);
|
||||
assertThat(jsonMap).containsEntry("failoverClientCertificateHash", SAMPLE_CERT2_HASH);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server.registrar;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.AppEngineRule.THE_REGISTRAR_GAE_USER_ID;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.appengine.api.users.User;
|
||||
import com.google.appengine.api.users.UserService;
|
||||
import com.google.common.testing.NullPointerTester;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.model.registrar.RegistrarContact;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/** Unit tests for {@link SessionUtils}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SessionUtilsTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Mock
|
||||
private UserService userService;
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest req;
|
||||
|
||||
@Mock
|
||||
private HttpServletResponse rsp;
|
||||
|
||||
@Mock
|
||||
private HttpSession session;
|
||||
|
||||
private SessionUtils sessionUtils;
|
||||
private final User jart = new User("jart@google.com", "google.com", THE_REGISTRAR_GAE_USER_ID);
|
||||
private final User bozo = new User("bozo@bing.com", "bing.com", "badGaeUserId");
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
sessionUtils = new SessionUtils(userService);
|
||||
when(req.getSession()).thenReturn(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectIfNotLoggedIn_loggedIn_doesNothing() throws Exception {
|
||||
when(userService.isUserLoggedIn()).thenReturn(true);
|
||||
assertThat(sessionUtils.redirectIfNotLoggedIn(req, rsp)).isTrue();
|
||||
verifyZeroInteractions(req, rsp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectIfNotLoggedIn_notLoggedIn_sendsTemporaryRedirect() throws Exception {
|
||||
when(userService.isUserLoggedIn()).thenReturn(false);
|
||||
when(req.getRequestURI()).thenReturn("foo");
|
||||
when(userService.createLoginURL(eq("foo"))).thenReturn("bar");
|
||||
assertThat(sessionUtils.redirectIfNotLoggedIn(req, rsp)).isFalse();
|
||||
verify(rsp).setStatus(eq(302));
|
||||
verify(rsp).setHeader(eq("Location"), eq("bar"));
|
||||
verifyNoMoreInteractions(rsp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckRegistrarConsoleLogin_authedButNoSession_createsSession() throws Exception {
|
||||
when(userService.getCurrentUser()).thenReturn(jart);
|
||||
assertThat(sessionUtils.checkRegistrarConsoleLogin(req)).isTrue();
|
||||
verify(session).setAttribute(eq("clientId"), eq("TheRegistrar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckRegistrarConsoleLogin_authedWithValidSession_doesNothing() throws Exception {
|
||||
when(session.getAttribute("clientId")).thenReturn("TheRegistrar");
|
||||
when(userService.getCurrentUser()).thenReturn(jart);
|
||||
assertThat(sessionUtils.checkRegistrarConsoleLogin(req)).isTrue();
|
||||
verify(session).getAttribute("clientId");
|
||||
verifyNoMoreInteractions(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckRegistrarConsoleLogin_sessionRevoked_invalidates() throws Exception {
|
||||
RegistrarContact.updateContacts(
|
||||
Registrar.loadByClientId("TheRegistrar"),
|
||||
new java.util.HashSet<RegistrarContact>());
|
||||
when(session.getAttribute("clientId")).thenReturn("TheRegistrar");
|
||||
when(userService.getCurrentUser()).thenReturn(jart);
|
||||
assertThat(sessionUtils.checkRegistrarConsoleLogin(req)).isFalse();
|
||||
verify(session).invalidate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckRegistrarConsoleLogin_notLoggedIn_throwsIse() throws Exception {
|
||||
thrown.expect(IllegalStateException.class);
|
||||
assertThat(sessionUtils.checkRegistrarConsoleLogin(req)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckRegistrarConsoleLogin_notAllowed_returnsFalse() throws Exception {
|
||||
when(userService.getCurrentUser()).thenReturn(bozo);
|
||||
assertThat(sessionUtils.checkRegistrarConsoleLogin(req)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullness() throws Exception {
|
||||
new NullPointerTester()
|
||||
.setDefault(HttpServletRequest.class, req)
|
||||
.setDefault(HttpServletResponse.class, rsp)
|
||||
.testAllPublicStaticMethods(SessionUtils.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.ui.server.registrar;
|
||||
|
||||
import static com.google.common.base.Strings.repeat;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.security.JsonHttpTestUtils.createJsonPayload;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.model.registrar.RegistrarAddress;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Unit tests for security_settings.js use of {@link RegistrarServlet}.
|
||||
*
|
||||
* <p>The default read and session validation tests are handled by the superclass.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WhoisSettingsTest extends RegistrarServletTestCase {
|
||||
|
||||
@Test
|
||||
public void testPost_update_success() throws Exception {
|
||||
Registrar modified = Registrar.loadByClientId(CLIENT_ID).asBuilder()
|
||||
.setEmailAddress("hello.kitty@example.com")
|
||||
.setPhoneNumber("+1.2125650000")
|
||||
.setFaxNumber("+1.2125650001")
|
||||
.setReferralUrl("http://acme.com/")
|
||||
.setWhoisServer("ns1.foo.bar")
|
||||
.setLocalizedAddress(new RegistrarAddress.Builder()
|
||||
.setStreet(ImmutableList.of("76 Ninth Avenue", "Eleventh Floor"))
|
||||
.setCity("New York")
|
||||
.setState("NY")
|
||||
.setZip("10009")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build();
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", modified.toJsonMap())));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get().get("status")).isEqualTo("SUCCESS");
|
||||
assertThat(json.get().get("results")).isEqualTo(asList(modified.toJsonMap()));
|
||||
assertThat(Registrar.loadByClientId(CLIENT_ID)).isEqualTo(modified);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_badUsStateCode_returnsFormFieldError() throws Exception {
|
||||
Registrar modified = Registrar.loadByClientId(CLIENT_ID).asBuilder()
|
||||
.setEmailAddress("hello.kitty@example.com")
|
||||
.setPhoneNumber("+1.2125650000")
|
||||
.setFaxNumber("+1.2125650001")
|
||||
.setLocalizedAddress(new RegistrarAddress.Builder()
|
||||
.setStreet(ImmutableList.of("76 Ninth Avenue", "Eleventh Floor"))
|
||||
.setCity("New York")
|
||||
.setState("ZZ")
|
||||
.setZip("10009")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build();
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", modified.toJsonMap())));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get().get("status")).isEqualTo("ERROR");
|
||||
assertThat(json.get().get("field")).isEqualTo("localizedAddress.state");
|
||||
assertThat(json.get().get("message")).isEqualTo("Unknown US state code.");
|
||||
assertThat(Registrar.loadByClientId(CLIENT_ID)).isNotEqualTo(modified);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_badAddress_returnsFormFieldError() throws Exception {
|
||||
Registrar modified = Registrar.loadByClientId(CLIENT_ID).asBuilder()
|
||||
.setEmailAddress("hello.kitty@example.com")
|
||||
.setPhoneNumber("+1.2125650000")
|
||||
.setFaxNumber("+1.2125650001")
|
||||
.setLocalizedAddress(new RegistrarAddress.Builder()
|
||||
.setStreet(ImmutableList.of("76 Ninth Avenue", repeat("lol", 200)))
|
||||
.setCity("New York")
|
||||
.setState("NY")
|
||||
.setZip("10009")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build();
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", modified.toJsonMap())));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get().get("status")).isEqualTo("ERROR");
|
||||
assertThat(json.get().get("field")).isEqualTo("localizedAddress.street[1]");
|
||||
assertThat((String) json.get().get("message"))
|
||||
.contains("Number of characters (600) not in range");
|
||||
assertThat(Registrar.loadByClientId(CLIENT_ID)).isNotEqualTo(modified);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_badWhoisServer_returnsFormFieldError() throws Exception {
|
||||
Registrar modified = Registrar.loadByClientId(CLIENT_ID).asBuilder()
|
||||
.setWhoisServer("tears@dry.tragical.lol")
|
||||
.build();
|
||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of(
|
||||
"op", "update",
|
||||
"args", modified.toJsonMap())));
|
||||
servlet.service(req, rsp);
|
||||
assertThat(json.get().get("status")).isEqualTo("ERROR");
|
||||
assertThat(json.get().get("field")).isEqualTo("whoisServer");
|
||||
assertThat(json.get().get("message")).isEqualTo("Not a valid hostname.");
|
||||
assertThat(Registrar.loadByClientId(CLIENT_ID)).isNotEqualTo(modified);
|
||||
}
|
||||
}
|
59
javatests/google/registry/ui/server/registrar/testdata/update_registrar.json
vendored
Normal file
59
javatests/google/registry/ui/server/registrar/testdata/update_registrar.json
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
"op": "update",
|
||||
"args": {
|
||||
"clientIdentifier": "theregistrar",
|
||||
"driveFolderId": null,
|
||||
"registrarName": "The Registrar",
|
||||
"lastUpdateTime": "2015-01-22T17:27:36.999Z",
|
||||
"state": "ACTIVE",
|
||||
"type": "REAL",
|
||||
"contacts": [
|
||||
{
|
||||
"visibleInWhoisAsAdmin": true,
|
||||
"faxNumber": null,
|
||||
"phoneNumber": null,
|
||||
"name": "Extra Terrestrial",
|
||||
"visibleInWhoisAsTech": false,
|
||||
"emailAddress": "etphonehome@example.com",
|
||||
"gaeUserId": null,
|
||||
"types": "ADMIN,BILLING,TECH,WHOIS"
|
||||
}
|
||||
],
|
||||
"allowedTlds": [
|
||||
"ga"
|
||||
],
|
||||
"clientCertificateHash": null,
|
||||
"faxNumber": "",
|
||||
"ianaIdentifier": "1",
|
||||
"phoneNumber": "+1.2223335555",
|
||||
"internationalizedAddress": null,
|
||||
"whoisServer": "foo.bar.baz",
|
||||
"creationTime": "2014-04-15T21:57:54.765Z",
|
||||
"clientCertificate": null,
|
||||
"emailAddress": "thase@the.registrar",
|
||||
"ipAddressWhitelist": [
|
||||
"1.1.1.1\/32",
|
||||
"2.2.2.2\/32",
|
||||
"4.4.4.4\/32"
|
||||
],
|
||||
"localizedAddress": {
|
||||
"street": [
|
||||
"123 Street Rd",
|
||||
"Ste 156",
|
||||
""
|
||||
],
|
||||
"city": "New York",
|
||||
"state": "NY",
|
||||
"zip": "10011",
|
||||
"countryCode": "US"
|
||||
},
|
||||
"billingIdentifier": null,
|
||||
"url": null,
|
||||
"icannReferralEmail": "asdf@asdf.com",
|
||||
"phonePasscode": null,
|
||||
"referralUrl": "",
|
||||
"blockPremiumNames": false,
|
||||
"lastCertificateUpdateTime": null,
|
||||
"e": false
|
||||
}
|
||||
}
|
69
javatests/google/registry/ui/server/registrar/testdata/update_registrar_duplicate_contacts.json
vendored
Normal file
69
javatests/google/registry/ui/server/registrar/testdata/update_registrar_duplicate_contacts.json
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"op": "update",
|
||||
"args": {
|
||||
"clientIdentifier": "theregistrar",
|
||||
"driveFolderId": null,
|
||||
"registrarName": "The Registrar",
|
||||
"lastUpdateTime": "2015-01-22T17:27:36.999Z",
|
||||
"state": "ACTIVE",
|
||||
"type": "REAL",
|
||||
"contacts": [
|
||||
{
|
||||
"visibleInWhoisAsAdmin": true,
|
||||
"faxNumber": null,
|
||||
"phoneNumber": null,
|
||||
"name": "Extra Terrestrial",
|
||||
"visibleInWhoisAsTech": false,
|
||||
"emailAddress": "etphonehome@example.com",
|
||||
"gaeUserId": null,
|
||||
"types": "ADMIN,BILLING,TECH,WHOIS"
|
||||
},
|
||||
{
|
||||
"visibleInWhoisAsAdmin": true,
|
||||
"faxNumber": null,
|
||||
"phoneNumber": null,
|
||||
"name": "E.T.",
|
||||
"visibleInWhoisAsTech": false,
|
||||
"emailAddress": "etphonehome@example.com",
|
||||
"gaeUserId": null,
|
||||
"types": "MARKETING"
|
||||
}
|
||||
],
|
||||
"allowedTlds": [
|
||||
"ga"
|
||||
],
|
||||
"clientCertificateHash": null,
|
||||
"faxNumber": "",
|
||||
"ianaIdentifier": "1",
|
||||
"phoneNumber": "+1.2223335555",
|
||||
"internationalizedAddress": null,
|
||||
"whoisServer": "foo.bar.baz",
|
||||
"creationTime": "2014-04-15T21:57:54.765Z",
|
||||
"clientCertificate": null,
|
||||
"emailAddress": "thase@the.registrar",
|
||||
"ipAddressWhitelist": [
|
||||
"1.1.1.1\/32",
|
||||
"2.2.2.2\/32",
|
||||
"4.4.4.4\/32"
|
||||
],
|
||||
"localizedAddress": {
|
||||
"street": [
|
||||
"123 Street Rd",
|
||||
"Ste 156",
|
||||
""
|
||||
],
|
||||
"city": "New York",
|
||||
"state": "NY",
|
||||
"zip": "10011",
|
||||
"countryCode": "US"
|
||||
},
|
||||
"billingIdentifier": null,
|
||||
"url": null,
|
||||
"icannReferralEmail": "asdf@asdf.com",
|
||||
"phonePasscode": null,
|
||||
"referralUrl": "",
|
||||
"blockPremiumNames": false,
|
||||
"lastCertificateUpdateTime": null,
|
||||
"e": false
|
||||
}
|
||||
}
|
16
javatests/google/registry/ui/server/registrar/testdata/update_registrar_email.txt
vendored
Normal file
16
javatests/google/registry/ui/server/registrar/testdata/update_registrar_email.txt
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
The following changes were made to the registrar:
|
||||
whoisServer -> [null, foo.bar.baz]
|
||||
ipAddressWhitelist -> [null, [1.1.1.1/32, 2.2.2.2/32, 4.4.4.4/32]]
|
||||
localizedAddress.street.0 -> [123 Example Bőulevard, 123 Street Rd]
|
||||
localizedAddress.street.1 -> [null, Ste 156]
|
||||
localizedAddress.city -> [Williamsburg, New York]
|
||||
localizedAddress.zip -> [11211, 10011]
|
||||
phoneNumber -> [+1.2223334444, +1.2223335555]
|
||||
emailAddress -> [new.registrar@example.com, thase@the.registrar]
|
||||
contacts ->
|
||||
ADDED:
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Extra Terrestrial, emailAddress=etphonehome@example.com, phoneNumber=null, faxNumber=null, types=[ADMIN, BILLING, TECH, WHOIS], gaeUserId=null, visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false}
|
||||
REMOVED:
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=John Doe, emailAddress=johndoe@theregistrar.com, phoneNumber=+1.1234567890, faxNumber=null, types=[ADMIN], gaeUserId=31337, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false}
|
||||
FINAL CONTENTS:
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Extra Terrestrial, emailAddress=etphonehome@example.com, phoneNumber=null, faxNumber=null, types=[ADMIN, BILLING, TECH, WHOIS], gaeUserId=null, visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false}
|
Loading…
Add table
Add a link
Reference in a new issue