diff --git a/java/google/registry/flows/BUILD b/java/google/registry/flows/BUILD index 325806d73..218dcbd40 100644 --- a/java/google/registry/flows/BUILD +++ b/java/google/registry/flows/BUILD @@ -4,6 +4,8 @@ package( licenses(["notice"]) # Apache 2.0 +load("@io_bazel_rules_closure//closure:defs.bzl", "closure_template_java_library") + filegroup( name = "flows_files", @@ -21,6 +23,7 @@ java_library( ]), visibility = ["//visibility:public"], deps = [ + ":soy_java_wrappers", "//java/com/google/common/annotations", "//java/com/google/common/base", "//java/com/google/common/collect", @@ -31,6 +34,7 @@ java_library( "//third_party/java/dagger", "//third_party/java/joda_money", "//third_party/java/joda_time", + "//third_party/java/json_simple", "//third_party/java/jsr305_annotations", "//third_party/java/jsr330_inject", "//third_party/java/objectify:objectify-v4_1", @@ -47,5 +51,14 @@ java_library( "//java/google/registry/tmch", "//java/google/registry/util", "//java/google/registry/xml", + "//third_party/java_src/soy/java/com/google/template/soy", + + "@io_bazel_rules_closure//closure/templates", ], ) + +closure_template_java_library( + name = "soy_java_wrappers", + srcs = glob(["soy/*.soy"]), + java_package = "google.registry.flows.soy", +) diff --git a/java/google/registry/ui/server/api/CheckApiAction.java b/java/google/registry/flows/CheckApiAction.java similarity index 68% rename from java/google/registry/ui/server/api/CheckApiAction.java rename to java/google/registry/flows/CheckApiAction.java index 1c5b7a0d3..572e3c475 100644 --- a/java/google/registry/ui/server/api/CheckApiAction.java +++ b/java/google/registry/flows/CheckApiAction.java @@ -12,40 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -package google.registry.ui.server.api; +package google.registry.flows; import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Strings.nullToEmpty; +import static com.google.common.io.Resources.getResource; import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN; -import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension.FEE_0_6; import static google.registry.model.registry.Registries.findTldForNameOrThrow; -import static google.registry.ui.server.SoyTemplateUtils.createTofuSupplier; import static google.registry.util.DomainNameUtils.canonicalizeDomainName; import static java.nio.charset.StandardCharsets.UTF_8; import static org.json.simple.JSONValue.toJSONString; -import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.net.InternetDomainName; import com.google.common.net.MediaType; +import com.google.template.soy.SoyFileSet; import com.google.template.soy.tofu.SoyTofu; import dagger.Module; import dagger.Provides; -import google.registry.config.RegistryEnvironment; -import google.registry.flows.EppException; -import google.registry.flows.EppRequestSource; -import google.registry.flows.FlowRunner; -import google.registry.flows.PasswordOnlyTransportCredentials; -import google.registry.flows.StatelessRequestSessionMetadata; -import google.registry.flows.domain.DomainCheckFlow; +import google.registry.config.RegistryConfig; +import google.registry.flows.soy.DomainCheckFeeEppSoyInfo; import google.registry.model.domain.fee.FeeCheckResponseExtension; import google.registry.model.domain.fee.FeeCheckResponseExtension.FeeCheck; -import google.registry.model.eppcommon.Trid; -import google.registry.model.eppinput.EppInput; import google.registry.model.eppoutput.CheckData.DomainCheck; import google.registry.model.eppoutput.CheckData.DomainCheckData; import google.registry.model.eppoutput.EppResponse; @@ -53,8 +45,6 @@ import google.registry.request.Action; import google.registry.request.Parameter; import google.registry.request.RequestParameters; import google.registry.request.Response; -import google.registry.ui.soy.api.DomainCheckFeeEppSoyInfo; -import google.registry.util.Clock; import google.registry.util.FormattingLogger; import java.util.Map; @@ -63,7 +53,7 @@ import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; /** - * A servlet that returns availability and premium checks as json. + * A servlet that returns availability and premium checks as JSON. * *

This action returns plain JSON without a safety prefix, so it's vital that the output not be * user controlled, lest it open an XSS vector. Do not modify this to return the domain name in the @@ -74,62 +64,60 @@ public class CheckApiAction implements Runnable { private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); - private static final Supplier TOFU_SUPPLIER = - createTofuSupplier(DomainCheckFeeEppSoyInfo.getInstance()); - - private final StatelessRequestSessionMetadata sessionMetadata = - new StatelessRequestSessionMetadata( - RegistryEnvironment.get().config().getCheckApiServletRegistrarClientId(), - ImmutableSet.of(FEE_0_6.getUri())); + private static final SoyTofu TOFU = + SoyFileSet.builder().add(getResource(DomainCheckFeeEppSoyInfo.class, + DomainCheckFeeEppSoyInfo.getInstance().getFileName())).build().compileToTofu(); @Inject @Parameter("domain") String domain; @Inject Response response; - @Inject Clock clock; + @Inject EppController eppController; + @Inject RegistryConfig config; @Inject CheckApiAction() {} @Override public void run() { - Map checkResponse = doCheck(domain); response.setHeader("Content-Disposition", "attachment"); response.setHeader("X-Content-Type-Options", "nosniff"); response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN, "*"); response.setContentType(MediaType.JSON_UTF_8); - response.setPayload(toJSONString(checkResponse)); + response.setPayload(toJSONString(doCheck())); } - // TODO(rgr): add whitebox instrumentation for this? - private Map doCheck(String domainString) { + private Map doCheck() { + String domainString; try { - domainString = canonicalizeDomainName(nullToEmpty(domainString)); + domainString = canonicalizeDomainName(nullToEmpty(domain)); // Validate the TLD. findTldForNameOrThrow(InternetDomainName.from(domainString)); } catch (IllegalStateException | IllegalArgumentException e) { return fail("Must supply a valid domain name on an authoritative TLD"); } try { - byte[] inputXmlBytes = TOFU_SUPPLIER.get() + byte[] inputXml = TOFU .newRenderer(DomainCheckFeeEppSoyInfo.DOMAINCHECKFEE) .setData(ImmutableMap.of("domainName", domainString)) .render() .getBytes(UTF_8); - EppResponse response = new FlowRunner( - DomainCheckFlow.class, - unmarshal(EppInput.class, inputXmlBytes), - Trid.create(getClass().getSimpleName()), - sessionMetadata, - new PasswordOnlyTransportCredentials(), - EppRequestSource.CHECK_API, - false, - false, - inputXmlBytes, - null, - clock) - .run() - .getResponse(); + SessionMetadata sessionMetadata = new StatelessRequestSessionMetadata( + config.getCheckApiServletRegistrarClientId(), + ImmutableSet.of(FEE_0_6.getUri())); + EppResponse response = eppController + .handleEppCommand( + sessionMetadata, + new PasswordOnlyTransportCredentials(), + EppRequestSource.CHECK_API, + false, // This endpoint is never a dry run. + false, // This endpoint is never a superuser. + inputXml) + .getResponse(); + if (!response.getResult().getCode().isSuccess()) { + return fail(response.getResult().getMsg()); + } DomainCheckData checkData = (DomainCheckData) response.getResponseData().get(0); DomainCheck check = (DomainCheck) checkData.getChecks().get(0); boolean available = check.getName().getAvail(); - ImmutableMap.Builder builder = new ImmutableMap.Builder() + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + builder .put("status", "success") .put("available", available); if (available) { @@ -141,16 +129,14 @@ public class CheckApiAction implements Runnable { builder.put("reason", check.getReason()); } return builder.build(); - } catch (EppException e) { - return fail(e.getMessage()); } catch (Exception e) { logger.warning(e, "Unknown error"); return fail("Invalid request"); } } - private Map fail(String reason) { - return ImmutableMap.of( + private Map fail(String reason) { + return ImmutableMap.of( "status", "error", "reason", reason); } diff --git a/java/google/registry/flows/EppController.java b/java/google/registry/flows/EppController.java index f6a334323..5a308adba 100644 --- a/java/google/registry/flows/EppController.java +++ b/java/google/registry/flows/EppController.java @@ -14,7 +14,6 @@ package google.registry.flows; -import static google.registry.flows.EppXmlTransformer.marshalWithLenientRetry; import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.flows.picker.FlowPicker.getFlowClass; @@ -47,11 +46,8 @@ public final class EppController { @Inject EppMetrics metrics; @Inject EppController() {} - /** - * Read an EPP envelope from the client, find the matching flow, execute it, and return - * the response marshalled to a byte array. - */ - public byte[] handleEppCommand( + /** Read EPP XML, execute the matching flow, and return an {@link EppOutput}. */ + public EppOutput handleEppCommand( SessionMetadata sessionMetadata, TransportCredentials credentials, EppRequestSource eppRequestSource, @@ -85,17 +81,16 @@ public final class EppController { if (eppOutput.isResponse()) { metrics.setEppStatus(eppOutput.getResponse().getResult().getCode()); } - return marshalWithLenientRetry(eppOutput); + return eppOutput; } catch (EppException e) { // The command failed. Send the client an error message. metrics.setEppStatus(e.getResult().getCode()); - return marshalWithLenientRetry(getErrorResponse(clock, e.getResult(), trid)); + return getErrorResponse(clock, e.getResult(), trid); } catch (Throwable e) { // Something bad and unexpected happened. Send the client a generic error, and log it. logger.severe(e, "Unexpected failure"); metrics.setEppStatus(Code.CommandFailed); - return marshalWithLenientRetry( - getErrorResponse(clock, Result.create(Code.CommandFailed), trid)); + return getErrorResponse(clock, Result.create(Code.CommandFailed), trid); } finally { metrics.export(); } diff --git a/java/google/registry/flows/EppRequestHandler.java b/java/google/registry/flows/EppRequestHandler.java index 974c3598c..274c5df73 100644 --- a/java/google/registry/flows/EppRequestHandler.java +++ b/java/google/registry/flows/EppRequestHandler.java @@ -15,6 +15,7 @@ package google.registry.flows; +import static google.registry.flows.EppXmlTransformer.marshalWithLenientRetry; import static java.nio.charset.StandardCharsets.UTF_8; import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import static javax.servlet.http.HttpServletResponse.SC_OK; @@ -48,13 +49,15 @@ public class EppRequestHandler { byte[] inputXmlBytes) { try { response.setPayload(new String( - eppController.handleEppCommand( - sessionMetadata, - credentials, - eppRequestSource, - isDryRun, - isSuperuser, - inputXmlBytes), UTF_8)); + marshalWithLenientRetry( + eppController.handleEppCommand( + sessionMetadata, + credentials, + eppRequestSource, + isDryRun, + isSuperuser, + inputXmlBytes)), + UTF_8)); response.setContentType(APPLICATION_EPP_XML); // Note that we always return 200 (OK) even if the EppController returns an error response. // This is because returning an non-OK HTTP status code will cause the proxy server to diff --git a/java/google/registry/ui/soy/api/DomainCheckFeeEpp.soy b/java/google/registry/flows/soy/DomainCheckFeeEpp.soy similarity index 90% rename from java/google/registry/ui/soy/api/DomainCheckFeeEpp.soy rename to java/google/registry/flows/soy/DomainCheckFeeEpp.soy index 5141113c4..4c8b00a75 100644 --- a/java/google/registry/ui/soy/api/DomainCheckFeeEpp.soy +++ b/java/google/registry/flows/soy/DomainCheckFeeEpp.soy @@ -1,10 +1,8 @@ {namespace registry.soy.api autoescape="strict"} -/** - * Domain check fee request for one domain - * @param domainName - */ +/** Domain check fee request for one domain. */ {template .domaincheckfee} +{@param domainName: string} diff --git a/java/google/registry/module/frontend/BUILD b/java/google/registry/module/frontend/BUILD index d074baeb5..89f47715e 100644 --- a/java/google/registry/module/frontend/BUILD +++ b/java/google/registry/module/frontend/BUILD @@ -24,7 +24,6 @@ java_library( "//java/google/registry/request", "//java/google/registry/request:modules", "//java/google/registry/ui", - "//java/google/registry/ui/server/api", "//java/google/registry/ui/server/registrar", "//java/google/registry/util", "//java/google/registry/whois", @@ -40,7 +39,6 @@ java_binary( create_executable = 0, runtime_deps = [ ":frontend", - "//java/google/registry/ui/server/api", # CheckApiServlet "//java/google/registry/ui/server/registrar", # ResourceServlet ], ) diff --git a/java/google/registry/module/frontend/FrontendRequestComponent.java b/java/google/registry/module/frontend/FrontendRequestComponent.java index 3977f63d4..8a20712bb 100644 --- a/java/google/registry/module/frontend/FrontendRequestComponent.java +++ b/java/google/registry/module/frontend/FrontendRequestComponent.java @@ -16,6 +16,8 @@ package google.registry.module.frontend; import dagger.Subcomponent; +import google.registry.flows.CheckApiAction; +import google.registry.flows.CheckApiAction.CheckApiModule; import google.registry.flows.EppConsoleAction; import google.registry.flows.EppTlsAction; import google.registry.flows.TlsCredentials.EppTlsModule; @@ -31,8 +33,6 @@ import google.registry.rdap.RdapNameserverAction; import google.registry.rdap.RdapNameserverSearchAction; import google.registry.request.RequestModule; import google.registry.request.RequestScope; -import google.registry.ui.server.api.CheckApiAction; -import google.registry.ui.server.api.CheckApiAction.CheckApiModule; import google.registry.ui.server.registrar.ConsoleUiAction; import google.registry.ui.server.registrar.RegistrarPaymentAction; import google.registry.ui.server.registrar.RegistrarPaymentSetupAction; diff --git a/java/google/registry/ui/BUILD b/java/google/registry/ui/BUILD index d1d74f8c4..03af8eb17 100644 --- a/java/google/registry/ui/BUILD +++ b/java/google/registry/ui/BUILD @@ -18,7 +18,6 @@ filegroup( "//java/google/registry/ui/js:js_files", "//java/google/registry/ui/js/registrar:js_files", "//java/google/registry/ui/soy:js_files", - "//java/google/registry/ui/soy/api:js_files", "//java/google/registry/ui/soy/registrar:js_files", ], ) diff --git a/java/google/registry/ui/server/api/BUILD b/java/google/registry/ui/server/api/BUILD deleted file mode 100644 index e2a5c7210..000000000 --- a/java/google/registry/ui/server/api/BUILD +++ /dev/null @@ -1,29 +0,0 @@ -package(default_visibility = ["//java/google/registry:registry_project"]) - -licenses(["notice"]) # Apache 2.0 - - -java_library( - name = "api", - srcs = glob(["*.java"]), - deps = [ - "//java/com/google/common/annotations", - "//java/com/google/common/base", - "//java/com/google/common/collect", - "//java/com/google/common/net", - "//third_party/java/dagger", - "//third_party/java/jsr330_inject", - "//java/google/registry/config", - "//java/google/registry/flows", - "//java/google/registry/model", - "//java/google/registry/request", - "//java/google/registry/ui/server", - "//java/google/registry/ui/soy/api:soy_java_wrappers", - "//java/google/registry/util", - "//third_party/java/json_simple", - "//third_party/java/jsr305_annotations", - "//third_party/java/servlet/servlet_api", - - "@io_bazel_rules_closure//closure/templates", - ], -) diff --git a/java/google/registry/ui/server/api/package-info.java b/java/google/registry/ui/server/api/package-info.java deleted file mode 100644 index 849951978..000000000 --- a/java/google/registry/ui/server/api/package-info.java +++ /dev/null @@ -1,16 +0,0 @@ -// 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. - -@javax.annotation.ParametersAreNonnullByDefault -package google.registry.ui.server.api; diff --git a/java/google/registry/ui/soy/api/BUILD b/java/google/registry/ui/soy/api/BUILD deleted file mode 100644 index 859800c5a..000000000 --- a/java/google/registry/ui/soy/api/BUILD +++ /dev/null @@ -1,23 +0,0 @@ -package(default_visibility = ["//java/google/registry:registry_project"]) - -licenses(["notice"]) # Apache 2.0 - -load("@io_bazel_rules_closure//closure:defs.bzl", "closure_template_java_library", "closure_template_js_library") - - -filegroup( - name = "js_files", - srcs = ["DomainCheckFeeEpp.soy.js"], -) - -closure_template_java_library( - name = "soy_java_wrappers", - srcs = glob(["*.soy"]), - java_package = "google.registry.ui.soy.api", -) - -closure_template_js_library( - name = "DomainCheckFeeEpp", - srcs = ["DomainCheckFeeEpp.soy"], - globals = "//java/google/registry/ui:globals.txt", -) diff --git a/javatests/google/registry/flows/BUILD b/javatests/google/registry/flows/BUILD index 5040d2925..71e4893d8 100644 --- a/javatests/google/registry/flows/BUILD +++ b/javatests/google/registry/flows/BUILD @@ -33,6 +33,7 @@ java_library( "//third_party/java/appengine:appengine-testing", "//third_party/java/joda_money", "//third_party/java/joda_time", + "//third_party/java/json_simple", "//third_party/java/jsr305_annotations", "//third_party/java/junit", "//third_party/java/mockito", @@ -48,8 +49,6 @@ java_library( "//java/google/registry/monitoring/whitebox", "//java/google/registry/pricing", "//java/google/registry/request", - "//java/google/registry/security", - "//java/google/registry/security:servlets", "//java/google/registry/tmch", "//java/google/registry/util", "//java/google/registry/xml", diff --git a/javatests/google/registry/ui/server/api/CheckApiActionTest.java b/javatests/google/registry/flows/CheckApiActionTest.java similarity index 93% rename from javatests/google/registry/ui/server/api/CheckApiActionTest.java rename to javatests/google/registry/flows/CheckApiActionTest.java index c15084ace..03be4f757 100644 --- a/javatests/google/registry/ui/server/api/CheckApiActionTest.java +++ b/javatests/google/registry/flows/CheckApiActionTest.java @@ -12,18 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -package google.registry.ui.server.api; +package google.registry.flows; import static com.google.common.truth.Truth.assertThat; import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.persistActiveDomain; import static google.registry.testing.DatastoreHelper.persistReservedList; import static google.registry.testing.DatastoreHelper.persistResource; +import static org.mockito.Mockito.mock; import com.google.common.collect.ImmutableSet; +import google.registry.config.RegistryEnvironment; import google.registry.model.registrar.Registrar; import google.registry.model.registry.Registry; +import google.registry.monitoring.whitebox.EppMetrics; import google.registry.testing.AppEngineRule; import google.registry.testing.FakeResponse; import google.registry.util.SystemClock; @@ -62,7 +65,10 @@ public class CheckApiActionTest { private Map getCheckResponse(String domain) { action.domain = domain; action.response = new FakeResponse(); - action.clock = new SystemClock(); + action.config = RegistryEnvironment.UNITTEST.config(); + action.eppController = new EppController(); + action.eppController.clock = new SystemClock(); + action.eppController.metrics = mock(EppMetrics.class); action.run(); return (Map) JSONValue.parse(((FakeResponse) action.response).getPayload()); } diff --git a/javatests/google/registry/server/BUILD b/javatests/google/registry/server/BUILD index d0dc5d80c..0e391cba3 100644 --- a/javatests/google/registry/server/BUILD +++ b/javatests/google/registry/server/BUILD @@ -54,10 +54,8 @@ java_library( "//java/com/google/common/net", "//third_party/java/jsr305_annotations", "//third_party/java/servlet/servlet_api", - "//java/google/registry/flows", "//java/google/registry/module/backend", "//java/google/registry/module/frontend", - "//java/google/registry/ui/server/api", "//java/google/registry/ui/server/registrar", ], ) diff --git a/javatests/google/registry/ui/server/api/BUILD b/javatests/google/registry/ui/server/api/BUILD deleted file mode 100644 index b9b6c4f2f..000000000 --- a/javatests/google/registry/ui/server/api/BUILD +++ /dev/null @@ -1,33 +0,0 @@ -package( - default_testonly = 1, - default_visibility = ["//java/google/registry:registry_project"], -) - -licenses(["notice"]) # Apache 2.0 - -load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules") - - -java_library( - name = "api", - srcs = glob(["*.java"]), - deps = [ - "//java/com/google/common/collect", - "//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", - "//java/google/registry/model", - "//java/google/registry/ui/server/api", - "//java/google/registry/util", - "//javatests/google/registry/testing", - ], -) - -GenTestRules( - name = "GeneratedTestRules", - test_files = glob(["*Test.java"]), - deps = [":api"], -)