Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter non defined rpc methods by name #2261

Merged
merged 5 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 44 additions & 6 deletions rskj-core/src/main/java/co/rsk/rpc/netty/JsonRpcCustomServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,27 @@
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.googlecode.jsonrpc4j.JsonResponse;
import com.googlecode.jsonrpc4j.JsonRpcBasicServer;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

import static co.rsk.jsonrpc.JsonRpcError.METHOD_NOT_FOUND;

public class JsonRpcCustomServer extends JsonRpcBasicServer {
public static final String METHOD_NOT_FOUND_MSG = "method not found";
private final List<ModuleDescription> modules;
private final Set<String> methodNames;
private final ObjectMapper objectMapper;

public JsonRpcCustomServer(final Object handler, final Class<?> remoteInterface, List<ModuleDescription> modules) {
super(new ObjectMapper(), handler, remoteInterface);
public JsonRpcCustomServer(final Object handler, final Class<?> remoteInterface, List<ModuleDescription> modules, ObjectMapper objetMapper) {
super(objetMapper, handler, remoteInterface);
this.modules = new ArrayList<>(modules);
this.methodNames = extractMethodNames(remoteInterface);
this.objectMapper = objetMapper;
}

@Override
Expand All @@ -44,7 +52,12 @@ protected JsonResponse handleJsonNodeRequest(final JsonNode node) throws JsonPar
return super.handleJsonNodeRequest(node);
}

String method = Optional.ofNullable(node.get("method")).map(JsonNode::asText).orElse("");
String method = Optional.ofNullable(node.get(METHOD)).map(JsonNode::asText).orElse("");

if(!methodNames.contains(method)) {
Object requestId = node.get(ID);
return buildError(requestId, METHOD_NOT_FOUND, METHOD_NOT_FOUND_MSG);
}

String[] methodParts = method.split("_");
JsonResponse response;
Expand Down Expand Up @@ -82,4 +95,29 @@ private long getTimeout(String moduleName, String methodName) {
}
return moduleDescription.getTimeout(methodName);
}

private Set<String> extractMethodNames(Class<?> remoteInterface) {
if (remoteInterface == null) {
return Collections.emptySet();
}

return Arrays.stream(remoteInterface.getMethods())
.map(Method::getName)
.collect(Collectors.toSet());
}

private JsonResponse buildError(Object id, int errorCode, String errorMessage) {
ObjectNode response = objectMapper.createObjectNode();
response.put(JSONRPC, VERSION);
if(id != null) {
response.set(ID, objectMapper.valueToTree(id));
}
ObjectNode error = objectMapper.createObjectNode();
error.put(ERROR_CODE, errorCode);
error.put(ERROR_MESSAGE, errorMessage);

response.set(ERROR, error);
return new JsonResponse(response, errorCode);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public class JsonRpcWeb3ServerHandler extends SimpleChannelInboundHandler<ByteBu
private final int maxResponseSize;

public JsonRpcWeb3ServerHandler(Web3 service, JsonRpcWeb3ServerProperties jsonRpcWeb3ServerProperties) {
this.jsonRpcServer = new JsonRpcCustomServer(service, service.getClass(), jsonRpcWeb3ServerProperties.getRpcModules());
this.jsonRpcServer = new JsonRpcCustomServer(service, service.getClass(), jsonRpcWeb3ServerProperties.getRpcModules(), mapper);
List<JsonRpcInterceptor> interceptors = new ArrayList<>();
interceptors.add(new JsonRpcRequestValidatorInterceptor(jsonRpcWeb3ServerProperties.getMaxBatchRequestsSize()));
jsonRpcServer.setInterceptorList(interceptors);
Expand Down Expand Up @@ -107,8 +107,6 @@ protected void channelRead0(ChannelHandlerContext ctx, ByteBufHolder request) th
int errorCode = ErrorResolver.JsonError.CUSTOM_SERVER_ERROR_LOWER;
responseContent = buildErrorContent(errorCode, unexpectedErrorMsg);
responseCode = errorCode;
} finally {
ReflectionUtil.clearCache();
}

ctx.fireChannelRead(new Web3Result(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class JsonRPCParamValidationTest {
@BeforeEach
void setUp() {
handler = mock(Web3EthModule.class);
this.jsonRpcServer = new JsonRpcCustomServer(handler, handler.getClass(), Collections.emptyList());
this.jsonRpcServer = new JsonRpcCustomServer(handler, handler.getClass(), Collections.emptyList(), objectMapper);
jsonRpcServer.setErrorResolver(new MultipleErrorResolver(new RskErrorResolver(), AnnotationsErrorResolver.INSTANCE, DefaultErrorResolver.INSTANCE));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void testHandleJsonNodeRequest() throws Exception {
JsonNode request = objectMapper.readTree(FIRST_METHOD_REQUEST);
String response = "test_method_response";
Web3Test handler = mock(Web3Test.class);
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, modules);
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, modules, objectMapper);

when(handler.test_first(anyString())).thenReturn(response);

Expand All @@ -72,7 +72,7 @@ void testHandleJsonNodeRequest_WithResponseLimit() throws Exception {
Web3Test handler = mock(Web3Test.class);
//expected response would be {"jsonrpc":"2.0","id":1,"result":"test_method_response"} with 56 bytes
ResponseSizeLimitContext.createResponseSizeContext(55);
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, modules);
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, modules, objectMapper);

when(handler.test_first(anyString())).thenReturn(response);

Expand All @@ -83,7 +83,7 @@ void testHandleJsonNodeRequest_WithResponseLimit() throws Exception {
void testHandleJsonNodeRequest_WithMethodModule() throws Exception {
JsonNode request = objectMapper.readTree(SECOND_METHOD_REQUEST);
Web3Test handler = mock(Web3Test.class);
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, getModulesWithMethodTimeout(0, 125));
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, getModulesWithMethodTimeout(0, 125), objectMapper);
String response = "test_method_response";

when(handler.test_second("param", "param2")).thenAnswer(invocation -> {
Expand All @@ -99,7 +99,7 @@ void testHandleJsonNodeRequest_WithMethodModule() throws Exception {
void testHandleJsonNodeRequest_WithMethodTimeout() throws Exception {
JsonNode request = objectMapper.readTree(SECOND_METHOD_REQUEST);
Web3Test handler = mock(Web3Test.class);
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, getModulesWithMethodTimeout(125, 0));
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, getModulesWithMethodTimeout(125, 0), objectMapper);

when(handler.test_second(anyString(), anyString())).thenAnswer(invocation -> {
waitFor(150);
Expand All @@ -113,7 +113,7 @@ void testHandleJsonNodeRequest_WithMethodTimeout() throws Exception {
void testHandleJsonNodeRequest_methodTimeoutOverModule() throws Exception {
JsonNode request = objectMapper.readTree(SECOND_METHOD_REQUEST);
Web3Test handler = mock(Web3Test.class);
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, getModulesWithMethodTimeout(500, 100));
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, getModulesWithMethodTimeout(500, 100), objectMapper);
String response = "test_method_response";

when(handler.test_second("param", "param2")).thenAnswer(invocation -> {
Expand Down Expand Up @@ -158,7 +158,7 @@ void testHandleJsonNodeRequest_WithMethodTimeout_BatchRequest_OK() throws Except
JsonNode request = objectMapper.readTree(jsonRequest);
Web3Test handler = mock(Web3Test.class);

jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, getModulesWithMethodTimeout(timeoutPerMethod, 0));
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, getModulesWithMethodTimeout(timeoutPerMethod, 0), objectMapper);

when(handler.test_second(anyString(), anyString())).thenAnswer(invocation -> {
waitFor(sleepTimePerRequest);
Expand Down Expand Up @@ -198,7 +198,7 @@ void testHandleJsonNodeRequest_WithMethodTimeout_BatchRequest_FAIL() throws Exce
JsonNode request = objectMapper.readTree(jsonRequest);
Web3Test handler = mock(Web3Test.class);

jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, getModulesWithMethodTimeout(timeoutPerMethod, 0));
jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, getModulesWithMethodTimeout(timeoutPerMethod, 0), objectMapper);

when(handler.test_second(anyString(), anyString())).thenAnswer(invocation -> {
waitFor(sleepTimePerRequest);
Expand All @@ -209,6 +209,25 @@ void testHandleJsonNodeRequest_WithMethodTimeout_BatchRequest_FAIL() throws Exce
verify(handler, times(1)).test_second(anyString(), anyString());
}

@Test
void sendingRequestWithNonDeclaredMethodShouldFail() throws Exception {
String jsonRequest = " {\n" +
" \"jsonrpc\": \"2.0\",\n" +
" \"method\": \"invalid_method\",\n" +
" \"params\": [],\n" +
" \"id\": 1\n" +
" }";

String expectedResponse = "{\"jsonrpc\":\"2.0\",\"id\":1,\"error\":{\"code\":-32601,\"message\":\"method not found\"}}";
JsonNode request = objectMapper.readTree(jsonRequest);
Web3Test handler = mock(Web3Test.class);

jsonRpcCustomServer = new JsonRpcCustomServer(handler, Web3Test.class, modules, objectMapper);

JsonResponse actualResponse = jsonRpcCustomServer.handleJsonNodeRequest(request);
assertEquals(expectedResponse, actualResponse.getResponse().toString());
}


public interface Web3Test {
String test_first(String param1);
Expand Down
Loading