blob: 9d8527d612b2633fdd984bbe9df899a1b207e786 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
* file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
* to You 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 org.apache.tuweni.scuttlebutt.rpc;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.concurrent.AsyncResult;
import org.apache.tuweni.crypto.sodium.Signature;
import org.apache.tuweni.io.Base64;
import org.apache.tuweni.junit.VertxExtension;
import org.apache.tuweni.junit.VertxInstance;
import org.apache.tuweni.scuttlebutt.handshake.vertx.ClientHandler;
import org.apache.tuweni.scuttlebutt.handshake.vertx.SecureScuttlebuttVertxClient;
import java.io.BufferedWriter;
import java.io.File;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.function.Consumer;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import io.vertx.core.Vertx;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.logl.Level;
import org.logl.LoggerProvider;
import org.logl.logl.SimpleLogger;
import org.logl.vertx.LoglLogDelegateFactory;
/**
* Test used with a local installation of Patchwork on the developer machine.
* <p>
* Usable as a demo or to check manually connections.
*/
@ExtendWith(VertxExtension.class)
class PatchworkIntegrationTest {
public static class MyClientHandler implements ClientHandler {
private final Consumer<Bytes> sender;
private final Runnable terminationFn;
public MyClientHandler(Consumer<Bytes> sender, Runnable terminationFn) {
this.sender = sender;
this.terminationFn = terminationFn;
}
@Override
public void receivedMessage(Bytes message) {
RPCMessage rpcMessage = new RPCMessage(message);
System.out.println(rpcMessage.asString());
}
@Override
public void streamClosed() {
System.out.println("Stream closed?");
}
void sendMessage(Bytes bytes) {
System.out.println("Sending message?");
sender.accept(bytes);
}
void closeStream() {
terminationFn.run();
}
}
@Disabled
@Test
void runWithPatchWork(@VertxInstance Vertx vertx) throws Exception {
String host = "localhost";
int port = 8008;
LoggerProvider loggerProvider = SimpleLogger.withLogLevel(Level.DEBUG).toPrintWriter(
new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out, UTF_8))));
LoglLogDelegateFactory.setProvider(loggerProvider);
Optional<String> ssbDir = Optional.fromNullable(System.getenv().get("ssb_dir"));
Optional<String> homePath =
Optional.fromNullable(System.getProperty("user.home")).transform(home -> home + "/.ssb");
Optional<String> path = ssbDir.or(homePath);
if (!path.isPresent()) {
throw new Exception("Cannot find ssb directory config value");
}
String secretPath = path.get() + "/secret";
File file = new File(secretPath);
if (!file.exists()) {
throw new Exception("Secret file does not exist");
}
Scanner s = new Scanner(file, UTF_8.name());
s.useDelimiter("\n");
ArrayList<String> list = new ArrayList<String>();
while (s.hasNext()) {
String next = s.next();
// Filter out the comment lines
if (!next.startsWith("#")) {
list.add(next);
}
}
String secretJSON = String.join("", list);
ObjectMapper mapper = new ObjectMapper();
HashMap<String, String> values = mapper.readValue(secretJSON, new TypeReference<Map<String, String>>() {});
String pubKey = values.get("public").replace(".ed25519", "");
String privateKey = values.get("private").replace(".ed25519", "");
Bytes pubKeyBytes = Base64.decode(pubKey);
Bytes privKeyBytes = Base64.decode(privateKey);
Signature.PublicKey pub = Signature.PublicKey.fromBytes(pubKeyBytes);
Signature.SecretKey secretKey = Signature.SecretKey.fromBytes(privKeyBytes);
Signature.KeyPair keyPair = new Signature.KeyPair(pub, secretKey);
String networkKeyBase64 = "1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s=";
String serverPublicKey = pubKey; // TODO use your own identity public key here.
Signature.PublicKey publicKey = Signature.PublicKey.fromBytes(Base64.decode(serverPublicKey));
Bytes32 networkKeyBytes32 = Bytes32.wrap(Base64.decode(networkKeyBase64));
SecureScuttlebuttVertxClient secureScuttlebuttVertxClient =
new SecureScuttlebuttVertxClient(loggerProvider, vertx, keyPair, networkKeyBytes32);
AsyncResult<ClientHandler> onConnect =
secureScuttlebuttVertxClient.connectTo(port, host, publicKey, MyClientHandler::new);
MyClientHandler clientHandler = (MyClientHandler) onConnect.get();
assertTrue(onConnect.isDone());
assertFalse(onConnect.isCompletedExceptionally());
Thread.sleep(1000);
assertNotNull(clientHandler);
// An RPC command that just tells us our public key (like ssb-server whoami on the command line.)
String rpcRequestBody = "{\"name\": [\"whoami\"],\"type\": \"async\",\"args\":[]}";
Bytes rpcRequest = RPCCodec.encodeRequest(rpcRequestBody, RPCFlag.BodyType.JSON);
System.out.println("Attempting RPC request...");
clientHandler.sendMessage(rpcRequest);
for (int i = 0; i < 10; i++) {
clientHandler.sendMessage(RPCCodec.encodeRequest(rpcRequestBody, RPCFlag.BodyType.JSON));
}
Thread.sleep(10000);
secureScuttlebuttVertxClient.stop().join();
}
}