Added builtin ClassicHandler

This commit is contained in:
Finn
2026-01-18 18:17:35 +01:00
parent 50eac7dbd5
commit da254a6c8e
38 changed files with 982 additions and 1185 deletions

View File

@@ -21,25 +21,23 @@ import java.security.cert.CertificateException;
import java.util.List;
/**
* Abstract class defining the client-side protocol operations and interactions with INS and web servers.
* Abstract class defining the client-side protocol operations and interactions with INS and servers.
*/
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.INS)
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
public abstract class ProtocolClient extends DefaultMethodsOverrider {
/**
* Handles everything with INS-Connection.
*/
private NetworkClient clientToINS;
/**
* Handles everything with WebServer-Connection.
*/
private NetworkClient clientToWeb;
/**
* Manages the folder structure for client certificates.
*/
@Getter
private final ClientCertificateFolderStructure folderStructure;
/**
* Handles everything with INS-Connection.
*/
private NetworkClient clientToINS;
/**
* Handles everything with Server-Connection.
*/
private NetworkClient clientToServer;
/**
* The reference to the ProtocolBridge Object
*/
@@ -50,9 +48,9 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
*/
private ProtocolVersion insServerVersion = null;
/**
* Stores the protocol version of the connected webserver.
* Stores the protocol version of the connected server.
*/
private ProtocolVersion webServerVersion = null;
private ProtocolVersion serverVersion = null;
/**
* Initializes the ProtocolClient, setting up certificate folders and the INS client connection.
@@ -74,38 +72,38 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
}
/**
* Connects to a WebServer.
* Connects to a Server.
*
* @param host WebServer host
* @param port WebServer port
* @param host Server host
* @param port Server port
*/
public final void connectToWebServer(String host, int port) {
public final void connectToServer(String host, int port) {
if (!protocolBridge.isRunningAsClient())
throw new IllegalStateException("Not running as client");
if (clientToWeb != null && clientToWeb.isConnected())
if (clientToServer != null && clientToServer.isConnected())
return;
createWebClient(host, port);
createServerClient(host, port);
}
/**
* Gets the WebServer connection client.
* Gets the Server connection client.
*
* @return the NetworkClient handling the WebServer connection.
* @return the NetworkClient handling the Server connection.
*/
public final NetworkClient getClientWebConnection() {
return clientToWeb;
public final NetworkClient getClientServerConnection() {
return clientToServer;
}
/**
* Initialize connection to WebServer
* Initialize connection to Server
*
* @param host WebServer host
* @param port WebServer port
* @param host Server host
* @param port Server port
*/
private final void createWebClient(String host, int port) {
clientToWeb = new NetworkClient.ClientBuilder()
private final void createServerClient(String host, int port) {
clientToServer = new NetworkClient.ClientBuilder()
.setLogger(protocolBridge.getLogger())
.setProxy(protocolBridge.getProxy())
.setHost(host)
@@ -122,6 +120,7 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
/**
* Injects the ProtocolBridge.
*
* @param bridge the Bridge instance.
* @throws IOException when NetworkServer failed to create.
*/
@@ -181,17 +180,17 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
*
* @return the ProtocolVersion of the server, or PV_1_0_0_CLASSIC if not set.
*/
public final ProtocolVersion getWebServerVersion() {
return webServerVersion == null ? ProtocolVersion.PV_1_0_0_CLASSIC : webServerVersion;
public final ProtocolVersion getServerVersion() {
return serverVersion == null ? ProtocolVersion.PV_1_0_0_CLASSIC : serverVersion;
}
/**
* Sets the protocol version of the connected server.
*
* @param webServerVersion the ProtocolVersion to set for the server.
* @param serverVersion the ProtocolVersion to set for the server.
*/
public final void setWebServerVersion(ProtocolVersion webServerVersion) {
if (webServerVersion == null) this.webServerVersion = insServerVersion;
public final void setServerVersion(ProtocolVersion serverVersion) {
if (serverVersion == null) this.serverVersion = insServerVersion;
}
/**
@@ -213,7 +212,7 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
}
/**
* Handles disconnect events, resetting the server version and closing the web client connection if necessary.
* Handles disconnect events, resetting the server version and closing the server client connection if necessary.
*
* @param event the ClientDisconnectedEvent triggered on INS disconnection.
*/
@@ -221,10 +220,10 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
// Reset server version on INS disconnect
if (!clientToINS.isConnected()) {
insServerVersion = null;
disconnectFromWebServer();
disconnectFromServer();
}
if (!clientToWeb.isConnected()) webServerVersion = null;
if (!clientToServer.isConnected()) serverVersion = null;
}
/**
@@ -244,7 +243,7 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
*/
public final boolean supportINSServerStable() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getWebServerVersion().getCompatibleVersions()) {
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
// Check if compatible version is stable
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
if (yes) break;
@@ -349,125 +348,126 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
}
//fwfwef
/**
* Checks if the connected webserver is a stable server.
* Checks if the connected server is a stable server.
*
* @return true if the server is stable, false otherwise.
*/
public final boolean isWebStableServer() {
public final boolean isStableServer() {
// Check if the server version is stable
return !isWebBetaServer() && !isWebClassicServer();
return !isBetaServer() && !isClassicServer();
}
/**
* Checks if the connected webserver or its compatible versions support stable protocol.
* Checks if the connected server or its compatible versions support stable protocol.
*
* @return true if stable protocol is supported, false otherwise.
*/
public final boolean supportWebServerStable() {
public final boolean supportServerStable() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getWebServerVersion().getCompatibleVersions()) {
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
// Check if compatible version is stable
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
if (yes) break;
}
// Check if the server version is stable
return isWebBetaServer() || yes;
return isBetaServer() || yes;
}
/**
* Checks if the connected webserver is a beta server.
* Checks if the connected server is a beta server.
*
* @return true if the server is beta, false otherwise.
*/
public final boolean isWebBetaServer() {
public final boolean isBetaServer() {
// Check if the server version is beta
return getWebServerVersion().getProtocolType() == ProtocolVersion.ProtocolType.BETA;
return getServerVersion().getProtocolType() == ProtocolVersion.ProtocolType.BETA;
}
/**
* Checks if the connected webserver or its compatible versions support beta protocol.
* Checks if the connected server or its compatible versions support beta protocol.
*
* @return true if beta protocol is supported, false otherwise.
*/
public final boolean supportWebServerBeta() {
public final boolean supportServerBeta() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getWebServerVersion().getCompatibleVersions()) {
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
// Check if compatible version is beta
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
if (yes) break;
}
// Check if the server version is beta
return isWebStableServer() || yes;
return isStableServer() || yes;
}
/**
* Checks if the connected webserver is a classic server.
* Checks if the connected server is a classic server.
*
* @return true if the server is classic, false otherwise.
*/
public final boolean isWebClassicServer() {
public final boolean isClassicServer() {
// Check if the server version is classic
return getWebServerVersion().getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
return getServerVersion().getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
}
/**
* Checks if the connected webserver or its compatible versions support classic protocol.
* Checks if the connected server or its compatible versions support classic protocol.
*
* @return true if classic protocol is supported, false otherwise.
*/
public final boolean supportWebServerClassic() {
public final boolean supportServerClassic() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getWebServerVersion().getCompatibleVersions()) {
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
// Check if compatible version is classic
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
if (yes) break;
}
// Check if the server version is classic
return isWebClassicServer() || yes;
return isClassicServer() || yes;
}
/**
* Checks if the connected webserver supports the protocol version of the given packet.
* Checks if the connected server supports the protocol version of the given packet.
*
* @param packet the OACPacket to check against the server's supported protocol version.
* @return true if the server supports the packet's protocol version, false otherwise.
*/
public final boolean supportWebServerPacket(OACPacket packet) {
public final boolean supportServerPacket(OACPacket packet) {
// Check if the server supports the protocol version of the packet
return supportWebServerVersion(packet.getProtocolVersion());
return supportServerVersion(packet.getProtocolVersion());
}
/**
* Checks if the connected webserver or its compatible versions support the specified protocol version.
* Checks if the connected server or its compatible versions support the specified protocol version.
*
* @param targetVersion the ProtocolVersion to check for support.
* @return true if the server or its compatible versions support the target version, false otherwise.
*/
public final boolean supportWebServerVersion(ProtocolVersion targetVersion) {
public final boolean supportServerVersion(ProtocolVersion targetVersion) {
// Directly check if the server version matches or is in the list of compatible versions
return getWebServerVersion() == targetVersion || getWebServerVersion().getCompatibleVersions().contains(targetVersion);
return getServerVersion() == targetVersion || getServerVersion().getCompatibleVersions().contains(targetVersion);
}
/**
* Checks if the connected webserver or its compatible versions support the specified protocol.
* Checks if the connected server or its compatible versions support the specified protocol.
*
* @param protocol the Protocol to check for support.
* @return true if the server or its compatible versions support the protocol, false otherwise.
*/
public final boolean supportWebServerProtocol(ProtocolVersion.Protocol protocol) {
public final boolean supportServerProtocol(ProtocolVersion.Protocol protocol) {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getWebServerVersion().getCompatibleVersions()) {
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
// Check if compatible version supports the protocol
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
if (yes) break;
}
// Check if the server version supports the protocol
return getWebServerVersion().getSupportedProtocols().contains(protocol) || yes;
return getServerVersion().getSupportedProtocols().contains(protocol) || yes;
}
/**
@@ -491,12 +491,12 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
}
/**
* Disconnects from the WebServer.
* Disconnects from the Server.
*/
public final void disconnectFromWebServer() {
if (clientToWeb != null) {
clientToWeb.disconnect();
clientToWeb = null;
public final void disconnectFromServer() {
if (clientToServer != null) {
clientToServer.disconnect();
clientToServer = null;
}
}
@@ -508,7 +508,8 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
* @param status The response status from the server.
* @param records The list of records returned by the server.
*/
public abstract void onResponse(INSResponseStatus status, List<INSRecord> records);
public void onResponse(INSResponseStatus status, List<INSRecord> records) {
}
/**
* Called after a query was sent to the INS server.
@@ -525,7 +526,7 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
/**
* Manages the folder structure for client certificates.
*/
public final class ClientCertificateFolderStructure {
public static final class ClientCertificateFolderStructure {
public final File certificatesFolder;
public final File publicFolder;

View File

@@ -0,0 +1,11 @@
package org.openautonomousconnection.protocol.side.client;
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
/**
* Abstract class defining the client-side protocol operations and interactions with INS and servers.
*/
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
public class ProtocolWebClient extends ProtocolClient {
}

View File

@@ -10,7 +10,7 @@ import org.openautonomousconnection.protocol.versions.ProtocolVersion;
* Event triggered when a client successfully connects to a INS protocol server.
*/
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.INS)
public final class ConnectedToProtocolWebServerEvent extends Event {
public final class ConnectedToProtocolServerEvent extends Event {
/**
* Reference to the ProtocolClient object.
@@ -18,7 +18,7 @@ public final class ConnectedToProtocolWebServerEvent extends Event {
@Getter
private final ProtocolClient client;
public ConnectedToProtocolWebServerEvent(ProtocolClient client) {
public ConnectedToProtocolServerEvent(ProtocolClient client) {
this.client = client;
}

View File

@@ -1,176 +1,17 @@
package org.openautonomousconnection.protocol.side.ins;
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
import lombok.Getter;
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
import org.openautonomousconnection.protocol.packets.OACPacket;
import org.openautonomousconnection.protocol.side.server.CustomConnectedClient;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
/**
* Represents a connected protocol client on the INS server side.
*/
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.INS)
public final class ConnectedProtocolClient {
/**
* The connection handler associated with this protocol client.
*/
@Getter
private final ConnectionHandler connectionHandler;
/**
* The Protocol Server associated with this protocol client.
*/
@Getter
private final ProtocolINSServer protocolINSServer;
/**
* The protocol version of the connected client.
*/
private ProtocolVersion clientVersion = null;
public final class ConnectedProtocolClient extends CustomConnectedClient {
public ConnectedProtocolClient(ConnectionHandler connectionHandler, ProtocolINSServer protocolINSServer) {
this.connectionHandler = connectionHandler;
this.protocolINSServer = protocolINSServer;
}
/**
* Gets the protocol version of the connected client.
* Defaults to PV_1_0_0_CLASSIC if not set.
*
* @return The protocol version of the client.
*/
public ProtocolVersion getClientVersion() {
return clientVersion == null ? ProtocolVersion.PV_1_0_0_CLASSIC : clientVersion;
}
/**
* Sets the protocol version of the connected client.
*
* @param clientVersion The protocol version to set.
*/
public void setClientVersion(ProtocolVersion clientVersion) {
if (clientVersion == null) this.clientVersion = clientVersion;
}
/**
* Checks if the connected client is a stable client.
*
* @return True if the client is stable, false otherwise.
*/
public boolean isStableClient() {
// Check if the server version is stable
return !isBetaClient() && !isClassicClient();
}
/**
* Checks if the connected client supports stable protocol versions.
*
* @return True if the client supports stable versions, false otherwise.
*/
public boolean supportClientStable() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is stable
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
if (yes) break;
}
// Check if the client version is stable
return isStableClient() || yes;
}
/**
* Checks if the connected client is a beta client.
*
* @return True if the client is beta, false otherwise.
*/
public boolean isBetaClient() {
// Check if the server version is beta
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.BETA;
}
/**
* Checks if the connected client supports beta protocol versions.
*
* @return True if the client supports beta versions, false otherwise.
*/
public boolean supportClientBeta() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is beta
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
if (yes) break;
}
// Check if the client version is beta
return isBetaClient() || yes;
}
/**
* Checks if the connected client is a classic client.
*
* @return True if the client is classic, false otherwise.
*/
public boolean isClassicClient() {
// Check if the server version is classic
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
}
/**
* Checks if the connected client supports classic protocol versions.
*
* @return True if the client supports classic versions, false otherwise.
*/
public boolean supportClientClassic() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is classic
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
if (yes) break;
}
// Check if the client version is classic
return isClassicClient() || yes;
}
/**
* Checks if the connected client supports the given packet's protocol version.
*
* @param packet The packet to check.
* @return True if the client supports the packet's protocol version, false otherwise.
*/
public boolean supportClientPacket(OACPacket packet) {
return supportClientVersion(packet.getProtocolVersion());
}
/**
* Checks if the connected client supports the given protocol version.
*
* @param targetVersion The protocol version to check.
* @return True if the client supports the target version, false otherwise.
*/
public boolean supportClientVersion(ProtocolVersion targetVersion) {
// Check if the client version matches or is compatible with the target version
return getClientVersion() == targetVersion || getClientVersion().getCompatibleVersions().contains(targetVersion);
}
/**
* Checks if the connected client supports the given protocol.
*
* @param protocol The protocol to check.
* @return True if the client supports the protocol, false otherwise.
*/
public boolean supportClientProtocol(ProtocolVersion.Protocol protocol) {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version supports the protocol
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
if (yes) break;
}
// Check if the client version supports the protocol
return getClientVersion().getSupportedProtocols().contains(protocol) || yes;
super(connectionHandler, protocolINSServer);
}
}

View File

@@ -1,53 +1,26 @@
package org.openautonomousconnection.protocol.side.ins;
import dev.unlegitdqrk.unlegitlibrary.file.ConfigurationManager;
import dev.unlegitdqrk.unlegitlibrary.network.system.server.NetworkServer;
import dev.unlegitdqrk.unlegitlibrary.network.utils.NetworkUtils;
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
import lombok.Getter;
import org.openautonomousconnection.protocol.ProtocolBridge;
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
import org.openautonomousconnection.protocol.side.server.ProtocolCustomServer;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord;
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
/**
* Abstract class representing a INS server in the protocol.
*/
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.INS)
public abstract class ProtocolINSServer extends DefaultMethodsOverrider {
/**
* The network server instance.
*/
@Getter
private NetworkServer networkServer;
public abstract class ProtocolINSServer extends ProtocolCustomServer {
/**
* The configuration manager for handling server configurations.
*/
private final ConfigurationManager configurationManager;
/**
* The reference to the ProtocolBridge Object
*/
@Getter
private ProtocolBridge protocolBridge;
/**
* List of connected protocol clients.
*/
@Getter
private List<ConnectedProtocolClient> clients;
/**
* The folder structure for server certificates.
*/
@Getter
private ServerCertificateFolderStructure folderStructure;
/**
* Constructs a ProtocolINSServer with the specified configuration file.
@@ -56,7 +29,9 @@ public abstract class ProtocolINSServer extends DefaultMethodsOverrider {
* @throws IOException If an I/O error occurs.
* @throws CertificateException If a certificate error occurs.
*/
public ProtocolINSServer(File configFile) throws IOException, CertificateException {
public ProtocolINSServer(File configFile) throws Exception {
super("ca_ins_", "cert_ins_");
// Ensure the configuration file exists
if (!configFile.exists()) configFile.createNewFile();
@@ -75,99 +50,7 @@ public abstract class ProtocolINSServer extends DefaultMethodsOverrider {
configurationManager.saveProperties();
}
// Initialize the folder structure
folderStructure = new ServerCertificateFolderStructure();
// Check for the existence of necessary certificate files
checkFileExists(folderStructure.publicCAFolder, folderStructure.caPrefix, ".pem");
checkFileExists(folderStructure.publicCAFolder, folderStructure.caPrefix, ".srl");
checkFileExists(folderStructure.privateCAFolder, folderStructure.caPrefix, ".key");
checkFileExists(folderStructure.publicServerFolder, folderStructure.certPrefix, ".crt");
checkFileExists(folderStructure.privateServerFolder, folderStructure.certPrefix, ".key");
// Initialize the protocol bridge and clients list
this.clients = new ArrayList<>();
}
/**
* Injects the ProtocolBridge.
* @param bridge the Bridge instance.
* @throws IOException when NetworkServer failed to create.
*/
public final void attachBridge(ProtocolBridge bridge) throws IOException {
if (this.protocolBridge != null)
throw new IllegalStateException("ProtocolBridge already attached!");
this.protocolBridge = bridge;
createNetworkServer();
}
/**
* Build the network server with the specified settings
*/
private void createNetworkServer() throws IOException {
// Define the certificate and key files based on the public IP address
File certFile = new File(folderStructure.publicServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".crt");
File keyFile = new File(folderStructure.privateServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".key");
this.networkServer = new NetworkServer.ServerBuilder().
setLogger(protocolBridge.getLogger()).
setEventManager(protocolBridge.getProtocolSettings().eventManager).
setPacketHandler(protocolBridge.getProtocolSettings().packetHandler).
setPort(protocolBridge.getProtocolSettings().port).
setRequireClientCertificate(false).setRootCAFolder(folderStructure.publicCAFolder).setServerCertificate(certFile, keyFile).
build();
}
/**
* Checks if the required certificate files exist in the specified folder.
*
* @param folder The folder to check for certificate files.
* @param prefix The prefix of the certificate files.
* @param extension The extension of the certificate files.
* @throws CertificateException If a certificate error occurs.
* @throws IOException If an I/O error occurs.
*/
private final void checkFileExists(File folder, String prefix, String extension) throws CertificateException, IOException {
boolean found = false;
// Check if the folder exists
if (folder == null) throw new FileNotFoundException("Folder does not exist");
// List all files in the folder
File[] files = folder.listFiles();
// Check if the folder is empty
if (files == null || files.length == 0)
throw new FileNotFoundException("Folder " + folder.getAbsolutePath() + " is empty");
// Validate each file in the folder
for (File file : files) {
if (!file.getName().startsWith(prefix))
throw new CertificateException(file.getAbsolutePath() + " is not valid");
// Check if the file matches the expected naming convention
if (!found) found = file.getName().equalsIgnoreCase(prefix + NetworkUtils.getPublicIPAddress() + extension);
}
// If the required file is not found, throw an exception
if (!found) throw new CertificateException("Missing " + prefix + NetworkUtils.getPublicIPAddress() + extension);
}
/**
* Retrieves a connected protocol client by its client ID.
*
* @param clientID The ID of the client to retrieve.
* @return The ConnectedProtocolClient with the specified ID, or null if not found.
*/
public final ConnectedProtocolClient getClientByID(int clientID) {
for (ConnectedProtocolClient client : clients)
if (client.getConnectionHandler().getClientID() == clientID) return client;
return null;
setCustomClient(ConnectedProtocolClient.class);
}
/**
@@ -206,7 +89,8 @@ public abstract class ProtocolINSServer extends DefaultMethodsOverrider {
* @param sub An optional subname, or {@code null}.
* @param type The record type requested.
*/
public void onQueryReceived(String tln, String name, String sub, INSRecordType type) {}
public void onQueryReceived(String tln, String name, String sub, INSRecordType type) {
}
/**
* Callback fired after an INS response was successfully sent to the client.
@@ -217,7 +101,8 @@ public abstract class ProtocolINSServer extends DefaultMethodsOverrider {
* @param type The requested record type.
* @param results The records returned to the client.
*/
public void onResponseSent(String tln, String name, String sub, INSRecordType type, List<INSRecord> results) {}
public void onResponseSent(String tln, String name, String sub, INSRecordType type, List<INSRecord> results) {
}
/**
* Callback fired when an INS response could not be delivered to the client.
@@ -229,7 +114,8 @@ public abstract class ProtocolINSServer extends DefaultMethodsOverrider {
* @param results The records that would have been sent.
* @param exception The exception describing the failure.
*/
public void onResponseSentFailed(String tln, String name, String sub, INSRecordType type, List<INSRecord> results, Exception exception) {}
public void onResponseSentFailed(String tln, String name, String sub, INSRecordType type, List<INSRecord> results, Exception exception) {
}
/**
* Resolves the information endpoint for a given Top-Level Name (TLN).
@@ -257,9 +143,8 @@ public abstract class ProtocolINSServer extends DefaultMethodsOverrider {
*
* @param tln the top-level name for which the info site should be resolved.
* Must not be null. Case-insensitive.
*
* @return a string in <code>"host:port"</code> format representing the TLN's info endpoint,
* or <code>null</code> if the TLN has no registered info site.
* or <code>null</code> if the TLN has no registered info site.
*/
public abstract String resolveTLNInfoSite(String tln);
@@ -271,46 +156,4 @@ public abstract class ProtocolINSServer extends DefaultMethodsOverrider {
public final String getINSFrontendSite() {
return configurationManager.getString("server.site.frontend");
}
/**
* Class representing the folder structure for server certificates.
*/
public final class ServerCertificateFolderStructure {
public final File certificatesFolder;
public final File publicFolder;
public final File privateFolder;
public final File privateCAFolder;
public final File privateServerFolder;
public final File publicCAFolder;
public final File publicServerFolder;
public final String caPrefix = "ca_ins_";
public final String certPrefix = "cert_ins_";
public ServerCertificateFolderStructure() {
certificatesFolder = new File("certificates");
publicFolder = new File(certificatesFolder, "public");
privateFolder = new File(certificatesFolder, "private");
privateCAFolder = new File(privateFolder, "ca");
privateServerFolder = new File(privateFolder, "server");
publicCAFolder = new File(publicFolder, "ca");
publicServerFolder = new File(publicFolder, "server");
if (!certificatesFolder.exists()) certificatesFolder.mkdirs();
if (!publicFolder.exists()) publicFolder.mkdirs();
if (!privateFolder.exists()) privateFolder.mkdirs();
if (!privateCAFolder.exists()) privateCAFolder.mkdirs();
if (!privateServerFolder.exists()) privateServerFolder.mkdirs();
if (!publicCAFolder.exists()) publicCAFolder.mkdirs();
if (!publicServerFolder.exists()) publicServerFolder.mkdirs();
}
}
}

View File

@@ -1,21 +0,0 @@
package org.openautonomousconnection.protocol.side.ins.events;
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
import lombok.Getter;
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
import org.openautonomousconnection.protocol.side.ins.ConnectedProtocolClient;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
/**
* Event triggered when a protocol client connects to the INS server.
*/
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.INS)
public final class ConnectedProtocolClientEvent extends Event {
@Getter
private final ConnectedProtocolClient protocolClient;
public ConnectedProtocolClientEvent(ConnectedProtocolClient protocolClient) {
this.protocolClient = protocolClient;
}
}

View File

@@ -0,0 +1,178 @@
package org.openautonomousconnection.protocol.side.server;
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
import lombok.Getter;
import org.openautonomousconnection.protocol.packets.OACPacket;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
public abstract class CustomConnectedClient {
@Getter
private final ConnectionHandler pipelineConnection;
@Getter
private final ProtocolCustomServer server;
private ProtocolVersion clientVersion = null;
@Getter
private boolean clientVersionLoaded = false;
public CustomConnectedClient(ConnectionHandler pipelineConnection, ProtocolCustomServer protocolServer) {
this.pipelineConnection = pipelineConnection;
this.server = protocolServer;
}
public synchronized void disconnect() {
try {
server.clientDisconnected(this);
} catch (Exception ignored) {
}
try {
pipelineConnection.disconnect();
} catch (Exception ignored) {
}
}
/**
* Gets the protocol version of the connected client.
*
* @return The protocol version of the client, defaults to PV_1_0_0_CLASSIC if not set.
*/
public ProtocolVersion getClientVersion() {
return clientVersion == null ? ProtocolVersion.PV_1_0_0_CLASSIC : clientVersion;
}
/**
* Sets the protocol version of the connected client.
*
* @param clientVersion The protocol version to set.
*/
public void setClientVersion(ProtocolVersion clientVersion) {
if (clientVersionLoaded) return;
if (clientVersion == null) return;
this.clientVersion = clientVersion;
this.clientVersionLoaded = true;
}
/**
* Checks if the connected client is a stable client.
*
* @return True if the client is stable, false otherwise.
*/
public boolean isStableClient() {
// Check if the server version is stable
return !isBetaClient() && !isClassicClient();
}
/**
* Checks if the connected client supports stable protocol versions.
*
* @return True if the client supports stable versions, false otherwise.
*/
public boolean supportClientStable() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is stable
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
if (yes) break;
}
// Check if the client version is stable
return isStableClient() || yes;
}
/**
* Checks if the connected client is a beta client.
*
* @return True if the client is beta, false otherwise.
*/
public boolean isBetaClient() {
// Check if the server version is beta
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.BETA;
}
/**
* Checks if the connected client supports beta protocol versions.
*
* @return True if the client supports beta versions, false otherwise.
*/
public boolean supportClientBeta() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is beta
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
if (yes) break;
}
// Check if the client version is beta
return isBetaClient() || yes;
}
/**
* Checks if the connected client is a classic client.
*
* @return True if the client is classic, false otherwise.
*/
public boolean isClassicClient() {
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
}
/**
* Checks if the connected client supports classic protocol versions.
*
* @return True if the client supports classic versions, false otherwise.
*/
public boolean supportClientClassic() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is classic
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
if (yes) break;
}
// Check if the client version is classic
return isClassicClient() || yes;
}
/**
* Checks if the connected client supports the protocol version of the given packet.
*
* @param packet The packet to check support for.
* @return True if the client supports the packet's protocol version, false otherwise.
*/
public boolean supportClientPacket(OACPacket packet) {
return supportClientVersion(packet.getProtocolVersion());
}
/**
* Checks if the connected client supports the given protocol version.
*
* @param targetVersion The protocol version to check support for.
* @return True if the client supports the target version, false otherwise.
*/
public boolean supportClientVersion(ProtocolVersion targetVersion) {
// Check if the client version matches the target version or is compatible
return getClientVersion() == targetVersion || getClientVersion().getCompatibleVersions().contains(targetVersion);
}
/**
* Checks if the connected client supports the given protocol.
*
* @param protocol The protocol to check support for.
* @return True if the client supports the protocol, false otherwise.
*/
public boolean supportClientProtocol(ProtocolVersion.Protocol protocol) {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version supports the protocol
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
if (yes) break;
}
// Check if the client version supports the protocol
return getClientVersion().getSupportedProtocols().contains(protocol) || yes;
}
}

View File

@@ -0,0 +1,206 @@
package org.openautonomousconnection.protocol.side.server;
import dev.unlegitdqrk.unlegitlibrary.network.system.server.NetworkServer;
import dev.unlegitdqrk.unlegitlibrary.network.utils.NetworkUtils;
import lombok.Getter;
import lombok.Setter;
import org.openautonomousconnection.protocol.ProtocolBridge;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
public abstract class ProtocolCustomServer {
/**
* Structure for server.
*/
@Getter
private final ServerCertificateFolderStructure folderStructure;
/**
* Certificate files for SSL.
*/
private final File certFile;
/**
* Certificate files for SSL.
*/
private final File keyFile;
/**
* The reference to the ProtocolBridge Object
*/
@Getter
private ProtocolBridge protocolBridge;
/**
* List of connected web clients.
*/
@Getter
private List<CustomConnectedClient> clients;
@Setter
@Getter
private Class<? extends CustomConnectedClient> customClient;
/**
* The network server handling pipeline connections.
*/
@Getter
private NetworkServer pipelineServer;
/**
* Initializes the web server with the given configuration, authentication, and rules files.
*
* @throws Exception If an error occurs during initialization.
*/
public ProtocolCustomServer(String caPrefix, String certPrefix) throws Exception {
// Initialize the list of connected clients
this.clients = new ArrayList<>();
// Set up folder structure for certificates
folderStructure = new ServerCertificateFolderStructure(caPrefix, certPrefix);
// Check for necessary certificate files
checkFileExists(folderStructure.publicServerFolder, folderStructure.certPrefix, ".crt");
checkFileExists(folderStructure.privateServerFolder, folderStructure.certPrefix, ".key");
// Set up certificate files based on public IP address
this.certFile = new File(folderStructure.publicServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".crt");
this.keyFile = new File(folderStructure.privateServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".key");
}
/**
* Injects the ProtocolBridge.
*
* @param bridge the Bridge instance.
* @throws IOException when NetworkServer failed to create.
*/
public final void attachBridge(ProtocolBridge bridge) throws IOException {
if (this.protocolBridge != null)
throw new IllegalStateException("ProtocolBridge already attached!");
this.protocolBridge = bridge;
createNetworkServer();
}
/**
* Initialize the pipeline server
*/
private void createNetworkServer() {
pipelineServer = new NetworkServer.ServerBuilder().
setPort(protocolBridge.getProtocolSettings().port).setTimeout(0).
setPacketHandler(protocolBridge.getProtocolSettings().packetHandler).setEventManager(protocolBridge.getProtocolSettings().eventManager).
setLogger(protocolBridge.getLogger()).
setServerCertificate(certFile, keyFile).setRootCAFolder(folderStructure.publicCAFolder).
build();
}
/**
* Retrieves a connected web client by its client ID.
*
* @param clientID The client ID to search for.
* @return The connected web client with the specified ID, or null if not found.
*/
public final <T extends CustomConnectedClient> T getClientByID(int clientID) {
for (CustomConnectedClient client : clients)
if (client.getPipelineConnection().getClientID() == clientID) return (T) client;
return null;
}
/**
* Checks if the required certificate files exist in the specified folder.
*
* @param folder The folder to check for certificate files.
* @param prefix The prefix of the certificate files.
* @param extension The extension of the certificate files.
* @throws CertificateException If a required certificate file is missing or invalid.
* @throws IOException If an I/O error occurs while checking the files.
*/
private void checkFileExists(File folder, String prefix, String extension) throws CertificateException, IOException {
boolean found = false;
// Ensure the folder exists
if (folder == null) throw new FileNotFoundException("Folder does not exist");
// List all files in the folder
File[] files = folder.listFiles();
if (files == null || files.length == 0)
throw new FileNotFoundException("Folder " + folder.getAbsolutePath() + " is empty");
// Check for the required certificate file
for (File file : files) {
if (!file.getName().startsWith(prefix))
throw new CertificateException(file.getAbsolutePath() + " is not valid");
// Check for file matching the public IP address
if (!found) found = file.getName().equalsIgnoreCase(prefix + NetworkUtils.getPublicIPAddress() + extension);
}
// Throw exception if the required file is not found
if (!found) throw new CertificateException("Missing " + prefix + NetworkUtils.getPublicIPAddress() + extension);
}
public final void clientDisconnected(CustomConnectedClient client) {
clients.remove(client);
onDisconnect(client);
}
/**
* Optional callback when the connection closes.
*/
public void onDisconnect(CustomConnectedClient client) {
}
/**
* Represents the folder structure for server certificates.
*/
public final class ServerCertificateFolderStructure {
public final File certificatesFolder;
public final File publicFolder;
public final File privateFolder;
public final File privateCAFolder;
public final File privateServerFolder;
public final File publicCAFolder;
public final File publicServerFolder;
@Getter
private String caPrefix = "ca_server_";
@Getter
private String certPrefix = "cert_server_";
public ServerCertificateFolderStructure(String caPrefix, String certPrefix) {
this.caPrefix = caPrefix;
this.certPrefix = certPrefix;
certificatesFolder = new File("certificates");
publicFolder = new File(certificatesFolder, "public");
privateFolder = new File(certificatesFolder, "private");
privateCAFolder = new File(privateFolder, "ca");
privateServerFolder = new File(privateFolder, "server");
publicCAFolder = new File(publicFolder, "ca");
publicServerFolder = new File(publicFolder, "server");
if (!certificatesFolder.exists()) certificatesFolder.mkdirs();
if (!publicFolder.exists()) publicFolder.mkdirs();
if (!privateFolder.exists()) privateFolder.mkdirs();
if (!privateCAFolder.exists()) privateCAFolder.mkdirs();
if (!privateServerFolder.exists()) privateServerFolder.mkdirs();
if (!publicCAFolder.exists()) publicCAFolder.mkdirs();
if (!publicServerFolder.exists()) publicServerFolder.mkdirs();
}
}
}

View File

@@ -0,0 +1,21 @@
package org.openautonomousconnection.protocol.side.server.events;
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
import lombok.Getter;
import org.openautonomousconnection.protocol.side.server.CustomConnectedClient;
/**
* Event triggered when a web client connects to the web server.
*/
public final class S_CustomClientConnectedEvent extends Event {
/**
* The connected web client.
*/
@Getter
private final CustomConnectedClient client;
public S_CustomClientConnectedEvent(CustomConnectedClient client) {
this.client = client;
}
}

View File

@@ -0,0 +1,21 @@
package org.openautonomousconnection.protocol.side.server.events;
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
import lombok.Getter;
import org.openautonomousconnection.protocol.side.server.CustomConnectedClient;
/**
* Event triggered when a web client connects to the web server.
*/
public final class S_CustomClientDisconnectedEvent extends Event {
/**
* The connected web client.
*/
@Getter
private final CustomConnectedClient client;
public S_CustomClientDisconnectedEvent(CustomConnectedClient client) {
this.client = client;
}
}

View File

@@ -2,258 +2,18 @@ package org.openautonomousconnection.protocol.side.web;
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
import lombok.Getter;
import org.openautonomousconnection.protocol.packets.OACPacket;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.WebRequestPacket;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.WebResponsePacket;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.WebStreamChunkPacket;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.WebStreamEndPacket;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.WebStreamStartPacket;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.openautonomousconnection.protocol.side.server.CustomConnectedClient;
/**
* A connected web client using pure protocol packets.
*/
public final class ConnectedWebClient {
public final class ConnectedWebClient extends CustomConnectedClient {
@Getter
private final ConnectionHandler pipelineConnection;
private final ProtocolWebServer server;
@Getter
private SSLSocket webSocket;
@Getter
private ProtocolWebServer server;
private ObjectOutputStream out;
private ObjectInputStream in;
private ProtocolVersion clientVersion = null;
@Getter
private boolean clientVersionLoaded = false;
private Thread receiveThread;
public ConnectedWebClient(ConnectionHandler pipelineConnection) {
this.pipelineConnection = pipelineConnection;
public ConnectedWebClient(ConnectionHandler pipelineConnection, ProtocolWebServer webServer) {
super(pipelineConnection, webServer);
this.server = webServer;
}
public boolean isConnected() {
return webSocket != null &&
webSocket.isConnected() &&
!webSocket.isClosed() &&
pipelineConnection.isConnected();
}
public void attachWebServer(SSLSocket socket, ProtocolWebServer server) throws IOException {
if (this.webSocket != null) return;
this.webSocket = socket;
this.server = server;
// IMPORTANT: ObjectOutputStream first, flush, then ObjectInputStream
this.out = new ObjectOutputStream(webSocket.getOutputStream());
this.out.flush();
this.in = new ObjectInputStream(webSocket.getInputStream());
this.receiveThread = new Thread(this::receiveLoop, "OAC-WebClient-Receiver");
this.receiveThread.start();
}
private void receiveLoop() {
try {
while (isConnected()) {
Object obj = in.readObject();
if (!(obj instanceof OACPacket packet)) continue;
if (packet instanceof WebRequestPacket req) {
// server decides whether it returns normal response or does streaming itself
WebResponsePacket resp = server.onWebRequest(this, req);
if (resp != null) send(resp);
}
}
} catch (Exception ignored) {
} finally {
disconnect();
}
}
public synchronized void send(Object packet) throws IOException {
if (!isConnected()) return;
out.writeObject(packet);
out.flush();
}
public synchronized void streamStart(WebStreamStartPacket start) throws IOException {
send(start);
}
public synchronized void streamChunk(WebStreamChunkPacket chunk) throws IOException {
send(chunk);
}
public synchronized void streamEnd(WebStreamEndPacket end) throws IOException {
send(end);
}
public synchronized void disconnect() {
try { server.onDisconnect(this); } catch (Exception ignored) {}
try { pipelineConnection.disconnect(); } catch (Exception ignored) {}
try { if (in != null) in.close(); } catch (Exception ignored) {}
try { if (out != null) out.close(); } catch (Exception ignored) {}
try { if (webSocket != null) webSocket.close(); } catch (Exception ignored) {}
in = null;
out = null;
webSocket = null;
}
/**
* Gets the protocol version of the connected client.
*
* @return The protocol version of the client, defaults to PV_1_0_0_CLASSIC if not set.
*/
public ProtocolVersion getClientVersion() {
return clientVersion == null ? ProtocolVersion.PV_1_0_0_CLASSIC : clientVersion;
}
/**
* Sets the protocol version of the connected client.
*
* @param clientVersion The protocol version to set.
*/
public void setClientVersion(ProtocolVersion clientVersion) {
if (clientVersionLoaded) return;
if (clientVersion == null) return;
this.clientVersion = clientVersion;
this.clientVersionLoaded = true;
}
/**
* Checks if the connected client is a stable client.
*
* @return True if the client is stable, false otherwise.
*/
public boolean isStableClient() {
// Check if the server version is stable
return !isBetaClient() && !isClassicClient();
}
/**
* Checks if the connected client supports stable protocol versions.
*
* @return True if the client supports stable versions, false otherwise.
*/
public boolean supportClientStable() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is stable
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
if (yes) break;
}
// Check if the client version is stable
return isStableClient() || yes;
}
/**
* Checks if the connected client is a beta client.
*
* @return True if the client is beta, false otherwise.
*/
public boolean isBetaClient() {
// Check if the server version is beta
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.BETA;
}
/**
* Checks if the connected client supports beta protocol versions.
*
* @return True if the client supports beta versions, false otherwise.
*/
public boolean supportClientBeta() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is beta
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
if (yes) break;
}
// Check if the client version is beta
return isBetaClient() || yes;
}
/**
* Checks if the connected client is a classic client.
*
* @return True if the client is classic, false otherwise.
*/
public boolean isClassicClient() {
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
}
/**
* Checks if the connected client supports classic protocol versions.
*
* @return True if the client supports classic versions, false otherwise.
*/
public boolean supportClientClassic() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is classic
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
if (yes) break;
}
// Check if the client version is classic
return isClassicClient() || yes;
}
/**
* Checks if the connected client supports the protocol version of the given packet.
*
* @param packet The packet to check support for.
* @return True if the client supports the packet's protocol version, false otherwise.
*/
public boolean supportClientPacket(OACPacket packet) {
return supportClientVersion(packet.getProtocolVersion());
}
/**
* Checks if the connected client supports the given protocol version.
*
* @param targetVersion The protocol version to check support for.
* @return True if the client supports the target version, false otherwise.
*/
public boolean supportClientVersion(ProtocolVersion targetVersion) {
// Check if the client version matches the target version or is compatible
return getClientVersion() == targetVersion || getClientVersion().getCompatibleVersions().contains(targetVersion);
}
/**
* Checks if the connected client supports the given protocol.
*
* @param protocol The protocol to check support for.
* @return True if the client supports the protocol, false otherwise.
*/
public boolean supportClientProtocol(ProtocolVersion.Protocol protocol) {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version supports the protocol
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
if (yes) break;
}
// Check if the client version supports the protocol
return getClientVersion().getSupportedProtocols().contains(protocol) || yes;
}
}

View File

@@ -1,35 +1,24 @@
package org.openautonomousconnection.protocol.side.web;
import dev.unlegitdqrk.unlegitlibrary.file.ConfigurationManager;
import dev.unlegitdqrk.unlegitlibrary.file.FileUtils;
import dev.unlegitdqrk.unlegitlibrary.network.system.server.NetworkServer;
import dev.unlegitdqrk.unlegitlibrary.network.utils.NetworkUtils;
import dev.unlegitdqrk.unlegitlibrary.string.RandomString;
import lombok.Getter;
import org.openautonomousconnection.protocol.ProtocolBridge;
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.WebRequestPacket;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.WebResponsePacket;
import org.openautonomousconnection.protocol.side.web.events.WebClientConnectedEvent;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebRequestPacket;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket;
import org.openautonomousconnection.protocol.side.server.ProtocolCustomServer;
import org.openautonomousconnection.protocol.side.web.managers.AuthManager;
import org.openautonomousconnection.protocol.side.web.managers.RuleManager;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Represents the web server for the protocol.
*/
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
public abstract class ProtocolWebServer {
public abstract class ProtocolWebServer extends ProtocolCustomServer {
/**
* Folder for web content.
*/
@@ -41,46 +30,11 @@ public abstract class ProtocolWebServer {
*/
@Getter
private final File errorsFolder;
/**
* Structure for server.
*/
@Getter
private final ServerCertificateFolderStructure folderStructure;
/**
* Certificate files for SSL.
*/
private final File certFile;
/**
* Certificate files for SSL.
*/
private final File keyFile;
/**
* The configuration for the web server.
*/
@Getter
private final WebServerConfig serverConfig;
/**
* The reference to the ProtocolBridge Object
*/
@Getter
private ProtocolBridge protocolBridge;
/**
* The network server handling pipeline connections.
*/
@Getter
private NetworkServer pipelineServer;
/**
* The SSL server socket for web connections.
*/
@Getter
private SSLServerSocket webServer;
/**
* List of connected web clients.
*/
@Getter
private List<ConnectedWebClient> clients;
/**
* A unique secret for session management.
*/
@@ -91,25 +45,17 @@ public abstract class ProtocolWebServer {
* Initializes the web server with the given configuration, authentication, and rules files.
*
* @param serverConfig The configuration.
* @param authFile The authentication file.
* @param rulesFile The rules file.
* @param authFile The authentication file.
* @param rulesFile The rules file.
* @throws Exception If an error occurs during initialization.
*/
public ProtocolWebServer(WebServerConfig serverConfig, File authFile, File rulesFile) throws Exception {
// Initialize the list of connected clients
this.clients = new ArrayList<>();
super("ca_server_", "cert_server_");
// Store the configuration file
this.serverConfig = serverConfig;
this.serverConfig.attachWebServer(this);
// Set up folder structure for certificates
folderStructure = new ServerCertificateFolderStructure();
// Check for necessary certificate files
checkFileExists(folderStructure.publicServerFolder, folderStructure.certPrefix, ".crt");
checkFileExists(folderStructure.privateServerFolder, folderStructure.certPrefix, ".key");
// Set up content and error folders
contentFolder = new File("content");
errorsFolder = new File("errors");
@@ -118,10 +64,6 @@ public abstract class ProtocolWebServer {
if (!contentFolder.exists()) contentFolder.mkdir();
if (!errorsFolder.exists()) errorsFolder.mkdir();
// Set up certificate files based on public IP address
this.certFile = new File(folderStructure.publicServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".crt");
this.keyFile = new File(folderStructure.privateServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".key");
// Create auth and rules files with default content if they don't exist
if (!authFile.exists()) {
authFile.createNewFile();
@@ -157,202 +99,16 @@ public abstract class ProtocolWebServer {
AuthManager.loadAuthFile(authFile);
RuleManager.loadRules(rulesFile);
setCustomClient(ConnectedWebClient.class);
}
/**
* Injects the ProtocolBridge.
* @param bridge the Bridge instance.
* @throws IOException when NetworkServer failed to create.
*/
public final void attachBridge(ProtocolBridge bridge) throws IOException {
if (this.protocolBridge != null)
throw new IllegalStateException("ProtocolBridge already attached!");
this.protocolBridge = bridge;
createNetworkServer();
}
/**
* Initialize the pipeline server
*/
private void createNetworkServer() {
pipelineServer = new NetworkServer.ServerBuilder().
setPort(protocolBridge.getProtocolSettings().port).setTimeout(0).
setPacketHandler(protocolBridge.getProtocolSettings().packetHandler).setEventManager(protocolBridge.getProtocolSettings().eventManager).
setLogger(protocolBridge.getLogger()).
setServerCertificate(certFile, keyFile).setRootCAFolder(folderStructure.publicCAFolder).
build();
}
/**
* Retrieves a connected web client by its client ID.
*
* @param clientID The client ID to search for.
* @return The connected web client with the specified ID, or null if not found.
*/
public final ConnectedWebClient getClientByID(int clientID) {
for (ConnectedWebClient client : clients)
if (client.getPipelineConnection().getClientID() == clientID) return client;
return null;
}
/**
* Starts the web server to accept and handle client connections.
*
* @throws Exception If an error occurs while starting the server.
*/
public final void startWebServer() throws Exception {
// Start the pipeline server
pipelineServer.start();
// Create the SSL server socket for web connections
webServer = (SSLServerSocket) NetworkServer.ServerBuilder.
createSSLServerSocketFactory(folderStructure.publicCAFolder, certFile, keyFile).
createServerSocket(serverConfig.getPort());
webServer.setSoTimeout(0);
webServer.setEnabledProtocols(pipelineServer.getServerSocket().getEnabledProtocols());
// Stop WebServer if pipelineServer dies
new Thread(() -> {
while (true) {
// Check if the pipeline server is still running
if (pipelineServer == null || !pipelineServer.getServerSocket().isBound()) {
try {
// Stop the web server
onPipelineStop();
} catch (IOException e) {
pipelineServer.getLogger().exception("Failed to stop WebServer", e);
}
Thread.currentThread().interrupt();
break;
}
try {
// Sleep for a while before checking again
Thread.sleep(1000);
} catch (InterruptedException ignored) {
}
}
}).start();
// Handle every client
new Thread(() -> {
while (true) {
try {
// Accept incoming client connections
SSLSocket client = (SSLSocket) webServer.accept();
for (ConnectedWebClient connectedWebClient : clients) {
if (connectedWebClient.getPipelineConnection().getClientID() != -1 && connectedWebClient.isClientVersionLoaded()) {
// Assign socket to an existing connected client
connectedWebClient.attachWebServer(client, this);
protocolBridge.getProtocolSettings().eventManager.executeEvent(new WebClientConnectedEvent(connectedWebClient));
}
}
} catch (IOException e) {
pipelineServer.getLogger().exception("Failed to accept WebClient", e);
}
}
}).start();
}
/**
* Optional callback when the connection closes.
*/
public void onDisconnect(ConnectedWebClient client) {}
/**
* Called when the server receives a WebRequestPacket from the client.
*
* @param client The connected web client (pipeline + web socket).
* @param client The connected web client (pipeline + web socket).
* @param request The full decoded request packet.
* @return The response packet that should be sent back to the client.
*/
public abstract WebResponsePacket onWebRequest(ConnectedWebClient client, WebRequestPacket request);
/**
* Handles the shutdown of the web server when the pipeline server stops.
*
* @throws IOException If an I/O error occurs while closing the web server.
*/
private void onPipelineStop() throws IOException {
webServer.close();
}
/**
* Checks if the required certificate files exist in the specified folder.
*
* @param folder The folder to check for certificate files.
* @param prefix The prefix of the certificate files.
* @param extension The extension of the certificate files.
* @throws CertificateException If a required certificate file is missing or invalid.
* @throws IOException If an I/O error occurs while checking the files.
*/
private void checkFileExists(File folder, String prefix, String extension) throws CertificateException, IOException {
boolean found = false;
// Ensure the folder exists
if (folder == null) throw new FileNotFoundException("Folder does not exist");
// List all files in the folder
File[] files = folder.listFiles();
if (files == null || files.length == 0)
throw new FileNotFoundException("Folder " + folder.getAbsolutePath() + " is empty");
// Check for the required certificate file
for (File file : files) {
if (!file.getName().startsWith(prefix))
throw new CertificateException(file.getAbsolutePath() + " is not valid");
// Check for file matching the public IP address
if (!found) found = file.getName().equalsIgnoreCase(prefix + NetworkUtils.getPublicIPAddress() + extension);
}
// Throw exception if the required file is not found
if (!found) throw new CertificateException("Missing " + prefix + NetworkUtils.getPublicIPAddress() + extension);
}
/**
* Represents the folder structure for server certificates.
*/
public final class ServerCertificateFolderStructure {
public final File certificatesFolder;
public final File publicFolder;
public final File privateFolder;
public final File privateCAFolder;
public final File privateServerFolder;
public final File publicCAFolder;
public final File publicServerFolder;
public final String caPrefix = "ca_server_";
public final String certPrefix = "cert_server_";
public ServerCertificateFolderStructure() {
certificatesFolder = new File("certificates");
publicFolder = new File(certificatesFolder, "public");
privateFolder = new File(certificatesFolder, "private");
privateCAFolder = new File(privateFolder, "ca");
privateServerFolder = new File(privateFolder, "server");
publicCAFolder = new File(publicFolder, "ca");
publicServerFolder = new File(publicFolder, "server");
if (!certificatesFolder.exists()) certificatesFolder.mkdirs();
if (!publicFolder.exists()) publicFolder.mkdirs();
if (!privateFolder.exists()) privateFolder.mkdirs();
if (!privateCAFolder.exists()) privateCAFolder.mkdirs();
if (!privateServerFolder.exists()) privateServerFolder.mkdirs();
if (!publicCAFolder.exists()) publicCAFolder.mkdirs();
if (!publicServerFolder.exists()) publicServerFolder.mkdirs();
}
}
}

View File

@@ -4,7 +4,6 @@ import dev.unlegitdqrk.unlegitlibrary.file.ConfigurationManager;
import java.io.File;
import java.io.IOException;
import java.lang.module.Configuration;
public class WebServerConfig {

View File

@@ -1,24 +0,0 @@
package org.openautonomousconnection.protocol.side.web.events;
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
import lombok.Getter;
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
import org.openautonomousconnection.protocol.side.web.ConnectedWebClient;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
/**
* Event triggered when a web client connects to the web server.
*/
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
public final class WebClientConnectedEvent extends Event {
/**
* The connected web client.
*/
@Getter
private final ConnectedWebClient webClient;
public WebClientConnectedEvent(ConnectedWebClient webClient) {
this.webClient = webClient;
}
}