Moved classic version to an own branch #3
114
README.MD
114
README.MD
@@ -1,48 +1,35 @@
|
|||||||
# Open Autonomous Connection Protocol
|
# Open Autonomous Connection Protocol
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> This is the classic version!
|
||||||
|
> Classic version is not longer maintained or supported please switch the Branch to master
|
||||||
|
> The new Protocol has a Backwards compatibility and is supporting the classic Version
|
||||||
|
|
||||||
This is the Protocol for our Open Autonomous Connection project.<br />
|
This is the Protocol for our Open Autonomous Connection project.<br />
|
||||||
You can easily implement this Protocol via Maven.<br />
|
You can easily implement this Protocol via Maven.<br />
|
||||||
Feel free to join our Discord.
|
Feel free to join our Discord.
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
## License Notice
|
|
||||||
|
|
||||||
This project (OAC) is licensed under
|
|
||||||
the [Open Autonomous Public License (OAPL)](https://open-autonomous-connection.org/license.html).
|
|
||||||
|
|
||||||
**Third-party components:**
|
|
||||||
|
|
||||||
- *UnlegitLibrary* is authored by the same copyright holder and is used here under a special agreement:
|
|
||||||
While [UnlegitLibrary](https://repo.unlegitdqrk.dev/UnlegitDqrk/unlegitlibrary/) is generally distributed under
|
|
||||||
the [GNU GPLv3](https://repo.unlegitdqrk.dev/UnlegitDqrk/unlegitlibrary/src/branch/master/LICENSE),
|
|
||||||
it is additionally licensed under OAPL **exclusively for the OAC project**.
|
|
||||||
Therefore, within OAC, the OAPL terms apply to UnlegitLibrary as well.<br/>
|
|
||||||
<br />
|
<br />
|
||||||
### Take a look into [Certificate Generation](https://repo.unlegitdqrk.dev/UnlegitDqrk/unlegitlibrary/src/branch/master#certificate-generation-for-networksystem).
|
|
||||||
# Bugs/Problems
|
# Bugs/Problems
|
||||||
- Project not tested yet
|
|
||||||
# In progress
|
# In progress
|
||||||
- WebServer
|
- Cleanup Code
|
||||||
# TODO
|
# TODO
|
||||||
- Finishing WebServer
|
- Subdomains
|
||||||
- Writing INS Backend and Frontend
|
- Fragments
|
||||||
- Writing WebClient
|
|
||||||
- Writing WebServer
|
|
||||||
- Documentation / Wiki
|
|
||||||
# Maven
|
# Maven
|
||||||
|
|
||||||
### pom.xml
|
### pom.xml
|
||||||
|
|
||||||
```
|
```
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openautonomousconnection</groupId>
|
<groupId>me.openautonomousconnection</groupId>
|
||||||
<artifactId>protocol</artifactId>
|
<artifactId>protocol</artifactId>
|
||||||
<version>VERSION</version>
|
<version>1.0.0-Classic</version>
|
||||||
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Repository:
|
### Repository:
|
||||||
|
|
||||||
```
|
```
|
||||||
<repository>
|
<repository>
|
||||||
<id>oac</id>
|
<id>oac</id>
|
||||||
@@ -52,3 +39,78 @@ the [Open Autonomous Public License (OAPL)](https://open-autonomous-connection.o
|
|||||||
</snapshots>
|
</snapshots>
|
||||||
</repository>
|
</repository>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
#### Note: These examples are very basic
|
||||||
|
### Server
|
||||||
|
|
||||||
|
```java
|
||||||
|
import me.finn.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolSettings;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolVersion;
|
||||||
|
import side.org.openautonomousconnection.protocol.ProtocolServer;
|
||||||
|
|
||||||
|
public class Server extends ProtocolServer {
|
||||||
|
|
||||||
|
public Server() throws IOException, InterruptedException {
|
||||||
|
super(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
ProtocolBridge protocolBridge = new ProtocolBridge(ProtocolVersion.PV_1_0_0, new ProtocolSettings(), new Server());
|
||||||
|
protocolBridge.getProtocolServer().setProtocolBridge(protocolBridge);
|
||||||
|
protocolBridge.getProtocolServer().startServer();
|
||||||
|
} catch (IOException | InterruptedException | InvocationTargetException | InstantiationException |
|
||||||
|
IllegalAccessException | NoSuchMethodException exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Domain> getDomains() throws SQLException {
|
||||||
|
return List.of(); // Your method here to get all registered domains
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(ConnectionHandler connectionHandler, String message) {
|
||||||
|
System.out.println("Received message: " + message + " from client: " + connectionHandler.getClientID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### Client
|
||||||
|
|
||||||
|
```java
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolSettings;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolVersion;
|
||||||
|
import domain.org.openautonomousconnection.protocol.Domain;
|
||||||
|
import side.org.openautonomousconnection.protocol.ProtocolClient;
|
||||||
|
import utils.org.openautonomousconnection.protocol.SiteType;
|
||||||
|
|
||||||
|
public class Client extends ProtocolClient {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
ProtocolBridge protocolBridge = new ProtocolBridge(ProtocolVersion.PV_1_0_0, new ProtocolSettings(), new Client());
|
||||||
|
protocolBridge.getProtocolClient().setProtocolBridge(protocolBridge);
|
||||||
|
protocolBridge.getProtocolServer().startClient();
|
||||||
|
} catch (IOException | InterruptedException | InvocationTargetException | InstantiationException |
|
||||||
|
IllegalAccessException | NoSuchMethodException exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleHTMLContent(SiteType siteType, Domain domain, String htmlContent) {
|
||||||
|
System.out.println("Website html content received. This site is " + siteType.name);
|
||||||
|
System.out.println(htmlContent); // Render content in a webview for example
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(String message) {
|
||||||
|
System.out.println("Received message: " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
4
pom.xml
4
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>org.openautonomousconnection</groupId>
|
<groupId>org.openautonomousconnection</groupId>
|
||||||
<artifactId>protocol</artifactId>
|
<artifactId>protocol</artifactId>
|
||||||
<version>1.0.0-BETA.11</version>
|
<version>1.0.0-Classic</version>
|
||||||
<organization>
|
<organization>
|
||||||
<name>Open Autonomous Connection</name>
|
<name>Open Autonomous Connection</name>
|
||||||
<url>https://open-autonomous-connection.org/</url>
|
<url>https://open-autonomous-connection.org/</url>
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>dev.unlegitdqrk</groupId>
|
<groupId>dev.unlegitdqrk</groupId>
|
||||||
<artifactId>unlegitlibrary</artifactId>
|
<artifactId>unlegitlibrary</artifactId>
|
||||||
<version>1.6.6</version>
|
<version>1.6.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
|
|||||||
@@ -1,384 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
package org.openautonomousconnection.protocol;
|
package org.openautonomousconnection.protocol;
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.utils.Logger;
|
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
||||||
import lombok.Getter;
|
import org.openautonomousconnection.protocol.packets.v1_0_0.DomainPacket;
|
||||||
import lombok.Setter;
|
import org.openautonomousconnection.protocol.packets.v1_0_0.MessagePacket;
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
import org.openautonomousconnection.protocol.packets.v1_0_0.PingPacket;
|
||||||
import org.openautonomousconnection.protocol.listeners.ClientListener;
|
import org.openautonomousconnection.protocol.side.ProtocolClient;
|
||||||
import org.openautonomousconnection.protocol.listeners.INSServerListener;
|
import org.openautonomousconnection.protocol.side.ProtocolServer;
|
||||||
import org.openautonomousconnection.protocol.listeners.WebServerListener;
|
import org.openautonomousconnection.protocol.utils.APIInformation;
|
||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.AuthPacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.INSQueryPacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.INSResponsePacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.UnsupportedClassicPacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.classic.Classic_DomainPacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.classic.Classic_MessagePacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.classic.Classic_PingPacket;
|
|
||||||
import org.openautonomousconnection.protocol.side.client.ProtocolClient;
|
|
||||||
import org.openautonomousconnection.protocol.side.ins.ProtocolINSServer;
|
|
||||||
import org.openautonomousconnection.protocol.side.web.ProtocolWebServer;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerClient;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerINSServer;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerWebServer;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ClientListener;
|
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Proxy;
|
import java.io.InputStreamReader;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
/**
|
public class ProtocolBridge extends DefaultMethodsOverrider {
|
||||||
* The main bridge class for the protocol connection.
|
private APIInformation apiInformation;
|
||||||
* It manages the protocol settings, version, and side instances.
|
|
||||||
*/
|
|
||||||
public final class ProtocolBridge {
|
|
||||||
/**
|
|
||||||
* The protocol settings for the current connection
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ProtocolSettings protocolSettings;
|
private final ProtocolSettings protocolSettings;
|
||||||
|
|
||||||
/**
|
|
||||||
* The protocol version for the current connection
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ProtocolVersion protocolVersion;
|
private final ProtocolVersion protocolVersion;
|
||||||
|
|
||||||
/**
|
private final ProtocolServer protocolServer;
|
||||||
* The logger instance for logging events and errors
|
private final ProtocolClient protocolClient;
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private Logger logger;
|
|
||||||
|
|
||||||
/**
|
public final boolean isRunningAsServer() {
|
||||||
* The protocol side instances
|
return protocolServer != null;
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private ProtocolINSServer protocolINSServer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The protocol side instances
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private ProtocolClient protocolClient;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The protocol side instances
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private ProtocolWebServer protocolWebServer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The classic protocol handlers for INS server side
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private ClassicHandlerINSServer classicHandlerINSServer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The classic protocol handlers for web server side
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private ClassicHandlerWebServer classicHandlerWebServer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The classic protocol handlers for client side
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private ClassicHandlerClient classicHandlerClient;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The proxy for client side
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private Proxy proxy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the ProtocolBridge instance for the INS server side
|
|
||||||
*
|
|
||||||
* @param protocolINSServer The ProtocolINSServer instance
|
|
||||||
* @param protocolSettings The ProtocolSettings instance
|
|
||||||
* @param protocolVersion The ProtocolVersion instance
|
|
||||||
* @param logFolder The folder to store the log files
|
|
||||||
* @throws Exception if an error occurs while initializing the ProtocolBridge
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.INS)
|
|
||||||
public ProtocolBridge(ProtocolINSServer protocolINSServer, ProtocolSettings protocolSettings, ProtocolVersion protocolVersion, File logFolder) throws Exception {
|
|
||||||
// Assign the parameters to the class fields
|
|
||||||
this.protocolINSServer = protocolINSServer;
|
|
||||||
this.protocolSettings = protocolSettings;
|
|
||||||
this.protocolVersion = protocolVersion;
|
|
||||||
|
|
||||||
// Initialize the logger and protocol version
|
|
||||||
initializeLogger(logFolder);
|
|
||||||
initializeProtocolVersion();
|
|
||||||
|
|
||||||
// Register the appropriate listeners and packets
|
|
||||||
registerListeners();
|
|
||||||
registerPackets();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public final ProtocolClient getProtocolClient() {
|
||||||
* Initialize the ProtocolBridge instance for the web server side
|
return protocolClient;
|
||||||
*
|
|
||||||
* @param protocolWebServer The ProtocolWebServer instance
|
|
||||||
* @param protocolSettings The ProtocolSettings instance
|
|
||||||
* @param protocolVersion The ProtocolVersion instance
|
|
||||||
* @param logFolder The folder to store the log files
|
|
||||||
* @throws Exception if an error occurs while initializing the ProtocolBridge
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
|
||||||
public ProtocolBridge(ProtocolWebServer protocolWebServer, ProtocolSettings protocolSettings, ProtocolVersion protocolVersion, File logFolder) throws Exception {
|
|
||||||
// Assign the parameters to the class fields
|
|
||||||
this.protocolWebServer = protocolWebServer;
|
|
||||||
this.protocolSettings = protocolSettings;
|
|
||||||
this.protocolVersion = protocolVersion;
|
|
||||||
|
|
||||||
// Initialize the logger and protocol version
|
|
||||||
initializeLogger(logFolder);
|
|
||||||
initializeProtocolVersion();
|
|
||||||
|
|
||||||
// Register the appropriate listeners and packets
|
|
||||||
registerListeners();
|
|
||||||
registerPackets();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public final ProtocolSettings getProtocolSettings() {
|
||||||
* Initialize the ProtocolBridge instance for the client side
|
return protocolSettings;
|
||||||
*
|
}
|
||||||
* @param protocolClient The ProtocolClient instance
|
|
||||||
* @param protocolSettings The ProtocolSettings instance
|
public final ProtocolServer getProtocolServer() {
|
||||||
* @param protocolVersion The ProtocolVersion instance
|
return protocolServer;
|
||||||
* @param logFolder The folder to store the log files
|
}
|
||||||
* @throws Exception if an error occurs while initializing the ProtocolBridge
|
|
||||||
*/
|
public final ProtocolVersion getProtocolVersion() {
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
|
return protocolVersion;
|
||||||
public ProtocolBridge(ProtocolClient protocolClient, ProtocolSettings protocolSettings, ProtocolVersion protocolVersion, File logFolder) throws Exception {
|
}
|
||||||
// Assign the parameters to the class fields
|
|
||||||
|
private static ProtocolBridge instance;
|
||||||
|
|
||||||
|
public static ProtocolBridge getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProtocolBridge(ProtocolVersion protocolVersion, ProtocolSettings protocolSettings, ProtocolClient protocolClient, APIInformation apiInformation) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||||
|
this(protocolVersion, protocolSettings, protocolClient);
|
||||||
|
this.apiInformation = apiInformation;
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProtocolBridge(ProtocolVersion protocolVersion, ProtocolSettings protocolSettings, ProtocolClient protocolClient) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||||
|
checkUpdates();
|
||||||
|
|
||||||
|
protocolSettings.packetHandler.registerPacket(new DomainPacket());
|
||||||
|
protocolSettings.packetHandler.registerPacket(new PingPacket());
|
||||||
|
protocolSettings.packetHandler.registerPacket(new MessagePacket());
|
||||||
|
|
||||||
|
this.protocolServer = null;
|
||||||
|
|
||||||
|
this.protocolVersion = protocolVersion;
|
||||||
|
this.protocolSettings = protocolSettings;
|
||||||
|
this.apiInformation = null;
|
||||||
this.protocolClient = protocolClient;
|
this.protocolClient = protocolClient;
|
||||||
this.protocolSettings = protocolSettings;
|
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProtocolBridge(ProtocolVersion protocolVersion, ProtocolSettings protocolSettings, ProtocolServer protocolServer) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||||
|
checkUpdates();
|
||||||
|
|
||||||
|
this.apiInformation = null;
|
||||||
|
this.protocolClient = null;
|
||||||
|
|
||||||
this.protocolVersion = protocolVersion;
|
this.protocolVersion = protocolVersion;
|
||||||
|
this.protocolSettings = protocolSettings;
|
||||||
|
this.protocolServer = protocolServer;
|
||||||
|
|
||||||
// Initialize the logger and protocol version
|
protocolSettings.packetHandler.registerPacket(new DomainPacket());
|
||||||
initializeLogger(logFolder);
|
protocolSettings.packetHandler.registerPacket(new PingPacket());
|
||||||
initializeProtocolVersion();
|
protocolSettings.packetHandler.registerPacket(new MessagePacket());
|
||||||
|
|
||||||
// Register the appropriate listeners and packets
|
instance = this;
|
||||||
registerListeners();
|
|
||||||
registerPackets();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public ProtocolBridge(ProtocolVersion protocolVersion, ProtocolSettings protocolSettings, ProtocolServer protocolServer, APIInformation apiInformation) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||||
* Register the appropriate packets based on the current protocol version
|
this(protocolVersion, protocolSettings, protocolServer);
|
||||||
*/
|
this.apiInformation = apiInformation;
|
||||||
private void registerPackets() {
|
instance = this;
|
||||||
// Classic packets
|
|
||||||
Classic_DomainPacket cDomainPacket = new Classic_DomainPacket();
|
|
||||||
Classic_MessagePacket cMessagePacket = new Classic_MessagePacket();
|
|
||||||
Classic_PingPacket cPingPacket = new Classic_PingPacket();
|
|
||||||
|
|
||||||
if (isPacketSupported(cDomainPacket)) protocolSettings.packetHandler.registerPacket(cDomainPacket);
|
|
||||||
if (isPacketSupported(cMessagePacket)) protocolSettings.packetHandler.registerPacket(cMessagePacket);
|
|
||||||
if (isPacketSupported(cPingPacket)) protocolSettings.packetHandler.registerPacket(cPingPacket);
|
|
||||||
|
|
||||||
// 1.0.0-BETA packets
|
|
||||||
AuthPacket v100bAuthPath = new AuthPacket();
|
|
||||||
UnsupportedClassicPacket v100bUnsupportedClassicPacket = new UnsupportedClassicPacket();
|
|
||||||
INSQueryPacket v100BINSQueryPacket = new INSQueryPacket();
|
|
||||||
INSResponsePacket v100BINSResponsePacket = new INSResponsePacket(this);
|
|
||||||
|
|
||||||
if (isPacketSupported(v100bAuthPath)) protocolSettings.packetHandler.registerPacket(v100bAuthPath);
|
|
||||||
if (isPacketSupported(v100bUnsupportedClassicPacket))
|
|
||||||
protocolSettings.packetHandler.registerPacket(v100bUnsupportedClassicPacket);
|
|
||||||
if (isPacketSupported(v100BINSQueryPacket))
|
|
||||||
protocolSettings.packetHandler.registerPacket(v100BINSQueryPacket);
|
|
||||||
if (isPacketSupported(v100BINSResponsePacket))
|
|
||||||
protocolSettings.packetHandler.registerPacket(v100BINSResponsePacket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private final void checkUpdates() {
|
||||||
* Register the appropriate listeners based on the current side
|
|
||||||
*
|
|
||||||
* @throws Exception if an error occurs while registering the listeners
|
|
||||||
*/
|
|
||||||
private void registerListeners() throws Exception {
|
|
||||||
// Classic listeners
|
|
||||||
if (isClassicSupported()) {
|
|
||||||
Classic_ClientListener classicListener = new Classic_ClientListener();
|
|
||||||
classicListener.setProtocolBridge(this);
|
|
||||||
protocolSettings.eventManager.registerListener(classicListener.getClass());
|
|
||||||
} else protocolSettings.eventManager.unregisterListener(Classic_ClientListener.class);
|
|
||||||
|
|
||||||
// INS Listeners
|
|
||||||
if (isRunningAsINSServer()) {
|
|
||||||
INSServerListener serverListener = new INSServerListener();
|
|
||||||
serverListener.setINSServer(protocolINSServer);
|
|
||||||
protocolSettings.eventManager.registerListener(serverListener.getClass());
|
|
||||||
protocolSettings.eventManager.unregisterListener(WebServerListener.class);
|
|
||||||
protocolSettings.eventManager.unregisterListener(ClientListener.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Web Listeners
|
|
||||||
if (isRunningAsWebServer()) {
|
|
||||||
WebServerListener serverListener = new WebServerListener();
|
|
||||||
serverListener.setWebServer(protocolWebServer);
|
|
||||||
protocolSettings.eventManager.registerListener(serverListener.getClass());
|
|
||||||
protocolSettings.eventManager.unregisterListener(INSServerListener.class);
|
|
||||||
protocolSettings.eventManager.unregisterListener(ClientListener.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client Listeners
|
|
||||||
if (isRunningAsClient()) {
|
|
||||||
ClientListener clientListener = new ClientListener();
|
|
||||||
clientListener.setClient(protocolClient);
|
|
||||||
protocolSettings.eventManager.registerListener(clientListener.getClass());
|
|
||||||
protocolSettings.eventManager.unregisterListener(INSServerListener.class);
|
|
||||||
protocolSettings.eventManager.unregisterListener(WebServerListener.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the logger instance
|
|
||||||
*
|
|
||||||
* @param logFolder The folder to store the log files
|
|
||||||
*/
|
|
||||||
private void initializeLogger(File logFolder) {
|
|
||||||
// Create a temporary logger instance to avoid final field issues
|
|
||||||
Logger tmpLogger = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Initialize temporary logger
|
URL oracle = new URL("https://raw.githubusercontent.com/Open-Autonomous-Connection/Protocol/master/src/main/java/me/openautonomousconnection/protocol/version.txt");
|
||||||
tmpLogger = new Logger(logFolder, false, true);
|
|
||||||
} catch (IOException | NoSuchFieldException | IllegalAccessException exception) {
|
|
||||||
exception.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign the temporary logger to the final field
|
BufferedReader in = new BufferedReader(new InputStreamReader(oracle.openStream()));
|
||||||
this.logger = tmpLogger;
|
String version = "";
|
||||||
}
|
String inputLine;
|
||||||
|
while ((inputLine = in.readLine()) != null) version += inputLine;
|
||||||
|
|
||||||
/**
|
if (!version.equalsIgnoreCase(Files.readString(new File("version.txt").toPath()))) {
|
||||||
* Initialize the protocol version
|
System.out.println();
|
||||||
* Validate if the protocol version is valid for the current side
|
System.out.println("========================================================");
|
||||||
* If not, log an error and exit the application
|
System.out.println("IMPORTANT: A NEW PROTOCOL VERSION IS PUBLISHED ON GITHUB");
|
||||||
*/
|
System.out.println("========================================================");
|
||||||
private void initializeProtocolVersion() {
|
System.out.println();
|
||||||
// Check if the protocol version is valid for the current side
|
}
|
||||||
// If not, log an error and exit the application
|
} catch (IOException exception) {
|
||||||
if (!validateProtocolSide()) {
|
System.out.println();
|
||||||
this.logger.error("Invalid protocol version '" + protocolVersion.toString() + "'!");
|
System.out.println("=======================================================================");
|
||||||
System.exit(1);
|
System.out.println("IMPORTANT: PROTOCOL VERSION CHECK COULD NOT COMPLETED! VISIT OUR GITHUB");
|
||||||
|
System.out.println(" https://github.com/Open-Autonomous-Connection ");
|
||||||
|
System.out.println("=======================================================================");
|
||||||
|
System.out.println();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public final APIInformation getApiInformation() {
|
||||||
* Check if the classic protocol is supported by the current protocol version
|
return apiInformation;
|
||||||
*
|
|
||||||
* @return true if the classic protocol is supported, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean isClassicSupported() {
|
|
||||||
boolean yes = false;
|
|
||||||
for (ProtocolVersion compatibleVersion : protocolVersion.getCompatibleVersions()) {
|
|
||||||
// Check if the compatible version is classic
|
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
|
||||||
if (yes) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the current protocol version is classic or if it is supported by any of the compatible versions
|
|
||||||
return protocolVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC || yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the target protocol is supported by the current protocol version
|
|
||||||
*
|
|
||||||
* @param protocol The target protocol to check
|
|
||||||
* @return true If the target protocol is supported, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean isProtocolSupported(ProtocolVersion.Protocol protocol) {
|
|
||||||
boolean yes = false;
|
|
||||||
for (ProtocolVersion compatibleVersion : protocolVersion.getCompatibleVersions()) {
|
|
||||||
// Check if the compatible version supports the target protocol
|
|
||||||
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
|
|
||||||
if (yes) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the current protocol version supports the target protocol or if it is supported by any of the compatible versions
|
|
||||||
return protocolVersion.getSupportedProtocols().contains(protocol) || yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the target packet is supported by the current protocol version
|
|
||||||
*
|
|
||||||
* @param packet The target packet to check
|
|
||||||
* @return true if the target packet is supported, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean isPacketSupported(OACPacket packet) {
|
|
||||||
return isVersionSupported(packet.getProtocolVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the target protocol version is supported by the current protocol version
|
|
||||||
*
|
|
||||||
* @param targetVersion The target protocol version to check
|
|
||||||
* @return true if the target protocol version is supported, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean isVersionSupported(ProtocolVersion targetVersion) {
|
|
||||||
// Check if the target protocol version is the same as the current protocol version or if it is in the list of compatible versions
|
|
||||||
return protocolVersion == targetVersion || protocolVersion.getCompatibleVersions().contains(targetVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate if the protocol version is valid for the current side
|
|
||||||
*
|
|
||||||
* @return true if the protocol version is valid for the current side, false otherwise
|
|
||||||
*/
|
|
||||||
private boolean validateProtocolSide() {
|
|
||||||
return
|
|
||||||
(isRunningAsClient() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT) ||
|
|
||||||
(isRunningAsClient() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT_WEB) ||
|
|
||||||
(isRunningAsClient() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT_INS) ||
|
|
||||||
(isRunningAsClient() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.ALL) ||
|
|
||||||
|
|
||||||
(isRunningAsWebServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.WEB) ||
|
|
||||||
(isRunningAsWebServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT_WEB) ||
|
|
||||||
(isRunningAsWebServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.WEB_INS) ||
|
|
||||||
(isRunningAsWebServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.ALL) ||
|
|
||||||
|
|
||||||
(isRunningAsINSServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.INS) ||
|
|
||||||
(isRunningAsINSServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.WEB_INS) ||
|
|
||||||
(isRunningAsINSServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT_INS) ||
|
|
||||||
(isRunningAsINSServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the current instance is running as a INS server
|
|
||||||
*
|
|
||||||
* @return true if the current instance is running as a INS server, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean isRunningAsINSServer() {
|
|
||||||
return protocolINSServer != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the current instance is running as a client
|
|
||||||
*
|
|
||||||
* @return true if the current instance is running as a client, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean isRunningAsClient() {
|
|
||||||
return protocolClient != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the current instance is running as a web server
|
|
||||||
*
|
|
||||||
* @return true if the current instance is running as a web server, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean isRunningAsWebServer() {
|
|
||||||
return protocolWebServer != null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
package org.openautonomousconnection.protocol;
|
package org.openautonomousconnection.protocol;
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.EventManager;
|
import dev.unlegitdqrk.unlegitlibrary.event.EventManager;
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
||||||
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
||||||
|
|
||||||
/**
|
public class ProtocolSettings extends DefaultMethodsOverrider {
|
||||||
* Settings for the protocol connection.
|
|
||||||
*/
|
|
||||||
public final class ProtocolSettings extends DefaultMethodsOverrider {
|
|
||||||
|
|
||||||
/**
|
public String host = "45.155.173.50";
|
||||||
* The host to connect to.
|
public int port = 8345;
|
||||||
*/
|
public PacketHandler packetHandler = new PacketHandler();
|
||||||
public String host;
|
public EventManager eventManager = new EventManager();
|
||||||
|
|
||||||
/**
|
|
||||||
* The port to connect to.
|
|
||||||
*/
|
|
||||||
public int port;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The protocol version to use.
|
|
||||||
*/
|
|
||||||
public PacketHandler packetHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The event manager to use.
|
|
||||||
*/
|
|
||||||
public EventManager eventManager;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public enum ProtocolVersion implements Serializable {
|
||||||
|
PV_1_0_0("1.0.0");
|
||||||
|
;
|
||||||
|
public final String version;
|
||||||
|
|
||||||
|
ProtocolVersion(String version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.annotations;
|
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation to provide metadata about protocol handlers or classes.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface ProtocolInfo {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the side of the protocol that the annotated class or method is associated with.
|
|
||||||
* Default is ALL, indicating that it can be used on any side.
|
|
||||||
*
|
|
||||||
* @return The protocol side.
|
|
||||||
*/
|
|
||||||
ProtocolVersion.ProtocolSide protocolSide() default ProtocolVersion.ProtocolSide.ALL;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.annotations.processing;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.reflections.GenericReflectClass;
|
|
||||||
import net.bytebuddy.agent.ByteBuddyAgent;
|
|
||||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.instrument.Instrumentation;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.any;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
|
||||||
|
|
||||||
public class CallTracker<A extends Annotation> extends GenericReflectClass<A> {
|
|
||||||
private static final AtomicReference<Class<? extends Annotation>> atomicClass = new AtomicReference<>();
|
|
||||||
|
|
||||||
public CallTracker(CallInterceptor interceptor) {
|
|
||||||
super();
|
|
||||||
atomicClass.set(this.persistentClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void premain(String agentArgs, Instrumentation inst) {
|
|
||||||
ByteBuddyAgent.install();
|
|
||||||
|
|
||||||
new AgentBuilder.Default()
|
|
||||||
.type(any()) // instrument all classes, you can restrict here
|
|
||||||
.transform((builder, type, classLoader, module, protectionDomain) ->
|
|
||||||
builder.visit(Advice.to(CallInterceptor.class).on(isMethod()))).installOn(inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract static class CallInterceptor {
|
|
||||||
private static final Set<CallInterceptor> interceptors = new HashSet<>();
|
|
||||||
|
|
||||||
public CallInterceptor() {
|
|
||||||
interceptors.add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Advice.OnMethodEnter
|
|
||||||
static void intercept(@Advice.Origin Method method) {
|
|
||||||
for (CallInterceptor interceptor : interceptors) {
|
|
||||||
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
|
|
||||||
|
|
||||||
if (stack.length <= 3) return;
|
|
||||||
|
|
||||||
StackTraceElement caller = stack[3];
|
|
||||||
interceptor.onCall(method, caller);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (method.isAnnotationPresent(atomicClass.get())) {
|
|
||||||
// StackTraceElement[] stack = Thread.currentThread().getStackTrace();
|
|
||||||
// // stack[0] = getStackTrace
|
|
||||||
// // stack[1] = intercept
|
|
||||||
// // stack[2] = Advice dispatcher
|
|
||||||
// // stack[3+] = your actual caller
|
|
||||||
// if (stack.length <= 3)
|
|
||||||
// return;
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// StackTraceElement caller = stack[3];
|
|
||||||
//
|
|
||||||
// System.out.println("Annotated method " + method.getName()
|
|
||||||
// + " was called by " + caller.getClassName() + "." + caller.getMethodName());
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Code executed on any method call
|
|
||||||
*/
|
|
||||||
public abstract void onCall(Method method, @Nullable StackTraceElement callerMethod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
// Author: maple
|
|
||||||
// date: 9/29/25
|
|
||||||
|
|
||||||
package org.openautonomousconnection.protocol.annotations.processing;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.reflections.annotation.processing.AnnotationProcessor;
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|
||||||
import org.openautonomousconnection.protocol.exceptions.IncompatibleProtocolSideException;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process ProtocolInfo annotation and throw exception on mismatching annotation and ProtocolSide
|
|
||||||
*/
|
|
||||||
public class ProtocolInfoProcessing extends AnnotationProcessor<ProtocolInfo> {
|
|
||||||
|
|
||||||
private final CallTracker<ProtocolInfo> tracker;
|
|
||||||
|
|
||||||
private final AtomicReference<Set<Method>> methodReferences = new AtomicReference<>();
|
|
||||||
private final AtomicReference<Set<Class<?>>> typeReferences = new AtomicReference<>();
|
|
||||||
|
|
||||||
public ProtocolInfoProcessing() {
|
|
||||||
super("org.openautonomousconnection.protocol");
|
|
||||||
|
|
||||||
this.process();
|
|
||||||
|
|
||||||
this.methodReferences.set(this.annotatedMethods);
|
|
||||||
|
|
||||||
this.typeReferences.set(this.annotatedTypes);
|
|
||||||
|
|
||||||
this.tracker = new CallTracker<>(new CallTracker.CallInterceptor() {
|
|
||||||
@Override
|
|
||||||
public void onCall(Method method, @Nullable StackTraceElement callerMethod) {
|
|
||||||
ProtocolVersion.ProtocolSide side, callerSide;
|
|
||||||
Object o;
|
|
||||||
|
|
||||||
if ((o = methodGetByName(callerMethod.getMethodName())) != null)
|
|
||||||
callerSide = ((Method) o).getAnnotation(ProtocolInfo.class).protocolSide();
|
|
||||||
else if ((o = typeHasAnnotation(callerMethod.getClassName())) != null)
|
|
||||||
callerSide = ((Class<?>) o).getAnnotation(ProtocolInfo.class).protocolSide();
|
|
||||||
else return;
|
|
||||||
|
|
||||||
|
|
||||||
if (methodReferences.get().contains(method))
|
|
||||||
side = method.getAnnotation(ProtocolInfo.class).protocolSide();
|
|
||||||
else if (typeReferences.get().contains(method.getDeclaringClass()))
|
|
||||||
side = method.getDeclaringClass().getAnnotation(ProtocolInfo.class).protocolSide();
|
|
||||||
else return;
|
|
||||||
|
|
||||||
if (callerSide.equals(ProtocolVersion.ProtocolSide.CLIENT) && !side.equals(callerSide))
|
|
||||||
throw new IncompatibleProtocolSideException(callerSide, side);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private Method methodGetByName(String methodName) {
|
|
||||||
for (Method method : this.annotatedMethods) if (method.getName().equals(methodName)) return method;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Class<?> typeHasAnnotation(String typeName) {
|
|
||||||
for (Class<?> type : this.annotatedTypes) if (type.getName().equals(typeName)) return type;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processType(Class<?> type) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processMethod(Method method) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processField(Field field) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processConstructor(Constructor constructor) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.domain;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.string.StringUtils;
|
||||||
|
import org.openautonomousconnection.protocol.utils.DomainUtils;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class Domain implements Serializable {
|
||||||
|
public final String name;
|
||||||
|
public final String topLevelDomain;
|
||||||
|
private final String destination;
|
||||||
|
private final String path;
|
||||||
|
|
||||||
|
public Domain(String name, String topLevelDomain, String destination, String path) {
|
||||||
|
if (path == null) path = "";
|
||||||
|
|
||||||
|
this.name = name;
|
||||||
|
this.topLevelDomain = topLevelDomain;
|
||||||
|
this.destination = destination;
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String realDestination() {
|
||||||
|
String tmpDestination = destination.endsWith("/") ? destination : destination + "/";
|
||||||
|
String tmpPath = getPath();
|
||||||
|
|
||||||
|
if (tmpPath == null) tmpPath = "";
|
||||||
|
if (tmpPath.startsWith("/")) tmpPath = tmpPath.substring("/".length());
|
||||||
|
if (tmpPath.endsWith("/")) tmpPath = tmpPath.substring(0, tmpPath.length() - "/".length());
|
||||||
|
|
||||||
|
return tmpDestination + tmpPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getPath() {
|
||||||
|
if (path.endsWith("/")) return path.substring(0, path.length() - "/".length());
|
||||||
|
if (path.startsWith("/")) return path.substring("/".length());
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String parsedDestination() {
|
||||||
|
if (destination.toLowerCase().startsWith("https://github.com/")) {
|
||||||
|
String base = "https://raw.githubusercontent.com/";
|
||||||
|
String username = DomainUtils.getPath(destination).split("/")[0];
|
||||||
|
String site = DomainUtils.getPath(destination).split("/")[1];
|
||||||
|
|
||||||
|
String tmpPath = getPath();
|
||||||
|
if (tmpPath == null || StringUtils.isEmptyString(tmpPath)) tmpPath = "index.html";
|
||||||
|
if (tmpPath.startsWith("/")) tmpPath = tmpPath.substring("/".length());
|
||||||
|
if (tmpPath.endsWith("/")) tmpPath = tmpPath.substring(0, tmpPath.length() - "/".length());
|
||||||
|
|
||||||
|
base = base + username + "/" + site + "/main/" + tmpPath;
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realDestination();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Object clone() throws CloneNotSupportedException {
|
||||||
|
return new Domain(name, topLevelDomain, destination, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof Domain other)) return false;
|
||||||
|
return other.name.equalsIgnoreCase(name) && other.topLevelDomain.equalsIgnoreCase(topLevelDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return "{parsed='" + parsedDestination() + "';real='" + realDestination() + "'}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.domain;
|
||||||
|
|
||||||
|
public class LocalDomain extends Domain {
|
||||||
|
public LocalDomain(String name, String endName, String path) {
|
||||||
|
super(name, endName, null, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.domain;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class RequestDomain extends Domain implements Serializable {
|
||||||
|
|
||||||
|
public RequestDomain(String name, String topLevelDomain, String path) {
|
||||||
|
super(name, topLevelDomain, null, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.events.v1_0_0;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolVersion;
|
||||||
|
import org.openautonomousconnection.protocol.domain.Domain;
|
||||||
|
import org.openautonomousconnection.protocol.domain.RequestDomain;
|
||||||
|
|
||||||
|
public class DomainPacketReceivedEvent extends Event {
|
||||||
|
|
||||||
|
public final ProtocolVersion protocolVersion;
|
||||||
|
public final Domain domain;
|
||||||
|
public final RequestDomain requestDomain;
|
||||||
|
public final int clientID;
|
||||||
|
|
||||||
|
public DomainPacketReceivedEvent(ProtocolVersion protocolVersion, Domain domain, RequestDomain requestDomain, int clientID) {
|
||||||
|
this.protocolVersion = protocolVersion;
|
||||||
|
this.domain = domain;
|
||||||
|
this.requestDomain = requestDomain;
|
||||||
|
this.clientID = clientID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Object clone() throws CloneNotSupportedException {
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object obj) {
|
||||||
|
return super.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.events.v1_0_0;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolVersion;
|
||||||
|
import org.openautonomousconnection.protocol.domain.Domain;
|
||||||
|
import org.openautonomousconnection.protocol.domain.RequestDomain;
|
||||||
|
|
||||||
|
public class PingPacketReceivedEvent extends Event {
|
||||||
|
|
||||||
|
public final ProtocolVersion protocolVersion;
|
||||||
|
public final Domain domain;
|
||||||
|
public final RequestDomain requestDomain;
|
||||||
|
public final boolean reachable;
|
||||||
|
public final int clientID;
|
||||||
|
|
||||||
|
public PingPacketReceivedEvent(ProtocolVersion protocolVersion, Domain domain, RequestDomain requestDomain, boolean reachable, int clientID) {
|
||||||
|
this.protocolVersion = protocolVersion;
|
||||||
|
this.domain = domain;
|
||||||
|
this.requestDomain = requestDomain;
|
||||||
|
this.reachable = reachable;
|
||||||
|
this.clientID = clientID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Object clone() throws CloneNotSupportedException {
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object obj) {
|
||||||
|
return super.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.exceptions;
|
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception thrown when an unsupported protocol side method is called.
|
|
||||||
*/
|
|
||||||
public class IncompatibleProtocolSideException extends RuntimeException {
|
|
||||||
public IncompatibleProtocolSideException(ProtocolVersion.ProtocolSide callerSide, ProtocolVersion.ProtocolSide side) {
|
|
||||||
super(callerSide.name() + " is incompatible with called method of ProtocolSide " + side.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.exceptions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception thrown when an unsupported protocol is encountered.
|
|
||||||
*/
|
|
||||||
public final class UnsupportedProtocolException extends RuntimeException {
|
|
||||||
|
|
||||||
public UnsupportedProtocolException() {
|
|
||||||
this("Selected protocol is not supported!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnsupportedProtocolException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnsupportedProtocolException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnsupportedProtocolException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnsupportedProtocolException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
|
||||||
super(message, cause, enableSuppression, writableStackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
package org.openautonomousconnection.protocol.listeners;
|
package org.openautonomousconnection.protocol.listeners;
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.EventListener;
|
import dev.unlegitdqrk.unlegitlibrary.event.EventListener;
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.Listener;
|
import dev.unlegitdqrk.unlegitlibrary.event.Listener;
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.events.ClientConnectedEvent;
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.events.ClientDisconnectedEvent;
|
import org.openautonomousconnection.protocol.domain.LocalDomain;
|
||||||
import lombok.Getter;
|
import org.openautonomousconnection.protocol.events.v1_0_0.DomainPacketReceivedEvent;
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
import org.openautonomousconnection.protocol.events.v1_0_0.PingPacketReceivedEvent;
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.AuthPacket;
|
import org.openautonomousconnection.protocol.packets.v1_0_0.PingPacket;
|
||||||
import org.openautonomousconnection.protocol.side.client.ProtocolClient;
|
import org.openautonomousconnection.protocol.utils.SiteType;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.utils.WebsitesContent;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
public class ClientListener extends EventListener {
|
||||||
* Listener for client-side events such as connection and disconnection.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
|
|
||||||
public final class ClientListener extends EventListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The reference to the ProtocolClient object
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private ProtocolClient client;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the client variable
|
|
||||||
*
|
|
||||||
* @param client The Instance of the ProtocolClient
|
|
||||||
*/
|
|
||||||
public void setClient(ProtocolClient client) {
|
|
||||||
if (this.client != null) return;
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the event when a client connects.
|
|
||||||
* Sends an authentication packet to the server.
|
|
||||||
*
|
|
||||||
* @param event The client connected event.
|
|
||||||
*/
|
|
||||||
@Listener
|
@Listener
|
||||||
public void onConnect(ClientConnectedEvent event) {
|
public void onDomain(DomainPacketReceivedEvent event) {
|
||||||
|
boolean exists = event.domain != null;
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
try {
|
try {
|
||||||
event.getClient().sendPacket(new AuthPacket(client.getProtocolBridge()));
|
if (!ProtocolBridge.getInstance().getProtocolClient().getClient().sendPacket(new PingPacket(event.requestDomain, event.domain, false))) {
|
||||||
} catch (IOException | ClassNotFoundException exception) {
|
ProtocolBridge.getInstance().getProtocolClient().handleHTMLContent(SiteType.PROTOCOL, new LocalDomain("error-occurred", "html", ""),
|
||||||
event.getClient().getLogger().exception("Failed to send auth packet", exception);
|
WebsitesContent.ERROR_OCCURRED(event.domain.toString() + "/" + event.domain.getPath()));
|
||||||
event.getClient().disconnect();
|
|
||||||
}
|
}
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
ProtocolBridge.getInstance().getProtocolClient().handleHTMLContent(SiteType.PROTOCOL, new LocalDomain("error-occurred", "html", ""),
|
||||||
|
WebsitesContent.ERROR_OCCURRED(event.domain.toString() + "/" + event.domain.getPath() + "\n" + e.getMessage()));
|
||||||
|
}
|
||||||
|
} else ProtocolBridge.getInstance().getProtocolClient().handleHTMLContent(SiteType.PROTOCOL, new LocalDomain("domain-not-found", "html", ""), WebsitesContent.DOMAIN_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the event when a client disconnects.
|
|
||||||
* Notifies the protocol client of the disconnection.
|
|
||||||
*
|
|
||||||
* @param event The client disconnected event.
|
|
||||||
*/
|
|
||||||
@Listener
|
@Listener
|
||||||
public void onDisconnect(ClientDisconnectedEvent event) {
|
public void onPing(PingPacketReceivedEvent event) {
|
||||||
client.onINSDisconnect(event);
|
if (event.reachable) {
|
||||||
|
String destination = event.domain.parsedDestination();
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL url = new URL(destination);
|
||||||
|
HttpURLConnection connection2 = (HttpURLConnection) url.openConnection();
|
||||||
|
connection2.setRequestMethod("GET");
|
||||||
|
|
||||||
|
StringBuilder content = new StringBuilder();
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection2.getInputStream()))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) content.append(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProtocolBridge.getInstance().getProtocolClient().handleHTMLContent(SiteType.PUBLIC, event.domain, content.toString());
|
||||||
|
} catch (IOException exception) {
|
||||||
|
ProtocolBridge.getInstance().getProtocolClient().handleHTMLContent(SiteType.PROTOCOL, new LocalDomain("error-occurred", "html", ""),
|
||||||
|
WebsitesContent.ERROR_OCCURRED(exception.getMessage().replace(event.domain.parsedDestination(), event.domain.toString() + "/" + event.domain.getPath())));
|
||||||
|
}
|
||||||
|
} else ProtocolBridge.getInstance().getProtocolClient().handleHTMLContent(SiteType.PROTOCOL, new LocalDomain("error-not-reached", "html", ""), WebsitesContent.DOMAIN_NOT_REACHABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Object clone() throws CloneNotSupportedException {
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object obj) {
|
||||||
|
return super.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.listeners;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.EventListener;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.Listener;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.ConnectionHandlerConnectedEvent;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.ConnectionHandlerDisconnectedEvent;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.S_PacketReceivedEvent;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.INSQueryPacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.INSResponsePacket;
|
|
||||||
import org.openautonomousconnection.protocol.side.ins.ConnectedProtocolClient;
|
|
||||||
import org.openautonomousconnection.protocol.side.ins.ProtocolINSServer;
|
|
||||||
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 org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener for INS server connection events.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.INS)
|
|
||||||
public final class INSServerListener extends EventListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The reference to the INSServer object
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private ProtocolINSServer insServer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the insServer variable
|
|
||||||
*
|
|
||||||
* @param insServer The Instance of the INSServer
|
|
||||||
*/
|
|
||||||
public void setINSServer(ProtocolINSServer insServer) {
|
|
||||||
if (this.insServer != null) return;
|
|
||||||
this.insServer = insServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the event when a connection handler connects to the INS server.
|
|
||||||
* Adds the connected client to the ProtocolBridge's INS server client list.
|
|
||||||
*
|
|
||||||
* @param event The connection handler connected event.
|
|
||||||
*/
|
|
||||||
@Listener
|
|
||||||
public void onConnect(ConnectionHandlerConnectedEvent event) {
|
|
||||||
insServer.getClients().add(new ConnectedProtocolClient(event.getConnectionHandler(), insServer));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the event when a connection handler disconnects from the INS server.
|
|
||||||
* Removes the disconnected client from the ProtocolBridge's INS server client list.
|
|
||||||
*
|
|
||||||
* @param event The connection handler disconnected event.
|
|
||||||
*/
|
|
||||||
@Listener
|
|
||||||
public void onDisconnect(ConnectionHandlerDisconnectedEvent event) {
|
|
||||||
insServer.getClients().removeIf(client -> client.getConnectionHandler().getClientID() == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles incoming INS query packets from connected clients.
|
|
||||||
* <p>
|
|
||||||
* This method performs the following steps:
|
|
||||||
* <ul>
|
|
||||||
* <li>Checks whether the received packet is an {@link INSQueryPacket}</li>
|
|
||||||
* <li>Notifies the INS server through {@code onQueryReceived}</li>
|
|
||||||
* <li>Resolves the request via {@code resolve()}</li>
|
|
||||||
* <li>Wraps the result in an {@link INSResponsePacket}</li>
|
|
||||||
* <li>Sends the response back to the requesting client</li>
|
|
||||||
* </ul>
|
|
||||||
* If sending the response fails, the INS server receives an
|
|
||||||
* {@code onResponseSentFailed(...)} callback.
|
|
||||||
*
|
|
||||||
* @param event The packet event received by the network system.
|
|
||||||
*/
|
|
||||||
@Listener
|
|
||||||
public void onPacket(S_PacketReceivedEvent event) {
|
|
||||||
if (!(event.getPacket() instanceof INSQueryPacket q)) return;
|
|
||||||
|
|
||||||
insServer.onQueryReceived(q.tln, q.name, q.sub, q.type);
|
|
||||||
List<INSRecord> resolved = new ArrayList<>();
|
|
||||||
INSResponseStatus status = null;
|
|
||||||
|
|
||||||
if (q.sub == null && q.tln.equalsIgnoreCase("oac")) {
|
|
||||||
if (q.name.equalsIgnoreCase("info")) {
|
|
||||||
// Return INS server info site
|
|
||||||
String[] hostPort = insServer.getINSInfoSite().split(":");
|
|
||||||
resolved = List.of(new INSRecord(q.type, hostPort[0], -1, -1, Integer.parseInt(hostPort[1]), 0));
|
|
||||||
} else if (q.name.equalsIgnoreCase("register")) {
|
|
||||||
// Return INS frontend site
|
|
||||||
String[] hostPort = insServer.getINSFrontendSite().split(":");
|
|
||||||
resolved = List.of(new INSRecord(q.type, hostPort[0], -1, -1, Integer.parseInt(hostPort[1]), 0));
|
|
||||||
} else {
|
|
||||||
// Not a special name → use normal resolving
|
|
||||||
resolved = insServer.resolve(q.tln, q.name, q.sub, q.type);
|
|
||||||
}
|
|
||||||
} else if (q.sub == null && q.name.equalsIgnoreCase("info")) {
|
|
||||||
// Return TLN server info site
|
|
||||||
String resolve = insServer.resolveTLNInfoSite(q.tln);
|
|
||||||
if (resolve == null) status = INSResponseStatus.INVALID_REQUEST;
|
|
||||||
else {
|
|
||||||
String[] hostPort = resolve.split(":");
|
|
||||||
resolved = List.of(new INSRecord(q.type, hostPort[0], -1, -1, Integer.parseInt(hostPort[1]), 0));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Normal resolving
|
|
||||||
resolved = insServer.resolve(q.tln, q.name, q.sub, q.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = status == null && resolved.isEmpty() ? INSResponseStatus.NOT_FOUND : INSResponseStatus.OK;
|
|
||||||
INSResponsePacket response = new INSResponsePacket(status, resolved, q.clientId, insServer.getProtocolBridge());
|
|
||||||
|
|
||||||
try {
|
|
||||||
event.getConnectionHandler().sendPacket(response);
|
|
||||||
insServer.onResponseSent(q.tln, q.name, q.sub, q.type, resolved);
|
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
|
||||||
insServer.onResponseSentFailed(q.tln, q.name, q.sub, q.type, resolved, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.listeners;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.event.EventListener;
|
||||||
|
|
||||||
|
public class ServerListener extends EventListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Object clone() throws CloneNotSupportedException {
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object obj) {
|
||||||
|
return super.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.listeners;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.EventListener;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.Listener;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.ConnectionHandlerConnectedEvent;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.ConnectionHandlerDisconnectedEvent;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|
||||||
import org.openautonomousconnection.protocol.side.web.ConnectedWebClient;
|
|
||||||
import org.openautonomousconnection.protocol.side.web.ProtocolWebServer;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener for web server connection events.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
|
||||||
public final class WebServerListener extends EventListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The reference to the ProtocolWebServer object
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private ProtocolWebServer webServer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the webServer variable
|
|
||||||
*
|
|
||||||
* @param webServer The Instance of the ProtocolWebServer
|
|
||||||
*/
|
|
||||||
public void setWebServer(ProtocolWebServer webServer) {
|
|
||||||
if (this.webServer != null) return;
|
|
||||||
this.webServer = webServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the event when a connection is established.
|
|
||||||
* Adds the connected client to the protocol web server's client list.
|
|
||||||
*
|
|
||||||
* @param event The connection handler connected event.
|
|
||||||
*/
|
|
||||||
@Listener
|
|
||||||
public void onConnect(ConnectionHandlerConnectedEvent event) {
|
|
||||||
webServer.getClients().add(new ConnectedWebClient(event.getConnectionHandler()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the event when a connection is disconnected.
|
|
||||||
* Removes the disconnected client from the protocol web server's client list.
|
|
||||||
*
|
|
||||||
* @param event The connection handler disconnected event.
|
|
||||||
*/
|
|
||||||
@Listener
|
|
||||||
public void onDisconnect(ConnectionHandlerDisconnectedEvent event) {
|
|
||||||
webServer.getClients().removeIf(client -> client.getPipelineConnection().getClientID() == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.packets;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract class representing a packet in the Open Autonomous Connection (OAC) protocol.
|
|
||||||
* This class extends the base Packet class and includes additional functionality specific to OAC.
|
|
||||||
*/
|
|
||||||
public abstract class OACPacket extends Packet {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The protocol version associated with this packet.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ProtocolVersion protocolVersion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The response code for the packet, defaulting to RESPONSE_NOT_REQUIRED.
|
|
||||||
*/
|
|
||||||
private INSResponseStatus responseCode = INSResponseStatus.RESPONSE_NOT_REQUIRED;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for OACPacket.
|
|
||||||
*
|
|
||||||
* @param id The unique identifier for the packet.
|
|
||||||
* @param protocolVersion The protocol version associated with this packet.
|
|
||||||
*/
|
|
||||||
public OACPacket(int id, ProtocolVersion protocolVersion) {
|
|
||||||
super(id);
|
|
||||||
this.protocolVersion = protocolVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the response code for the packet.
|
|
||||||
*
|
|
||||||
* @return The INSResponseCode associated with the packet.
|
|
||||||
*/
|
|
||||||
protected final INSResponseStatus getResponseCode() {
|
|
||||||
return responseCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the response code for the packet.
|
|
||||||
*
|
|
||||||
* @param responseCode The INSResponseCode to set for the packet.
|
|
||||||
*/
|
|
||||||
protected final void setResponseCode(INSResponseStatus responseCode) {
|
|
||||||
this.responseCode = responseCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the packet data to the output stream.
|
|
||||||
*
|
|
||||||
* @param packetHandler The packet handler managing the packet.
|
|
||||||
* @param objectOutputStream The output stream to write the packet data to.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
* @throws ClassNotFoundException If a class cannot be found during serialization.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final void write(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
|
||||||
// Write the specific packet data
|
|
||||||
onWrite(packetHandler, objectOutputStream);
|
|
||||||
|
|
||||||
// Write the response code if the protocol version is not classic
|
|
||||||
if (protocolVersion != ProtocolVersion.PV_1_0_0_CLASSIC) objectOutputStream.writeObject(responseCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void read(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
|
||||||
// Read the specific packet data
|
|
||||||
onRead(packetHandler, objectInputStream);
|
|
||||||
|
|
||||||
// Read the response code if the protocol version is not classic
|
|
||||||
if (protocolVersion != ProtocolVersion.PV_1_0_0_CLASSIC)
|
|
||||||
responseCode = (INSResponseStatus) objectInputStream.readObject();
|
|
||||||
else responseCode = INSResponseStatus.RESPONSE_NOT_REQUIRED;
|
|
||||||
|
|
||||||
// Call the response code read handler
|
|
||||||
onResponseCodeRead(packetHandler, objectInputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract method to be implemented by subclasses for writing specific packet data.
|
|
||||||
*
|
|
||||||
* @param packetHandler The packet handler managing the packet.
|
|
||||||
* @param objectOutputStream The output stream to write the packet data to.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
* @throws ClassNotFoundException If a class cannot be found during serialization.
|
|
||||||
*/
|
|
||||||
public abstract void onWrite(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract method to be implemented by subclasses for reading specific packet data.
|
|
||||||
*
|
|
||||||
* @param packetHandler The packet handler managing the packet.
|
|
||||||
* @param objectInputStream The input stream to read the packet data from.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
* @throws ClassNotFoundException If a class cannot be found during deserialization.
|
|
||||||
*/
|
|
||||||
public abstract void onRead(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method called after the response code has been read from the input stream.
|
|
||||||
* Subclasses can override this method to handle any additional logic based on the response code.
|
|
||||||
*
|
|
||||||
* @param packetHandler The packet handler managing the packet.
|
|
||||||
* @param objectInputStream The input stream from which the response code was read.
|
|
||||||
*/
|
|
||||||
protected void onResponseCodeRead(PacketHandler packetHandler, ObjectInputStream objectInputStream) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.packets.v1_0_0;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolVersion;
|
||||||
|
import org.openautonomousconnection.protocol.domain.Domain;
|
||||||
|
import org.openautonomousconnection.protocol.domain.RequestDomain;
|
||||||
|
import org.openautonomousconnection.protocol.events.v1_0_0.DomainPacketReceivedEvent;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
public class DomainPacket extends Packet {
|
||||||
|
private int clientID;
|
||||||
|
private RequestDomain requestDomain;
|
||||||
|
private Domain domain;
|
||||||
|
private ProtocolVersion protocolVersion;
|
||||||
|
|
||||||
|
public DomainPacket(RequestDomain requestDomain, Domain domain) {
|
||||||
|
this();
|
||||||
|
|
||||||
|
this.requestDomain = requestDomain;
|
||||||
|
this.domain = domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DomainPacket() {
|
||||||
|
super(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
||||||
|
protocolVersion = ProtocolBridge.getInstance().getProtocolVersion();
|
||||||
|
|
||||||
|
if (ProtocolBridge.getInstance().isRunningAsServer()) {
|
||||||
|
objectOutputStream.writeInt(clientID);
|
||||||
|
objectOutputStream.writeObject(requestDomain);
|
||||||
|
objectOutputStream.writeObject(domain);
|
||||||
|
} else {
|
||||||
|
clientID = ProtocolBridge.getInstance().getProtocolClient().getClient().getClientID();
|
||||||
|
objectOutputStream.writeInt(clientID);
|
||||||
|
objectOutputStream.writeObject(requestDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
objectOutputStream.writeObject(protocolVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
||||||
|
if (ProtocolBridge.getInstance().isRunningAsServer()) {
|
||||||
|
clientID = objectInputStream.readInt();
|
||||||
|
requestDomain = (RequestDomain) objectInputStream.readObject();
|
||||||
|
protocolVersion = (ProtocolVersion) objectInputStream.readObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
domain = ProtocolBridge.getInstance().getProtocolServer().getDomain(requestDomain);
|
||||||
|
} catch (SQLException exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolBridge.getInstance().getProtocolServer().getServer().getEventManager().executeEvent(new DomainPacketReceivedEvent(protocolVersion, domain, requestDomain, clientID));
|
||||||
|
ProtocolBridge.getInstance().getProtocolServer().getServer().getConnectionHandlerByID(clientID).sendPacket(new DomainPacket(requestDomain, domain));
|
||||||
|
} else {
|
||||||
|
clientID = objectInputStream.readInt();
|
||||||
|
requestDomain = (RequestDomain) objectInputStream.readObject();
|
||||||
|
domain = (Domain) objectInputStream.readObject();
|
||||||
|
protocolVersion = (ProtocolVersion) objectInputStream.readObject();
|
||||||
|
|
||||||
|
ProtocolBridge.getInstance().getProtocolClient().getClient().getEventManager().executeEvent(new DomainPacketReceivedEvent(protocolVersion, domain, requestDomain, clientID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Object clone() throws CloneNotSupportedException {
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object obj) {
|
||||||
|
return super.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.packets.v1_0_0;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
public class MessagePacket extends Packet {
|
||||||
|
private ProtocolVersion protocolVersion;
|
||||||
|
private String message;
|
||||||
|
private int clientID;
|
||||||
|
|
||||||
|
public MessagePacket(int id, String message) {
|
||||||
|
super(id);
|
||||||
|
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessagePacket() {
|
||||||
|
super(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
||||||
|
protocolVersion = ProtocolBridge.getInstance().getProtocolVersion();
|
||||||
|
|
||||||
|
if (ProtocolBridge.getInstance().isRunningAsServer()) objectOutputStream.writeInt(clientID);
|
||||||
|
else {
|
||||||
|
clientID = ProtocolBridge.getInstance().getProtocolClient().getClient().getClientID();
|
||||||
|
objectOutputStream.writeInt(clientID);
|
||||||
|
}
|
||||||
|
|
||||||
|
objectOutputStream.writeUTF(message);
|
||||||
|
objectOutputStream.writeObject(protocolVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
||||||
|
if (ProtocolBridge.getInstance().isRunningAsServer()) {
|
||||||
|
int clientID = objectInputStream.readInt();
|
||||||
|
String message = objectInputStream.readUTF();
|
||||||
|
protocolVersion = (ProtocolVersion) objectInputStream.readObject();
|
||||||
|
|
||||||
|
ProtocolBridge.getInstance().getProtocolServer().handleMessage(ProtocolBridge.getInstance().getProtocolServer().getServer().getConnectionHandlerByID(clientID), message);
|
||||||
|
} else {
|
||||||
|
int clientID = objectInputStream.readInt();
|
||||||
|
String message = objectInputStream.readUTF();
|
||||||
|
protocolVersion = (ProtocolVersion) objectInputStream.readObject();
|
||||||
|
|
||||||
|
ProtocolBridge.getInstance().getProtocolClient().handleMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Object clone() throws CloneNotSupportedException {
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object obj) {
|
||||||
|
return super.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.packets.v1_0_0;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolVersion;
|
||||||
|
import org.openautonomousconnection.protocol.domain.Domain;
|
||||||
|
import org.openautonomousconnection.protocol.domain.RequestDomain;
|
||||||
|
import org.openautonomousconnection.protocol.events.v1_0_0.PingPacketReceivedEvent;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
public class PingPacket extends Packet {
|
||||||
|
private RequestDomain requestDomain;
|
||||||
|
private Domain domain;
|
||||||
|
private int clientID;
|
||||||
|
private boolean reachable;
|
||||||
|
private ProtocolVersion protocolVersion;
|
||||||
|
|
||||||
|
public PingPacket(RequestDomain requestDomain, Domain domain, boolean reachable) {
|
||||||
|
this();
|
||||||
|
|
||||||
|
this.requestDomain = requestDomain;
|
||||||
|
this.domain = domain;
|
||||||
|
this.reachable = reachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PingPacket() {
|
||||||
|
super(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
||||||
|
protocolVersion = ProtocolBridge.getInstance().getProtocolVersion();
|
||||||
|
|
||||||
|
if (ProtocolBridge.getInstance().isRunningAsServer()) {
|
||||||
|
objectOutputStream.writeInt(clientID);
|
||||||
|
objectOutputStream.writeObject(requestDomain);
|
||||||
|
objectOutputStream.writeObject(domain);
|
||||||
|
objectOutputStream.writeBoolean(reachable);
|
||||||
|
} else {
|
||||||
|
clientID = ProtocolBridge.getInstance().getProtocolClient().getClient().getClientID();
|
||||||
|
objectOutputStream.writeInt(clientID);
|
||||||
|
objectOutputStream.writeObject(requestDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
objectOutputStream.writeObject(protocolVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
||||||
|
if (ProtocolBridge.getInstance().isRunningAsServer()) {
|
||||||
|
clientID = objectInputStream.readInt();
|
||||||
|
requestDomain = (RequestDomain) objectInputStream.readObject();
|
||||||
|
protocolVersion = (ProtocolVersion) objectInputStream.readObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
domain = ProtocolBridge.getInstance().getProtocolServer().ping(requestDomain);
|
||||||
|
} catch (SQLException exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
reachable = domain != null;
|
||||||
|
ProtocolBridge.getInstance().getProtocolServer().getServer().getEventManager().executeEvent(new PingPacketReceivedEvent(protocolVersion, domain, requestDomain, reachable, clientID));
|
||||||
|
ProtocolBridge.getInstance().getProtocolServer().getServer().getConnectionHandlerByID(clientID).sendPacket(new PingPacket(requestDomain, domain, reachable));
|
||||||
|
} else {
|
||||||
|
clientID = objectInputStream.readInt();
|
||||||
|
requestDomain = (RequestDomain) objectInputStream.readObject();
|
||||||
|
domain = (Domain) objectInputStream.readObject();
|
||||||
|
boolean reachable = objectInputStream.readBoolean();
|
||||||
|
protocolVersion = (ProtocolVersion) objectInputStream.readObject();
|
||||||
|
|
||||||
|
ProtocolBridge.getInstance().getProtocolClient().getClient().getEventManager().executeEvent(new PingPacketReceivedEvent(protocolVersion, domain, requestDomain, reachable, clientID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Object clone() throws CloneNotSupportedException {
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object obj) {
|
||||||
|
return super.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.packets.v1_0_0.beta;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.file.FileUtils;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.utils.NetworkUtils;
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
|
||||||
import org.openautonomousconnection.protocol.side.client.events.ConnectedToProtocolINSServerEvent;
|
|
||||||
import org.openautonomousconnection.protocol.side.ins.ConnectedProtocolClient;
|
|
||||||
import org.openautonomousconnection.protocol.side.ins.events.ConnectedProtocolClientEvent;
|
|
||||||
import org.openautonomousconnection.protocol.side.web.ConnectedWebClient;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authentication packet used between client and INS/Web servers.
|
|
||||||
* <p>
|
|
||||||
* Responsibilities:
|
|
||||||
* <ul>
|
|
||||||
* <li>Client → Server: Sends client ID and protocol version</li>
|
|
||||||
* <li>Server → Client: Sends CA key, CA certificate and CA serial files</li>
|
|
||||||
* <li>Performs version compatibility validation</li>
|
|
||||||
* <li>Triggers authentication callbacks on both sides</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public final class AuthPacket extends OACPacket {
|
|
||||||
|
|
||||||
private ProtocolBridge protocolBridge;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new authentication packet for sending CA data or client identity.
|
|
||||||
*
|
|
||||||
* @param protocolBridge The protocol context of the current instance.
|
|
||||||
*/
|
|
||||||
public AuthPacket(ProtocolBridge protocolBridge) {
|
|
||||||
this();
|
|
||||||
this.protocolBridge = protocolBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registration constructor
|
|
||||||
*/
|
|
||||||
public AuthPacket() {
|
|
||||||
super(4, ProtocolVersion.PV_1_0_0_BETA);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes authentication data to the output stream.
|
|
||||||
* <p>
|
|
||||||
* Behavior differs based on the running side:
|
|
||||||
* <ul>
|
|
||||||
* <li>INS Server → sends CA bundle to the client</li>
|
|
||||||
* <li>Client → sends client ID + protocol version</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onWrite(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
|
||||||
if (protocolBridge.isRunningAsINSServer()) {
|
|
||||||
objectOutputStream.writeObject(protocolBridge.getProtocolVersion());
|
|
||||||
|
|
||||||
// Read ca files
|
|
||||||
String caKey = "N/A";
|
|
||||||
String caPem = "N/A";
|
|
||||||
String caSrl = "N/A";
|
|
||||||
try {
|
|
||||||
objectOutputStream.writeUTF(protocolBridge.getProtocolINSServer().getFolderStructure().caPrefix + NetworkUtils.getPublicIPAddress());
|
|
||||||
|
|
||||||
caKey = FileUtils.readFileFull(new File(
|
|
||||||
protocolBridge.getProtocolINSServer().getFolderStructure().privateCAFolder,
|
|
||||||
protocolBridge.getProtocolINSServer().getFolderStructure().caPrefix + NetworkUtils.getPublicIPAddress() + ".key"));
|
|
||||||
|
|
||||||
caPem = FileUtils.readFileFull(new File(
|
|
||||||
protocolBridge.getProtocolINSServer().getFolderStructure().publicCAFolder,
|
|
||||||
protocolBridge.getProtocolINSServer().getFolderStructure().caPrefix + NetworkUtils.getPublicIPAddress() + ".pem"));
|
|
||||||
|
|
||||||
caSrl = FileUtils.readFileFull(new File(
|
|
||||||
protocolBridge.getProtocolINSServer().getFolderStructure().publicCAFolder,
|
|
||||||
protocolBridge.getProtocolINSServer().getFolderStructure().caPrefix + NetworkUtils.getPublicIPAddress() + ".srl"));
|
|
||||||
} catch (Exception exception) {
|
|
||||||
protocolBridge.getLogger().exception("Failed to read ca-files", exception);
|
|
||||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send ca data
|
|
||||||
objectOutputStream.writeUTF(caKey);
|
|
||||||
objectOutputStream.writeUTF(caPem);
|
|
||||||
objectOutputStream.writeUTF(caSrl);
|
|
||||||
} else if (protocolBridge.isRunningAsClient()) {
|
|
||||||
objectOutputStream.writeInt(protocolBridge.getProtocolClient().getClientINSConnection().getClientID());
|
|
||||||
objectOutputStream.writeObject(protocolBridge.getProtocolVersion());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads authentication data and updates protocol state.
|
|
||||||
* <p>
|
|
||||||
* Behavior:
|
|
||||||
* <ul>
|
|
||||||
* <li>Server validates version and registers new connected client</li>
|
|
||||||
* <li>Client saves received CA files and completes TLS initialization</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onRead(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
|
||||||
if (protocolBridge.isRunningAsINSServer() || protocolBridge.isRunningAsWebServer()) {
|
|
||||||
int clientID = objectInputStream.readInt();
|
|
||||||
ProtocolVersion clientVersion = (ProtocolVersion) objectInputStream.readObject();
|
|
||||||
ConnectionHandler connectionHandler = protocolBridge.getProtocolINSServer().getNetworkServer().getConnectionHandlerByID(clientID);
|
|
||||||
|
|
||||||
if (!protocolBridge.isVersionSupported(clientVersion)) {
|
|
||||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
|
||||||
connectionHandler.disconnect();
|
|
||||||
return;
|
|
||||||
} else setResponseCode(INSResponseStatus.RESPONSE_AUTH_SUCCESS);
|
|
||||||
|
|
||||||
|
|
||||||
if (protocolBridge.isRunningAsINSServer()) {
|
|
||||||
ConnectedProtocolClient client = protocolBridge.getProtocolINSServer().getClientByID(clientID);
|
|
||||||
client.setClientVersion(clientVersion);
|
|
||||||
protocolBridge.getProtocolSettings().eventManager.executeEvent(new ConnectedProtocolClientEvent(client));
|
|
||||||
} else {
|
|
||||||
ConnectedWebClient client = protocolBridge.getProtocolWebServer().getClientByID(clientID);
|
|
||||||
client.setClientVersion(clientVersion);
|
|
||||||
}
|
|
||||||
} else if (protocolBridge.isRunningAsClient()) {
|
|
||||||
ProtocolVersion serverVersion = (ProtocolVersion) objectInputStream.readObject();
|
|
||||||
|
|
||||||
if (!protocolBridge.isVersionSupported(serverVersion)) {
|
|
||||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
|
||||||
protocolBridge.getProtocolClient().getClientINSConnection().disconnect();
|
|
||||||
return;
|
|
||||||
} else setResponseCode(INSResponseStatus.RESPONSE_AUTH_SUCCESS);
|
|
||||||
|
|
||||||
String caPrefix = objectInputStream.readUTF();
|
|
||||||
|
|
||||||
String caKey = objectInputStream.readUTF();
|
|
||||||
String caPem = objectInputStream.readUTF();
|
|
||||||
String caSrl = objectInputStream.readUTF();
|
|
||||||
|
|
||||||
if (caKey.equalsIgnoreCase("N/A") || caPem.equalsIgnoreCase("N/A") || caSrl.equalsIgnoreCase("N/A"))
|
|
||||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
|
||||||
else {
|
|
||||||
|
|
||||||
File caPemFile = new File(protocolBridge.getProtocolClient().getFolderStructure().publicCAFolder, caPrefix + ".pem");
|
|
||||||
File caSrlFile = new File(protocolBridge.getProtocolClient().getFolderStructure().publicCAFolder, caPrefix + ".srl");
|
|
||||||
File caKeyFile = new File(protocolBridge.getProtocolClient().getFolderStructure().privateCAFolder, caPrefix + ".key");
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!caPemFile.exists()) caPemFile.createNewFile();
|
|
||||||
if (!caSrlFile.exists()) caSrlFile.createNewFile();
|
|
||||||
if (!caKeyFile.exists()) caKeyFile.createNewFile();
|
|
||||||
|
|
||||||
FileUtils.writeFile(caPemFile, caPem);
|
|
||||||
FileUtils.writeFile(caSrlFile, caKey);
|
|
||||||
FileUtils.writeFile(caKeyFile, caSrl);
|
|
||||||
} catch (Exception exception) {
|
|
||||||
protocolBridge.getLogger().exception("Failed to create/save ca-files", exception);
|
|
||||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protocolBridge.getProtocolClient().setServerVersion(serverVersion);
|
|
||||||
protocolBridge.getProtocolSettings().eventManager.executeEvent(new ConnectedToProtocolINSServerEvent(protocolBridge.getProtocolClient()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.packets.v1_0_0.beta;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
|
||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Packet used by clients to query INS records from an INS server.
|
|
||||||
* <p>
|
|
||||||
* Contains all information required for resolving an InfoName:
|
|
||||||
* <ul>
|
|
||||||
* <li>TLN</li>
|
|
||||||
* <li>Name</li>
|
|
||||||
* <li>Optional subname </li>
|
|
||||||
* <li>Record type</li>
|
|
||||||
* <li>Client ID for routing responses</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public final class INSQueryPacket extends OACPacket {
|
|
||||||
|
|
||||||
public String tln;
|
|
||||||
public String name;
|
|
||||||
public String sub;
|
|
||||||
public INSRecordType type;
|
|
||||||
public int clientId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new INS query packet with all required parameters.
|
|
||||||
*
|
|
||||||
* @param tln The top-level namespace.
|
|
||||||
* @param name The InfoName.
|
|
||||||
* @param sub Optional subname ("www") or null.
|
|
||||||
* @param type Record type requested.
|
|
||||||
* @param clientId Sender client ID for routing.
|
|
||||||
*/
|
|
||||||
public INSQueryPacket(String tln, String name, String sub, INSRecordType type, int clientId) {
|
|
||||||
super(6, ProtocolVersion.PV_1_0_0_BETA);
|
|
||||||
this.tln = tln;
|
|
||||||
this.name = name;
|
|
||||||
this.sub = sub;
|
|
||||||
this.type = type;
|
|
||||||
this.clientId = clientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registration constructor
|
|
||||||
*/
|
|
||||||
public INSQueryPacket() {
|
|
||||||
super(6, ProtocolVersion.PV_1_0_0_BETA);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes the INS query into the stream.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onWrite(PacketHandler handler, ObjectOutputStream out) throws IOException {
|
|
||||||
out.writeUTF(tln);
|
|
||||||
out.writeUTF(name);
|
|
||||||
|
|
||||||
out.writeBoolean(sub != null);
|
|
||||||
if (sub != null) out.writeUTF(sub);
|
|
||||||
|
|
||||||
out.writeObject(type);
|
|
||||||
out.writeInt(clientId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deserializes the INS query from the stream.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onRead(PacketHandler handler, ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
tln = in.readUTF();
|
|
||||||
name = in.readUTF();
|
|
||||||
|
|
||||||
boolean hasSub = in.readBoolean();
|
|
||||||
sub = hasSub ? in.readUTF() : null;
|
|
||||||
|
|
||||||
type = (INSRecordType) in.readObject();
|
|
||||||
clientId = in.readInt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.packets.v1_0_0.beta;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
|
||||||
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.INSResponseStatus;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Response packet returned by an INS server after resolving a query.
|
|
||||||
* <p>
|
|
||||||
* Contains:
|
|
||||||
* <ul>
|
|
||||||
* <li>Status code ({@link INSResponseStatus})</li>
|
|
||||||
* <li>List of resolved {@link INSRecord} entries</li>
|
|
||||||
* <li>The ID of the requesting client</li>
|
|
||||||
* </ul>
|
|
||||||
* On the client side, {@link org.openautonomousconnection.protocol.side.client.ProtocolClient#onResponse(INSResponseStatus, List)}
|
|
||||||
* is automatically invoked through {@link #onResponseCodeRead}.
|
|
||||||
*/
|
|
||||||
public final class INSResponsePacket extends OACPacket {
|
|
||||||
|
|
||||||
private final ProtocolBridge bridge;
|
|
||||||
public INSResponseStatus status;
|
|
||||||
public List<INSRecord> records;
|
|
||||||
public int clientId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a populated response packet.
|
|
||||||
*
|
|
||||||
* @param status The resolution status.
|
|
||||||
* @param records List of resolved records.
|
|
||||||
* @param clientId ID of requesting client.
|
|
||||||
* @param bridge Protocol runtime context.
|
|
||||||
*/
|
|
||||||
public INSResponsePacket(INSResponseStatus status, List<INSRecord> records, int clientId, ProtocolBridge bridge) {
|
|
||||||
super(7, ProtocolVersion.PV_1_0_0_BETA);
|
|
||||||
this.status = status;
|
|
||||||
this.records = records;
|
|
||||||
this.clientId = clientId;
|
|
||||||
this.bridge = bridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registration Constructor
|
|
||||||
*
|
|
||||||
* @param bridge Protocol runtime context.
|
|
||||||
*/
|
|
||||||
public INSResponsePacket(ProtocolBridge bridge) {
|
|
||||||
super(7, ProtocolVersion.PV_1_0_0_BETA);
|
|
||||||
this.bridge = bridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes the response status, records and client ID.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onWrite(PacketHandler handler, ObjectOutputStream out) throws IOException {
|
|
||||||
out.writeObject(status);
|
|
||||||
out.writeInt(records.size());
|
|
||||||
|
|
||||||
for (INSRecord rec : records) {
|
|
||||||
out.writeObject(rec);
|
|
||||||
}
|
|
||||||
|
|
||||||
out.writeInt(clientId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deserializes the response, reconstructing the record list.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onRead(PacketHandler handler, ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
status = (INSResponseStatus) in.readObject();
|
|
||||||
|
|
||||||
int size = in.readInt();
|
|
||||||
records = new ArrayList<>(size);
|
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
records.add((INSRecord) in.readObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
clientId = in.readInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after reading the server's response code.
|
|
||||||
* <p>
|
|
||||||
* If running on a client, forwards the result to the client-side API.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onResponseCodeRead(PacketHandler handler, ObjectInputStream in) {
|
|
||||||
if (bridge.isRunningAsClient()) {
|
|
||||||
bridge.getProtocolClient().onResponse(status, records);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.packets.v1_0_0.beta;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal compatibility packet used when a classic-protocol packet is received
|
|
||||||
* but not supported by the current protocol version.
|
|
||||||
* <p>
|
|
||||||
* Instead of rejecting the packet entirely, the content and class name are forwarded
|
|
||||||
* to the appropriate compatibility handler:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerINSServer}</li>
|
|
||||||
* <li>{@link org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerClient}</li>
|
|
||||||
* <li>{@link org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerWebServer}</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public final class UnsupportedClassicPacket extends OACPacket {
|
|
||||||
private Class<? extends OACPacket> unsupportedClassicPacket;
|
|
||||||
private Object[] content;
|
|
||||||
private ProtocolBridge protocolBridge;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a packet describing the unsupported classic packet and its content.
|
|
||||||
*
|
|
||||||
* @param unsupportedClassicPacket The packet class that was not understood.
|
|
||||||
* @param content Serialized field values.
|
|
||||||
* @param protocolBridge The protocol context.
|
|
||||||
*/
|
|
||||||
public UnsupportedClassicPacket(Class<? extends OACPacket> unsupportedClassicPacket, Object[] content, ProtocolBridge protocolBridge) {
|
|
||||||
this();
|
|
||||||
this.unsupportedClassicPacket = unsupportedClassicPacket;
|
|
||||||
this.content = content;
|
|
||||||
this.protocolBridge = protocolBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registration Constructor
|
|
||||||
*/
|
|
||||||
public UnsupportedClassicPacket() {
|
|
||||||
super(5, ProtocolVersion.PV_1_0_0_BETA);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the class name and serialized object fields to the stream.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onWrite(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
|
||||||
if (protocolBridge.isRunningAsClient())
|
|
||||||
objectOutputStream.writeInt(protocolBridge.getProtocolClient().getClientINSConnection().getClientID());
|
|
||||||
|
|
||||||
objectOutputStream.writeUTF(unsupportedClassicPacket.getName());
|
|
||||||
objectOutputStream.writeInt(content.length);
|
|
||||||
for (Object o : content) objectOutputStream.writeObject(o);
|
|
||||||
setResponseCode(INSResponseStatus.RESPONSE_NOT_REQUIRED);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the unsupported packet data and forwards it to the appropriate compatibility handler.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onRead(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
|
||||||
int clientID = 0;
|
|
||||||
if (protocolBridge.isRunningAsINSServer()) clientID = objectInputStream.readInt();
|
|
||||||
String className = objectInputStream.readUTF();
|
|
||||||
int size = objectInputStream.readInt();
|
|
||||||
content = new Object[size];
|
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
content[i] = objectInputStream.readObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (protocolBridge.isRunningAsINSServer())
|
|
||||||
protocolBridge.getClassicHandlerINSServer().unsupportedClassicPacket(className, content, protocolBridge.getProtocolINSServer().getClientByID(clientID));
|
|
||||||
else if (protocolBridge.isRunningAsClient())
|
|
||||||
protocolBridge.getClassicHandlerClient().unsupportedClassicPacket(className, content);
|
|
||||||
else if (protocolBridge.isRunningAsWebServer())
|
|
||||||
protocolBridge.getClassicHandlerWebServer().unsupportedClassicPacket(className, content, protocolBridge.getProtocolINSServer().getClientByID(clientID));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.packets.v1_0_0.classic;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.UnsupportedClassicPacket;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.events.Classic_DomainPacketReceivedEvent;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
public final class Classic_DomainPacket extends OACPacket {
|
|
||||||
private Classic_RequestDomain requestDomain;
|
|
||||||
private Classic_Domain domain;
|
|
||||||
private int clientID;
|
|
||||||
private ProtocolBridge bridge;
|
|
||||||
|
|
||||||
public Classic_DomainPacket(int toClient, Classic_RequestDomain requestDomain, Classic_Domain domain, ProtocolBridge protocolBridge) {
|
|
||||||
this();
|
|
||||||
this.clientID = toClient;
|
|
||||||
this.bridge = protocolBridge;
|
|
||||||
|
|
||||||
this.requestDomain = requestDomain;
|
|
||||||
this.domain = domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Registration constructor
|
|
||||||
public Classic_DomainPacket() {
|
|
||||||
super(2, ProtocolVersion.PV_1_0_0_CLASSIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onWrite(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
|
||||||
if (bridge.isRunningAsINSServer()) {
|
|
||||||
objectOutputStream.writeInt(clientID);
|
|
||||||
objectOutputStream.writeObject(requestDomain);
|
|
||||||
objectOutputStream.writeObject(domain);
|
|
||||||
} else if (bridge.isRunningAsClient()) {
|
|
||||||
clientID = bridge.getProtocolClient().getClientINSConnection().getClientID();
|
|
||||||
objectOutputStream.writeInt(clientID);
|
|
||||||
objectOutputStream.writeObject(requestDomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
objectOutputStream.writeObject(Classic_ProtocolVersion.PV_1_0_0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRead(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
|
||||||
if (bridge.isRunningAsINSServer()) {
|
|
||||||
clientID = objectInputStream.readInt();
|
|
||||||
requestDomain = (Classic_RequestDomain) objectInputStream.readObject();
|
|
||||||
Classic_ProtocolVersion protocolVersion = (Classic_ProtocolVersion) objectInputStream.readObject();
|
|
||||||
|
|
||||||
try {
|
|
||||||
domain = bridge.getClassicHandlerINSServer().getDomain(requestDomain);
|
|
||||||
} catch (SQLException exception) {
|
|
||||||
exception.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
bridge.getProtocolINSServer().getNetworkServer().getEventManager().executeEvent(new Classic_DomainPacketReceivedEvent(protocolVersion, domain, requestDomain, clientID));
|
|
||||||
|
|
||||||
if (bridge.getProtocolINSServer().getClientByID(clientID).supportClientClassic())
|
|
||||||
bridge.getProtocolINSServer().getNetworkServer().getConnectionHandlerByID(clientID).sendPacket(new Classic_DomainPacket(clientID, requestDomain, domain, bridge));
|
|
||||||
else
|
|
||||||
bridge.getProtocolINSServer().getNetworkServer().getConnectionHandlerByID(clientID).sendPacket(new UnsupportedClassicPacket(Classic_PingPacket.class, new Object[]{clientID, requestDomain, domain}, bridge));
|
|
||||||
} else if (bridge.isRunningAsClient()) {
|
|
||||||
clientID = objectInputStream.readInt();
|
|
||||||
requestDomain = (Classic_RequestDomain) objectInputStream.readObject();
|
|
||||||
domain = (Classic_Domain) objectInputStream.readObject();
|
|
||||||
Classic_ProtocolVersion protocolVersion = (Classic_ProtocolVersion) objectInputStream.readObject();
|
|
||||||
|
|
||||||
bridge.getProtocolClient().getClientINSConnection().getEventManager().executeEvent(new Classic_DomainPacketReceivedEvent(protocolVersion, domain, requestDomain, clientID));
|
|
||||||
} else if (bridge.isRunningAsWebServer()) {
|
|
||||||
clientID = objectInputStream.readInt();
|
|
||||||
requestDomain = (Classic_RequestDomain) objectInputStream.readObject();
|
|
||||||
Classic_ProtocolVersion protocolVersion = (Classic_ProtocolVersion) objectInputStream.readObject();
|
|
||||||
|
|
||||||
bridge.getProtocolWebServer().getPipelineServer().getConnectionHandlerByID(clientID).sendPacket(new UnsupportedClassicPacket(Classic_PingPacket.class, new Object[]{clientID, requestDomain, domain}, bridge));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.packets.v1_0_0.classic;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
|
|
||||||
public final class Classic_MessagePacket extends OACPacket {
|
|
||||||
private String message;
|
|
||||||
private int clientID;
|
|
||||||
private ProtocolBridge bridge;
|
|
||||||
|
|
||||||
// Constructor with message and client id
|
|
||||||
public Classic_MessagePacket(String message, int toClient, ProtocolBridge bridge) {
|
|
||||||
this();
|
|
||||||
this.message = message;
|
|
||||||
this.clientID = toClient;
|
|
||||||
this.bridge = bridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Classic_MessagePacket() {
|
|
||||||
super(3, ProtocolVersion.PV_1_0_0_CLASSIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onWrite(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
|
||||||
if (bridge.isRunningAsINSServer() || bridge.isRunningAsWebServer())
|
|
||||||
objectOutputStream.writeInt(clientID);
|
|
||||||
else if (bridge.isRunningAsClient()) {
|
|
||||||
clientID = bridge.getProtocolClient().getClientINSConnection().getClientID();
|
|
||||||
objectOutputStream.writeInt(clientID);
|
|
||||||
}
|
|
||||||
|
|
||||||
objectOutputStream.writeUTF(message);
|
|
||||||
objectOutputStream.writeObject(Classic_ProtocolVersion.PV_1_0_0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRead(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
|
||||||
if (bridge.isRunningAsINSServer()) {
|
|
||||||
clientID = objectInputStream.readInt();
|
|
||||||
String message = objectInputStream.readUTF();
|
|
||||||
Classic_ProtocolVersion protocolVersion = (Classic_ProtocolVersion) objectInputStream.readObject();
|
|
||||||
|
|
||||||
bridge.getClassicHandlerINSServer().handleMessage(bridge.getProtocolINSServer().getClientByID(clientID), message, protocolVersion);
|
|
||||||
} else if (bridge.isRunningAsClient()) {
|
|
||||||
clientID = objectInputStream.readInt();
|
|
||||||
String message = objectInputStream.readUTF();
|
|
||||||
Classic_ProtocolVersion protocolVersion = (Classic_ProtocolVersion) objectInputStream.readObject();
|
|
||||||
|
|
||||||
bridge.getClassicHandlerClient().handleMessage(message, protocolVersion);
|
|
||||||
} else if (bridge.isRunningAsWebServer()) {
|
|
||||||
clientID = objectInputStream.readInt();
|
|
||||||
String message = objectInputStream.readUTF();
|
|
||||||
Classic_ProtocolVersion protocolVersion = (Classic_ProtocolVersion) objectInputStream.readObject();
|
|
||||||
|
|
||||||
bridge.getClassicHandlerWebServer().handleMessage(bridge.getProtocolINSServer().getClientByID(clientID), message, protocolVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.packets.v1_0_0.classic;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.UnsupportedClassicPacket;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.events.Classic_PingPacketReceivedEvent;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
public final class Classic_PingPacket extends OACPacket {
|
|
||||||
private Classic_RequestDomain requestDomain;
|
|
||||||
private Classic_Domain domain;
|
|
||||||
private int clientID;
|
|
||||||
private boolean reachable;
|
|
||||||
private Classic_ProtocolVersion protocolVersion;
|
|
||||||
private ProtocolBridge bridge;
|
|
||||||
|
|
||||||
public Classic_PingPacket(Classic_RequestDomain requestDomain, Classic_Domain domain, boolean reachable, ProtocolBridge bridge) {
|
|
||||||
this();
|
|
||||||
this.bridge = bridge;
|
|
||||||
|
|
||||||
this.requestDomain = requestDomain;
|
|
||||||
this.domain = domain;
|
|
||||||
this.reachable = reachable;
|
|
||||||
this.protocolVersion = Classic_ProtocolVersion.PV_1_0_0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Classic_PingPacket() {
|
|
||||||
super(1, ProtocolVersion.PV_1_0_0_CLASSIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onWrite(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
|
||||||
if (bridge.isRunningAsINSServer()) {
|
|
||||||
objectOutputStream.writeInt(clientID);
|
|
||||||
objectOutputStream.writeObject(requestDomain);
|
|
||||||
objectOutputStream.writeObject(domain);
|
|
||||||
objectOutputStream.writeBoolean(reachable);
|
|
||||||
} else if (bridge.isRunningAsClient()) {
|
|
||||||
clientID = bridge.getProtocolClient().getClientINSConnection().getClientID();
|
|
||||||
objectOutputStream.writeInt(clientID);
|
|
||||||
objectOutputStream.writeObject(requestDomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
objectOutputStream.writeObject(protocolVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRead(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
|
||||||
if (bridge.isRunningAsINSServer()) {
|
|
||||||
clientID = objectInputStream.readInt();
|
|
||||||
requestDomain = (Classic_RequestDomain) objectInputStream.readObject();
|
|
||||||
protocolVersion = (Classic_ProtocolVersion) objectInputStream.readObject();
|
|
||||||
|
|
||||||
try {
|
|
||||||
domain = bridge.getClassicHandlerINSServer().ping(requestDomain);
|
|
||||||
} catch (SQLException exception) {
|
|
||||||
exception.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
reachable = domain != null;
|
|
||||||
bridge.getProtocolINSServer().getNetworkServer().getEventManager().executeEvent(new Classic_PingPacketReceivedEvent(protocolVersion, domain, requestDomain, reachable, clientID));
|
|
||||||
if (bridge.getProtocolINSServer().getClientByID(clientID).supportClientClassic())
|
|
||||||
bridge.getProtocolINSServer().getNetworkServer().getConnectionHandlerByID(clientID).sendPacket(new Classic_PingPacket(requestDomain, domain, reachable, bridge));
|
|
||||||
else
|
|
||||||
bridge.getProtocolINSServer().getNetworkServer().getConnectionHandlerByID(clientID).sendPacket(new UnsupportedClassicPacket(Classic_PingPacket.class, new Object[]{requestDomain, domain, reachable}, bridge));
|
|
||||||
} else if (bridge.isRunningAsClient()) {
|
|
||||||
clientID = objectInputStream.readInt();
|
|
||||||
requestDomain = (Classic_RequestDomain) objectInputStream.readObject();
|
|
||||||
domain = (Classic_Domain) objectInputStream.readObject();
|
|
||||||
boolean reachable = objectInputStream.readBoolean();
|
|
||||||
Classic_ProtocolVersion protocolVersion = (Classic_ProtocolVersion) objectInputStream.readObject();
|
|
||||||
|
|
||||||
bridge.getClassicHandlerClient().validationCompleted(domain, reachable ? INSResponseStatus.OK : INSResponseStatus.NOT_FOUND);
|
|
||||||
bridge.getProtocolClient().getClientINSConnection().getEventManager().executeEvent(new Classic_PingPacketReceivedEvent(protocolVersion, domain, requestDomain, reachable, clientID));
|
|
||||||
} else if (bridge.isRunningAsWebServer()) {
|
|
||||||
clientID = objectInputStream.readInt();
|
|
||||||
requestDomain = (Classic_RequestDomain) objectInputStream.readObject();
|
|
||||||
protocolVersion = (Classic_ProtocolVersion) objectInputStream.readObject();
|
|
||||||
|
|
||||||
bridge.getProtocolWebServer().getPipelineServer().getConnectionHandlerByID(clientID).sendPacket(new UnsupportedClassicPacket(Classic_PingPacket.class, new Object[]{requestDomain}, bridge));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.side;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
|
import org.openautonomousconnection.protocol.domain.Domain;
|
||||||
|
import org.openautonomousconnection.protocol.domain.RequestDomain;
|
||||||
|
import org.openautonomousconnection.protocol.listeners.ClientListener;
|
||||||
|
import org.openautonomousconnection.protocol.listeners.ServerListener;
|
||||||
|
import org.openautonomousconnection.protocol.packets.v1_0_0.DomainPacket;
|
||||||
|
import org.openautonomousconnection.protocol.utils.SiteType;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
public abstract class ProtocolClient extends DefaultMethodsOverrider {
|
||||||
|
|
||||||
|
private NetworkClient client;
|
||||||
|
private ProtocolBridge protocolBridge;
|
||||||
|
|
||||||
|
public abstract void handleHTMLContent(SiteType siteType, Domain domain, String htmlContent);
|
||||||
|
public abstract void handleMessage(String message);
|
||||||
|
|
||||||
|
public final NetworkClient getClient() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final ProtocolBridge getProtocolBridge() {
|
||||||
|
return protocolBridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setProtocolBridge(ProtocolBridge protocolBridge) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||||
|
this.protocolBridge = protocolBridge;
|
||||||
|
|
||||||
|
client = new NetworkClient.ClientBuilder()
|
||||||
|
.setEventManager(protocolBridge.getProtocolSettings().eventManager).setPacketHandler(protocolBridge.getProtocolSettings().packetHandler)
|
||||||
|
.setPort(protocolBridge.getProtocolSettings().port).setHost(protocolBridge.getProtocolSettings().host).
|
||||||
|
build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void startClient() throws Exception {
|
||||||
|
client.getEventManager().unregisterListener(ServerListener.class);
|
||||||
|
client.getEventManager().registerListener(ClientListener.class);
|
||||||
|
|
||||||
|
client.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void disconnectClient() throws IOException {
|
||||||
|
client.getEventManager().unregisterListener(ClientListener.class);
|
||||||
|
client.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void resolveSite(RequestDomain requestDomain) throws IOException, ClassNotFoundException {
|
||||||
|
if (!client.isConnected()) return;
|
||||||
|
|
||||||
|
client.sendPacket(new DomainPacket(requestDomain, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.side;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.network.system.server.NetworkServer;
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
||||||
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
|
import org.openautonomousconnection.protocol.domain.Domain;
|
||||||
|
import org.openautonomousconnection.protocol.domain.RequestDomain;
|
||||||
|
import org.openautonomousconnection.protocol.listeners.ClientListener;
|
||||||
|
import org.openautonomousconnection.protocol.listeners.ServerListener;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.net.*;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class ProtocolServer extends DefaultMethodsOverrider {
|
||||||
|
public abstract List<Domain> getDomains() throws SQLException;
|
||||||
|
public abstract List<String> getTopLevelDomains() throws SQLException;
|
||||||
|
public abstract void handleMessage(ConnectionHandler connectionHandler, String message);
|
||||||
|
public abstract String getDNSServerInfoSite() throws SQLException;
|
||||||
|
public abstract String getInfoSite(String topLevelDomain) throws SQLException;
|
||||||
|
public abstract String getInterfaceSite() throws SQLException;
|
||||||
|
|
||||||
|
private NetworkServer server;
|
||||||
|
private ProtocolBridge protocolBridge;
|
||||||
|
|
||||||
|
public final void setProtocolBridge(ProtocolBridge protocolBridge) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||||
|
this.protocolBridge = protocolBridge;
|
||||||
|
|
||||||
|
server = new NetworkServer.ServerBuilder()
|
||||||
|
.setEventManager(protocolBridge.getProtocolSettings().eventManager).setPacketHandler(protocolBridge.getProtocolSettings().packetHandler)
|
||||||
|
.setPort(protocolBridge.getProtocolSettings().port).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final ProtocolBridge getProtocolBridge() {
|
||||||
|
return protocolBridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean startServer() throws Exception {
|
||||||
|
server.getEventManager().registerListener(ServerListener.class);
|
||||||
|
server.getEventManager().unregisterListener(ClientListener.class);
|
||||||
|
|
||||||
|
return server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final NetworkServer getServer() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean stopServer() throws IOException {
|
||||||
|
server.getEventManager().unregisterListener(ServerListener.class);
|
||||||
|
return server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Domain ping(RequestDomain requestDomain) throws SQLException {
|
||||||
|
Domain domain = getDomain(requestDomain);
|
||||||
|
boolean reachable = false;
|
||||||
|
|
||||||
|
String destination = domain.parsedDestination();
|
||||||
|
|
||||||
|
if (!destination.startsWith("http://") && !destination.startsWith("https://")) destination = "http://" + destination;
|
||||||
|
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL u = new URL(destination);
|
||||||
|
|
||||||
|
connection = (HttpURLConnection) u.openConnection();
|
||||||
|
connection.setRequestMethod("HEAD");
|
||||||
|
|
||||||
|
int code = connection.getResponseCode();
|
||||||
|
|
||||||
|
reachable = code == 200;
|
||||||
|
} catch (IOException exception) {
|
||||||
|
InetAddress address = null;
|
||||||
|
try {
|
||||||
|
InetAddress address1 = InetAddress.getByName(destination);
|
||||||
|
String ip = address1.getHostAddress();
|
||||||
|
address = InetAddress.getByName(ip);
|
||||||
|
reachable = address.isReachable(10000);
|
||||||
|
} catch (IOException exc) {
|
||||||
|
reachable = false;
|
||||||
|
exc.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
reachable = false;
|
||||||
|
exception.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (connection != null) connection.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean domainExists(RequestDomain domain) throws SQLException {
|
||||||
|
return getDomain(domain) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean domainExists(Domain domain) throws SQLException {
|
||||||
|
return domainExists(new RequestDomain(domain.name, domain.topLevelDomain, domain.getPath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Domain getDomain(RequestDomain domain) throws SQLException {
|
||||||
|
return getDomain(domain.name, domain.topLevelDomain, domain.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean topLevelDomainExists(String topLevelDomain) throws SQLException {
|
||||||
|
return topLevelDomain.equalsIgnoreCase("oac") || getTopLevelDomains().contains(topLevelDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Domain getDomain(String name, String topLevelDomain, String path) throws SQLException {
|
||||||
|
if (!topLevelDomainExists(topLevelDomain)) return null;
|
||||||
|
|
||||||
|
if (name.equalsIgnoreCase("info") && topLevelDomain.equalsIgnoreCase("oac")) return new Domain(name, topLevelDomain, getDNSServerInfoSite(), path);
|
||||||
|
if (name.equalsIgnoreCase("interface") && topLevelDomain.equalsIgnoreCase("oac")) return new Domain(name, topLevelDomain, getInterfaceSite(), path);
|
||||||
|
|
||||||
|
if (name.equalsIgnoreCase("info")) return new Domain(name, topLevelDomain, getInfoSite(topLevelDomain), path);
|
||||||
|
|
||||||
|
for (Domain domain : getDomains()) if (domain.name.equals(name) && domain.topLevelDomain.equals(topLevelDomain)) return new Domain(domain.name, domain.topLevelDomain, domain.realDestination(), path);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.side.client;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.events.ClientDisconnectedEvent;
|
|
||||||
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.packets.OACPacket;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.INSQueryPacket;
|
|
||||||
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 org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract class defining the client-side protocol operations and interactions with INS and web servers.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.INS)
|
|
||||||
public abstract class ProtocolClient extends DefaultMethodsOverrider {
|
|
||||||
/**
|
|
||||||
* Handles everything with INS-Connection.
|
|
||||||
*/
|
|
||||||
private final NetworkClient clientToINS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages the folder structure for client certificates.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ClientCertificateFolderStructure folderStructure;
|
|
||||||
/**
|
|
||||||
* The reference to the ProtocolBridge Object
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ProtocolBridge protocolBridge;
|
|
||||||
/**
|
|
||||||
* Stores the protocol version of the connected server.
|
|
||||||
*/
|
|
||||||
private ProtocolVersion serverVersion = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the ProtocolClient, setting up certificate folders and the INS client connection.
|
|
||||||
*
|
|
||||||
* @throws CertificateException if there are issues with the certificates.
|
|
||||||
* @throws IOException if there are I/O issues during initialization.
|
|
||||||
*/
|
|
||||||
public ProtocolClient(ProtocolBridge protocolBridge) throws CertificateException, IOException {
|
|
||||||
this.protocolBridge = protocolBridge;
|
|
||||||
|
|
||||||
// Initialize and verify certificate folders and files
|
|
||||||
folderStructure = new ClientCertificateFolderStructure();
|
|
||||||
|
|
||||||
// Initialize connection to INS server
|
|
||||||
clientToINS = new NetworkClient.ClientBuilder().setLogger(protocolBridge.getLogger()).setProxy(protocolBridge.getProxy()).
|
|
||||||
setHost(protocolBridge.getProtocolSettings().host).setPort(protocolBridge.getProtocolSettings().port).
|
|
||||||
setPacketHandler(protocolBridge.getProtocolSettings().packetHandler).setEventManager(protocolBridge.getProtocolSettings().eventManager).
|
|
||||||
setRootCAFolder(folderStructure.publicCAFolder).setClientCertificatesFolder(folderStructure.publicClientFolder, folderStructure.privateClientFolder).
|
|
||||||
build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the INS connection client.
|
|
||||||
*
|
|
||||||
* @return the NetworkClient handling the INS connection.
|
|
||||||
*/
|
|
||||||
public final NetworkClient getClientINSConnection() {
|
|
||||||
return clientToINS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 any required certificate file is missing or invalid.
|
|
||||||
* @throws IOException if there are I/O issues during the check.
|
|
||||||
*/
|
|
||||||
private final void checkFileExists(File folder, String prefix, String extension) throws CertificateException, IOException {
|
|
||||||
boolean found = false;
|
|
||||||
// Check if folder exists
|
|
||||||
if (folder == null) throw new FileNotFoundException("Folder does not exist");
|
|
||||||
|
|
||||||
// List files in the folder
|
|
||||||
File[] files = folder.listFiles();
|
|
||||||
|
|
||||||
// Check if 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 for specific files
|
|
||||||
if (!found) found = file.getName().equalsIgnoreCase(prefix + NetworkUtils.getPublicIPAddress() + extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the specific file is not found, throw an exception
|
|
||||||
if (!found) throw new CertificateException("Missing " + prefix + NetworkUtils.getPublicIPAddress() + extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the protocol version of the connected server.
|
|
||||||
*
|
|
||||||
* @return the ProtocolVersion of the server, or PV_1_0_0_CLASSIC if not set.
|
|
||||||
*/
|
|
||||||
public final ProtocolVersion getServerVersion() {
|
|
||||||
return serverVersion == null ? ProtocolVersion.PV_1_0_0_CLASSIC : serverVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the protocol version of the connected server.
|
|
||||||
*
|
|
||||||
* @param serverVersion the ProtocolVersion to set for the server.
|
|
||||||
*/
|
|
||||||
public final void setServerVersion(ProtocolVersion serverVersion) {
|
|
||||||
if (serverVersion == null) this.serverVersion = serverVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles INS disconnection events, resetting the server version and closing the web client connection if necessary.
|
|
||||||
*
|
|
||||||
* @param event the ClientDisconnectedEvent triggered on INS disconnection.
|
|
||||||
*/
|
|
||||||
public final void onINSDisconnect(ClientDisconnectedEvent event) {
|
|
||||||
// Reset server version on INS disconnect
|
|
||||||
serverVersion = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the connected server is a stable server.
|
|
||||||
*
|
|
||||||
* @return true if the server is stable, false otherwise.
|
|
||||||
*/
|
|
||||||
public final boolean isStableServer() {
|
|
||||||
// Check if the server version is stable
|
|
||||||
return !isBetaServer() && !isClassicServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the connected server or its compatible versions support stable protocol.
|
|
||||||
*
|
|
||||||
* @return true if stable protocol is supported, false otherwise.
|
|
||||||
*/
|
|
||||||
public final boolean supportServerStable() {
|
|
||||||
boolean yes = false;
|
|
||||||
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 isStableServer() || yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the connected server is a beta server.
|
|
||||||
*
|
|
||||||
* @return true if the server is beta, false otherwise.
|
|
||||||
*/
|
|
||||||
public final boolean isBetaServer() {
|
|
||||||
// Check if the server version is beta
|
|
||||||
return getServerVersion().getProtocolType() == ProtocolVersion.ProtocolType.BETA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the connected server or its compatible versions support beta protocol.
|
|
||||||
*
|
|
||||||
* @return true if beta protocol is supported, false otherwise.
|
|
||||||
*/
|
|
||||||
public final boolean supportServerBeta() {
|
|
||||||
boolean yes = false;
|
|
||||||
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 isBetaServer() || yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the connected server is a classic server.
|
|
||||||
*
|
|
||||||
* @return true if the server is classic, false otherwise.
|
|
||||||
*/
|
|
||||||
public final boolean isClassicServer() {
|
|
||||||
// Check if the server version is classic
|
|
||||||
return getServerVersion().getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the connected server or its compatible versions support classic protocol.
|
|
||||||
*
|
|
||||||
* @return true if classic protocol is supported, false otherwise.
|
|
||||||
*/
|
|
||||||
public final boolean supportServerClassic() {
|
|
||||||
boolean yes = false;
|
|
||||||
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 isClassicServer() || yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 supportServerPacket(OACPacket packet) {
|
|
||||||
// Check if the server supports the protocol version of the packet
|
|
||||||
return supportServerVersion(packet.getProtocolVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 supportServerVersion(ProtocolVersion targetVersion) {
|
|
||||||
// Directly check if the server version matches or is in the list of compatible versions
|
|
||||||
return getServerVersion() == targetVersion || getServerVersion().getCompatibleVersions().contains(targetVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 supportServerProtocol(ProtocolVersion.Protocol protocol) {
|
|
||||||
boolean yes = false;
|
|
||||||
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 getServerVersion().getSupportedProtocols().contains(protocol) || yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an INS query to the INS server.
|
|
||||||
* <p>
|
|
||||||
* The client requests a specific record type for a given TLN, name and optional subname.
|
|
||||||
* After sending the packet, {@link #onQuerySent(String, String, String, INSRecordType)} is invoked.
|
|
||||||
*
|
|
||||||
* @param tln The TLN.
|
|
||||||
* @param name The InfoName.
|
|
||||||
* @param sub Optional subname or {@code null}.
|
|
||||||
* @param type The requested record type.
|
|
||||||
* @throws IOException If sending the packet fails.
|
|
||||||
* @throws ClassNotFoundException If packet serialization fails.
|
|
||||||
*/
|
|
||||||
public final void sendINSQuery(String tln, String name, String sub, INSRecordType type) throws IOException, ClassNotFoundException {
|
|
||||||
if (!protocolBridge.isRunningAsClient()) return;
|
|
||||||
|
|
||||||
getClientINSConnection().sendPacket(new INSQueryPacket(tln, name, sub, type, getClientINSConnection().getClientID()));
|
|
||||||
onQuerySent(tln, name, sub, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the client receives an INS response from the server.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* @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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after a query was sent to the INS server.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* @param tln The TLN requested.
|
|
||||||
* @param name The InfoName.
|
|
||||||
* @param sub Optional subname.
|
|
||||||
* @param type The requested record type.
|
|
||||||
*/
|
|
||||||
public void onQuerySent(String tln, String name, String sub, INSRecordType type) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages the folder structure for client certificates.
|
|
||||||
*/
|
|
||||||
public final class ClientCertificateFolderStructure {
|
|
||||||
public final File certificatesFolder;
|
|
||||||
|
|
||||||
public final File publicFolder;
|
|
||||||
public final File privateFolder;
|
|
||||||
|
|
||||||
public final File privateCAFolder;
|
|
||||||
public final File privateClientFolder;
|
|
||||||
|
|
||||||
public final File publicCAFolder;
|
|
||||||
public final File publicClientFolder;
|
|
||||||
|
|
||||||
public ClientCertificateFolderStructure() {
|
|
||||||
certificatesFolder = new File("certificates");
|
|
||||||
|
|
||||||
publicFolder = new File(certificatesFolder, "public");
|
|
||||||
privateFolder = new File(certificatesFolder, "private");
|
|
||||||
|
|
||||||
privateCAFolder = new File(privateFolder, "ca");
|
|
||||||
privateClientFolder = new File(privateFolder, "client");
|
|
||||||
|
|
||||||
publicCAFolder = new File(publicFolder, "ca");
|
|
||||||
publicClientFolder = new File(publicFolder, "client");
|
|
||||||
|
|
||||||
if (!certificatesFolder.exists()) certificatesFolder.mkdirs();
|
|
||||||
|
|
||||||
if (!publicFolder.exists()) publicFolder.mkdirs();
|
|
||||||
if (!privateFolder.exists()) privateFolder.mkdirs();
|
|
||||||
|
|
||||||
if (!privateCAFolder.exists()) privateCAFolder.mkdirs();
|
|
||||||
if (!privateClientFolder.exists()) privateClientFolder.mkdirs();
|
|
||||||
|
|
||||||
if (!publicCAFolder.exists()) publicCAFolder.mkdirs();
|
|
||||||
if (!publicClientFolder.exists()) publicClientFolder.mkdirs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.side.client.events;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|
||||||
import org.openautonomousconnection.protocol.side.client.ProtocolClient;
|
|
||||||
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 ConnectedToProtocolINSServerEvent extends Event {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to the ProtocolClient object.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ProtocolClient client;
|
|
||||||
|
|
||||||
public ConnectedToProtocolINSServerEvent(ProtocolClient client) {
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
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.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 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,298 +0,0 @@
|
|||||||
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.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 final NetworkServer networkServer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The configuration manager for handling server configurations.
|
|
||||||
*/
|
|
||||||
private final ConfigurationManager configurationManager;
|
|
||||||
/**
|
|
||||||
* The reference to the ProtocolBridge Object
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final 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.
|
|
||||||
*
|
|
||||||
* @param configFile The configuration file for the INS server.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
* @throws CertificateException If a certificate error occurs.
|
|
||||||
*/
|
|
||||||
public ProtocolINSServer(File configFile, ProtocolBridge protocolBridge) throws IOException, CertificateException {
|
|
||||||
this.protocolBridge = protocolBridge;
|
|
||||||
// Ensure the configuration file exists
|
|
||||||
if (!configFile.exists()) configFile.createNewFile();
|
|
||||||
|
|
||||||
// Load the configuration properties
|
|
||||||
configurationManager = new ConfigurationManager(configFile);
|
|
||||||
configurationManager.loadProperties();
|
|
||||||
|
|
||||||
// Set default values for configuration properties if not already set
|
|
||||||
if (!configurationManager.isSet("server.site.info")) {
|
|
||||||
configurationManager.set("server.site.info", "INS-SERVER INFO SITE IP:PORT");
|
|
||||||
configurationManager.saveProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!configurationManager.isSet("server.site.frontend")) {
|
|
||||||
configurationManager.set("server.site.frontend", "SERVER IP TO INS-FRONTEND:PORT");
|
|
||||||
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");
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
// Initialize the protocol bridge and clients list
|
|
||||||
this.clients = new ArrayList<>();
|
|
||||||
|
|
||||||
// Build the network server with the specified settings
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the INS information site URL from the configuration.
|
|
||||||
*
|
|
||||||
* @return The INS information site URL.
|
|
||||||
*/
|
|
||||||
public final String getINSInfoSite() {
|
|
||||||
return configurationManager.getString("server.site.info");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves a request for an INS record based on TLN, name, subname and record type.
|
|
||||||
* <p>
|
|
||||||
* The implementation should:
|
|
||||||
* <ul>
|
|
||||||
* <li>Locate the corresponding InfoName in storage</li>
|
|
||||||
* <li>Return all matching {@link INSRecord} entries</li>
|
|
||||||
* <li>Handle CNAME recursion, TTL rules, and filtering for the requested type</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param tln The top-level name.
|
|
||||||
* @param name The InfoName.
|
|
||||||
* @param sub The optional subname , may be {@code null}.
|
|
||||||
* @param type The INS record type being requested.
|
|
||||||
* @return A list of resolved INS records. May be empty if no record exists.
|
|
||||||
*/
|
|
||||||
public abstract List<INSRecord> resolve(String tln, String name, String sub, INSRecordType type);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback fired whenever the INS server receives a query packet.
|
|
||||||
* <p>This method is optional.</p>
|
|
||||||
*
|
|
||||||
* @param tln The top-level name of the request.
|
|
||||||
* @param name The InfoName being queried.
|
|
||||||
* @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) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback fired after an INS response was successfully sent to the client.
|
|
||||||
*
|
|
||||||
* @param tln The requested TLN.
|
|
||||||
* @param name The InfoName.
|
|
||||||
* @param sub Optional subname or {@code null}.
|
|
||||||
* @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) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback fired when an INS response could not be delivered to the client.
|
|
||||||
*
|
|
||||||
* @param tln The requested TLN.
|
|
||||||
* @param name The InfoName.
|
|
||||||
* @param sub Optional subname.
|
|
||||||
* @param type The record type requested.
|
|
||||||
* @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) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves the information endpoint for a given Top-Level Name (TLN).
|
|
||||||
*
|
|
||||||
* <p>This method is part of the INS server's internal resolution logic.
|
|
||||||
* Each TLN
|
|
||||||
* need to define a special "info site" which provides metadata, documentation,
|
|
||||||
* or administrative information for that TLN.
|
|
||||||
*
|
|
||||||
* <p>The returned string must always be in the format:
|
|
||||||
* <pre>
|
|
||||||
* host:port
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>This method is used automatically by the INS protocol handler when a client
|
|
||||||
* queries an InfoName of the form:
|
|
||||||
* <pre>
|
|
||||||
* info.<tln>
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>If no TLN-specific info endpoint exists or the TLN does not exist, the implementation can:
|
|
||||||
* <ul>
|
|
||||||
* <li>return <code>null</code> to signal that no info site is registered</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @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.
|
|
||||||
*/
|
|
||||||
public abstract String resolveTLNInfoSite(String tln);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the INS registration site URL from the configuration.
|
|
||||||
*
|
|
||||||
* @return The INS registration site URL.
|
|
||||||
*/
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,734 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.side.web;
|
|
||||||
|
|
||||||
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.web.managers.AuthManager;
|
|
||||||
import org.openautonomousconnection.protocol.side.web.managers.RuleManager;
|
|
||||||
import org.openautonomousconnection.protocol.side.web.managers.SessionManager;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLSocket;
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a connected web client.
|
|
||||||
* Manages the connection, handles HTTP requests, and serves files.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
|
||||||
public final class ConnectedWebClient {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The connection handler associated with this web client.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ConnectionHandler pipelineConnection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The SSL socket for the web client connection.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private SSLSocket webSocket;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The output stream for sending data to the client.
|
|
||||||
*/
|
|
||||||
private ObjectOutputStream outputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The input stream for receiving data from the client.
|
|
||||||
*/
|
|
||||||
private ObjectInputStream inputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The protocol version of the connected client.
|
|
||||||
*/
|
|
||||||
private ProtocolVersion clientVersion = null;
|
|
||||||
/**
|
|
||||||
* Indicates if the client version has been loaded.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private boolean clientVersionLoaded = false;
|
|
||||||
/**
|
|
||||||
* The reference to the ProtocolWebServer Object
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private ProtocolWebServer protocolWebServer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a ConnectedWebClient with the given connection handler.
|
|
||||||
*
|
|
||||||
* @param pipelineConnection The connection handler for the web client.
|
|
||||||
*/
|
|
||||||
public ConnectedWebClient(ConnectionHandler pipelineConnection) {
|
|
||||||
this.pipelineConnection = pipelineConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an HTTP redirect response to the client.
|
|
||||||
*
|
|
||||||
* @param out The output stream to send the response to.
|
|
||||||
* @param location The URL to redirect to.
|
|
||||||
* @param cookies Optional cookies to set in the response.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
*/
|
|
||||||
private static void sendRedirect(OutputStream out, String location, Map<String, String> cookies) throws IOException {
|
|
||||||
// Send HTTP 302 Found response with Location header
|
|
||||||
out.write(("OAC 302 Found\r\n").getBytes());
|
|
||||||
out.write(("Location: " + location + "\r\n").getBytes());
|
|
||||||
|
|
||||||
// Set cookies if provided
|
|
||||||
if (cookies != null) {
|
|
||||||
for (var entry : cookies.entrySet()) {
|
|
||||||
out.write((entry.getKey() + ": " + entry.getValue() + "\r\n").getBytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of headers
|
|
||||||
out.write("\r\n".getBytes());
|
|
||||||
out.flush();
|
|
||||||
} /**
|
|
||||||
* Thread for receiving data from the client.
|
|
||||||
*/
|
|
||||||
private final Thread receiveThread = new Thread(this::receive);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses POST parameters from the input stream.
|
|
||||||
*
|
|
||||||
* @param in The input stream to read from.
|
|
||||||
* @return A map of POST parameter names to values.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
*/
|
|
||||||
private static Map<String, String> parsePostParams(InputStream in) throws IOException {
|
|
||||||
// Read the entire input stream into a string
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
while (reader.ready()) {
|
|
||||||
sb.append((char) reader.read());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split the string into key-value pairs and decode them
|
|
||||||
Map<String, String> map = new HashMap<>();
|
|
||||||
String[] pairs = sb.toString().split("&");
|
|
||||||
for (String p : pairs) {
|
|
||||||
// Split each pair into key and value
|
|
||||||
String[] kv = p.split("=", 2);
|
|
||||||
if (kv.length == 2)
|
|
||||||
// Decode and store in the map
|
|
||||||
map.put(URLDecoder.decode(kv[0], StandardCharsets.UTF_8), URLDecoder.decode(kv[1], StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalizes a file path to prevent directory traversal attacks.
|
|
||||||
*
|
|
||||||
* @param path The raw file path.
|
|
||||||
* @return The normalized file path.
|
|
||||||
*/
|
|
||||||
private static String normalizePath(String path) {
|
|
||||||
// Replace backslashes with forward slashes and remove ".." segments
|
|
||||||
path = path.replace("/", File.separator).replace("\\", "/");
|
|
||||||
// Remove any ".." segments to prevent directory traversal
|
|
||||||
while (path.contains("..")) path = path.replace("..", "");
|
|
||||||
|
|
||||||
// Remove leading slashes
|
|
||||||
if (path.startsWith("/")) path = path.substring(1);
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses query parameters from a raw URL path.
|
|
||||||
*
|
|
||||||
* @param rawPath The raw URL path containing query parameters.
|
|
||||||
* @return A map of query parameter names to values.
|
|
||||||
*/
|
|
||||||
private static Map<String, String> parseQueryParams(String rawPath) {
|
|
||||||
// Extract query parameters from the URL path
|
|
||||||
Map<String, String> map = new HashMap<>();
|
|
||||||
if (rawPath.contains("?")) {
|
|
||||||
// Split the query string into key-value pairs
|
|
||||||
String[] params = rawPath.substring(rawPath.indexOf("?") + 1).split("&");
|
|
||||||
for (String p : params) {
|
|
||||||
// Split each pair into key and value
|
|
||||||
String[] kv = p.split("=");
|
|
||||||
if (kv.length == 2) map.put(kv[0], kv[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the request is a multipart/form-data request.
|
|
||||||
*
|
|
||||||
* @param headers The HTTP headers of the request.
|
|
||||||
* @return True if the request is multipart/form-data, false otherwise.
|
|
||||||
*/
|
|
||||||
private static boolean isMultipart(Map<String, String> headers) {
|
|
||||||
String contentType = headers.get("content-type");
|
|
||||||
return contentType != null && contentType.startsWith("multipart/form-data");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles a multipart/form-data request, saving uploaded files to the specified directory.
|
|
||||||
*
|
|
||||||
* @param in The input stream to read the request body from.
|
|
||||||
* @param headers The HTTP headers of the request.
|
|
||||||
* @param uploadDir The directory to save uploaded files to.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
*/
|
|
||||||
private static void handleMultipart(InputStream in, Map<String, String> headers, File uploadDir) throws IOException {
|
|
||||||
// Ensure the upload directory exists
|
|
||||||
if (!uploadDir.exists()) uploadDir.mkdirs();
|
|
||||||
|
|
||||||
// Extract the boundary from the Content-Type header
|
|
||||||
String contentType = headers.get("content-type");
|
|
||||||
String boundary = "--" + contentType.split("boundary=")[1];
|
|
||||||
|
|
||||||
// Read the entire request body into a buffer
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
byte[] lineBuffer = new byte[8192];
|
|
||||||
int read;
|
|
||||||
while ((read = in.read(lineBuffer)) != -1) {
|
|
||||||
buffer.write(lineBuffer, 0, read);
|
|
||||||
if (buffer.size() > 10 * 1024 * 1024) break; // 10 MB max
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the multipart data
|
|
||||||
String data = buffer.toString(StandardCharsets.UTF_8);
|
|
||||||
String[] parts = data.split(boundary);
|
|
||||||
|
|
||||||
// Process each part
|
|
||||||
for (String part : parts) {
|
|
||||||
if (part.contains("Content-Disposition")) {
|
|
||||||
String name = null;
|
|
||||||
String filename = null;
|
|
||||||
|
|
||||||
// Extract headers from the part
|
|
||||||
for (String headerLine : part.split("\r\n")) {
|
|
||||||
if (headerLine.startsWith("Content-Disposition")) {
|
|
||||||
if (headerLine.contains("filename=\"")) {
|
|
||||||
int start = headerLine.indexOf("filename=\"") + 10;
|
|
||||||
int end = headerLine.indexOf("\"", start);
|
|
||||||
filename = headerLine.substring(start, end);
|
|
||||||
}
|
|
||||||
if (headerLine.contains("name=\"")) {
|
|
||||||
int start = headerLine.indexOf("name=\"") + 6;
|
|
||||||
int end = headerLine.indexOf("\"", start);
|
|
||||||
name = headerLine.substring(start, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the file if a filename is provided
|
|
||||||
if (filename != null && !filename.isEmpty()) {
|
|
||||||
int headerEnd = part.indexOf("\r\n\r\n");
|
|
||||||
byte[] fileData = part.substring(headerEnd + 4).getBytes(StandardCharsets.UTF_8);
|
|
||||||
File outFile = new File(uploadDir, filename);
|
|
||||||
Files.write(outFile.toPath(), fileData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an response to the client.
|
|
||||||
*
|
|
||||||
* @param out
|
|
||||||
* @param code
|
|
||||||
* @param file
|
|
||||||
* @param headers
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private static void sendResponse(OutputStream out, int code, File file, Map<String, String> headers) throws IOException {
|
|
||||||
byte[] body = Files.readAllBytes(file.toPath());
|
|
||||||
sendResponse(out, code, body, "text/html", headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an response to the client.
|
|
||||||
*
|
|
||||||
* @param out The output stream to send the response to.
|
|
||||||
* @param code The HTTP status code.
|
|
||||||
* @param file The file to read the response body from.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
*/
|
|
||||||
private static void sendResponse(OutputStream out, int code, File file) throws IOException {
|
|
||||||
sendResponse(out, code, Files.readString(file.toPath()), "text/html");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an response to the client.
|
|
||||||
*
|
|
||||||
* @param out The output stream to send the response to.
|
|
||||||
* @param code The HTTP status code.
|
|
||||||
* @param body The response body as a string.
|
|
||||||
* @param contentType The content type of the response.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
*/
|
|
||||||
private static void sendResponse(OutputStream out, int code, String body, String contentType) throws IOException {
|
|
||||||
sendResponse(out, code, body.getBytes(StandardCharsets.UTF_8), contentType, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an response to the client.
|
|
||||||
*
|
|
||||||
* @param out The output stream to send the response to.
|
|
||||||
* @param code The HTTP status code.
|
|
||||||
* @param file The file to read the response body from.
|
|
||||||
* @param contentType The content type of the response.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
*/
|
|
||||||
private static void sendResponse(OutputStream out, int code, File file, String contentType) throws IOException {
|
|
||||||
byte[] bytes = Files.readAllBytes(file.toPath());
|
|
||||||
sendResponse(out, code, bytes, contentType, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an response to the client.
|
|
||||||
*
|
|
||||||
* @param out The output stream to send the response to.
|
|
||||||
* @param code The HTTP status code.
|
|
||||||
* @param body The response body as a byte array.
|
|
||||||
* @param contentType The content type of the response.
|
|
||||||
* @param headers Additional headers to include in the response.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
*/
|
|
||||||
private static void sendResponse(OutputStream out, int code, byte[] body, String contentType, Map<String, String> headers) throws IOException {
|
|
||||||
// Send response status line and headers
|
|
||||||
out.write(("OAC " + code + " " + getStatusText(code) + "\r\n").getBytes());
|
|
||||||
out.write(("Content-Type: " + contentType + "\r\n").getBytes());
|
|
||||||
out.write(("Content-Length: " + body.length + "\r\n").getBytes());
|
|
||||||
|
|
||||||
// Write additional headers if provided
|
|
||||||
if (headers != null) headers.forEach((k, v) -> {
|
|
||||||
try {
|
|
||||||
out.write((k + ": " + v + "\r\n").getBytes());
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// End of headers
|
|
||||||
out.write("\r\n".getBytes());
|
|
||||||
out.write(body);
|
|
||||||
out.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the standard status text for a given status code.
|
|
||||||
*
|
|
||||||
* @param code The status code.
|
|
||||||
* @return The corresponding status text.
|
|
||||||
*/
|
|
||||||
private static String getStatusText(int code) {
|
|
||||||
return switch (code) {
|
|
||||||
case 200 -> "OK";
|
|
||||||
case 301 -> "Moved Permanently";
|
|
||||||
case 302 -> "Found";
|
|
||||||
case 400 -> "Bad Request";
|
|
||||||
case 401 -> "Unauthorized";
|
|
||||||
case 403 -> "Forbidden";
|
|
||||||
case 404 -> "Not Found";
|
|
||||||
case 500 -> "Internal Server Error";
|
|
||||||
default -> "Unknown";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the content type based on the file extension.
|
|
||||||
*
|
|
||||||
* @param name The file name.
|
|
||||||
* @return The corresponding content type.
|
|
||||||
*/
|
|
||||||
private static String getContentType(String name) {
|
|
||||||
return switch (name.substring(name.lastIndexOf('.') + 1).toLowerCase()) {
|
|
||||||
case "html", "php" -> "text/html";
|
|
||||||
case "js" -> "text/javascript";
|
|
||||||
case "css" -> "text/css";
|
|
||||||
case "json" -> "application/json";
|
|
||||||
case "png" -> "image/png";
|
|
||||||
case "jpg", "jpeg" -> "image/jpeg";
|
|
||||||
case "mp4" -> "video/mp4";
|
|
||||||
case "mp3" -> "audio/mpeg3";
|
|
||||||
case "wav" -> "audio/wav";
|
|
||||||
case "pdf" -> "application/pdf";
|
|
||||||
default -> "text/plain";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders a PHP file by executing it with the PHP interpreter and captures cookies.
|
|
||||||
*
|
|
||||||
* @param file The PHP file to render.
|
|
||||||
* @return A PHPResponse containing the output and cookies.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
* @throws InterruptedException If the process is interrupted.
|
|
||||||
*/
|
|
||||||
private static PHPResponse renderPHPWithCookies(File file) throws IOException, InterruptedException {
|
|
||||||
// Execute the PHP file using the PHP interpreter
|
|
||||||
ProcessBuilder pb = new ProcessBuilder("php", file.getAbsolutePath());
|
|
||||||
pb.redirectErrorStream(true);
|
|
||||||
Process p = pb.start();
|
|
||||||
|
|
||||||
// Capture the output of the PHP process
|
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
|
||||||
InputStream processIn = p.getInputStream();
|
|
||||||
byte[] buf = new byte[8192];
|
|
||||||
int read;
|
|
||||||
while ((read = processIn.read(buf)) != -1) {
|
|
||||||
output.write(buf, 0, read);
|
|
||||||
}
|
|
||||||
p.waitFor();
|
|
||||||
|
|
||||||
// Parse the output to separate headers and body, and extract cookies
|
|
||||||
String fullOutput = output.toString(StandardCharsets.UTF_8);
|
|
||||||
Map<String, String> cookies = new HashMap<>();
|
|
||||||
|
|
||||||
// Split headers and body
|
|
||||||
String[] parts = fullOutput.split("\r\n\r\n", 2);
|
|
||||||
String body;
|
|
||||||
if (parts.length == 2) {
|
|
||||||
// Get headers and body
|
|
||||||
String headers = parts[0];
|
|
||||||
body = parts[1];
|
|
||||||
|
|
||||||
// Extract cookies from headers
|
|
||||||
for (String headerLine : headers.split("\r\n")) {
|
|
||||||
if (headerLine.toLowerCase().startsWith("set-cookie:")) {
|
|
||||||
String cookie = headerLine.substring("set-cookie:".length()).trim();
|
|
||||||
String[] kv = cookie.split(";", 2);
|
|
||||||
String[] pair = kv[0].split("=", 2);
|
|
||||||
if (pair.length == 2) cookies.put(pair[0], pair[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No headers, only body
|
|
||||||
body = fullOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PHPResponse(body, cookies);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the SSL socket for the web client and starts the receive thread.
|
|
||||||
*
|
|
||||||
* @param webSocket The SSL socket to set.
|
|
||||||
*/
|
|
||||||
public void setWebSocket(SSLSocket webSocket) {
|
|
||||||
if (webSocket != null) this.webSocket = webSocket;
|
|
||||||
this.receiveThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the web client is currently connected.
|
|
||||||
*
|
|
||||||
* @return True if connected, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean isConnected() {
|
|
||||||
return this.webSocket != null && this.webSocket.isConnected() && !this.webSocket.isClosed() && this.receiveThread.isAlive() && pipelineConnection.isConnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disconnects the web client, closing streams and the socket.
|
|
||||||
*
|
|
||||||
* @return True if disconnection was successful, false if already disconnected.
|
|
||||||
*/
|
|
||||||
public synchronized boolean disconnect() {
|
|
||||||
if (!this.isConnected()) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// Disconnect the underlying connection handler
|
|
||||||
pipelineConnection.disconnect();
|
|
||||||
|
|
||||||
// Interrupt the receive thread if it's still alive
|
|
||||||
if (this.receiveThread.isAlive()) {
|
|
||||||
this.receiveThread.interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Close streams and the socket
|
|
||||||
this.outputStream.close();
|
|
||||||
this.inputStream.close();
|
|
||||||
this.webSocket.close();
|
|
||||||
} catch (IOException var2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nullify references
|
|
||||||
this.webSocket = null;
|
|
||||||
this.outputStream = null;
|
|
||||||
this.inputStream = null;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) clientVersionLoaded = true;
|
|
||||||
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() {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives and processes requests from the client.
|
|
||||||
* Handles authentication, file serving, and PHP rendering.
|
|
||||||
*/
|
|
||||||
private void receive() {
|
|
||||||
try {
|
|
||||||
while (this.isConnected()) {
|
|
||||||
Object received = this.inputStream.readObject();
|
|
||||||
|
|
||||||
try (InputStream in = webSocket.getInputStream(); OutputStream out = webSocket.getOutputStream()) {
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
|
|
||||||
String line;
|
|
||||||
String path = "/main.html";
|
|
||||||
Map<String, String> headers = new HashMap<>();
|
|
||||||
while ((line = reader.readLine()) != null && !line.isEmpty()) {
|
|
||||||
if (line.toLowerCase().startsWith("get") || line.toLowerCase().startsWith("post")) {
|
|
||||||
path = line.split(" ")[1];
|
|
||||||
}
|
|
||||||
if (line.contains(":")) {
|
|
||||||
String[] parts = line.split(":", 2);
|
|
||||||
headers.put(parts[0].trim().toLowerCase(), parts[1].trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
path = URLDecoder.decode(path, StandardCharsets.UTF_8);
|
|
||||||
path = normalizePath(path);
|
|
||||||
|
|
||||||
File file = new File(protocolWebServer.getProtocolBridge().getProtocolWebServer().getContentFolder(), path);
|
|
||||||
|
|
||||||
String sessionId = null;
|
|
||||||
if (headers.containsKey("cookie")) {
|
|
||||||
for (String cookie : headers.get("cookie").split(";")) {
|
|
||||||
cookie = cookie.trim();
|
|
||||||
if (cookie.startsWith("SESSIONID=")) {
|
|
||||||
sessionId = cookie.substring("SESSIONID=".length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file.exists() || !file.isFile()) {
|
|
||||||
sendResponse(out, 404, new File(protocolWebServer.getProtocolBridge().getProtocolWebServer().getErrorsFolder(), "404.html"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String clientIp = webSocket.getInetAddress().getHostAddress();
|
|
||||||
String userAgent = headers.getOrDefault("user-agent", null);
|
|
||||||
|
|
||||||
boolean loggedIn = sessionId != null && SessionManager.isValid(sessionId, clientIp, userAgent, protocolWebServer);
|
|
||||||
|
|
||||||
if (path.equals("/403-login") && headers.getOrDefault("content-type", "").startsWith("application/x-www-form-urlencoded")) {
|
|
||||||
Map<String, String> postParams = parsePostParams(in);
|
|
||||||
String login = postParams.get("login");
|
|
||||||
String password = postParams.get("password");
|
|
||||||
|
|
||||||
if (AuthManager.checkAuth(login, password)) {
|
|
||||||
String newSessionId = SessionManager.create(login, clientIp, userAgent, protocolWebServer);
|
|
||||||
Map<String, String> cookies = Map.of("Set-Cookie", "SESSIONID=" + newSessionId + "; HttpOnly; Path=/");
|
|
||||||
sendRedirect(out, "/main.html", cookies);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
sendRedirect(out, "/403.php", null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMultipart(headers)) {
|
|
||||||
handleMultipart(in, headers, new File(protocolWebServer.getProtocolBridge().getProtocolWebServer().getContentFolder(), "uploads"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RuleManager.requiresAuth(path) && !loggedIn) {
|
|
||||||
PHPResponse phpResp = renderPHPWithCookies(new File(protocolWebServer.getProtocolBridge().getProtocolWebServer().getContentFolder(), "403.php"));
|
|
||||||
sendResponse(out, 200, phpResp.body.getBytes(StandardCharsets.UTF_8), "text/html", phpResp.cookies);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (RuleManager.isDenied(path) && !RuleManager.isAllowed(path)) {
|
|
||||||
sendResponse(out, 403, new File(protocolWebServer.getProtocolBridge().getProtocolWebServer().getErrorsFolder(), "403.php"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path.endsWith(".php")) {
|
|
||||||
PHPResponse phpResp = renderPHPWithCookies(file);
|
|
||||||
sendResponse(out, 200, phpResp.body.getBytes(StandardCharsets.UTF_8), "text/html", phpResp.cookies);
|
|
||||||
} else {
|
|
||||||
sendResponse(out, 200, Files.readAllBytes(file.toPath()), getContentType(path), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception var2) {
|
|
||||||
this.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set protocol bridge
|
|
||||||
*
|
|
||||||
* @param protocolWebServer The ProtocolWebServer object
|
|
||||||
*/
|
|
||||||
public void setProtocolWebServer(ProtocolWebServer protocolWebServer) {
|
|
||||||
if (this.protocolWebServer == null) this.protocolWebServer = protocolWebServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the response from a PHP script, including body and cookies.
|
|
||||||
*/
|
|
||||||
private static class PHPResponse {
|
|
||||||
String body;
|
|
||||||
Map<String, String> cookies;
|
|
||||||
|
|
||||||
public PHPResponse(String body, Map<String, String> cookies) {
|
|
||||||
this.body = body;
|
|
||||||
this.cookies = cookies;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,377 +0,0 @@
|
|||||||
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.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 final class ProtocolWebServer {
|
|
||||||
/**
|
|
||||||
* Folder for web content.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final File contentFolder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Folder for error pages.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final File errorsFolder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure for server.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ServerCertificateFolderStructure folderStructure;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration manager for server settings.
|
|
||||||
*/
|
|
||||||
private final ConfigurationManager configurationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Certificate files for SSL.
|
|
||||||
*/
|
|
||||||
private final File certFile;
|
|
||||||
/**
|
|
||||||
* Certificate files for SSL.
|
|
||||||
*/
|
|
||||||
private final File keyFile;
|
|
||||||
/**
|
|
||||||
* The configuration file for the web server.
|
|
||||||
*/
|
|
||||||
private final File configFile;
|
|
||||||
/**
|
|
||||||
* The reference to the ProtocolBridge Object
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final 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.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private String uniqueSessionString;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the web server with the given configuration, authentication, and rules files.
|
|
||||||
*
|
|
||||||
* @param configFile The configuration file.
|
|
||||||
* @param authFile The authentication file.
|
|
||||||
* @param rulesFile The rules file.
|
|
||||||
* @throws Exception If an error occurs during initialization.
|
|
||||||
*/
|
|
||||||
public ProtocolWebServer(File configFile, File authFile, File rulesFile, ProtocolBridge protocolBridge) throws Exception {
|
|
||||||
this.protocolBridge = protocolBridge;
|
|
||||||
|
|
||||||
// Initialize the list of connected clients
|
|
||||||
this.clients = new ArrayList<>();
|
|
||||||
|
|
||||||
// Store the configuration file
|
|
||||||
this.configFile = configFile;
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
// Load configuration settings
|
|
||||||
this.configurationManager = getConfigurationManager(configFile);
|
|
||||||
|
|
||||||
// Set up content and error folders
|
|
||||||
contentFolder = new File("content");
|
|
||||||
errorsFolder = new File("errors");
|
|
||||||
|
|
||||||
// Create folders if they don't exist
|
|
||||||
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();
|
|
||||||
FileUtils.writeFile(authFile, """
|
|
||||||
admin:5e884898da28047151d0e56f8dc6292773603d0d6aabbddab8f91d8e5f99f6c7
|
|
||||||
user:e99a18c428cb38d5f260853678922e03abd8335f
|
|
||||||
""");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create default rules file if it doesn't exist
|
|
||||||
if (!rulesFile.exists()) {
|
|
||||||
rulesFile.createNewFile();
|
|
||||||
FileUtils.writeFile(rulesFile, """
|
|
||||||
{
|
|
||||||
"allow": [
|
|
||||||
"index.html",
|
|
||||||
"css/*",
|
|
||||||
"private/info.php"
|
|
||||||
],
|
|
||||||
"deny": [
|
|
||||||
"private/*"
|
|
||||||
],
|
|
||||||
"auth": [
|
|
||||||
"private/*",
|
|
||||||
"admin/*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
""");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load authentication and rules
|
|
||||||
uniqueSessionString = AuthManager.sha256(new RandomString(new Random(System.currentTimeMillis()).nextInt(10, 20)).nextString());
|
|
||||||
|
|
||||||
AuthManager.loadAuthFile(authFile);
|
|
||||||
RuleManager.loadRules(rulesFile);
|
|
||||||
|
|
||||||
// Initialize the pipeline server
|
|
||||||
pipelineServer = new NetworkServer.ServerBuilder().
|
|
||||||
setPort(configurationManager.getInt("port.pipeline")).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 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 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(configurationManager.getInt("port"));
|
|
||||||
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.setWebSocket(client);
|
|
||||||
connectedWebClient.setProtocolWebServer(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
pipelineServer.getLogger().exception("Failed to accept WebClient", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the configuration manager for the web server.
|
|
||||||
*
|
|
||||||
* @return The configuration manager.
|
|
||||||
* @throws IOException If an I/O error occurs while loading or saving the configuration.
|
|
||||||
*/
|
|
||||||
public ConfigurationManager getConfigurationManager() throws IOException {
|
|
||||||
return getConfigurationManager(configFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads and initializes the configuration manager with default settings if necessary.
|
|
||||||
*
|
|
||||||
* @param configFile The configuration file to load.
|
|
||||||
* @return The initialized configuration manager.
|
|
||||||
* @throws IOException If an I/O error occurs while loading or saving the configuration.
|
|
||||||
*/
|
|
||||||
private ConfigurationManager getConfigurationManager(File configFile) throws IOException {
|
|
||||||
if (!configFile.exists()) configFile.createNewFile();
|
|
||||||
|
|
||||||
ConfigurationManager configurationManager = new ConfigurationManager(configFile);
|
|
||||||
configurationManager.loadProperties();
|
|
||||||
|
|
||||||
if (!configurationManager.isSet("port.webserver")) {
|
|
||||||
configurationManager.set("port.webserver", 9824);
|
|
||||||
configurationManager.saveProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!configurationManager.isSet("port.pipeline")) {
|
|
||||||
configurationManager.set("port.pipeline", 9389);
|
|
||||||
configurationManager.saveProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!configurationManager.isSet("filemaxuploadmb")) {
|
|
||||||
configurationManager.set("filemaxuploadmb", 1000);
|
|
||||||
configurationManager.saveProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!configurationManager.isSet("sessionexpireminutes")) {
|
|
||||||
configurationManager.set("sessionexpireminutes", 60);
|
|
||||||
configurationManager.saveProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
return configurationManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 ConnectedWebClientEvent extends Event {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The connected web client.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ConnectedWebClient webClient;
|
|
||||||
|
|
||||||
public ConnectedWebClientEvent(ConnectedWebClient webClient) {
|
|
||||||
this.webClient = webClient;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.side.web.managers;
|
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages authentication for web clients.
|
|
||||||
* Loads user credentials from a file and verifies login attempts.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
|
||||||
public final class AuthManager {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map of usernames to their SHA-256 hashed passwords
|
|
||||||
*/
|
|
||||||
private static final Map<String, String> users = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the authentication file and populates the users map.
|
|
||||||
* The file should contain lines in the format: username:hashed_password
|
|
||||||
* Lines starting with '#' are treated as comments and ignored.
|
|
||||||
*
|
|
||||||
* @param authFile The authentication file to load.
|
|
||||||
* @throws IOException If an I/O error occurs reading from the file.
|
|
||||||
*/
|
|
||||||
public static void loadAuthFile(File authFile) throws IOException {
|
|
||||||
// Create the file if it doesn't exist
|
|
||||||
if (!authFile.exists()) authFile.createNewFile();
|
|
||||||
for (String line : Files.readAllLines(authFile.toPath(), StandardCharsets.UTF_8)) {
|
|
||||||
// Trim whitespace and ignore comments/empty lines
|
|
||||||
line = line.trim();
|
|
||||||
if (line.isEmpty() || line.startsWith("#")) continue;
|
|
||||||
|
|
||||||
// Split the line into username and hashed password
|
|
||||||
String[] parts = line.split(":", 2);
|
|
||||||
if (parts.length == 2) {
|
|
||||||
users.put(parts[0], parts[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the provided login and password are valid.
|
|
||||||
*
|
|
||||||
* @param login The username to check.
|
|
||||||
* @param password The password to verify.
|
|
||||||
* @return True if the credentials are valid, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean checkAuth(String login, String password) {
|
|
||||||
// Retrieve the stored hashed password for the given username
|
|
||||||
String storedHash = users.get(login);
|
|
||||||
if (storedHash == null) return false;
|
|
||||||
|
|
||||||
// Hash the provided password and compare it to the stored hash
|
|
||||||
String hash = sha256(password);
|
|
||||||
return storedHash.equalsIgnoreCase(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes the SHA-256 hash of the given input string.
|
|
||||||
*
|
|
||||||
* @param input The input string to hash.
|
|
||||||
* @return The hexadecimal representation of the SHA-256 hash.
|
|
||||||
*/
|
|
||||||
public static String sha256(String input) {
|
|
||||||
try {
|
|
||||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
||||||
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
|
||||||
|
|
||||||
// Convert the byte array to a hexadecimal string
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (byte b : digest) sb.append(String.format("%02x", b));
|
|
||||||
return sb.toString();
|
|
||||||
} catch (Exception e) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.side.web.managers;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages access rules for web resources.
|
|
||||||
* Loads allow, deny, and auth rules from a JSON file and provides methods to check access.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
|
||||||
public final class RuleManager {
|
|
||||||
/**
|
|
||||||
* Lists of path patterns for allow, deny, and auth rules
|
|
||||||
*/
|
|
||||||
private static List<String> allow;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists of path patterns for allow, deny, and auth rules
|
|
||||||
*/
|
|
||||||
private static List<String> deny;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists of path patterns for allow, deny, and auth rules
|
|
||||||
*/
|
|
||||||
private static List<String> auth;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads rules from a JSON file.
|
|
||||||
* The JSON should have the structure:
|
|
||||||
* {
|
|
||||||
* "allow": ["pattern1", "pattern2", ...],
|
|
||||||
* "deny": ["pattern1", "pattern2", ...],
|
|
||||||
* "auth": ["pattern1", "pattern2", ...]
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @param rulesFile The JSON file containing the rules.
|
|
||||||
* @throws Exception If an error occurs reading the file or parsing JSON.
|
|
||||||
*/
|
|
||||||
public static void loadRules(File rulesFile) throws Exception {
|
|
||||||
// Load and parse the JSON file
|
|
||||||
String json = new String(Files.readAllBytes(rulesFile.toPath()));
|
|
||||||
Map<String, List<String>> map = new Gson().fromJson(json, new TypeToken<Map<String, List<String>>>() {
|
|
||||||
}.getType());
|
|
||||||
|
|
||||||
// Default to empty lists if keys are missing
|
|
||||||
allow = map.getOrDefault("allow", List.of());
|
|
||||||
deny = map.getOrDefault("deny", List.of());
|
|
||||||
auth = map.getOrDefault("auth", List.of());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given path is allowed based on the allow rules.
|
|
||||||
*
|
|
||||||
* @param path The path to check.
|
|
||||||
* @return True if the path is allowed, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean isAllowed(String path) {
|
|
||||||
return allow.stream().anyMatch(p -> pathMatches(path, p));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given path is denied based on the deny rules.
|
|
||||||
*
|
|
||||||
* @param path The path to check.
|
|
||||||
* @return True if the path is denied, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean isDenied(String path) {
|
|
||||||
return deny.stream().anyMatch(p -> pathMatches(path, p));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given path requires authentication based on the auth rules.
|
|
||||||
*
|
|
||||||
* @param path The path to check.
|
|
||||||
* @return True if the path requires authentication, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean requiresAuth(String path) {
|
|
||||||
return auth.stream().anyMatch(p -> pathMatches(path, p));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to check if a path matches a pattern.
|
|
||||||
* Patterns can include '*' as a wildcard.
|
|
||||||
*
|
|
||||||
* @param path The path to check.
|
|
||||||
* @param pattern The pattern to match against.
|
|
||||||
* @return True if the path matches the pattern, false otherwise.
|
|
||||||
*/
|
|
||||||
private static boolean pathMatches(String path, String pattern) {
|
|
||||||
pattern = pattern.replace("/", File.separator).replace("*", ".*");
|
|
||||||
return path.matches(pattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.side.web.managers;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|
||||||
import org.openautonomousconnection.protocol.side.web.ProtocolWebServer;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages user sessions for web clients.
|
|
||||||
* Provides methods to create, validate, and invalidate sessions.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
|
||||||
public final class SessionManager {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map of session IDs to Session objects.
|
|
||||||
*/
|
|
||||||
private static final Map<String, Session> sessions = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Secure random number generator for session ID creation.
|
|
||||||
*/
|
|
||||||
private static final SecureRandom secureRandom = new SecureRandom();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new session for the given user.
|
|
||||||
*
|
|
||||||
* @param login The username associated with the session.
|
|
||||||
* @param ip The IP address of the client.
|
|
||||||
* @param userAgent The User-Agent string of the client.
|
|
||||||
* @param protocolWebServer The Protocol WebServer for the unique Session
|
|
||||||
* @return The generated session ID.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
*/
|
|
||||||
public static String create(String login, String ip, String userAgent, ProtocolWebServer protocolWebServer) throws IOException {
|
|
||||||
// Generate a secure random session ID
|
|
||||||
byte[] bytes = new byte[32];
|
|
||||||
secureRandom.nextBytes(bytes);
|
|
||||||
|
|
||||||
// Encode the bytes to a URL-safe Base64 string
|
|
||||||
String sessionId = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes) + protocolWebServer.getUniqueSessionString();
|
|
||||||
|
|
||||||
// Create and store the new session
|
|
||||||
sessions.put(sessionId, new Session(login, ip, userAgent, protocolWebServer));
|
|
||||||
return sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates a session ID against the provided IP and User-Agent.
|
|
||||||
*
|
|
||||||
* @param sessionId The session ID to validate.
|
|
||||||
* @param ip The IP address of the client.
|
|
||||||
* @param userAgent The User-Agent string of the client.
|
|
||||||
* @param protocolWebServer The Protocol WebServer to get the config for refreshing
|
|
||||||
* @return True if the session is valid, false otherwise.
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
*/
|
|
||||||
public static boolean isValid(String sessionId, String ip, String userAgent, ProtocolWebServer protocolWebServer) throws IOException {
|
|
||||||
// Retrieve the session associated with the session ID
|
|
||||||
Session session = sessions.get(sessionId);
|
|
||||||
|
|
||||||
// Check if the session exists, is not expired, and matches the IP and User-Agent
|
|
||||||
if (session == null || session.isExpired() || !session.matches(ip, userAgent)) {
|
|
||||||
sessions.remove(sessionId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh the session expiration time
|
|
||||||
session.refresh(protocolWebServer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates a session, removing it from the active sessions.
|
|
||||||
*
|
|
||||||
* @param sessionId The session ID to invalidate.
|
|
||||||
*/
|
|
||||||
public static void invalidate(String sessionId) {
|
|
||||||
sessions.remove(sessionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the username associated with a valid session ID.
|
|
||||||
*
|
|
||||||
* @param sessionId The session ID to look up.
|
|
||||||
* @return The username if the session is valid, null otherwise.
|
|
||||||
*/
|
|
||||||
public static String getUser(String sessionId) {
|
|
||||||
// Retrieve the session associated with the session ID
|
|
||||||
Session session = sessions.get(sessionId);
|
|
||||||
|
|
||||||
// Check if the session exists and is not expired
|
|
||||||
if (session == null || session.isExpired()) {
|
|
||||||
sessions.remove(sessionId);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the username associated with the session
|
|
||||||
return session.getLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleans up expired sessions from the session map.
|
|
||||||
* This method should be called periodically to prevent memory leaks.
|
|
||||||
*/
|
|
||||||
public static void cleanupExpiredSessions() {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
sessions.entrySet().removeIf(entry -> entry.getValue().isExpired());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a user session with associated metadata.
|
|
||||||
*/
|
|
||||||
private static class Session {
|
|
||||||
@Getter
|
|
||||||
String login;
|
|
||||||
String ip;
|
|
||||||
String userAgent;
|
|
||||||
long expiresAt;
|
|
||||||
|
|
||||||
Session(String login, String ip, String userAgent, ProtocolWebServer protocolWebServer) throws IOException {
|
|
||||||
this.login = login;
|
|
||||||
this.ip = ip;
|
|
||||||
this.userAgent = userAgent;
|
|
||||||
this.expiresAt = System.currentTimeMillis() + (long) protocolWebServer.getConfigurationManager().getInt("sessionexpireminutes") * 60 * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the session has expired.
|
|
||||||
*
|
|
||||||
* @return True if the session is expired, false otherwise.
|
|
||||||
*/
|
|
||||||
boolean isExpired() {
|
|
||||||
return System.currentTimeMillis() > expiresAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the session matches the given IP and User-Agent.
|
|
||||||
*
|
|
||||||
* @param ip The IP address to check.
|
|
||||||
* @param userAgent The User-Agent string to check.
|
|
||||||
* @return True if both match, false otherwise.
|
|
||||||
*/
|
|
||||||
boolean matches(String ip, String userAgent) {
|
|
||||||
return this.ip.equals(ip) && this.userAgent.equals(userAgent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refreshes the session's expiration time.
|
|
||||||
*
|
|
||||||
* @param protocolWebServer The Protocol WebServer to get the Config setting
|
|
||||||
* @throws IOException If an I/O error occurs.
|
|
||||||
*/
|
|
||||||
void refresh(ProtocolWebServer protocolWebServer) throws IOException {
|
|
||||||
this.expiresAt = System.currentTimeMillis() + (long) protocolWebServer.getConfigurationManager().getInt("sessionexpireminutes") * 60 * 1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.utils;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class APIInformation extends DefaultMethodsOverrider implements Serializable {
|
||||||
|
public final String username;
|
||||||
|
public final String apiApplication;
|
||||||
|
public final String apiKey;
|
||||||
|
|
||||||
|
public APIInformation(String username, String apiApplication, String apiKey) {
|
||||||
|
this.username = username;
|
||||||
|
this.apiApplication = apiApplication;
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.utils;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class DomainUtils extends DefaultMethodsOverrider {
|
||||||
|
|
||||||
|
public static String getTopLevelDomain(String url) throws MalformedURLException {
|
||||||
|
URL uri = null;
|
||||||
|
String tldString = null;
|
||||||
|
|
||||||
|
if (url.startsWith(SiteType.PUBLIC.name + "://")) url = url.substring((SiteType.PUBLIC.name + "://").length());
|
||||||
|
if (url.startsWith(SiteType.CLIENT.name + "://")) url = url.substring((SiteType.CLIENT.name + "://").length());
|
||||||
|
if (url.startsWith(SiteType.SERVER.name + "://")) url = url.substring((SiteType.SERVER.name + "://").length());
|
||||||
|
if (url.startsWith(SiteType.PROTOCOL.name + "://")) url = url.substring((SiteType.PROTOCOL.name + "://").length());
|
||||||
|
if (url.startsWith(SiteType.LOCAL.name + "://")) url = url.substring((SiteType.LOCAL.name + "://").length());
|
||||||
|
|
||||||
|
if (!url.startsWith("https://") && !url.startsWith("http://")) url = "https://" + url;
|
||||||
|
|
||||||
|
uri = new URL(url);
|
||||||
|
String[] domainNameParts = uri.getHost().split("\\.");
|
||||||
|
tldString = domainNameParts[domainNameParts.length - 1];
|
||||||
|
|
||||||
|
return tldString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDomainName(String url) throws URISyntaxException, MalformedURLException {
|
||||||
|
if (url.startsWith(SiteType.PUBLIC.name + "://")) url = url.substring((SiteType.PUBLIC.name + "://").length());
|
||||||
|
if (url.startsWith(SiteType.CLIENT.name + "://")) url = url.substring((SiteType.CLIENT.name + "://").length());
|
||||||
|
if (url.startsWith(SiteType.SERVER.name + "://")) url = url.substring((SiteType.SERVER.name + "://").length());
|
||||||
|
if (url.startsWith(SiteType.PROTOCOL.name + "://")) url = url.substring((SiteType.PROTOCOL.name + "://").length());
|
||||||
|
if (url.startsWith(SiteType.LOCAL.name + "://")) url = url.substring((SiteType.LOCAL.name + "://").length());
|
||||||
|
|
||||||
|
if (!url.startsWith("https://") && !url.startsWith("http://")) url = "https://" + url;
|
||||||
|
|
||||||
|
URI uri = new URI(url);
|
||||||
|
String domain = uri.getHost().replace("." + getTopLevelDomain(url), "");
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String getPath(String url) {
|
||||||
|
if (!url.startsWith(SiteType.PUBLIC.name + "://") && !url.startsWith(SiteType.CLIENT.name + "://") &&
|
||||||
|
!url.startsWith(SiteType.SERVER.name + "://") && !url.startsWith(SiteType.PROTOCOL.name + "://") &&
|
||||||
|
!url.startsWith(SiteType.LOCAL.name + "://") && !url.startsWith("http") && !url.startsWith("https")) {
|
||||||
|
url = SiteType.PUBLIC.name + "://" + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] split = url.split("/");
|
||||||
|
if (split.length <= 3) return "";
|
||||||
|
|
||||||
|
StringBuilder path = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 3; i < split.length; i++) path.append(split[i]).append("/");
|
||||||
|
|
||||||
|
String pathStr = path.toString();
|
||||||
|
if (pathStr.startsWith("/")) pathStr = pathStr.substring("/".length());
|
||||||
|
if (pathStr.endsWith("/")) pathStr = pathStr.substring(0, pathStr.length() - "/".length());
|
||||||
|
|
||||||
|
return pathStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.utils;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public enum SiteType implements Serializable {
|
||||||
|
CLIENT("oac-client"), SERVER("oac-server"),
|
||||||
|
PUBLIC("oac"), PROTOCOL("oac-protocol"), LOCAL("oac-local");
|
||||||
|
;
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
SiteType(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.site;
|
/*
|
||||||
|
* Copyright (C) 2024 Open Autonomous Connection - All Rights Reserved
|
||||||
|
*
|
||||||
|
* You are unauthorized to remove this copyright.
|
||||||
|
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/Open-Autonomous-Connection
|
||||||
|
* See LICENSE-File if exists
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.utils;
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
||||||
|
|
||||||
/**
|
public class WebsitesContent extends DefaultMethodsOverrider {
|
||||||
* This class contains predefined HTML content for various website responses in the Classic protocol.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final class Classic_WebsitesContent extends DefaultMethodsOverrider {
|
|
||||||
|
|
||||||
public static final String DOMAIN_NOT_FOUND = """
|
public static final String DOMAIN_NOT_FOUND = """
|
||||||
<html>
|
<html>
|
||||||
@@ -17,7 +21,7 @@ public final class Classic_WebsitesContent extends DefaultMethodsOverrider {
|
|||||||
<meta content="Domain not found" name="description"/>
|
<meta content="Domain not found" name="description"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>404 - This infoName was not found</h1>
|
<h1>404 - This domain was not found</h1>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
""";
|
""";
|
||||||
@@ -49,7 +53,6 @@ public final class Classic_WebsitesContent extends DefaultMethodsOverrider {
|
|||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
""";
|
""";
|
||||||
public static String ERROR_OCCURRED = ERROR_OCCURRED("No specified details!");
|
|
||||||
|
|
||||||
public static String ERROR_OCCURRED(String errorDetails) {
|
public static String ERROR_OCCURRED(String errorDetails) {
|
||||||
return """
|
return """
|
||||||
@@ -61,11 +64,13 @@ public final class Classic_WebsitesContent extends DefaultMethodsOverrider {
|
|||||||
<meta content="Site not reached" name="description"/>
|
<meta content="Site not reached" name="description"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>500 - Error occured while resolving infoName!</h1>
|
<h1>500 - Error occured while resolving domain!</h1>
|
||||||
<h4>Details:</h2>
|
<h4>Details:</h2>
|
||||||
<h5>""" + errorDetails + "</h5>" + """
|
<h5>""" + errorDetails + "</h5>" + """
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String ERROR_OCCURRED = ERROR_OCCURRED("No specified details!");
|
||||||
}
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
1.0
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum representing different protocol versions, their types, sides, and compatibility.
|
|
||||||
*/
|
|
||||||
public enum ProtocolVersion implements Serializable {
|
|
||||||
/**
|
|
||||||
* Support for old OAC-Project => <a href="https://repo.open-autonomous-connection.org/Open-Autonomous-Connection/">*_old</a>
|
|
||||||
*/
|
|
||||||
PV_1_0_0_CLASSIC("1.0.0", ProtocolType.CLASSIC, ProtocolSide.WEB_INS, List.of(Protocol.HTTP)),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* First Beta Version of OAC-Protocol
|
|
||||||
*/
|
|
||||||
PV_1_0_0_BETA("1.0.0", ProtocolType.BETA, ProtocolSide.ALL, List.of(Protocol.OAC));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The version string of the protocol version.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final String version;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of the protocol version.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ProtocolType protocolType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The side(s) the protocol version is intended for.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ProtocolSide protocolSide;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of protocol versions that are compatible with this version.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final List<ProtocolVersion> compatibleVersions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of supported protocols.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final List<Protocol> supportedProtocols;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for ProtocolVersion enum.
|
|
||||||
*
|
|
||||||
* @param version The version string.
|
|
||||||
* @param protocolType The type of the protocol.
|
|
||||||
* @param protocolSide The side(s) the protocol is intended for.
|
|
||||||
* @param supportedProtocols List of supported protocols.
|
|
||||||
* @param compatibleVersions Varargs of compatible protocol versions.
|
|
||||||
*/
|
|
||||||
ProtocolVersion(String version, ProtocolType protocolType, ProtocolSide protocolSide, List<Protocol> supportedProtocols, ProtocolVersion... compatibleVersions) {
|
|
||||||
this.version = version;
|
|
||||||
this.protocolType = protocolType;
|
|
||||||
this.protocolSide = protocolSide;
|
|
||||||
this.compatibleVersions = new ArrayList<>(Arrays.stream(compatibleVersions).toList());
|
|
||||||
if (!this.compatibleVersions.contains(this)) this.compatibleVersions.add(this);
|
|
||||||
this.supportedProtocols = supportedProtocols;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of the protocol version, including its version, type, side, supported protocols, and compatible versions.
|
|
||||||
*
|
|
||||||
* @return a string representation of the protocol version.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
StringBuilder compatible = new StringBuilder("[");
|
|
||||||
StringBuilder supported = new StringBuilder("[");
|
|
||||||
|
|
||||||
for (ProtocolVersion compatibleVersion : compatibleVersions) compatible.append(compatibleVersion.buildName());
|
|
||||||
for (Protocol supportedProtocol : supportedProtocols) supported.append(supportedProtocol.toString());
|
|
||||||
|
|
||||||
compatible.append("]");
|
|
||||||
supported.append("]");
|
|
||||||
|
|
||||||
return "{version=" + version + ";type=" + protocolType.toString() + ";side=" + protocolSide.toString() + ";supportedProtocols=" + supported + ";compatibleVersions=" + compatible + "}";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a name for the protocol version combining its version and type.
|
|
||||||
*
|
|
||||||
* @return a string representing the name of the protocol version.
|
|
||||||
*/
|
|
||||||
public final String buildName() {
|
|
||||||
return version + "-" + protocolType.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum representing different protocols.
|
|
||||||
*/
|
|
||||||
public enum Protocol implements Serializable {
|
|
||||||
HTTP,
|
|
||||||
HTTPS,
|
|
||||||
OAC;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the protocol in uppercase.
|
|
||||||
*
|
|
||||||
* @return the name of the protocol in uppercase.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
return name().toUpperCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum representing different types of protocol versions.
|
|
||||||
*/
|
|
||||||
public enum ProtocolType implements Serializable {
|
|
||||||
/**
|
|
||||||
* Classic Protocol Type, see old OAC-Project: <a href="https://repo.open-autonomous-connection.org/Open-Autonomous-Connection/">*_old</a>
|
|
||||||
*/
|
|
||||||
CLASSIC,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Beta Protocol Type, may be unstable and subject to change.
|
|
||||||
*/
|
|
||||||
BETA,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stable Protocol Type, recommended for production use.
|
|
||||||
*/
|
|
||||||
STABLE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the protocol in uppercase.
|
|
||||||
*
|
|
||||||
* @return the name of the protocol in uppercase.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
return name().toUpperCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum representing different sides where the protocol version can be used.
|
|
||||||
*/
|
|
||||||
public enum ProtocolSide implements Serializable {
|
|
||||||
/**
|
|
||||||
* Client Side only
|
|
||||||
*/
|
|
||||||
CLIENT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* INS Server Side only
|
|
||||||
*/
|
|
||||||
INS,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Web Server Side only
|
|
||||||
*/
|
|
||||||
WEB,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Both INS and Web Server Side
|
|
||||||
*/
|
|
||||||
WEB_INS,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Both Client and INS Server Side
|
|
||||||
*/
|
|
||||||
CLIENT_INS,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Both Client and Web Server Side
|
|
||||||
*/
|
|
||||||
CLIENT_WEB,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All Sides
|
|
||||||
*/
|
|
||||||
ALL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the protocol in uppercase.
|
|
||||||
*
|
|
||||||
* @return the name of the protocol in uppercase.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
return name().toUpperCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.beta;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a INS record inside the INS system.
|
|
||||||
* <p>
|
|
||||||
* This is the transport format used in responses and packets.
|
|
||||||
* Each record contains:
|
|
||||||
* <ul>
|
|
||||||
* <li>The record type</li>
|
|
||||||
* <li>A value</li>
|
|
||||||
* <li>Optional priority and weight fields</li>
|
|
||||||
* <li>Optional port field (SRV)</li>
|
|
||||||
* <li>A TTL defining how long the record may be cached</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public final class INSRecord implements Serializable {
|
|
||||||
|
|
||||||
public INSRecordType type;
|
|
||||||
public String value;
|
|
||||||
public int priority;
|
|
||||||
public int weight;
|
|
||||||
public int port;
|
|
||||||
public int ttl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an INS record object.
|
|
||||||
*
|
|
||||||
* @param type The INS record type.
|
|
||||||
* @param value The record’s data (IPv4, IPv6, hostname, text, etc.).
|
|
||||||
* @param priority MX / SRV priority value (ignored for other types).
|
|
||||||
* @param weight SRV weight (ignored for other types).
|
|
||||||
* @param port SRV port (ignored for other types).
|
|
||||||
* @param ttl Time-to-live for caching.
|
|
||||||
*/
|
|
||||||
public INSRecord(INSRecordType type, String value, int priority, int weight, int port, int ttl) {
|
|
||||||
this.type = type;
|
|
||||||
this.value = value;
|
|
||||||
this.priority = priority;
|
|
||||||
this.weight = weight;
|
|
||||||
this.port = port;
|
|
||||||
this.ttl = ttl;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return type + ":" + value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.beta;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents INS record types for the INS protocol.
|
|
||||||
* <p>
|
|
||||||
* Supported types:
|
|
||||||
* <ul>
|
|
||||||
* <li>A — IPv4 address</li>
|
|
||||||
* <li>AAAA — IPv6 address</li>
|
|
||||||
* <li>CNAME — Canonical name redirect</li>
|
|
||||||
* <li>TXT — Arbitrary text</li>
|
|
||||||
* <li>MX — Mail exchanger</li>
|
|
||||||
* <li>SRV — Service locator</li>
|
|
||||||
* <li>NS — Nameserver delegation</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public enum INSRecordType {
|
|
||||||
A,
|
|
||||||
AAAA,
|
|
||||||
CNAME,
|
|
||||||
TXT,
|
|
||||||
MX,
|
|
||||||
SRV,
|
|
||||||
NS,
|
|
||||||
INFO,
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.beta;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the possible response states returned by the INS server.
|
|
||||||
*/
|
|
||||||
public enum INSResponseStatus {
|
|
||||||
/**
|
|
||||||
* Request succeeded and matching records were found.
|
|
||||||
*/
|
|
||||||
OK,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* No records exist for the queried TLN/name/sub/type combination.
|
|
||||||
*/
|
|
||||||
NOT_FOUND,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The query was malformed or missing required parameters.
|
|
||||||
*/
|
|
||||||
INVALID_REQUEST,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal server error occurred while resolving the request.
|
|
||||||
*/
|
|
||||||
SERVER_ERROR,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Response is not required for the specific request type.
|
|
||||||
*/
|
|
||||||
RESPONSE_NOT_REQUIRED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authentication failed.
|
|
||||||
*/
|
|
||||||
RESPONSE_AUTH_FAILED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authentication succeeded.
|
|
||||||
*/
|
|
||||||
RESPONSE_AUTH_SUCCESS
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.events;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerINSServer;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This event is fired when a classic domain packet is received.
|
|
||||||
* This event is deprecated and will be marked for removal in future versions.
|
|
||||||
*
|
|
||||||
* @see ClassicHandlerINSServer
|
|
||||||
* @see org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerClient
|
|
||||||
* @see org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerWebServer
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final class Classic_DomainPacketReceivedEvent extends Event {
|
|
||||||
|
|
||||||
public final Classic_ProtocolVersion protocolVersion;
|
|
||||||
public final Classic_Domain domain;
|
|
||||||
public final Classic_RequestDomain requestDomain;
|
|
||||||
public final int clientID;
|
|
||||||
|
|
||||||
public Classic_DomainPacketReceivedEvent(Classic_ProtocolVersion protocolVersion, Classic_Domain domain, Classic_RequestDomain requestDomain, int clientID) {
|
|
||||||
this.protocolVersion = protocolVersion;
|
|
||||||
this.domain = domain;
|
|
||||||
this.requestDomain = requestDomain;
|
|
||||||
this.clientID = clientID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object clone() throws CloneNotSupportedException {
|
|
||||||
return super.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return super.equals(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return super.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return super.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.events;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerINSServer;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This event is fired when a classic ping packet is received.
|
|
||||||
* This event is deprecated and will be marked for removal in future versions.
|
|
||||||
*
|
|
||||||
* @see ClassicHandlerINSServer
|
|
||||||
* @see org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerClient
|
|
||||||
* @see org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerWebServer
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final class Classic_PingPacketReceivedEvent extends Event {
|
|
||||||
public final Classic_ProtocolVersion protocolVersion;
|
|
||||||
public final Classic_Domain domain;
|
|
||||||
public final Classic_RequestDomain requestDomain;
|
|
||||||
public final boolean reachable;
|
|
||||||
public final int clientID;
|
|
||||||
|
|
||||||
public Classic_PingPacketReceivedEvent(Classic_ProtocolVersion protocolVersion, Classic_Domain domain, Classic_RequestDomain requestDomain, boolean reachable, int clientID) {
|
|
||||||
this.protocolVersion = protocolVersion;
|
|
||||||
this.domain = domain;
|
|
||||||
this.requestDomain = requestDomain;
|
|
||||||
this.reachable = reachable;
|
|
||||||
this.clientID = clientID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object clone() throws CloneNotSupportedException {
|
|
||||||
return super.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return super.equals(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return super.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return super.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.classic.Classic_MessagePacket;
|
|
||||||
import org.openautonomousconnection.protocol.side.client.ProtocolClient;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.site.Classic_SiteType;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract class defining the client-side handler for Classic protocol operations.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
|
|
||||||
public abstract class ClassicHandlerClient {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to the ProtocolClient
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final ProtocolClient client;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the client variable
|
|
||||||
*
|
|
||||||
* @param client The ProtocolClient Object
|
|
||||||
*/
|
|
||||||
public ClassicHandlerClient(ProtocolClient client) {
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void unsupportedClassicPacket(String classicPacketClassName, Object[] content);
|
|
||||||
|
|
||||||
public abstract void handleHTMLContent(Classic_SiteType siteType, Classic_Domain domain, String html);
|
|
||||||
|
|
||||||
public abstract void handleMessage(String message, Classic_ProtocolVersion protocolVersion);
|
|
||||||
|
|
||||||
public final void sendMessage(String message) throws IOException, ClassNotFoundException {
|
|
||||||
client.getClientINSConnection().sendPacket(new Classic_MessagePacket(message, 0, client.getProtocolBridge()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void validationCompleted(Classic_Domain domain, INSResponseStatus insResponseStatus);
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers;
|
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|
||||||
import org.openautonomousconnection.protocol.side.ins.ConnectedProtocolClient;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract class defining the INS server-side handler for Classic protocol operations.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.INS)
|
|
||||||
public abstract class ClassicHandlerINSServer {
|
|
||||||
public abstract void handleMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion);
|
|
||||||
|
|
||||||
public abstract Classic_Domain getDomain(Classic_RequestDomain requestDomain) throws SQLException;
|
|
||||||
|
|
||||||
public abstract Classic_Domain ping(Classic_RequestDomain requestDomain) throws SQLException;
|
|
||||||
|
|
||||||
public abstract void unsupportedClassicPacket(String className, Object[] content, ConnectedProtocolClient client);
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers;
|
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|
||||||
import org.openautonomousconnection.protocol.side.ins.ConnectedProtocolClient;
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract class defining the web server-side handler for Classic protocol operations.
|
|
||||||
*/
|
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
|
||||||
public abstract class ClassicHandlerWebServer {
|
|
||||||
public abstract void handleMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion);
|
|
||||||
|
|
||||||
public abstract void unsupportedClassicPacket(String className, Object[] content, ConnectedProtocolClient client);
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Classic_Domain is an old representation of a InfoName, maintained for backward compatibility.
|
|
||||||
* It encapsulates the InfoName's name, top-level name, path, and destination.
|
|
||||||
* This class is deprecated and users are encouraged to use the InfoName class instead.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public class Classic_Domain implements Serializable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the domain.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The top-level domain.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final String topLevelDomain;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The path component of the domain.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final String path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The destination of the domain, typically the full URL or address.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final String destination;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ProtocolBridge reference.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final ProtocolBridge protocolBridge;
|
|
||||||
|
|
||||||
public Classic_Domain(String name, String topLevelDomain, String destination, String path, ProtocolBridge bridge) {
|
|
||||||
this.protocolBridge = bridge;
|
|
||||||
this.name = name;
|
|
||||||
this.topLevelDomain = topLevelDomain;
|
|
||||||
this.destination = destination;
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final Object clone() throws CloneNotSupportedException {
|
|
||||||
return new Classic_Domain(name, topLevelDomain, destination, path, protocolBridge);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean equals(Object obj) {
|
|
||||||
if (!(obj instanceof Classic_Domain other)) return false;
|
|
||||||
return other.name.equalsIgnoreCase(name) && other.topLevelDomain.equalsIgnoreCase(topLevelDomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int hashCode() {
|
|
||||||
return super.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects;
|
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class representing a local domain in the Classic protocol.
|
|
||||||
* This class extends Classic_Domain and is used for local domain representation.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final class Classic_LocalDomain extends Classic_Domain {
|
|
||||||
public Classic_LocalDomain(String name, String endName, String path, ProtocolBridge protocolBridge) {
|
|
||||||
super(name, endName, null, path, protocolBridge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects;
|
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class representing a request for a domain in the Classic protocol.
|
|
||||||
* This class extends Classic_Domain and is used for requesting domain information.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final class Classic_RequestDomain extends Classic_Domain implements Serializable {
|
|
||||||
|
|
||||||
public Classic_RequestDomain(String name, String topLevelDomain, String path, ProtocolBridge protocolBridge) {
|
|
||||||
super(name, topLevelDomain, null, path, protocolBridge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.site;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum representing different types of sites in the Classic protocol.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public enum Classic_SiteType implements Serializable {
|
|
||||||
/**
|
|
||||||
* Client site type.
|
|
||||||
*/
|
|
||||||
CLIENT("oac-client"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Web server site type.
|
|
||||||
*/
|
|
||||||
SERVER("oac-server"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* INS server site type.
|
|
||||||
*/
|
|
||||||
PUBLIC("oac"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Protocol site type.
|
|
||||||
*/
|
|
||||||
PROTOCOL("oac-protocol"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local site type.
|
|
||||||
*/
|
|
||||||
LOCAL("oac-local");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the site type.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
Classic_SiteType(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.EventListener;
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.Listener;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.classic.Classic_PingPacket;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.events.Classic_DomainPacketReceivedEvent;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.events.Classic_PingPacketReceivedEvent;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_LocalDomain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.site.Classic_SiteType;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.site.Classic_WebsitesContent;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class listens for events related to Classic protocol operations on the client side.
|
|
||||||
* It handles domain resolution and ping responses, facilitating communication with the INS server
|
|
||||||
* and web content retrieval.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public final class Classic_ClientListener extends EventListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to the ProtocolBridge
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private ProtocolBridge protocolBridge;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set protocol bridge
|
|
||||||
*
|
|
||||||
* @param protocolBridge The ProtocolBridge object
|
|
||||||
*/
|
|
||||||
public void setProtocolBridge(ProtocolBridge protocolBridge) {
|
|
||||||
if (this.protocolBridge != null) return;
|
|
||||||
this.protocolBridge = protocolBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the event when a domain packet is received.
|
|
||||||
* It checks if the domain exists and sends a ping request to the INS server.
|
|
||||||
* If the domain does not exist, it handles the error accordingly.
|
|
||||||
*
|
|
||||||
* @param event The event containing domain information.
|
|
||||||
*/
|
|
||||||
@Listener
|
|
||||||
public void onDomain(Classic_DomainPacketReceivedEvent event) {
|
|
||||||
// Check if the domain exists
|
|
||||||
boolean exists = event.domain != null;
|
|
||||||
|
|
||||||
if (exists) {
|
|
||||||
try {
|
|
||||||
// Send a ping request to the INS server
|
|
||||||
if (!protocolBridge.getProtocolClient().getClientINSConnection().sendPacket(new Classic_PingPacket(event.requestDomain, event.domain, false, protocolBridge))) {
|
|
||||||
// If sending the packet fails, handle the error
|
|
||||||
protocolBridge.getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-occurred", "html", "", protocolBridge),
|
|
||||||
Classic_WebsitesContent.ERROR_OCCURRED(event.domain + "/" + event.domain.path));
|
|
||||||
}
|
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
|
||||||
// Handle any exceptions that occur during the process
|
|
||||||
protocolBridge.getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-occurred", "html", "", protocolBridge),
|
|
||||||
Classic_WebsitesContent.ERROR_OCCURRED(event.domain + "/" + event.domain.path + ":\n" + e.getMessage()));
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
// If the domain does not exist, handle the error
|
|
||||||
protocolBridge.getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("domain-not-found", "html", "", protocolBridge), Classic_WebsitesContent.DOMAIN_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the event when a ping packet is received.
|
|
||||||
* If the domain is reachable, it fetches the HTML content from the domain.
|
|
||||||
* If not reachable, it handles the error accordingly.
|
|
||||||
*
|
|
||||||
* @param event The event containing ping response information.
|
|
||||||
*/
|
|
||||||
@Listener
|
|
||||||
public void onPing(Classic_PingPacketReceivedEvent event) {
|
|
||||||
// If the domain is reachable, fetch the HTML content
|
|
||||||
if (event.reachable) {
|
|
||||||
String destination = event.domain.destination;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Create a URL object
|
|
||||||
URL url = new URL(destination);
|
|
||||||
HttpURLConnection connection2 = (HttpURLConnection) url.openConnection();
|
|
||||||
connection2.setRequestMethod("GET");
|
|
||||||
|
|
||||||
// Read the response
|
|
||||||
StringBuilder content = new StringBuilder();
|
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection2.getInputStream()))) {
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) content.append(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the HTML content
|
|
||||||
protocolBridge.getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PUBLIC, event.domain, content.toString());
|
|
||||||
} catch (IOException exception) {
|
|
||||||
// Handle any exceptions that occur during the process
|
|
||||||
protocolBridge.getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-occurred", "html", "", protocolBridge),
|
|
||||||
Classic_WebsitesContent.ERROR_OCCURRED(exception.getMessage().replace(event.domain.destination, event.domain + "/" + event.domain.path)));
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
// If the domain is not reachable, handle the error
|
|
||||||
protocolBridge.getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-not-reached", "html", "", protocolBridge), Classic_WebsitesContent.DOMAIN_NOT_REACHABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object clone() throws CloneNotSupportedException {
|
|
||||||
return super.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return super.equals(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return super.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return super.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils;
|
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.site.Classic_SiteType;
|
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class for domain-related operations in the Classic protocol.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
class Classic_DomainUtils extends DefaultMethodsOverrider {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the top-level domain (TLD) from a given URL.
|
|
||||||
*
|
|
||||||
* @param url The URL from which to extract the TLD.
|
|
||||||
* @return The top-level domain as a string.
|
|
||||||
* @throws MalformedURLException If the URL is malformed.
|
|
||||||
*/
|
|
||||||
public static String getTopLevelDomain(String url) throws MalformedURLException {
|
|
||||||
URL uri = null;
|
|
||||||
String tldString = null;
|
|
||||||
|
|
||||||
if (url.startsWith(Classic_SiteType.PUBLIC.name + "://"))
|
|
||||||
url = url.substring((Classic_SiteType.PUBLIC.name + "://").length());
|
|
||||||
if (url.startsWith(Classic_SiteType.CLIENT.name + "://"))
|
|
||||||
url = url.substring((Classic_SiteType.CLIENT.name + "://").length());
|
|
||||||
if (url.startsWith(Classic_SiteType.SERVER.name + "://"))
|
|
||||||
url = url.substring((Classic_SiteType.SERVER.name + "://").length());
|
|
||||||
if (url.startsWith(Classic_SiteType.PROTOCOL.name + "://"))
|
|
||||||
url = url.substring((Classic_SiteType.PROTOCOL.name + "://").length());
|
|
||||||
if (url.startsWith(Classic_SiteType.LOCAL.name + "://"))
|
|
||||||
url = url.substring((Classic_SiteType.LOCAL.name + "://").length());
|
|
||||||
|
|
||||||
if (!url.startsWith("https://") && !url.startsWith("http://")) url = "https://" + url;
|
|
||||||
|
|
||||||
uri = new URL(url);
|
|
||||||
String[] domainNameParts = uri.getHost().split("\\.");
|
|
||||||
tldString = domainNameParts[domainNameParts.length - 1];
|
|
||||||
|
|
||||||
return tldString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the domain name (excluding the TLD) from a given URL.
|
|
||||||
*
|
|
||||||
* @param url The URL from which to extract the domain name.
|
|
||||||
* @return The domain name as a string.
|
|
||||||
* @throws URISyntaxException If the URL syntax is incorrect.
|
|
||||||
* @throws MalformedURLException If the URL is malformed.
|
|
||||||
*/
|
|
||||||
public static String getDomainName(String url) throws URISyntaxException, MalformedURLException {
|
|
||||||
if (url.startsWith(Classic_SiteType.PUBLIC.name + "://"))
|
|
||||||
url = url.substring((Classic_SiteType.PUBLIC.name + "://").length());
|
|
||||||
if (url.startsWith(Classic_SiteType.CLIENT.name + "://"))
|
|
||||||
url = url.substring((Classic_SiteType.CLIENT.name + "://").length());
|
|
||||||
if (url.startsWith(Classic_SiteType.SERVER.name + "://"))
|
|
||||||
url = url.substring((Classic_SiteType.SERVER.name + "://").length());
|
|
||||||
if (url.startsWith(Classic_SiteType.PROTOCOL.name + "://"))
|
|
||||||
url = url.substring((Classic_SiteType.PROTOCOL.name + "://").length());
|
|
||||||
if (url.startsWith(Classic_SiteType.LOCAL.name + "://"))
|
|
||||||
url = url.substring((Classic_SiteType.LOCAL.name + "://").length());
|
|
||||||
|
|
||||||
if (!url.startsWith("https://") && !url.startsWith("http://")) url = "https://" + url;
|
|
||||||
|
|
||||||
URI uri = new URI(url);
|
|
||||||
return uri.getHost().replace("." + getTopLevelDomain(url), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the path component from a given URL.
|
|
||||||
*
|
|
||||||
* @param url The URL from which to extract the path.
|
|
||||||
* @return The path as a string.
|
|
||||||
*/
|
|
||||||
public static String getPath(String url) {
|
|
||||||
if (!url.startsWith(Classic_SiteType.PUBLIC.name + "://") && !url.startsWith(Classic_SiteType.CLIENT.name + "://") &&
|
|
||||||
!url.startsWith(Classic_SiteType.SERVER.name + "://") && !url.startsWith(Classic_SiteType.PROTOCOL.name + "://") &&
|
|
||||||
!url.startsWith(Classic_SiteType.LOCAL.name + "://") && !url.startsWith("http") && !url.startsWith("https")) {
|
|
||||||
url = Classic_SiteType.PUBLIC.name + "://" + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] split = url.split("/");
|
|
||||||
if (split.length <= 3) return "";
|
|
||||||
|
|
||||||
StringBuilder path = new StringBuilder();
|
|
||||||
|
|
||||||
for (int i = 3; i < split.length; i++) path.append(split[i]).append("/");
|
|
||||||
|
|
||||||
String pathStr = path.toString();
|
|
||||||
if (pathStr.startsWith("/")) pathStr = pathStr.substring("/".length());
|
|
||||||
if (pathStr.endsWith("/")) pathStr = pathStr.substring(0, pathStr.length() - "/".length());
|
|
||||||
|
|
||||||
return pathStr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum representing the protocol versions for the Classic protocol.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
|
||||||
public enum Classic_ProtocolVersion implements Serializable {
|
|
||||||
PV_1_0_0("1.0.0");
|
|
||||||
public final String version;
|
|
||||||
|
|
||||||
Classic_ProtocolVersion(String version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user