Remove the web console EPP endpoint

This removes the "create Domain/Host/Contact" forms that were supposed to be used instead of regular EPPs for CC-TLD that wanted to support it.

We're removing it because we don't use it and want to reduce unneeded code for the registry 3.0 migration.

Also, this is a security risk, as it allowed to do "billable actions" (creating a new domain for example) with the only authentication being access to the registrar's G Suite account.

This bypassed the certificate, IP whitelist, and EPP password, which is bad.

PUBLIC:
Remove the web console EPP endpoint

This removes the "create Domain/Host/Contact" forms that were supposed to be used instead of regular EPPs for CC-TLD that wanted to support it.

We're removing it because we don't use it and want to reduce unneeded code for the registry 3.0 migration.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=236244195
This commit is contained in:
guyben 2019-02-28 19:37:30 -08:00 committed by Weimin Yu
parent f12d368da3
commit dfad79759e
52 changed files with 58 additions and 3788 deletions

View file

@ -1,73 +0,0 @@
// Copyright 2017 The Nomulus 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 google.registry.flows;
import static com.google.appengine.api.users.UserServiceFactory.getUserService;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableSetMultimap;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeHttpSession;
import google.registry.testing.ShardableTestCase;
import google.registry.testing.UserInfo;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
/** Tests for {@link EppConsoleAction}. */
@RunWith(JUnit4.class)
public class EppConsoleActionTest extends ShardableTestCase {
private static final byte[] INPUT_XML_BYTES = "<xml>".getBytes(UTF_8);
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder()
.withUserService(UserInfo.create("person@example.com", "12345"))
.build();
@Test
public void testAction() {
EppConsoleAction action = new EppConsoleAction();
action.inputXmlBytes = INPUT_XML_BYTES;
action.session = new FakeHttpSession();
action.clientId = "ClientIdentifier";
action.eppRequestHandler = mock(EppRequestHandler.class);
action.userService = getUserService();
action.registrarAccessor =
AuthenticatedRegistrarAccessor.createForTesting(ImmutableSetMultimap.of());
action.run();
ArgumentCaptor<TransportCredentials> credentialsCaptor =
ArgumentCaptor.forClass(TransportCredentials.class);
ArgumentCaptor<SessionMetadata> metadataCaptor = ArgumentCaptor.forClass(SessionMetadata.class);
verify(action.eppRequestHandler)
.executeEpp(
metadataCaptor.capture(),
credentialsCaptor.capture(),
eq(EppRequestSource.CONSOLE),
eq(false),
eq(false),
eq(INPUT_XML_BYTES));
assertThat(credentialsCaptor.getValue().toString()).contains("user=TestUserId");
assertThat(metadataCaptor.getValue().getClientId()).isEqualTo("ClientIdentifier");
}
}

View file

@ -1,61 +0,0 @@
// Copyright 2017 The Nomulus 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 google.registry.flows;
import com.google.common.collect.ImmutableSetMultimap;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.testing.AppEngineRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Test logging in with appengine admin user credentials. */
@RunWith(JUnit4.class)
public class EppLoginAdminUserTest extends EppTestCase {
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder()
.withDatastore()
.build();
@Before
public void initTransportCredentials() {
setTransportCredentials(
new GaeUserCredentials(
AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of(
"TheRegistrar", AuthenticatedRegistrarAccessor.Role.ADMIN,
"NewRegistrar", AuthenticatedRegistrarAccessor.Role.ADMIN))));
}
@Test
public void testLoginLogout_wrongPasswordStillWorks() throws Exception {
// For user-based logins the password in the epp xml is ignored.
assertThatLoginSucceeds("NewRegistrar", "incorrect");
assertThatLogoutSucceeds();
}
@Test
public void testNonAuthedMultiLogin_succeedsAsAdmin() throws Exception {
// The admin can log in as different registrars.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatLogoutSucceeds();
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatLogoutSucceeds();
assertThatLoginSucceeds("TheRegistrar", "password2");
}
}

View file

@ -1,81 +0,0 @@
// Copyright 2017 The Nomulus 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 google.registry.flows;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.testing.AppEngineRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Test logging in with appengine user credentials, such as via the console. */
@RunWith(JUnit4.class)
public class EppLoginUserTest extends EppTestCase {
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder()
.withDatastore()
.build();
@Before
public void initTest() {
setTransportCredentials(
new GaeUserCredentials(
AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of(
"NewRegistrar", AuthenticatedRegistrarAccessor.Role.OWNER))));
}
@Test
public void testLoginLogout() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatLogoutSucceeds();
}
@Test
public void testNonAuthedLogin_fails() throws Exception {
assertThatLogin("TheRegistrar", "password2")
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2200",
"MSG", "TestUserId doesn't have access to registrar TheRegistrar"));
}
@Test
public void testMultiLogin() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatLogoutSucceeds();
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatLogoutSucceeds();
assertThatLogin("TheRegistrar", "password2")
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2200",
"MSG", "TestUserId doesn't have access to registrar TheRegistrar"));
}
@Test
public void testLoginLogout_wrongPasswordStillWorks() throws Exception {
// For user-based logins the password in the epp xml is ignored.
assertThatLoginSucceeds("NewRegistrar", "incorrect");
assertThatLogoutSucceeds();
}
}

View file

@ -26,14 +26,12 @@ import static org.mockito.Mockito.verify;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.flogger.LoggerConfig;
import com.google.common.testing.TestLogHandler;
import google.registry.model.eppcommon.Trid;
import google.registry.model.eppoutput.EppOutput.ResponseOrGreeting;
import google.registry.model.eppoutput.EppResponse;
import google.registry.monitoring.whitebox.EppMetric;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeHttpSession;
@ -140,16 +138,6 @@ public class FlowRunnerTest extends ShardableTestCase {
+ "{clientId=TheRegistrar, failedLoginAttempts=0, serviceExtensionUris=}");
}
@Test
public void testRun_loggingStatement_gaeUserCredentials() throws Exception {
flowRunner.credentials =
new GaeUserCredentials(AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of()));
flowRunner.run(eppMetricBuilder);
assertThat(findFirstLogMessageByPrefix(handler, "EPP Command\n\t"))
.contains("user=TestUserId");
}
@Test
public void testRun_loggingStatement_tlsCredentials() throws Exception {
flowRunner.credentials = new TlsCredentials(true, "abc123def", Optional.of("127.0.0.1"));

View file

@ -1,58 +0,0 @@
// Copyright 2017 The Nomulus 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 google.registry.flows.session;
import com.google.common.collect.ImmutableSetMultimap;
import google.registry.flows.GaeUserCredentials;
import google.registry.flows.GaeUserCredentials.UserForbiddenException;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import org.junit.Test;
/**
* Unit tests for {@link LoginFlow} when accessed via a web frontend
* transport, i.e. with GAIA ids.
*/
public class LoginFlowViaConsoleTest extends LoginFlowTestCase {
@Test
public void testSuccess_withAccess() throws Exception {
credentials =
new GaeUserCredentials(
AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of(
"NewRegistrar", AuthenticatedRegistrarAccessor.Role.OWNER)));
doSuccessfulTest("login_valid.xml");
}
@Test
public void testFailure_withoutAccess() {
credentials =
new GaeUserCredentials(
AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of()));
doFailingTest("login_valid.xml", UserForbiddenException.class);
}
@Test
public void testFailure_withAccessToDifferentRegistrar() {
credentials =
new GaeUserCredentials(
AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of(
"TheRegistrar", AuthenticatedRegistrarAccessor.Role.OWNER)));
doFailingTest("login_valid.xml", UserForbiddenException.class);
}
}

View file

@ -5,4 +5,3 @@ PATH CLASS METHODS OK AUTH_METHODS
/registrar-ote-setup ConsoleOteSetupAction POST,GET n INTERNAL,API,LEGACY NONE PUBLIC
/registrar-ote-status OteStatusAction POST n API,LEGACY USER PUBLIC
/registrar-settings RegistrarSettingsAction POST n API,LEGACY USER PUBLIC
/registrar-xhr EppConsoleAction POST n API,LEGACY USER PUBLIC

View file

@ -26,7 +26,6 @@ import google.registry.module.frontend.FrontendServlet;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import javax.servlet.Filter;
@ -54,7 +53,6 @@ public final class RegistryTestServer {
// Frontend Services
route("/whois/*", FrontendServlet.class),
route("/rdap/*", FrontendServlet.class),
route("/registrar-xhr", FrontendServlet.class),
route("/check", FrontendServlet.class),
// Proxy Services

View file

@ -21,7 +21,6 @@ goog.require('goog.testing.MockControl');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.asserts');
goog.require('goog.testing.jsunit');
goog.require('goog.testing.mockmatchers');
goog.require('goog.testing.net.XhrIo');
goog.require('registry.registrar.ConsoleTestUtil');
goog.require('registry.testing');
@ -71,36 +70,6 @@ function testButter() {
}
/**
* The EPP login should be triggered if the user `isGaeLoggedIn`
* but not yet `isEppLoggedIn`.
*/
function testEppLogin() {
// This is a little complex, as handleHashChange triggers an async
// event to do the EPP login with a callback to come back to
// handleHashChange after completion.
registry.registrar.ConsoleTestUtil.visit(
test, {
isEppLoggedIn: true,
clientId: test.testClientId,
xsrfToken: test.testXsrfToken,
productName: 'Foo Registry'
}, function() {
test.sessionMock.login(
goog.testing.mockmatchers.isFunction).$does(function() {
test.sessionMock.$reset();
test.sessionMock.isEppLoggedIn().$returns(true).$anyTimes();
test.sessionMock.getClientId().$returns(
test.testClientId).$anyTimes();
test.sessionMock.$replay();
test.console.handleHashChange(test.testClientId);
}).$anyTimes();
});
assertTrue(test.console.session.isEppLoggedIn());
assertNotNull(goog.dom.getElement('domain-registrar-dashboard'));
}
/** Authed user with no path op specified should nav to welcome page. */
function testShowLoginOrDash() {
registry.registrar.ConsoleTestUtil.visit(test, {

View file

@ -16,14 +16,9 @@ goog.provide('registry.registrar.ConsoleTestUtil');
goog.setTestOnly('registry.registrar.ConsoleTestUtil');
goog.require('goog.History');
goog.require('goog.asserts');
goog.require('goog.dom.xml');
goog.require('goog.soy');
goog.require('goog.testing.mockmatchers');
goog.require('registry.registrar.Console');
goog.require('registry.registrar.EppSession');
goog.require('registry.soy.registrar.console');
goog.require('registry.xml');
/**
@ -34,14 +29,8 @@ goog.require('registry.xml');
*/
registry.registrar.ConsoleTestUtil.setup = function(test) {
test.historyMock = test.mockControl.createLooseMock(goog.History, true);
test.sessionMock = test.mockControl.createLooseMock(
registry.registrar.EppSession, true);
test.mockControl.createConstructorMock(goog, 'History')()
.$returns(test.historyMock);
test.mockControl
.createConstructorMock(registry.registrar, 'EppSession')(
goog.testing.mockmatchers.isObject)
.$returns(test.sessionMock);
};
/**
@ -76,10 +65,10 @@ registry.registrar.ConsoleTestUtil.renderConsoleMain = function(
/**
* Simulates visiting a page on the console. Sets path, then mocks
* session and calls `handleHashChange_`.
* Simulates visiting a page on the console. Sets path, then calls
* `handleHashChange_`.
* @param {!Object} test the test case to configure.
* @param {?Object=} opt_args may include path, isEppLoggedIn.
* @param {?Object=} opt_args may include path.
* @param {?Function=} opt_moar extra setup after called just before
* `$replayAll`. See memegen/3437690.
*/
@ -99,33 +88,17 @@ registry.registrar.ConsoleTestUtil.visit = function(
if (opt_args.isOwner === undefined) {
opt_args.isOwner = !opt_args.isAdmin;
}
if (opt_args.isEppLoggedIn === undefined) {
opt_args.isEppLoggedIn = true;
}
test.historyMock.$reset();
test.sessionMock.$reset();
test.historyMock.getToken().$returns(opt_args.path).$anyTimes();
test.sessionMock.isEppLoggedIn().$returns(opt_args.isEppLoggedIn).$anyTimes();
test.sessionMock.getClientId().$returns(opt_args.isEppLoggedIn ?
opt_args.clientId : null).$anyTimes();
if (opt_args.rspXml) {
test.sessionMock
.send(goog.testing.mockmatchers.isString,
goog.testing.mockmatchers.isFunction)
.$does(function(args, cb) {
// XXX: Args should be checked.
const xml = goog.dom.xml.loadXml(opt_args.rspXml);
goog.asserts.assert(xml != null);
cb(registry.xml.convertToJson(xml));
}).$anyTimes();
}
if (opt_moar) {
opt_moar();
}
test.mockControl.$replayAll();
/** @type {!registry.registrar.Console} */
test.console = new registry.registrar.Console(opt_args);
// XXX: Should be triggered via event passing.
test.console.setUp();
// Should be triggered via the History object in test.console.setUp(), but
// since we're using a mock that isn't happening. So we call it manually.
test.console.handleHashChange();
test.mockControl.$verifyAll();
};

View file

@ -1,119 +0,0 @@
// Copyright 2017 The Nomulus 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.
goog.setTestOnly();
goog.require('goog.dispose');
goog.require('goog.dom');
goog.require('goog.testing.MockControl');
goog.require('goog.testing.asserts');
goog.require('goog.testing.jsunit');
goog.require('registry.registrar.ConsoleTestUtil');
goog.require('registry.testing');
const $ = goog.dom.getRequiredElement;
const test = {
mockControl: new goog.testing.MockControl()
};
function setUp() {
registry.testing.addToDocument('<div id="test"/>');
registry.testing.addToDocument('<div class="kd-butterbar"/>');
registry.registrar.ConsoleTestUtil.renderConsoleMain($('test'), {});
registry.registrar.ConsoleTestUtil.setup(test);
}
function tearDown() {
goog.dispose(test.console);
test.mockControl.$tearDown();
}
/** Contact hash path should nav to contact page. */
function testVisitContact() {
registry.registrar.ConsoleTestUtil.visit(test, {
path: 'contact/pabloistrad',
rspXml: '<?xml version="1.0"?>' +
'<epp xmlns:domain="urn:ietf:params:xml:ns:domain-1.0"' +
' xmlns:contact="urn:ietf:params:xml:ns:contact-1.0"' +
' xmlns:host="urn:ietf:params:xml:ns:host-1.0"' +
' xmlns:launch="urn:ietf:params:xml:ns:launch-1.0"' +
' xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0"' +
' xmlns="urn:ietf:params:xml:ns:epp-1.0"' +
' xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1"' +
' xmlns:mark="urn:ietf:params:xml:ns:mark-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>Command completed successfully</msg>' +
' </result>' +
' <resData>' +
' <contact:infData>' +
' <contact:id>pabloistrad</contact:id>' +
' <contact:roid>1-roid</contact:roid>' +
' <contact:status s="ok"/>' +
' <contact:postalInfo type="int">' +
' <contact:name>name2</contact:name>' +
' <contact:addr>' +
' <contact:street></contact:street>' +
' <contact:city>city2</contact:city>' +
' <contact:cc>US</contact:cc>' +
' </contact:addr>' +
' </contact:postalInfo>' +
' <contact:voice/>' +
' <contact:fax/>' +
' <contact:email>test2.ui@example.com</contact:email>' +
' <contact:clID>daddy</contact:clID>' +
' <contact:crID>daddy</contact:crID>' +
' <contact:crDate>2014-05-06T22:16:36Z</contact:crDate>' +
' <contact:upID>daddy</contact:upID>' +
' <contact:upDate>2014-05-07T16:20:07Z</contact:upDate>' +
' <contact:authInfo>' +
' <contact:pw>asdfasdf</contact:pw>' +
' </contact:authInfo>' +
' </contact:infData>' +
' </resData>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>c4O3B0pRRKKSrrXsJvxP5w==-2</svTRID>' +
' </trID>' +
' </response>' +
'</epp>'
});
assertEquals(2, $('contact-postalInfo').childNodes.length);
}
/** Contact hash path should nav to contact page. */
function testEdit() {
testVisitContact();
registry.testing.assertVisible($('reg-app-btns-edit'));
registry.testing.click($('reg-app-btn-edit'));
registry.testing.assertHidden($('reg-app-btns-edit'));
registry.testing.assertVisible($('reg-app-btns-save'));
}
/** Contact hash path should nav to contact page. */
function testAddPostalInfo() {
testEdit();
const addPiBtn = $('domain-contact-postalInfo-add-button');
assertNull(addPiBtn.getAttribute('disabled'));
registry.testing.click(addPiBtn);
assertTrue(addPiBtn.hasAttribute('disabled'));
assertEquals(3, $('contact-postalInfo').childNodes.length);
}

View file

@ -1,475 +0,0 @@
// Copyright 2017 The Nomulus 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.
goog.setTestOnly();
goog.require('goog.History');
goog.require('goog.dispose');
goog.require('goog.dom');
goog.require('goog.testing.MockControl');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.asserts');
goog.require('goog.testing.jsunit');
goog.require('goog.testing.mockmatchers');
goog.require('goog.testing.net.XhrIo');
goog.require('registry.registrar.Console');
goog.require('registry.registrar.ConsoleTestUtil');
goog.require('registry.testing');
const $ = goog.dom.getRequiredElement;
const _ = goog.testing.mockmatchers.ignoreArgument;
const stubs = new goog.testing.PropertyReplacer();
const mocks = new goog.testing.MockControl();
let historyMock;
let registrarConsole;
function setUp() {
registry.testing.addToDocument('<div id="test"/>');
registry.testing.addToDocument('<div class="kd-butterbar"/>');
registry.registrar.ConsoleTestUtil.renderConsoleMain($('test'), {});
stubs.setPath('goog.net.XhrIo', goog.testing.net.XhrIo);
historyMock = mocks.createStrictMock(goog.History);
mocks.createConstructorMock(goog, 'History')().$returns(historyMock);
historyMock.addEventListener(_, _, _);
historyMock.setEnabled(true);
mocks.$replayAll();
registrarConsole = new registry.registrar.Console({
xsrfToken: '☢',
clientId: 'jartine'
});
mocks.$verifyAll();
}
function tearDown() {
goog.dispose(registrarConsole);
stubs.reset();
mocks.$tearDown();
goog.testing.net.XhrIo.cleanup();
}
/** Handles EPP login. */
function handleLogin() {
const request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <command>' +
' <login>' +
' <clID>jartine</clID>' +
' <pw>undefined</pw>' +
' <options>' +
' <version>1.0</version>' +
' <lang>en</lang>' +
' </options>' +
' <svcs>' +
' <objURI>urn:ietf:params:xml:ns:host-1.0</objURI>' +
' <objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>' +
' <objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>' +
' </svcs>' +
' </login>' +
' <clTRID>asdf-1235</clTRID>' +
' </command>' +
'</epp>');
const response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="2002">' +
' <msg>Registrar is already logged in</msg>' +
' </result>' +
' <trID>' +
' <clTRID>asdf-1235</clTRID>' +
' <svTRID>ytk1RO+8SmaDQxrTIdulnw==-3</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
const xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue(xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
}
function testView() {
historyMock.$reset();
historyMock.getToken().$returns('domain/justine.lol').$anyTimes();
mocks.$replayAll();
registrarConsole.handleHashChange();
handleLogin();
const request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <command>' +
' <info>' +
' <domain:info xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">' +
' <domain:name hosts="all">justine.lol</domain:name>' +
' </domain:info>' +
' </info>' +
' <clTRID>abc-1234</clTRID>' +
' </command>' +
'</epp>');
const response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>Command completed successfully</msg>' +
' </result>' +
' <resData>' +
' <domain:infData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">' +
' <domain:name>justine.lol</domain:name>' +
' <domain:roid>6-roid</domain:roid>' +
' <domain:status s="inactive"/>' +
' <domain:registrant>GK Chesterton</domain:registrant>' +
' <domain:contact type="admin">&lt;justine&gt;</domain:contact>' +
' <domain:contact type="billing">candycrush</domain:contact>' +
' <domain:contact type="tech">krieger</domain:contact>' +
' <domain:ns>' +
' <domain:hostObj>ns1.justine.lol</domain:hostObj>' +
' <domain:hostObj>ns2.justine.lol</domain:hostObj>' +
' </domain:ns>' +
' <domain:host>ns1.justine.lol</domain:host>' +
' <domain:clID>justine</domain:clID>' +
' <domain:crID>justine</domain:crID>' +
' <domain:crDate>2014-07-10T02:17:02Z</domain:crDate>' +
' <domain:exDate>2015-07-10T02:17:02Z</domain:exDate>' +
' <domain:authInfo>' +
' <domain:pw>lolcat</domain:pw>' +
' </domain:authInfo>' +
' </domain:infData>' +
' </resData>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>ytk1RO+8SmaDQxrTIdulnw==-4</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
const xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue('XHR is inactive.', xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
assertEquals('We require more vespene gas.',
0, goog.testing.net.XhrIo.getSendInstances().length);
mocks.$verifyAll();
assertTrue('Form should be read-only.', $('domain:exDate').readOnly);
assertContains('justine.lol', $('reg-content').innerHTML);
assertEquals('2015-07-10T02:17:02Z', $('domain:exDate').value);
assertEquals('GK Chesterton', $('domain:registrant').value);
assertEquals('<justine>', $('domain:contact[0].value').value);
assertEquals('candycrush', $('domain:contact[1].value').value);
assertEquals('krieger', $('domain:contact[2].value').value);
assertEquals('lolcat', $('domain:authInfo.domain:pw').value);
assertEquals('ns1.justine.lol', $('domain:ns.domain:hostObj[0].value').value);
assertEquals('ns2.justine.lol', $('domain:ns.domain:hostObj[1].value').value);
}
function testEdit() {
testView();
historyMock.$reset();
mocks.$replayAll();
registry.testing.click($('reg-app-btn-edit'));
assertFalse('Form should be edible.', $('domain:exDate').readOnly);
$('domain:registrant').value = 'Jonathan Swift';
$('domain:authInfo.domain:pw').value = '(✿◕‿◕)';
registry.testing.click($('reg-app-btn-save'));
let request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<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>justine.lol</domain:name>' +
' <domain:chg>' +
' <domain:registrant>Jonathan Swift</domain:registrant>' +
' <domain:authInfo>' +
' <domain:pw>(✿◕‿◕)</domain:pw>' +
' </domain:authInfo>' +
' </domain:chg>' +
' </domain:update>' +
' </update>' +
' <clTRID>abc-1234</clTRID>' +
' </command>' +
'</epp>');
let response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>This world is built from a million lies.</msg>' +
' </result>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>214CjbYuTsijoP8sgyFUNg==-e</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
let xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue('XHR is inactive.', xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <command>' +
' <info>' +
' <domain:info xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">' +
' <domain:name hosts="all">justine.lol</domain:name>' +
' </domain:info>' +
' </info>' +
' <clTRID>abc-1234</clTRID>' +
' </command>' +
'</epp>');
response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>How can we live in the land of the dead?</msg>' +
' </result>' +
' <resData>' +
' <domain:infData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">' +
' <domain:name>justine.lol</domain:name>' +
' <domain:roid>6-roid</domain:roid>' +
' <domain:status s="inactive"/>' +
' <domain:registrant>Jonathan Swift</domain:registrant>' +
' <domain:contact type="admin">&lt;justine&gt;</domain:contact>' +
' <domain:contact type="billing">candycrush</domain:contact>' +
' <domain:contact type="tech">krieger</domain:contact>' +
' <domain:ns>' +
' <domain:hostObj>ns1.justine.lol</domain:hostObj>' +
' <domain:hostObj>ns2.justine.lol</domain:hostObj>' +
' </domain:ns>' +
' <domain:host>ns1.justine.lol</domain:host>' +
' <domain:clID>justine</domain:clID>' +
' <domain:crID>justine</domain:crID>' +
' <domain:crDate>2014-07-10T02:17:02Z</domain:crDate>' +
' <domain:exDate>2015-07-10T02:17:02Z</domain:exDate>' +
' <domain:authInfo>' +
' <domain:pw>(✿◕‿◕)</domain:pw>' +
' </domain:authInfo>' +
' </domain:infData>' +
' </resData>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>ytk1RO+8SmaDQxrTIdulnw==-4</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue('XHR is inactive.', xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
assertEquals('We require more vespene gas.',
0, goog.testing.net.XhrIo.getSendInstances().length);
mocks.$verifyAll();
assertTrue($('domain:exDate').readOnly);
assertContains('justine.lol', $('reg-content').innerHTML);
assertEquals('2015-07-10T02:17:02Z', $('domain:exDate').value);
assertEquals('Jonathan Swift', $('domain:registrant').value);
assertEquals('<justine>', $('domain:contact[0].value').value);
assertEquals('candycrush', $('domain:contact[1].value').value);
assertEquals('krieger', $('domain:contact[2].value').value);
assertEquals('(✿◕‿◕)', $('domain:authInfo.domain:pw').value);
assertEquals('ns1.justine.lol', $('domain:ns.domain:hostObj[0].value').value);
assertEquals('ns2.justine.lol', $('domain:ns.domain:hostObj[1].value').value);
}
function testEdit_cancel_restoresOriginalValues() {
testView();
registry.testing.click($('reg-app-btn-edit'));
assertFalse('Form should be edible.', $('domain:exDate').readOnly);
$('domain:registrant').value = 'Jonathan Swift';
$('domain:authInfo.domain:pw').value = '(✿◕‿◕)';
registry.testing.click($('reg-app-btn-cancel'));
assertTrue('Form should be read-only.', $('domain:exDate').readOnly);
assertEquals('GK Chesterton', $('domain:registrant').value);
assertEquals('lolcat', $('domain:authInfo.domain:pw').value);
}
function testCreate() {
historyMock.$reset();
historyMock.getToken().$returns('domain').$anyTimes();
mocks.$replayAll();
registrarConsole.handleHashChange();
handleLogin();
mocks.$verifyAll();
assertFalse('Form should be edible.', $('domain:name').readOnly);
$('domain:name').value = 'bog.lol';
$('domain:period').value = '1';
$('domain:authInfo.domain:pw').value = 'attorney at lawl';
$('domain:registrant').value = 'Chris Pohl';
registry.testing.click($('domain-contact-add-button'));
$('domain:contact[0].value').value = 'BlutEngel';
$('domain:contact[0].@type').value = 'admin';
registry.testing.click($('domain-contact-add-button'));
$('domain:contact[1].value').value = 'Ravenous';
$('domain:contact[1].@type').value = 'tech';
registry.testing.click($('domain-contact-add-button'));
$('domain:contact[2].value').value = 'Dark Angels';
$('domain:contact[2].@type').value = 'billing';
historyMock.$reset();
mocks.$replayAll();
registry.testing.click($('reg-app-btn-save'));
let request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<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>bog.lol</domain:name>' +
' <domain:period unit="y">1</domain:period>' +
' <domain:registrant>Chris Pohl</domain:registrant>' +
' <domain:contact type="admin">BlutEngel</domain:contact>' +
' <domain:contact type="tech">Ravenous</domain:contact>' +
' <domain:contact type="billing">Dark Angels</domain:contact>' +
' <domain:authInfo>' +
' <domain:pw>attorney at lawl</domain:pw>' +
' </domain:authInfo>' +
' </domain:create>' +
' </create>' +
' <clTRID>abc-1234</clTRID>' +
' </command>' +
'</epp>');
let response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>Command completed successfully</msg>' +
' </result>' +
' <resData>' +
' <domain:creData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">' +
' <domain:name>bog.lol</domain:name>' +
' <domain:crDate>2014-07-17T08:19:24Z</domain:crDate>' +
' <domain:exDate>2015-07-17T08:19:24Z</domain:exDate>' +
' </domain:creData>' +
' </resData>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>OBPI6JvEQfOUaO8qGf+IKA==-7</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
let xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue('XHR is inactive.', xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <command>' +
' <info>' +
' <domain:info xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">' +
' <domain:name hosts="all">bog.lol</domain:name>' +
' </domain:info>' +
' </info>' +
' <clTRID>abc-1234</clTRID>' +
' </command>' +
'</epp>');
response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>Command completed successfully</msg>' +
' </result>' +
' <resData>' +
' <domain:infData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">' +
' <domain:name>bog.lol</domain:name>' +
' <domain:roid>1f-roid</domain:roid>' +
' <domain:status s="inactive"/>' +
' <domain:registrant>Chris Pohl</domain:registrant>' +
' <domain:contact type="admin">BlutEngel</domain:contact>' +
' <domain:contact type="tech">Ravenous</domain:contact>' +
' <domain:contact type="billing">Dark Angels</domain:contact>' +
' <domain:clID>justine</domain:clID>' +
' <domain:crID>justine</domain:crID>' +
' <domain:crDate>2014-07-17T08:19:24Z</domain:crDate>' +
' <domain:exDate>2015-07-17T08:19:24Z</domain:exDate>' +
' <domain:authInfo>' +
' <domain:pw>attorney at lawl</domain:pw>' +
' </domain:authInfo>' +
' </domain:infData>' +
' </resData>' +
' <extension>' +
' <rgp:infData xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0">' +
' <rgp:rgpStatus s="addPeriod"/>' +
' </rgp:infData>' +
' </extension>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>OBPI6JvEQfOUaO8qGf+IKA==-8</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue('XHR is inactive.', xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
assertEquals('We require more vespene gas.',
0, goog.testing.net.XhrIo.getSendInstances().length);
mocks.$verifyAll();
assertTrue('Form should be read-only.', $('domain:exDate').readOnly);
assertContains('bog.lol', $('reg-content').innerHTML);
assertEquals('2015-07-17T08:19:24Z', $('domain:exDate').value);
assertEquals('Chris Pohl', $('domain:registrant').value);
assertEquals('BlutEngel', $('domain:contact[0].value').value);
assertEquals('Ravenous', $('domain:contact[1].value').value);
assertEquals('Dark Angels', $('domain:contact[2].value').value);
assertEquals('attorney at lawl', $('domain:authInfo.domain:pw').value);
assertNull(goog.dom.getElement('domain:ns.domain:hostObj[0].value'));
}

View file

@ -1,415 +0,0 @@
// Copyright 2017 The Nomulus 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.
goog.setTestOnly();
goog.require('goog.History');
goog.require('goog.dispose');
goog.require('goog.dom');
goog.require('goog.testing.MockControl');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.asserts');
goog.require('goog.testing.jsunit');
goog.require('goog.testing.mockmatchers');
goog.require('goog.testing.net.XhrIo');
goog.require('registry.registrar.Console');
goog.require('registry.registrar.ConsoleTestUtil');
goog.require('registry.testing');
const $ = goog.dom.getRequiredElement;
const _ = goog.testing.mockmatchers.ignoreArgument;
const stubs = new goog.testing.PropertyReplacer();
const mocks = new goog.testing.MockControl();
let historyMock;
let registrarConsole;
function setUp() {
registry.testing.addToDocument('<div id="test"/>');
registry.testing.addToDocument('<div class="kd-butterbar"/>');
registry.registrar.ConsoleTestUtil.renderConsoleMain($('test'), {});
stubs.setPath('goog.net.XhrIo', goog.testing.net.XhrIo);
historyMock = mocks.createStrictMock(goog.History);
mocks.createConstructorMock(goog, 'History')().$returns(historyMock);
historyMock.addEventListener(_, _, _);
historyMock.setEnabled(true);
mocks.$replayAll();
registrarConsole = new registry.registrar.Console({
xsrfToken: '☢',
clientId: 'jartine'
});
mocks.$verifyAll();
}
function tearDown() {
goog.dispose(registrarConsole);
stubs.reset();
mocks.$tearDown();
goog.testing.net.XhrIo.cleanup();
}
/** Handles EPP login. */
function handleLogin() {
const request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <command>' +
' <login>' +
' <clID>jartine</clID>' +
' <pw>undefined</pw>' +
' <options>' +
' <version>1.0</version>' +
' <lang>en</lang>' +
' </options>' +
' <svcs>' +
' <objURI>urn:ietf:params:xml:ns:host-1.0</objURI>' +
' <objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>' +
' <objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>' +
' </svcs>' +
' </login>' +
' <clTRID>asdf-1235</clTRID>' +
' </command>' +
'</epp>');
const response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="2002">' +
' <msg>Registrar is already logged in</msg>' +
' </result>' +
' <trID>' +
' <clTRID>asdf-1235</clTRID>' +
' <svTRID>ytk1RO+8SmaDQxrTIdulnw==-3</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
const xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue(xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
}
function testView() {
historyMock.$reset();
historyMock.getToken().$returns('host/ns1.justine.lol').$anyTimes();
mocks.$replayAll();
registrarConsole.handleHashChange();
handleLogin();
const request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <command>' +
' <info>' +
' <host:info xmlns:host="urn:ietf:params:xml:ns:host-1.0">' +
' <host:name>ns1.justine.lol</host:name>' +
' </host:info>' +
' </info>' +
' <clTRID>abc-1234</clTRID>' +
' </command>' +
'</epp>');
const response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0"' +
' xmlns:host="urn:ietf:params:xml:ns:host-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>Command completed successfully</msg>' +
' </result>' +
' <resData>' +
' <host:infData>' +
' <host:name>ns1.justine.lol</host:name>' +
' <host:roid>8-roid</host:roid>' +
' <host:status s="ok"/>' +
' <host:addr ip="v4">8.8.8.8</host:addr>' +
' <host:addr ip="v6">feed:a:bee::1</host:addr>' +
' <host:clID>justine</host:clID>' +
' <host:crID>justine</host:crID>' +
' <host:crDate>2014-07-10T02:18:34Z</host:crDate>' +
' </host:infData>' +
' </resData>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>EweBEzCZTJirOqRmrtYrAA==-b</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
const xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue('XHR is inactive.', xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('application/epp+xml',
xhr.getLastRequestHeaders()['Content-Type']);
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
assertEquals('We require more vespene gas.',
0, goog.testing.net.XhrIo.getSendInstances().length);
mocks.$verifyAll();
assertTrue('Form should be read-only.', $('host:chgName').readOnly);
assertContains('ns1.justine.lol', $('reg-content').innerHTML);
assertEquals('ns1.justine.lol', $('host:chgName').value);
assertEquals('8.8.8.8', $('host:addr[0].value').value);
assertEquals('feed:a:bee::1', $('host:addr[1].value').value);
}
function testEditFirstAddr_ignoreSecond_addThird() {
testView();
historyMock.$reset();
mocks.$replayAll();
registry.testing.click($('reg-app-btn-edit'));
assertFalse('Form should be edible.', $('host:addr[0].value').readOnly);
$('host:addr[0].value').value = '1.2.3.4';
registry.testing.click($('domain-host-addr-add-button'));
$('host:addr[2].value').value = 'feed:a:fed::1';
registry.testing.click($('reg-app-btn-save'));
let request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <command>' +
' <update>' +
' <host:update xmlns:host="urn:ietf:params:xml:ns:host-1.0">' +
' <host:name>ns1.justine.lol</host:name>' +
' <host:add>' +
' <host:addr ip="v4">1.2.3.4</host:addr>' +
' <host:addr ip="v6">feed:a:fed::1</host:addr>' +
' </host:add>' +
' <host:rem>' +
' <host:addr ip="v4">8.8.8.8</host:addr>' +
' </host:rem>' +
' </host:update>' +
' </update>' +
' <clTRID>abc-1234</clTRID>' +
' </command>' +
'</epp>');
let response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>This world is built from a million lies.</msg>' +
' </result>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>214CjbYuTsijoP8sgyFUNg==-e</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
let xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue('XHR is inactive.', xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <command>' +
' <info>' +
' <host:info xmlns:host="urn:ietf:params:xml:ns:host-1.0">' +
' <host:name>ns1.justine.lol</host:name>' +
' </host:info>' +
' </info>' +
' <clTRID>abc-1234</clTRID>' +
' </command>' +
'</epp>');
response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0"' +
' xmlns:host="urn:ietf:params:xml:ns:host-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>Command completed successfully</msg>' +
' </result>' +
' <resData>' +
' <host:infData>' +
' <host:name>ns1.justine.lol</host:name>' +
' <host:roid>8-roid</host:roid>' +
' <host:status s="ok"/>' +
' <host:addr ip="v6">feed:a:bee::1</host:addr>' +
' <host:addr ip="v4">1.2.3.4</host:addr>' +
' <host:addr ip="v6">feed:a:fed::1</host:addr>' +
' <host:clID>justine</host:clID>' +
' <host:crID>justine</host:crID>' +
' <host:crDate>2014-07-10T02:18:34Z</host:crDate>' +
' </host:infData>' +
' </resData>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>EweBEzCZTJirOqRmrtYrAA==-b</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue('XHR is inactive.', xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
assertEquals('We require more vespene gas.',
0, goog.testing.net.XhrIo.getSendInstances().length);
mocks.$verifyAll();
assertTrue('Form should be read-only.', $('host:chgName').readOnly);
assertContains('ns1.justine.lol', $('reg-content').innerHTML);
assertEquals('ns1.justine.lol', $('host:chgName').value);
assertEquals('feed:a:bee::1', $('host:addr[0].value').value);
assertEquals('1.2.3.4', $('host:addr[1].value').value);
assertEquals('feed:a:fed::1', $('host:addr[2].value').value);
}
function testCreate() {
historyMock.$reset();
historyMock.getToken().$returns('host').$anyTimes();
mocks.$replayAll();
registrarConsole.handleHashChange();
handleLogin();
mocks.$verifyAll();
assertFalse('Form should be edible.', $('host:name').readOnly);
$('host:name').value = 'ns1.example.tld';
registry.testing.click($('domain-host-addr-add-button'));
$('host:addr[0].value').value = '192.0.2.2';
registry.testing.click($('domain-host-addr-add-button'));
$('host:addr[1].value').value = '192.0.2.29';
registry.testing.click($('domain-host-addr-add-button'));
$('host:addr[2].value').value = '1080:0:0:0:8:800:200C:417A';
historyMock.$reset();
mocks.$replayAll();
registry.testing.click($('reg-app-btn-save'));
let request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <command>' +
' <create>' +
' <host:create xmlns:host="urn:ietf:params:xml:ns:host-1.0">' +
' <host:name>ns1.example.tld</host:name>' +
' <host:addr ip="v4">192.0.2.2</host:addr>' +
' <host:addr ip="v4">192.0.2.29</host:addr>' +
' <host:addr ip="v6">1080:0:0:0:8:800:200C:417A</host:addr>' +
' </host:create>' +
' </create>' +
' <clTRID>abc-1234</clTRID>' +
' </command>' +
'</epp>');
let response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>Command completed successfully</msg>' +
' </result>' +
' <resData>' +
' <host:creData xmlns:host="urn:ietf:params:xml:ns:host-1.0">' +
' <host:name>ns1.example.tld</host:name>' +
' <host:crDate>1999-04-03T22:00:00.0Z</host:crDate>' +
' </host:creData>' +
' </resData>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>EweBEzCZTJirOqRmrtYrAA==-b</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
let xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue('XHR is inactive.', xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
request = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <command>' +
' <info>' +
' <host:info xmlns:host="urn:ietf:params:xml:ns:host-1.0">' +
' <host:name>ns1.example.tld</host:name>' +
' </host:info>' +
' </info>' +
' <clTRID>abc-1234</clTRID>' +
' </command>' +
'</epp>');
response = registry.testing.loadXml(
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>Command completed successfully</msg>' +
' </result>' +
' <resData>' +
' <host:infData xmlns:host="urn:ietf:params:xml:ns:host-1.0">' +
' <host:name>ns1.example.tld</host:name>' +
' <host:roid>NS1_EXAMPLE1-REP</host:roid>' +
' <host:status s="linked"/>' +
' <host:status s="clientUpdateProhibited"/>' +
' <host:addr ip="v4">192.0.2.2</host:addr>' +
' <host:addr ip="v4">192.0.2.29</host:addr>' +
' <host:addr ip="v6">1080:0:0:0:8:800:200C:417A</host:addr>' +
' <host:clID>TheRegistrar</host:clID>' +
' <host:crID>NewRegistrar</host:crID>' +
' <host:crDate>1999-04-03T22:00:00.0Z</host:crDate>' +
' <host:upID>NewRegistrar</host:upID>' +
' <host:upDate>1999-12-03T09:00:00.0Z</host:upDate>' +
' <host:trDate>2000-04-08T09:00:00.0Z</host:trDate>' +
' </host:infData>' +
' </resData>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>EweBEzCZTJirOqRmrtYrAA==-b</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
xhr = goog.testing.net.XhrIo.getSendInstances().pop();
assertTrue('XHR is inactive.', xhr.isActive());
assertEquals('/registrar-xhr?clientId=jartine', xhr.getLastUri());
assertEquals('☢', xhr.getLastRequestHeaders()['X-CSRF-Token']);
registry.testing.assertXmlEquals(request, xhr.getLastContent());
xhr.simulateResponse(200, response);
assertEquals('We require more vespene gas.',
0, goog.testing.net.XhrIo.getSendInstances().length);
mocks.$verifyAll();
assertTrue('Form should be read-only.', $('host:chgName').readOnly);
assertEquals('ns1.example.tld', $('host:chgName').value);
assertEquals('192.0.2.2', $('host:addr[0].value').value);
assertEquals('192.0.2.29', $('host:addr[1].value').value);
assertEquals('1080:0:0:0:8:800:200C:417A', $('host:addr[2].value').value);
}

View file

@ -15,15 +15,12 @@
goog.provide('registry.testing');
goog.setTestOnly('registry.testing');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.dom.xml');
goog.require('goog.events.EventType');
goog.require('goog.format.JsonPrettyPrinter');
goog.require('goog.html.testing');
goog.require('goog.json');
goog.require('goog.testing.asserts');
goog.require('goog.testing.events');
goog.require('goog.testing.events.Event');
goog.require('goog.testing.net.XhrIo');
@ -40,32 +37,6 @@ registry.testing.addToDocument = function(html) {
};
/**
* Extracts XML document from inside an `<iframe>`.
* @param {string} xmlText
* @return {!Document}
*/
registry.testing.loadXml = function(xmlText) {
var xml = goog.dom.xml.loadXml(xmlText);
goog.asserts.assert(xml != null);
if ('parsererror' in xml) {
fail(xml['parsererror']['keyValue']);
}
return xml;
};
/**
* Extracts plain text string from inside an `<iframe>`.
* @param {string|!Document|!Element} want
* @param {string|!Document|!Element} got
*/
registry.testing.assertXmlEquals = function(want, got) {
assertHTMLEquals(registry.testing.sanitizeXml_(want),
registry.testing.sanitizeXml_(got));
};
/**
* Simulates a mouse click on a browser element.
* @param {!Element} element
@ -135,22 +106,6 @@ registry.testing.assertReqMockRsp =
};
/**
* Removes stuff from XML text that we don't want to compare.
* @param {string|!Document|!Element} xml
* @return {string}
* @private
*/
registry.testing.sanitizeXml_ = function(xml) {
var xmlString = goog.isString(xml) ? xml : goog.dom.xml.serialize(xml);
return xmlString
.replace(/^\s*<\?.*?\?>\s*/, '') // Remove declaration thing.
.replace(/xmlns(:\w+)?="[^"]+"/g, '') // Remove namespace things.
.replace(/>\s+</g, '><') // Remove spaces between XML tags.
.replace(/<!--.*?-->/, ''); // Remove comments.
};
/**
* JSON pretty printer.
* @type {!goog.format.JsonPrettyPrinter}

View file

@ -1,183 +0,0 @@
// Copyright 2017 The Nomulus 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.
goog.setTestOnly();
goog.require('goog.dom.xml');
goog.require('goog.testing.asserts');
goog.require('goog.testing.jsunit');
goog.require('registry.testing');
goog.require('registry.xml');
function testEmptyElement_hasNoKeyValue() {
assertXmlTurnsIntoJson(
{'epp': {}},
'<epp></epp>');
}
function testSelfClosingRootElement_hasNoKeyValue() {
assertXmlTurnsIntoJson(
{'epp': {}},
'<epp/>');
}
function testElementWithWhitespaceTextContent_getsIgnored() {
assertXmlTurnsIntoJson(
{'epp': {}},
'<epp> \r\n </epp>');
}
function testElementWithTextContent_getsSetToKeyValueField() {
assertXmlTurnsIntoJson(
{'epp': {'keyValue': 'hello'}},
'<epp>hello</epp>');
}
function testTextWithSpacesOnSides_getsTrimmed() {
assertXmlTurnsIntoJson(
{'epp': {'keyValue': 'hello'}},
'<epp> hello </epp>');
}
function testAttribute_getsSetToFieldPrefixedByAtSymbol() {
assertXmlTurnsIntoJson(
{'epp': {'@ohmy': 'goth'}},
'<epp ohmy="goth"/>');
}
function testSingleNestedElement_keyIsNameAndValueIsNode() {
assertXmlTurnsIntoJson(
{'epp': {'ohmy': {'keyValue': 'goth'}}},
'<epp><ohmy>goth</ohmy></epp>');
}
function testMultipleNestedElements_valueBecomesArray() {
assertXmlTurnsIntoJson(
{'epp': {'ohmy': [{'keyValue': 'goth1'}, {'keyValue': 'goth2'}]}},
'<epp><ohmy>goth1</ohmy><ohmy>goth2</ohmy></epp>');
}
function testInterspersedText_throwsError() {
assertEquals(
'XML text "hello" interspersed with "there"',
assertThrows(function() {
registry.xml.convertToJson(
goog.dom.xml.loadXml(
'<epp> hello <omg/> there </epp>'));
}).message);
}
function testEppMessage() {
assertXmlTurnsIntoJson(
{
'epp': {
'@xmlns': 'urn:ietf:params:xml:ns:epp-1.0',
'response': {
'result': {
'@code': '1000',
'msg': {'keyValue': 'Command completed successfully'}
},
'resData': {
'domain:infData': {
'@xmlns:domain': 'urn:ietf:params:xml:ns:domain-1.0',
'domain:name': {'keyValue': 'justine.lol'},
'domain:roid': {'keyValue': '6-roid'},
'domain:status': {'@s': 'inactive'},
'domain:registrant': {'keyValue': 'GK Chesterton'},
'domain:contact': [
{'@type': 'admin', 'keyValue': '<justine>'},
{'@type': 'billing', 'keyValue': 'candycrush'},
{'@type': 'tech', 'keyValue': 'krieger'}
],
'domain:ns': {
'domain:hostObj': [
{'keyValue': 'ns1.justine.lol'},
{'keyValue': 'ns2.justine.lol'}
]
},
'domain:host': {'keyValue': 'ns1.justine.lol'},
'domain:clID': {'keyValue': 'justine'},
'domain:crID': {'keyValue': 'justine'},
'domain:crDate': {'keyValue': '2014-07-10T02:17:02Z'},
'domain:exDate': {'keyValue': '2015-07-10T02:17:02Z'},
'domain:authInfo': {
'domain:pw': {'keyValue': 'lolcat'}
}
}
},
'trID': {
'clTRID': {'keyValue': 'abc-1234'},
'svTRID': {'keyValue': 'ytk1RO+8SmaDQxrTIdulnw==-4'}
}
}
}
},
'<?xml version="1.0"?>' +
'<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">' +
' <response>' +
' <result code="1000">' +
' <msg>Command completed successfully</msg>' +
' </result>' +
' <resData>' +
' <domain:infData' +
' xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">' +
' <domain:name>justine.lol</domain:name>' +
' <domain:roid>6-roid</domain:roid>' +
' <domain:status s="inactive"/>' +
' <domain:registrant>GK Chesterton</domain:registrant>' +
' <domain:contact type="admin">&lt;justine&gt;</domain:contact>' +
' <domain:contact type="billing">candycrush</domain:contact>' +
' <domain:contact type="tech">krieger</domain:contact>' +
' <domain:ns>' +
' <domain:hostObj>ns1.justine.lol</domain:hostObj>' +
' <domain:hostObj>ns2.justine.lol</domain:hostObj>' +
' </domain:ns>' +
' <domain:host>ns1.justine.lol</domain:host>' +
' <domain:clID>justine</domain:clID>' +
' <domain:crID>justine</domain:crID>' +
' <domain:crDate>2014-07-10T02:17:02Z</domain:crDate>' +
' <domain:exDate>2015-07-10T02:17:02Z</domain:exDate>' +
' <domain:authInfo>' +
' <domain:pw>lolcat</domain:pw>' +
' </domain:authInfo>' +
' </domain:infData>' +
' </resData>' +
' <trID>' +
' <clTRID>abc-1234</clTRID>' +
' <svTRID>ytk1RO+8SmaDQxrTIdulnw==-4</svTRID>' +
' </trID>' +
' </response>' +
'</epp>');
}
/**
* Asserts `xml` turns into `json`.
* @param {!Object} json
* @param {string} xml
*/
function assertXmlTurnsIntoJson(json, xml) {
registry.testing.assertObjectEqualsPretty(
json, registry.xml.convertToJson(goog.dom.xml.loadXml(xml)));
}

View file

@ -26,7 +26,6 @@ import google.registry.model.ofy.OfyFilter;
import google.registry.module.frontend.FrontendServlet;
import google.registry.server.RegistryTestServer;
import google.registry.testing.CertificateSamples;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -44,8 +43,7 @@ public class RegistrarConsoleScreenshotTest {
.setRoutes(
route("/registrar", FrontendServlet.class),
route("/registrar-ote-status", FrontendServlet.class),
route("/registrar-settings", FrontendServlet.class),
route("/registrar-xhr", FrontendServlet.class))
route("/registrar-settings", FrontendServlet.class))
.setFilters(ObjectifyFilter.class, OfyFilter.class)
.setFixtures(BASIC)
.setEmail("Marla.Singer@google.com")
@ -286,77 +284,6 @@ public class RegistrarConsoleScreenshotTest {
driver.diffPage("page");
}
// EPP pages aren't being included in launch, so temporarily disable the following tests.
@Test
public void domainCreate() throws Throwable {
// TODO(b/17675279): Change labels to unicode.
driver.get(server.getUrl("/registrar#domain"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
@Ignore("TODO(b/26984251): Unflake nameserver ordering.")
public void domainView() throws Throwable {
driver.get(server.getUrl("/registrar#domain/love.xn--q9jyb4c"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
@Ignore("TODO(b/26984251): Unflake nameserver ordering.")
public void domainEdit() throws Throwable {
driver.get(server.getUrl("/registrar#domain/love.xn--q9jyb4c"));
driver.waitForElement(By.id("reg-app-btn-edit")).click();
Thread.sleep(1000);
driver.diffPage("page");
}
@Test
public void contactCreate() throws Throwable {
driver.get(server.getUrl("/registrar#contact"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void contactView() throws Throwable {
driver.get(server.getUrl("/registrar#contact/google"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void contactEdit() throws Throwable {
driver.get(server.getUrl("/registrar#contact/google"));
driver.waitForElement(By.id("reg-app-btn-edit")).click();
Thread.sleep(1000);
driver.diffPage("page");
}
@Test
public void hostCreate() throws Throwable {
driver.get(server.getUrl("/registrar#host"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void hostView() throws Throwable {
driver.get(server.getUrl("/registrar#host/ns1.love.xn--q9jyb4c"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void hostEdit() throws Throwable {
driver.get(server.getUrl("/registrar#host/ns1.love.xn--q9jyb4c"));
driver.waitForElement(By.id("reg-app-btn-edit")).click();
Thread.sleep(1000);
driver.diffPage("page");
}
@Test
public void indexPage_smallScrolledDown() throws Throwable {
driver.manage().window().setSize(new Dimension(400, 300));

View file

@ -17,9 +17,7 @@ package google.registry.webdriver;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.server.Fixture.BASIC;
import static google.registry.server.Route.route;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.loadRegistrar;
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@ -31,7 +29,6 @@ import google.registry.model.registrar.RegistrarContact;
import google.registry.module.frontend.FrontendServlet;
import google.registry.server.RegistryTestServer;
import google.registry.testing.AppEngineRule;
import google.registry.ui.server.registrar.ConsoleUiAction;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
@ -55,7 +52,6 @@ public class RegistrarConsoleWebTest {
new TestServerRule.Builder()
.setRunfiles(RegistryTestServer.RUNFILES)
.setRoutes(
route("/registrar-xhr", FrontendServlet.class),
route("/registrar", FrontendServlet.class),
route("/registrar-settings", FrontendServlet.class))
.setFilters(ObjectifyFilter.class, OfyFilter.class)
@ -209,44 +205,4 @@ public class RegistrarConsoleWebTest {
.getAttribute("value"))
.isEqualTo(registrar.getPhonePasscode());
}
@Test
public void testHostCreate_hostIsAnSld_eppErrorShowsInButterBar() throws Throwable {
driver.get(server.getUrl("/registrar#host"));
driver.waitForElement(By.id("domain-host-addr-add-button")).click();
driver.setFormFieldsById(ImmutableMap.of(
"host:name", "empire.vampyre",
"host:addr[0].value", "1.2.3.4"));
driver.findElement(By.id("reg-app-btn-save")).click();
Thread.sleep(1000); // TODO(b/26129174): Change butterbar code to add/remove dynamically.
assertThat(getButterBarText())
.isEqualTo("Host names must be at least two levels below the registry suffix");
}
@Test
public void testHostCreate() throws Throwable {
server.runInAppEngineEnvironment(
() -> {
createTld("vampyre");
persistActiveDomain("empire.vampyre");
return null;
});
driver.get(server.getUrl("/registrar#host"));
driver.waitForElement(By.id("domain-host-addr-add-button")).click();
driver.setFormFieldsById(ImmutableMap.of(
"host:name", "the.empire.vampyre",
"host:addr[0].value", "1.2.3.4"));
driver.findElement(By.id("reg-app-btn-save")).click();
Thread.sleep(1000); // TODO(b/26129174): Change butterbar code to add/remove dynamically.
assertThat(getButterBarText()).isEqualTo("Saved.");
}
private String getButterBarText() {
return (String) driver.executeScript(
String.format("return document.querySelector('.%s').innerText", css("kd-butterbar-text")));
}
private static String css(String name) {
return ConsoleUiAction.CSS_RENAMING_MAP_SUPPLIER.get().get(name);
}
}