From a9df49329daaa58304425277abfe35f97bf9deee Mon Sep 17 00:00:00 2001 From: Alexander Lehmann Date: Fri, 5 May 2023 23:03:08 +0200 Subject: [PATCH 1/3] count user state --- pom.xml | 4 ---- .../cx/lehmann/gemini/gemini/MainVerticle.java | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index b3a15d5..ab29cb7 100644 --- a/pom.xml +++ b/pom.xml @@ -58,10 +58,6 @@ ${junit-jupiter.version} test - - io.netty - netty-tcnative-boringssl-static - org.slf4j diff --git a/src/main/java/cx/lehmann/gemini/gemini/MainVerticle.java b/src/main/java/cx/lehmann/gemini/gemini/MainVerticle.java index 87dc1a9..46a3f06 100644 --- a/src/main/java/cx/lehmann/gemini/gemini/MainVerticle.java +++ b/src/main/java/cx/lehmann/gemini/gemini/MainVerticle.java @@ -126,8 +126,8 @@ public class MainVerticle extends AbstractVerticle { String quotedMessage=decodedMessage.replace("\n", "\n "); for (NetSocket socket:clients) { - socket.write(clientHash+":"+quotedMessage+"\n"); - } + socket.write(clientHash+":"+quotedMessage+"\n"); + } } } catch (SSLPeerUnverifiedException | CertificateEncodingException | NoSuchAlgorithmException ex) { // ex.printStackTrace(); @@ -136,12 +136,23 @@ public class MainVerticle extends AbstractVerticle { conn.close(); } else { System.out.println("conn2"); + for (NetSocket socket:clients) { + socket.write("one client connected. count is "+(clients.size()+1)+"\n"); + } clients.add(conn); conn.write("20 text/gemini\r\n"); conn.write("to post messages, go to\n"); conn.write("=> post post page\n"); conn.write("preferably in a new window\n"); + conn.write("currently "+clients.size()+" reading clients are connected\n"); conn.write("chat start\n"); + conn.closeHandler(v -> { + System.out.println("a client closed"); + clients.remove(conn); + for (NetSocket socket:clients) { + socket.write("one client disconnected. count is "+clients.size()+"\n"); + } + }); } } } From 2b3376a89b2c0567719e3c157ab977d35d599a26 Mon Sep 17 00:00:00 2001 From: Alexander Lehmann Date: Sun, 7 May 2023 01:42:50 +0200 Subject: [PATCH 2/3] add start page with chat explanation --- .../lehmann/gemini/gemini/MainVerticle.java | 131 ++++++++++-------- 1 file changed, 74 insertions(+), 57 deletions(-) diff --git a/src/main/java/cx/lehmann/gemini/gemini/MainVerticle.java b/src/main/java/cx/lehmann/gemini/gemini/MainVerticle.java index 46a3f06..97b2fc9 100644 --- a/src/main/java/cx/lehmann/gemini/gemini/MainVerticle.java +++ b/src/main/java/cx/lehmann/gemini/gemini/MainVerticle.java @@ -41,18 +41,18 @@ public class MainVerticle extends AbstractVerticle { List clients=new ArrayList<>(); -// X509TrustManager tm=new MyTrustManager(); - + // X509TrustManager tm=new MyTrustManager(); + @Override public void start(Promise startPromise) throws Exception { NetServerOptions options=new NetServerOptions(); vertx.exceptionHandler(ex -> {ex.printStackTrace();}); - + // String certPath="c:/temp/cert.pem"; String certPath="/home/lehmann/gemini-chat/cert.pem"; - -// TrustOptions trustOptions=new MyTrustOptions(vertx); + + // TrustOptions trustOptions=new MyTrustOptions(vertx); TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore keystore=KeyStore.getInstance("JKS"); @@ -61,26 +61,26 @@ public class MainVerticle extends AbstractVerticle { TrustManager tms[] = trustMgrFactory.getTrustManagers(); TrustManager tm=tms[0]; - + TrustManager trustManager = new MyTrustManager(tm); options.setPemKeyCertOptions(new PemKeyCertOptions() .setCertPath(certPath) .setKeyPath(certPath)) .setSsl(true) -// .setTrustOptions(trustOptions) - .setTrustOptions(TrustOptions.wrap(trustManager)) + // .setTrustOptions(trustOptions) + .setTrustOptions(TrustOptions.wrap(trustManager)) -// .setOpenSslEngineOptions(new OpenSSLEngineOptions()) + // .setOpenSslEngineOptions(new OpenSSLEngineOptions()) .setClientAuth(ClientAuth.REQUEST) - ; + ; + + // SSLContext sc = SSLContext.getInstance("SSL"); + // sc.init(null, new X509TrustManager[] { tm }, null); + // HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); -// SSLContext sc = SSLContext.getInstance("SSL"); -// sc.init(null, new X509TrustManager[] { tm }, null); -// HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); - vertx.createNetServer(options).connectHandler(conn -> { conn.handler(event -> { - System.out.println(new Date().toString()+"accepted connection:"+conn.remoteAddress()); + System.out.println(new Date().toString()+" accepted connection:"+conn.remoteAddress()); String url=event.toString("UTF-8"); if(!url.endsWith("\r\n")) { conn.write("40 format error\r\n"); @@ -89,17 +89,34 @@ public class MainVerticle extends AbstractVerticle { url=url.substring(0, url.length()-2); System.out.println("url:"+url); String path=url.substring(9); - if(path.indexOf('/')>=0) { - path=path.substring(path.indexOf('/')); - } else { - path=""; - } + if(path.indexOf('/')>=0) { + path=path.substring(path.indexOf('/')); + } else { + path=""; + } System.out.println("path:"+path); - if(path.equals("")) { - conn.write("30 gemini://gemini.lehmann.cx:11965/\r\n"); - conn.close(); - } - else if(path.startsWith("/post")) { + if(path.equals("")) { + conn.write("30 gemini://gemini.lehmann.cx:11965/\r\n"); + conn.close(); + } + else if(path.equals("/")) { + conn.write("20 text/gemini\r\n"); + conn.write("# a very simple chat server\n"); + conn.write("the chat page loads indefintely (until the connection breaks at least)\n"); + conn.write("and shows chat messages sent by other users\n"); + conn.write("messages can be sent via the /post url and use the client certificate to authenticate\n"); + conn.write("currently the sha256 hash of the client cert is used as user-id\n"); + conn.write("\n"); + conn.write("the source code for the server is at\n"); + conn.write("=> https://tildegit.org/alexlehm/vertx-gemini-server\n"); + conn.write("the author of this chat is reachable via\n"); + conn.write("=> gemini://gemini.lehmann.cx/\n"); + conn.write("\n"); + conn.write("click on the link to get started\n"); + conn.write("=> /chat\n"); + conn.close(); + } + else if(path.startsWith("/post")) { System.out.println("post"); try { List certs = conn.peerCertificates(); @@ -115,22 +132,22 @@ public class MainVerticle extends AbstractVerticle { conn.write("message was sent\n"); conn.write("=> /post post another message\n"); - String decodedMessage; - try { - decodedMessage=URLDecoder.decode(message, "utf-8"); - } - catch(UnsupportedEncodingException ex) { - decodedMessage="error"; - } + String decodedMessage; + try { + decodedMessage=URLDecoder.decode(message, "utf-8"); + } + catch(UnsupportedEncodingException ex) { + decodedMessage="error"; + } - String quotedMessage=decodedMessage.replace("\n", "\n "); + String quotedMessage=decodedMessage.replace("\n", "\n "); - for (NetSocket socket:clients) { - socket.write(clientHash+":"+quotedMessage+"\n"); - } + for (NetSocket socket:clients) { + socket.write(clientHash+":"+quotedMessage+"\n"); + } } } catch (SSLPeerUnverifiedException | CertificateEncodingException | NoSuchAlgorithmException ex) { -// ex.printStackTrace(); + // ex.printStackTrace(); conn.write("60 cert required\r\n"); } conn.close(); @@ -156,25 +173,25 @@ public class MainVerticle extends AbstractVerticle { } } } - ); - }).listen(11965, server -> { - if (server.succeeded()) { - startPromise.complete(); - System.out.println("Gemini server started on port 11965 at "+new Date().toString()); - } else { - server.cause().printStackTrace(); - startPromise.fail(server.cause()); - } - }); - } + ); + }).listen(11965, server -> { + if (server.succeeded()) { + startPromise.complete(); + System.out.println("Gemini server started on port 11965 at "+new Date().toString()); + } else { + server.cause().printStackTrace(); + startPromise.fail(server.cause()); + } + }); + } - private static String getThumbprint(X509Certificate cert) - throws NoSuchAlgorithmException, CertificateEncodingException { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] der = cert.getEncoded(); - md.update(der); - byte[] digest = md.digest(); - String digestHex = DatatypeConverter.printHexBinary(digest); - return digestHex.toLowerCase(); - } + private static String getThumbprint(X509Certificate cert) + throws NoSuchAlgorithmException, CertificateEncodingException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] der = cert.getEncoded(); + md.update(der); + byte[] digest = md.digest(); + String digestHex = DatatypeConverter.printHexBinary(digest); + return digestHex.toLowerCase(); + } } From 85a080f4efc9d58252abfcfcc279af9979e110f8 Mon Sep 17 00:00:00 2001 From: Alexander Lehmann Date: Sun, 7 May 2023 01:48:03 +0200 Subject: [PATCH 3/3] add missing file --- .../lehmann/gemini/gemini/MyTrustManager.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/main/java/cx/lehmann/gemini/gemini/MyTrustManager.java diff --git a/src/main/java/cx/lehmann/gemini/gemini/MyTrustManager.java b/src/main/java/cx/lehmann/gemini/gemini/MyTrustManager.java new file mode 100644 index 0000000..d1094ce --- /dev/null +++ b/src/main/java/cx/lehmann/gemini/gemini/MyTrustManager.java @@ -0,0 +1,56 @@ +/** + * + */ +package cx.lehmann.gemini.gemini; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +/** + * @author Alexander Lehmann + * + */ +public class MyTrustManager implements X509TrustManager { + +// private final Logger LOGGER=LoggerFactory.getLogger(this.getClass()); + + final X509TrustManager tm; + + /** + * @param tm + */ + public MyTrustManager(TrustManager tm) { + this.tm=(X509TrustManager)tm; + } + + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { +// LOGGER.info("checkClientTrusted"); + System.out.println("checkClientTrusted"); + } + + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { +// LOGGER.info("checkServerTrusted"); + System.out.println("checkServerTrusted"); + } + +// X509Certificate certs[]= {}; + + @Override + public X509Certificate[] getAcceptedIssuers() { +// LOGGER.info("getAcceptedIssuers"); + System.out.println("getAcceptedIssuers"); + +// Exception ex=new Exception(); + +// ex.printStackTrace(); + + return tm.getAcceptedIssuers(); + } + + +}