Skip to content

Commit

Permalink
Gracefully dealing with bad input (Consensys#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
CjHare authored Mar 28, 2019
1 parent dfd1367 commit 4db65be
Show file tree
Hide file tree
Showing 25 changed files with 1,400 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import static io.restassured.RestAssured.given;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.emptyMap;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.mockserver.integration.ClientAndServer.startClientAndServer;
Expand All @@ -24,6 +25,10 @@
import static org.web3j.utils.Async.defaultExecutorService;

import tech.pegasys.ethfirewall.Runner;
import tech.pegasys.ethfirewall.jsonrpcproxy.model.EthFirewallRequest;
import tech.pegasys.ethfirewall.jsonrpcproxy.model.EthFirewallResponse;
import tech.pegasys.ethfirewall.jsonrpcproxy.model.EthNodeRequest;
import tech.pegasys.ethfirewall.jsonrpcproxy.model.EthNodeResponse;
import tech.pegasys.ethfirewall.signing.ChainIdProvider;
import tech.pegasys.ethfirewall.signing.ConfigurationChainId;
import tech.pegasys.ethfirewall.signing.TransactionSigner;
Expand All @@ -38,12 +43,12 @@
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.Resources;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.restassured.RestAssured;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.json.Json;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
Expand All @@ -54,19 +59,20 @@
import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.JsonRpc2_0Web3j;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.Response;

public class IntegrationTestBase {

private static final Logger LOG = LoggerFactory.getLogger(IntegrationTestBase.class);

private static final String LOCALHOST = "127.0.0.1";

private static Runner runner;
private static ClientAndServer ethNode;
private ObjectMapper objectMapper = new ObjectMapper();
JsonRpc2_0Web3j jsonRpc;

private JsonRpc2_0Web3j jsonRpc;

@BeforeClass
public static void setupEthFirewall() throws IOException, CipherException {
Expand Down Expand Up @@ -97,6 +103,10 @@ public static void setupEthFirewall() throws IOException, CipherException {
serverSocket.close();
}

protected Web3j jsonRpc() {
return jsonRpc;
}

@SuppressWarnings("UnstableApiUsage")
private static File createKeyFile() throws IOException {
final URL walletResource = Resources.getResource("keyfile.json");
Expand All @@ -119,44 +129,83 @@ public static void teardown() {
runner.stop();
}

public void configureEthNode(
public void setUpEthNodeResponse(final EthNodeRequest request, final EthNodeResponse response) {
final List<Header> headers = convertHeadersToMockServerHeaders(response.getHeaders());
ethNode
.when(request().withBody(json(request.getBody())), exactly(1))
.respond(
response()
.withBody(response.getBody())
.withHeaders(headers)
.withStatusCode(response.getStatusCode()));
}

public void setUpEthNodeResponse(
final EthFirewallRequest request,
final Object response,
final Map<String, String> responseHeaders,
final HttpResponseStatus status) {
final String responseBody = Json.encode(response);
final List<Header> headers = convertHeadersToMockServerHeaders(responseHeaders);
ethNode
.when(request().withBody(json(request.getBody())), exactly(1))
.respond(
response().withBody(responseBody).withHeaders(headers).withStatusCode(status.code()));
}

public void setUpEthNodeResponse(
final Request<?, ? extends Response<?>> request,
final Object response,
final Map<String, String> responseHeaders,
final int responseStatusCode)
throws JsonProcessingException {
final String requestBody = objectMapper.writeValueAsString(request);
final String responseBody = objectMapper.writeValueAsString(response);
List<Header> headers = convertHeadersToMockServerHeaders(responseHeaders);
final HttpResponseStatus status) {
final String requestBody = Json.encode(request);
final String responseBody = Json.encode(response);
final List<Header> headers = convertHeadersToMockServerHeaders(responseHeaders);
ethNode
.when(request().withBody(json(requestBody)), exactly(1))
.respond(
response()
.withBody(responseBody)
.withHeaders(headers)
.withStatusCode(responseStatusCode));
response().withBody(responseBody).withHeaders(headers).withStatusCode(status.code()));
}

public void sendRequestAndVerify(
final Request<?, ? extends Response<?>> proxyBodyRequest,
final Map<String, String> proxyHeaders,
final Object response,
final int ethNodeStatusCode,
final Map<String, String> ethNodeHeaders)
throws JsonProcessingException {
String responseBody = objectMapper.writeValueAsString(response);
public void sendVerifyingResponse(
final EthFirewallRequest request, final EthFirewallResponse expectResponse) {
given()
.when()
.body(request.getBody())
.headers(request.getHeaders())
.post()
.then()
.statusCode(expectResponse.getStatusCode())
.body(equalTo(expectResponse.getBody()))
.headers(expectResponse.getHeaders());
}

public void sendVerifyingResponse(
final Request<?, ? extends Response<?>> request,
final Map<String, String> requestHeaders,
final Object expectResponse,
final HttpResponseStatus expectStatus,
final Map<String, String> expectHeaders) {
final String responseBody = Json.encode(expectResponse);
given()
.when()
.body(proxyBodyRequest)
.headers(proxyHeaders)
.body(request)
.headers(requestHeaders)
.post()
.then()
.statusCode(ethNodeStatusCode)
.statusCode(expectStatus.code())
.body(equalTo(responseBody))
.headers(ethNodeHeaders);
.headers(expectHeaders);
}

public void verifyEthereumNodeReceived(final Request<?, ? extends Response<?>> proxyBodyRequest) {
ethNode.verify(
request()
.withBody(json(proxyBodyRequest))
.withHeaders(convertHeadersToMockServerHeaders(emptyMap())));
}

public void verifyEthNodeRequest(
public void verifyEthereumNodeReceived(
final Request<?, ? extends Response<?>> proxyBodyRequest,
final Map<String, String> proxyHeaders) {
ethNode.verify(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Map;

import com.google.common.collect.ImmutableMap;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.junit.Test;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.Response;
Expand All @@ -29,30 +30,41 @@
public class ProxyIntegrationTest extends IntegrationTestBase {

@Test
public void requestWithHeadersIsProxied() throws Exception {
final Request<?, NetVersion> netVersionRequest = jsonRpc.netVersion();
public void requestWithHeadersIsProxied() {
final Request<?, NetVersion> netVersionRequest = jsonRpc().netVersion();
final Response<String> netVersionResponse = new NetVersion();
netVersionResponse.setResult("4");

final Map<String, String> requestHeaders = ImmutableMap.of("Accept", "*/*");
final Map<String, String> responseHeaders = ImmutableMap.of("Content-Type", "Application/Json");

configureEthNode(netVersionRequest, netVersionResponse, responseHeaders, 200);
sendRequestAndVerify(
netVersionRequest, requestHeaders, netVersionResponse, 200, responseHeaders);
verifyEthNodeRequest(netVersionRequest, requestHeaders);
setUpEthNodeResponse(
netVersionRequest, netVersionResponse, responseHeaders, HttpResponseStatus.OK);
sendVerifyingResponse(
netVersionRequest,
requestHeaders,
netVersionResponse,
HttpResponseStatus.OK,
responseHeaders);
verifyEthereumNodeReceived(netVersionRequest, requestHeaders);
}

@Test
public void requestReturningErrorIsProxied() throws Exception {
final Request<?, EthProtocolVersion> ethProtocolVersionRequest = jsonRpc.ethProtocolVersion();
configureEthNode(ethProtocolVersionRequest, "Not Found", emptyMap(), 404);
sendRequestAndVerify(ethProtocolVersionRequest, emptyMap(), "Not Found", 404, emptyMap());
verifyEthNodeRequest(ethProtocolVersionRequest, emptyMap());
public void requestReturningErrorIsProxied() {
final Request<?, EthProtocolVersion> ethProtocolVersionRequest = jsonRpc().ethProtocolVersion();
setUpEthNodeResponse(
ethProtocolVersionRequest, "Not Found", emptyMap(), HttpResponseStatus.NOT_FOUND);
sendVerifyingResponse(
ethProtocolVersionRequest,
emptyMap(),
"Not Found",
HttpResponseStatus.NOT_FOUND,
emptyMap());
verifyEthereumNodeReceived(ethProtocolVersionRequest);
}

@Test
public void requestWithSendTransactionIsSignedBeforeProxying() throws Exception {
public void requestWithSendTransactionIsSignedBeforeProxying() {
final Transaction transaction =
new Transaction(
"0xb60e8dd61c5d32be8058bb8eb970870f07233155",
Expand All @@ -64,22 +76,31 @@ public void requestWithSendTransactionIsSignedBeforeProxying() throws Exception
new BigInteger("2441406250"),
"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675");
final Request<?, ? extends Response<?>> ethSendTransactionRequest =
jsonRpc.ethSendTransaction(transaction);
jsonRpc().ethSendTransaction(transaction);
ethSendTransactionRequest.setId(5);

Request<?, ? extends Response<?>> ethSendRawTransactionRequest =
jsonRpc.ethSendRawTransaction(
"0xf8b2a0e04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f28609184e72a0008276c094d46e8dd67c5d32be8058bb8eb970870f07244567849184e72aa9d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f07244567535a0f04e0e7b41adea417596550611138a3ec9a452abb6648d734107c53476e76a27a05b826d9e9b4e0dd0e7b8939c102a2079d71cfc27cd6b7bebe5a006d5ad17d780");
jsonRpc()
.ethSendRawTransaction(
"0xf8b2a0e04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f28609184e72a0008276c094d46e8dd67c5d32be8058bb8eb970870f07244567849184e72aa9d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f07244567535a0f04e0e7b41adea417596550611138a3ec9a452abb6648d734107c53476e76a27a05b826d9e9b4e0dd0e7b8939c102a2079d71cfc27cd6b7bebe5a006d5ad17d780");
// we create the eth_sendRawTransaction req with same id as the eth_sendTransaction req
ethSendRawTransactionRequest.setId(5);

Response<String> ethSendRawTransactionResponse = new EthSendTransaction();
ethSendRawTransactionResponse.setResult(
"0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331");

configureEthNode(ethSendRawTransactionRequest, ethSendRawTransactionResponse, emptyMap(), 200);
sendRequestAndVerify(
ethSendTransactionRequest, emptyMap(), ethSendRawTransactionResponse, 200, emptyMap());
verifyEthNodeRequest(ethSendRawTransactionRequest, emptyMap());
setUpEthNodeResponse(
ethSendRawTransactionRequest,
ethSendRawTransactionResponse,
emptyMap(),
HttpResponseStatus.OK);
sendVerifyingResponse(
ethSendTransactionRequest,
emptyMap(),
ethSendRawTransactionResponse,
HttpResponseStatus.OK,
emptyMap());
verifyEthereumNodeReceived(ethSendRawTransactionRequest);
}
}
Loading

0 comments on commit 4db65be

Please sign in to comment.