add fabric client

This commit is contained in:
1e99 2024-11-17 14:37:10 +01:00
parent 13315e708c
commit 1aabd0f3cf
4 changed files with 117 additions and 27 deletions

View file

@ -1,18 +1,45 @@
package eu.e99.svc.client.fabric; package eu.e99.svc.client.fabric;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.session.Session;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLSocketFactory;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
public class FabricSimplerVoiceChat implements ClientModInitializer { public class FabricSimplerVoiceChat implements ClientModInitializer {
public static final String NAMESPACE = "svc"; public static final String NAMESPACE = "svc";
public static final Logger LOGGER = LoggerFactory.getLogger(NAMESPACE);
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
LOGGER.info("Simpler Voice Chat Running"); System.out.printf("Simpler Voice Chat loading...%n");
SSLSocketFactory socketFactory;
try {
socketFactory = SVCClient.createSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
System.out.printf("Failed to create socket factory:%n");
e.printStackTrace(System.out);
return;
}
MinecraftClient client = MinecraftClient.getInstance();
Session session = client.getSession();
SVCClient voiceChat = new SVCClient(
"localhost",
6969,
session.getAccessToken(),
session.getUsername(),
session.getUuidOrNull(),
socketFactory
);
Thread.ofPlatform().start(voiceChat::start);
} }
} }

View file

@ -3,11 +3,9 @@ package eu.e99.svc.client.fabric;
import eu.e99.svc.AllTrustManager; import eu.e99.svc.AllTrustManager;
import eu.e99.svc.Connection; import eu.e99.svc.Connection;
import eu.e99.svc.SimplerVoiceChat; import eu.e99.svc.SimplerVoiceChat;
import eu.e99.svc.auth.MojangAPI;
import eu.e99.svc.io.BinaryMessage; import eu.e99.svc.io.BinaryMessage;
import eu.e99.svc.packet.AuthRequestPacket; import eu.e99.svc.packet.*;
import eu.e99.svc.packet.AuthResponsePacket;
import eu.e99.svc.packet.AuthSuccessPacket;
import eu.e99.svc.packet.ClientHelloPacket;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
@ -18,10 +16,11 @@ import java.net.Socket;
import java.security.KeyManagementException; import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.UUID;
public class SVCClient { public class SVCClient {
public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException { public static SSLSocketFactory createSocketFactory() throws NoSuchAlgorithmException, KeyManagementException {
TrustManager[] trustManagers = new TrustManager[]{ TrustManager[] trustManagers = new TrustManager[]{
new AllTrustManager(), new AllTrustManager(),
}; };
@ -29,37 +28,58 @@ public class SVCClient {
SSLContext sslContext = SSLContext.getInstance("TLS"); SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, new SecureRandom()); sslContext.init(null, trustManagers, new SecureRandom());
SSLSocketFactory socketFactory = sslContext.getSocketFactory(); return sslContext.getSocketFactory();
SVCClient voiceChat = new SVCClient("localhost", 6969, socketFactory);
voiceChat.start();
} }
private final String host; private final String host;
private final int port; private final int port;
private final String accessToken;
private final String username;
private final UUID uuid;
private final SSLSocketFactory socketFactory; private final SSLSocketFactory socketFactory;
public SVCClient(String host, int port, SSLSocketFactory socketFactory) { public SVCClient(String host, int port, String accessToken, String username, UUID uuid, SSLSocketFactory socketFactory) {
this.host = host; this.host = host;
this.port = port; this.port = port;
this.accessToken = accessToken;
this.username = username;
this.uuid = uuid;
this.socketFactory = socketFactory; this.socketFactory = socketFactory;
} }
public void start() { public void start() {
// Connect and auth // Connect and auth
while (true) {
try (Socket socket = this.socketFactory.createSocket()) { try (Socket socket = this.socketFactory.createSocket()) {
System.out.printf("Connecting to %s.%n", this.host);
socket.connect(new InetSocketAddress(this.host, this.port)); socket.connect(new InetSocketAddress(this.host, this.port));
Connection conn = new Connection(socket); Connection conn = new Connection(socket);
System.out.printf("Connected.");
this.handleHandshake(conn); boolean ok = this.handleHandshake(conn);
if (!ok) {
System.out.printf("Handshake failed.%n");
break;
}
System.out.printf("Successfully authenticated.%n");
} catch (IOException e) { } catch (IOException e) {
System.out.printf("Failed to connect.%n"); System.out.printf("Failed to connect.%n");
e.printStackTrace(System.out); e.printStackTrace(System.out);
} }
System.out.printf("Disconnected. Attempting reconnection in 30 seconds.%n");
try {
Thread.sleep(30_000);
} catch (InterruptedException e) {
System.out.printf("Failed to wait:%n");
e.printStackTrace(System.out);
}
}
} }
private void handleHandshake(Connection conn) throws IOException { private boolean handleHandshake(Connection conn) throws IOException {
ClientHelloPacket clientHello = new ClientHelloPacket(); ClientHelloPacket clientHello = new ClientHelloPacket();
clientHello.version = SimplerVoiceChat.PROTOCOL_VERSION; clientHello.version = SimplerVoiceChat.PROTOCOL_VERSION;
conn.writePacket(clientHello); conn.writePacket(clientHello);
@ -69,18 +89,35 @@ public class SVCClient {
switch (packet) { switch (packet) {
case AuthRequestPacket authRequest -> { case AuthRequestPacket authRequest -> {
System.out.printf("Joining fake server to authenticate.%n"); System.out.printf("Joining server to authenticate...%n");
boolean ok;
try {
ok = MojangAPI.joinServer(this.accessToken, this.uuid, authRequest.serverId);
} catch (Exception e) {
System.out.printf("Failed to join server:%n");
e.printStackTrace(System.out);
return false;
}
if (!ok) {
System.out.printf("Failed to join server.%n");
return false;
}
AuthResponsePacket authResponse = new AuthResponsePacket(); AuthResponsePacket authResponse = new AuthResponsePacket();
authResponse.username = "Test"; authResponse.username = this.username;
conn.writePacket(authResponse); conn.writePacket(authResponse);
} }
case AuthSuccessPacket authComplete -> { case AuthSuccessPacket authComplete -> {
System.out.printf("Successfully authenticated.%n"); return true;
return; }
case DisconnectPacket disconnect -> {
System.out.printf("Disconnected with reason \"%s\".%n", disconnect.reason);
return false;
} }
default -> { default -> {
System.out.printf("Got unexpected packet.%n"); System.out.printf("Got unexpected packet %s.%n", packet.getClass().getName());
} }
} }
} }

View file

@ -24,7 +24,7 @@ public class MojangAPI {
.build(); .build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
if (res.statusCode() == 204) { if (res.statusCode() != 200) {
return null; return null;
} }
@ -39,4 +39,29 @@ public class MojangAPI {
return new PlayerProfile(name, uuid); return new PlayerProfile(name, uuid);
} }
} }
public static boolean joinServer(String accessToken, UUID uuid, String serverId) throws IOException, InterruptedException {
try (HttpClient client = HttpClient.newHttpClient()) {
String loc = "https://sessionserver.mojang.com/session/minecraft/join";
URI uri = URI.create(loc);
JsonObject body = new JsonObject();
body.addProperty("accessToken", accessToken);
body.addProperty("selectedProfile", uuid.toString().replace("-", ""));
body.addProperty("serverId", serverId);
HttpRequest req = HttpRequest.newBuilder()
.uri(uri)
.POST(HttpRequest.BodyPublishers.ofString(body.toString()))
.build();
HttpResponse<Void> res = client.send(req, HttpResponse.BodyHandlers.discarding());
System.out.printf("%d%n", res.statusCode());
if (res.statusCode() != 204) {
return false;
}
return true;
}
}
} }

View file

@ -7,6 +7,7 @@ import eu.e99.svc.auth.PlayerProfile;
import eu.e99.svc.io.BinaryMessage; import eu.e99.svc.io.BinaryMessage;
import eu.e99.svc.packet.*; import eu.e99.svc.packet.*;
import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
@ -38,7 +39,7 @@ public class Server {
this.socket.notify(); this.socket.notify();
} }
System.out.printf("Failed to accept client.%n"); System.out.printf("Failed to handle client.%n");
e.printStackTrace(System.out); e.printStackTrace(System.out);
} }
}); });