- Added comments
This commit is contained in:
@@ -32,7 +32,7 @@ This project (OAC) is licensed under the [Open Autonomous Public License (OAPL)]
|
|||||||
### Repository:
|
### Repository:
|
||||||
```
|
```
|
||||||
<repository>
|
<repository>
|
||||||
<id>repounlegitdqrk</id>
|
<id>oac</id>
|
||||||
<url>https://repo.open-autonomous-connection.org/api/packages/open-autonomous-connection/maven</url>
|
<url>https://repo.open-autonomous-connection.org/api/packages/open-autonomous-connection/maven</url>
|
||||||
<snapshots>
|
<snapshots>
|
||||||
<enabled>true</enabled>
|
<enabled>true</enabled>
|
||||||
|
2
pom.xml
2
pom.xml
@@ -87,7 +87,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>dev.unlegitdqrk</groupId>
|
<groupId>dev.unlegitdqrk</groupId>
|
||||||
<artifactId>unlegitlibrary</artifactId>
|
<artifactId>unlegitlibrary</artifactId>
|
||||||
<version>1.6.2</version>
|
<version>1.6.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
|
@@ -17,134 +17,168 @@ import org.openautonomousconnection.protocol.side.client.ProtocolClient;
|
|||||||
import org.openautonomousconnection.protocol.side.dns.ProtocolDNSServer;
|
import org.openautonomousconnection.protocol.side.dns.ProtocolDNSServer;
|
||||||
import org.openautonomousconnection.protocol.side.web.ProtocolWebServer;
|
import org.openautonomousconnection.protocol.side.web.ProtocolWebServer;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.ClassicHandlerClient;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerClient;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.ClassicHandlerDNSServer;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerDNSServer;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.ClassicHandlerWebServer;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerWebServer;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_ClientListener;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ClientListener;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main bridge class for the protocol connection.
|
||||||
|
* It manages the protocol settings, version, and side instances.
|
||||||
|
*/
|
||||||
public class ProtocolBridge {
|
public class ProtocolBridge {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singleton instance of the ProtocolBridge class
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private static ProtocolBridge instance;
|
private static ProtocolBridge instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The protocol settings for the current connection
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final ProtocolSettings protocolSettings;
|
private final ProtocolSettings protocolSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The protocol version for the current connection
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final ProtocolVersion protocolVersion;
|
private final ProtocolVersion protocolVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger instance for logging events and errors
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final Logger logger;
|
private Logger logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The protocol side instances
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private ProtocolDNSServer protocolDNSServer;
|
private ProtocolDNSServer protocolDNSServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The protocol side instances
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private ProtocolClient protocolClient;
|
private ProtocolClient protocolClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The protocol side instances
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private ProtocolWebServer protocolWebServer;
|
private ProtocolWebServer protocolWebServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The classic protocol handlers for dns server side
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private ClassicHandlerDNSServer classicHandlerDNSServer;
|
private ClassicHandlerDNSServer classicHandlerDNSServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The classic protocol handlers for web server side
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private ClassicHandlerWebServer classicHandlerWebServer;
|
private ClassicHandlerWebServer classicHandlerWebServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The classic protocol handlers for client side
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private ClassicHandlerClient classicHandlerClient;
|
private ClassicHandlerClient classicHandlerClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the ProtocolBridge instance for the DNS server side
|
||||||
|
* @param protocolDNSServer The ProtocolDNSServer 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.DNS)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
||||||
public ProtocolBridge(ProtocolDNSServer protocolDNSServer, ProtocolSettings protocolSettings, ProtocolVersion protocolVersion, File logFolder) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
|
public ProtocolBridge(ProtocolDNSServer protocolDNSServer, ProtocolSettings protocolSettings, ProtocolVersion protocolVersion, File logFolder) throws Exception {
|
||||||
|
// Assign the parameters to the class fields
|
||||||
this.protocolDNSServer = protocolDNSServer;
|
this.protocolDNSServer = protocolDNSServer;
|
||||||
this.protocolSettings = protocolSettings;
|
this.protocolSettings = protocolSettings;
|
||||||
this.protocolVersion = protocolVersion;
|
this.protocolVersion = protocolVersion;
|
||||||
|
|
||||||
Logger tmpLogger = null;
|
// Initialize the logger and protocol version
|
||||||
try {
|
initializeLogger(logFolder);
|
||||||
tmpLogger = new Logger(logFolder, false, true);
|
initializeProtocolVersion();
|
||||||
} catch (IOException | NoSuchFieldException | IllegalAccessException exception) {
|
|
||||||
exception.printStackTrace();
|
|
||||||
tmpLogger = null;
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger = tmpLogger;
|
// Register the appropriate listeners and packets
|
||||||
protocolSettings.eventManager.registerListener(new DNSServerListener());
|
registerListeners();
|
||||||
protocolSettings.eventManager.unregisterListener(new WebServerListener());
|
|
||||||
protocolSettings.eventManager.unregisterListener(new ClientListener());
|
|
||||||
|
|
||||||
if (!validateProtocolSide()) {
|
|
||||||
this.logger.error("Invalid protocol version '" + protocolVersion.toString() + "'!");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isClassicSupported()) protocolSettings.eventManager.unregisterListener(new Classic_ClientListener());
|
|
||||||
registerPackets();
|
registerPackets();
|
||||||
|
|
||||||
|
// Set the static instance to this instance
|
||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the ProtocolBridge instance for the web server side
|
||||||
|
* @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)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
||||||
public ProtocolBridge(ProtocolWebServer protocolWebServer, ProtocolSettings protocolSettings, ProtocolVersion protocolVersion, File logFolder) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
|
public ProtocolBridge(ProtocolWebServer protocolWebServer, ProtocolSettings protocolSettings, ProtocolVersion protocolVersion, File logFolder) throws Exception {
|
||||||
|
// Assign the parameters to the class fields
|
||||||
this.protocolWebServer = protocolWebServer;
|
this.protocolWebServer = protocolWebServer;
|
||||||
this.protocolSettings = protocolSettings;
|
this.protocolSettings = protocolSettings;
|
||||||
this.protocolVersion = protocolVersion;
|
this.protocolVersion = protocolVersion;
|
||||||
|
|
||||||
Logger tmpLogger = null;
|
// Initialize the logger and protocol version
|
||||||
try {
|
initializeLogger(logFolder);
|
||||||
tmpLogger = new Logger(logFolder, false, true);
|
initializeProtocolVersion();
|
||||||
} catch (IOException | NoSuchFieldException | IllegalAccessException exception) {
|
|
||||||
exception.printStackTrace();
|
|
||||||
tmpLogger = null;
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger = tmpLogger;
|
// Register the appropriate listeners and packets
|
||||||
protocolSettings.eventManager.unregisterListener(new DNSServerListener());
|
registerListeners();
|
||||||
protocolSettings.eventManager.registerListener(new WebServerListener());
|
|
||||||
protocolSettings.eventManager.unregisterListener(new ClientListener());
|
|
||||||
|
|
||||||
if (!validateProtocolSide()) {
|
|
||||||
this.logger.error("Invalid protocol version '" + protocolVersion.toString() + "'!");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isClassicSupported()) protocolSettings.eventManager.unregisterListener(new Classic_ClientListener());
|
|
||||||
registerPackets();
|
registerPackets();
|
||||||
|
|
||||||
|
// Set the static instance to this instance
|
||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the ProtocolBridge instance for the client side
|
||||||
|
* @param protocolClient The ProtocolClient 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.CLIENT)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
|
||||||
public ProtocolBridge(ProtocolClient protocolClient, ProtocolSettings protocolSettings, ProtocolVersion protocolVersion, File logFolder) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
|
public ProtocolBridge(ProtocolClient protocolClient, ProtocolSettings protocolSettings, ProtocolVersion protocolVersion, File logFolder) throws Exception {
|
||||||
|
// Assign the parameters to the class fields
|
||||||
this.protocolClient = protocolClient;
|
this.protocolClient = protocolClient;
|
||||||
this.protocolSettings = protocolSettings;
|
this.protocolSettings = protocolSettings;
|
||||||
this.protocolVersion = protocolVersion;
|
this.protocolVersion = protocolVersion;
|
||||||
|
|
||||||
Logger tmpLogger = null;
|
// Initialize the logger and protocol version
|
||||||
try {
|
initializeLogger(logFolder);
|
||||||
tmpLogger = new Logger(logFolder, false, true);
|
initializeProtocolVersion();
|
||||||
} catch (IOException | NoSuchFieldException | IllegalAccessException exception) {
|
|
||||||
exception.printStackTrace();
|
|
||||||
tmpLogger = null;
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger = tmpLogger;
|
// Register the appropriate listeners and packets
|
||||||
protocolSettings.eventManager.registerListener(new ClientListener());
|
registerListeners();
|
||||||
protocolSettings.eventManager.unregisterListener(new WebServerListener());
|
|
||||||
protocolSettings.eventManager.unregisterListener(new DNSServerListener());
|
|
||||||
|
|
||||||
if (!validateProtocolSide()) {
|
|
||||||
this.logger.error("Invalid protocol version '" + protocolVersion.toString() + "'!");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isClassicSupported()) protocolSettings.eventManager.registerListener(new Classic_ClientListener());
|
|
||||||
registerPackets();
|
registerPackets();
|
||||||
|
|
||||||
|
// Set the static instance to this instance
|
||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the appropriate packets based on the current protocol version
|
||||||
|
*/
|
||||||
private void registerPackets() {
|
private void registerPackets() {
|
||||||
// Classic packets
|
// Classic packets
|
||||||
Classic_DomainPacket cDomainPacket = new Classic_DomainPacket();
|
Classic_DomainPacket cDomainPacket = new Classic_DomainPacket();
|
||||||
@@ -162,50 +196,132 @@ public class ProtocolBridge {
|
|||||||
GetDestinationPacket v100bGetDestinationPacket = new GetDestinationPacket();
|
GetDestinationPacket v100bGetDestinationPacket = new GetDestinationPacket();
|
||||||
|
|
||||||
if (isPacketSupported(v100bAuthPath)) protocolSettings.packetHandler.registerPacket(v100bAuthPath);
|
if (isPacketSupported(v100bAuthPath)) protocolSettings.packetHandler.registerPacket(v100bAuthPath);
|
||||||
if (isPacketSupported(v100bUnsupportedClassicPacket))
|
if (isPacketSupported(v100bUnsupportedClassicPacket)) protocolSettings.packetHandler.registerPacket(v100bUnsupportedClassicPacket);
|
||||||
protocolSettings.packetHandler.registerPacket(v100bUnsupportedClassicPacket);
|
if (isPacketSupported(v100bValidateDomainPacket)) protocolSettings.packetHandler.registerPacket(v100bValidateDomainPacket);
|
||||||
if (isPacketSupported(v100bValidateDomainPacket))
|
if (isPacketSupported(v100bGetDestinationPacket)) protocolSettings.packetHandler.registerPacket(v100bGetDestinationPacket);
|
||||||
protocolSettings.packetHandler.registerPacket(v100bValidateDomainPacket);
|
|
||||||
if (isPacketSupported(v100bGetDestinationPacket))
|
|
||||||
protocolSettings.packetHandler.registerPacket(v100bGetDestinationPacket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isPacketSupported(OACPacket packet) {
|
/**
|
||||||
return isVersionSupported(packet.getProtocolVersion());
|
* 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()) protocolSettings.eventManager.registerListener(Classic_ClientListener.class);
|
||||||
|
else protocolSettings.eventManager.unregisterListener(Classic_ClientListener.class);
|
||||||
|
|
||||||
|
// DNS Listeners
|
||||||
|
if (isRunningAsDNSServer()) {
|
||||||
|
protocolSettings.eventManager.registerListener(DNSServerListener.class);
|
||||||
|
protocolSettings.eventManager.unregisterListener(WebServerListener.class);
|
||||||
|
protocolSettings.eventManager.unregisterListener(ClientListener.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Web Listeners
|
||||||
|
if (isRunningAsWebServer()) {
|
||||||
|
protocolSettings.eventManager.registerListener(WebServerListener.class);
|
||||||
|
protocolSettings.eventManager.unregisterListener(DNSServerListener.class);
|
||||||
|
protocolSettings.eventManager.unregisterListener(ClientListener.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client Listeners
|
||||||
|
if (isRunningAsClient()) {
|
||||||
|
protocolSettings.eventManager.registerListener(ClientListener.class);
|
||||||
|
protocolSettings.eventManager.unregisterListener(DNSServerListener.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 {
|
||||||
|
// Initialize temporary logger
|
||||||
|
tmpLogger = new Logger(logFolder, false, true);
|
||||||
|
} catch (IOException | NoSuchFieldException | IllegalAccessException exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign the temporary logger to the final field
|
||||||
|
this.logger = tmpLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the protocol version
|
||||||
|
* Validate if the protocol version is valid for the current side
|
||||||
|
* If not, log an error and exit the application
|
||||||
|
*/
|
||||||
|
private void initializeProtocolVersion() {
|
||||||
|
// Check if the protocol version is valid for the current side
|
||||||
|
// If not, log an error and exit the application
|
||||||
|
if (!validateProtocolSide()) {
|
||||||
|
this.logger.error("Invalid protocol version '" + protocolVersion.toString() + "'!");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the classic protocol is supported by the current protocol version
|
||||||
|
* @return true if the classic protocol is supported, false otherwise
|
||||||
|
*/
|
||||||
public final boolean isClassicSupported() {
|
public final boolean isClassicSupported() {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : protocolVersion.getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : protocolVersion.getCompatibleVersions()) {
|
||||||
|
// Check if the compatible version is classic
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
||||||
if (yes) break;
|
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;
|
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 final boolean isProtocolSupported(ProtocolVersion.Protocol protocol) {
|
public final boolean isProtocolSupported(ProtocolVersion.Protocol protocol) {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : protocolVersion.getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : protocolVersion.getCompatibleVersions()) {
|
||||||
|
// Check if the compatible version supports the target protocol
|
||||||
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
|
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
|
||||||
if (yes) break;
|
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;
|
return protocolVersion.getSupportedProtocols().contains(protocol) || yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isRunningAsDNSServer() {
|
/**
|
||||||
return protocolDNSServer != null;
|
* 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 final boolean isPacketSupported(OACPacket packet) {
|
||||||
|
return isVersionSupported(packet.getProtocolVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isRunningAsClient() {
|
/**
|
||||||
return protocolClient != null;
|
* 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 final boolean isRunningAsWebServer() {
|
*/
|
||||||
return protocolWebServer != null;
|
public final 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() {
|
private boolean validateProtocolSide() {
|
||||||
return
|
return
|
||||||
(isRunningAsClient() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT) ||
|
(isRunningAsClient() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT) ||
|
||||||
@@ -224,7 +340,27 @@ public class ProtocolBridge {
|
|||||||
(isRunningAsDNSServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.ALL);
|
(isRunningAsDNSServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isVersionSupported(ProtocolVersion targetVersion) {
|
/**
|
||||||
return protocolVersion == targetVersion || protocolVersion.getCompatibleVersions().contains(targetVersion);
|
* Check if the current instance is running as a DNS server
|
||||||
|
* @return true if the current instance is running as a DNS server, false otherwise
|
||||||
|
*/
|
||||||
|
public final boolean isRunningAsDNSServer() {
|
||||||
|
return protocolDNSServer != 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 final 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 final boolean isRunningAsWebServer() {
|
||||||
|
return protocolWebServer != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,11 +4,29 @@ 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings for the protocol connection.
|
||||||
|
*/
|
||||||
public class ProtocolSettings extends DefaultMethodsOverrider {
|
public class ProtocolSettings extends DefaultMethodsOverrider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The host to connect to.
|
||||||
|
*/
|
||||||
public String host;
|
public String host;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The port to connect to.
|
||||||
|
*/
|
||||||
public int port;
|
public int port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The protocol version to use.
|
||||||
|
*/
|
||||||
public PacketHandler packetHandler;
|
public PacketHandler packetHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event manager to use.
|
||||||
|
*/
|
||||||
public EventManager eventManager;
|
public EventManager eventManager;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,16 @@ package org.openautonomousconnection.protocol.annotations;
|
|||||||
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation to provide metadata about protocol handlers or classes.
|
||||||
|
*/
|
||||||
public @interface ProtocolInfo {
|
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;
|
ProtocolVersion.ProtocolSide protocolSide() default ProtocolVersion.ProtocolSide.ALL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
package org.openautonomousconnection.protocol.exceptions;
|
package org.openautonomousconnection.protocol.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when an unsupported protocol is encountered.
|
||||||
|
*/
|
||||||
public class UnsupportedProtocolException extends RuntimeException {
|
public class UnsupportedProtocolException extends RuntimeException {
|
||||||
|
|
||||||
public UnsupportedProtocolException() {
|
public UnsupportedProtocolException() {
|
||||||
|
@@ -11,19 +11,32 @@ import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for client-side events such as connection and disconnection.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
|
||||||
public class ClientListener extends EventListener {
|
public class ClientListener extends EventListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 onConnect(ClientConnectedEvent event) {
|
||||||
try {
|
try {
|
||||||
event.client.sendPacket(new AuthPacket());
|
event.getClient().sendPacket(new AuthPacket());
|
||||||
} catch (IOException | ClassNotFoundException exception) {
|
} catch (IOException | ClassNotFoundException exception) {
|
||||||
ProtocolBridge.getInstance().getLogger().exception("Failed to send auth packet", exception);
|
ProtocolBridge.getInstance().getLogger().exception("Failed to send auth packet", exception);
|
||||||
event.client.disconnect();
|
event.getClient().disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 onDisconnect(ClientDisconnectedEvent event) {
|
||||||
ProtocolBridge.getInstance().getProtocolClient().onDNSDisconnect(event);
|
ProtocolBridge.getInstance().getProtocolClient().onDNSDisconnect(event);
|
||||||
|
@@ -9,17 +9,31 @@ import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|||||||
import org.openautonomousconnection.protocol.side.dns.ConnectedProtocolClient;
|
import org.openautonomousconnection.protocol.side.dns.ConnectedProtocolClient;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for DNS server connection events.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
||||||
public class DNSServerListener extends EventListener {
|
public class DNSServerListener extends EventListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the event when a connection handler connects to the DNS server.
|
||||||
|
* Adds the connected client to the ProtocolBridge's DNS server client list.
|
||||||
|
* @param event The connection handler connected event.
|
||||||
|
*/
|
||||||
@Listener
|
@Listener
|
||||||
public void onConnect(ConnectionHandlerConnectedEvent event) {
|
public void onConnect(ConnectionHandlerConnectedEvent event) {
|
||||||
ProtocolBridge.getInstance().getProtocolDNSServer().getClients().add(new ConnectedProtocolClient(event.connectionHandler));
|
ProtocolBridge.getInstance().getProtocolDNSServer().getClients().add(new ConnectedProtocolClient(event.getConnectionHandler()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the event when a connection handler disconnects from the DNS server.
|
||||||
|
* Removes the disconnected client from the ProtocolBridge's DNS server client list.
|
||||||
|
* @param event The connection handler disconnected event.
|
||||||
|
*/
|
||||||
@Listener
|
@Listener
|
||||||
public void onDisconnect(ConnectionHandlerDisconnectedEvent event) {
|
public void onDisconnect(ConnectionHandlerDisconnectedEvent event) {
|
||||||
ProtocolBridge.getInstance().getProtocolDNSServer().getClients().removeIf(client -> client.getConnectionHandler().getClientID() == -1);
|
ProtocolBridge.getInstance().getProtocolDNSServer().getClients().removeIf(client ->
|
||||||
|
client.getConnectionHandler().getClientID() == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -9,14 +9,27 @@ import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|||||||
import org.openautonomousconnection.protocol.side.web.ConnectedWebClient;
|
import org.openautonomousconnection.protocol.side.web.ConnectedWebClient;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for web server connection events.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
||||||
public class WebServerListener extends EventListener {
|
public class WebServerListener extends EventListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
@Listener
|
||||||
public void onConnect(ConnectionHandlerConnectedEvent event) {
|
public void onConnect(ConnectionHandlerConnectedEvent event) {
|
||||||
ProtocolBridge.getInstance().getProtocolWebServer().getClients().add(new ConnectedWebClient(event.connectionHandler));
|
ProtocolBridge.getInstance().getProtocolWebServer().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
|
@Listener
|
||||||
public void onDisconnect(ConnectionHandlerDisconnectedEvent event) {
|
public void onDisconnect(ConnectionHandlerDisconnectedEvent event) {
|
||||||
ProtocolBridge.getInstance().getProtocolWebServer().getClients().removeIf(client -> client.getPipelineConnection().getClientID() == -1);
|
ProtocolBridge.getInstance().getProtocolWebServer().getClients().removeIf(client -> client.getPipelineConnection().getClientID() == -1);
|
||||||
|
@@ -10,45 +10,101 @@ import java.io.IOException;
|
|||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
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 {
|
public abstract class OACPacket extends Packet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The protocol version associated with this packet.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final ProtocolVersion protocolVersion;
|
private final ProtocolVersion protocolVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The response code for the packet, defaulting to RESPONSE_NOT_REQUIRED.
|
||||||
|
*/
|
||||||
private DNSResponseCode responseCode = DNSResponseCode.RESPONSE_NOT_REQUIRED;
|
private DNSResponseCode responseCode = DNSResponseCode.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) {
|
public OACPacket(int id, ProtocolVersion protocolVersion) {
|
||||||
super(id);
|
super(id);
|
||||||
this.protocolVersion = protocolVersion;
|
this.protocolVersion = protocolVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the response code for the packet.
|
||||||
|
* @return The DNSResponseCode associated with the packet.
|
||||||
|
*/
|
||||||
protected final DNSResponseCode getResponseCode() {
|
protected final DNSResponseCode getResponseCode() {
|
||||||
return responseCode;
|
return responseCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the response code for the packet.
|
||||||
|
* @param responseCode The DNSResponseCode to set for the packet.
|
||||||
|
*/
|
||||||
protected final void setResponseCode(DNSResponseCode responseCode) {
|
protected final void setResponseCode(DNSResponseCode responseCode) {
|
||||||
this.responseCode = 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
|
@Override
|
||||||
public final void write(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
public final void write(PacketHandler packetHandler, ObjectOutputStream objectOutputStream) throws IOException, ClassNotFoundException {
|
||||||
|
// Write the specific packet data
|
||||||
onWrite(packetHandler, objectOutputStream);
|
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);
|
if (protocolVersion != ProtocolVersion.PV_1_0_0_CLASSIC) objectOutputStream.writeObject(responseCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void read(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
public final void read(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
||||||
|
// Read the specific packet data
|
||||||
onRead(packetHandler, objectInputStream);
|
onRead(packetHandler, objectInputStream);
|
||||||
if (protocolVersion != ProtocolVersion.PV_1_0_0_CLASSIC) {
|
|
||||||
responseCode = (DNSResponseCode) objectInputStream.readObject();
|
// Read the response code if the protocol version is not classic
|
||||||
onResponseCodeRead(packetHandler, objectInputStream);
|
if (protocolVersion != ProtocolVersion.PV_1_0_0_CLASSIC) responseCode = (DNSResponseCode) objectInputStream.readObject();
|
||||||
}
|
else responseCode = DNSResponseCode.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;
|
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;
|
public abstract void onRead(PacketHandler packetHandler, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException;
|
||||||
|
|
||||||
protected void onResponseCodeRead(PacketHandler packetHandler, ObjectInputStream objectInputStream) {
|
/**
|
||||||
}
|
* 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) {}
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,7 @@ import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
|||||||
import dev.unlegitdqrk.unlegitlibrary.network.utils.NetworkUtils;
|
import dev.unlegitdqrk.unlegitlibrary.network.utils.NetworkUtils;
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
import org.openautonomousconnection.protocol.packets.OACPacket;
|
||||||
import org.openautonomousconnection.protocol.side.client.events.ConnectedToProtocolServer;
|
import org.openautonomousconnection.protocol.side.client.events.ConnectedToProtocolDNSServerEvent;
|
||||||
import org.openautonomousconnection.protocol.side.dns.ConnectedProtocolClient;
|
import org.openautonomousconnection.protocol.side.dns.ConnectedProtocolClient;
|
||||||
import org.openautonomousconnection.protocol.side.dns.events.ConnectedProtocolClientEvent;
|
import org.openautonomousconnection.protocol.side.dns.events.ConnectedProtocolClientEvent;
|
||||||
import org.openautonomousconnection.protocol.side.web.ConnectedWebClient;
|
import org.openautonomousconnection.protocol.side.web.ConnectedWebClient;
|
||||||
@@ -130,7 +130,7 @@ public class AuthPacket extends OACPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProtocolBridge.getInstance().getProtocolClient().setServerVersion(serverVersion);
|
ProtocolBridge.getInstance().getProtocolClient().setServerVersion(serverVersion);
|
||||||
ProtocolBridge.getInstance().getProtocolSettings().eventManager.executeEvent(new ConnectedToProtocolServer());
|
ProtocolBridge.getInstance().getProtocolSettings().eventManager.executeEvent(new ConnectedToProtocolDNSServerEvent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,10 +5,10 @@ import org.openautonomousconnection.protocol.ProtocolBridge;
|
|||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
import org.openautonomousconnection.protocol.packets.OACPacket;
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.UnsupportedClassicPacket;
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.UnsupportedClassicPacket;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_Domain;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_DomainPacketReceivedEvent;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.events.Classic_DomainPacketReceivedEvent;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_RequestDomain;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
|
@@ -4,7 +4,7 @@ import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
|||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
import org.openautonomousconnection.protocol.packets.OACPacket;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
|
@@ -6,10 +6,10 @@ import org.openautonomousconnection.protocol.packets.OACPacket;
|
|||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.UnsupportedClassicPacket;
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.UnsupportedClassicPacket;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.DNSResponseCode;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.DNSResponseCode;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_Domain;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_PingPacketReceivedEvent;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.events.Classic_PingPacketReceivedEvent;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_RequestDomain;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
|
@@ -16,24 +16,50 @@ import org.openautonomousconnection.protocol.packets.v1_0_0.classic.Classic_Ping
|
|||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.DNSResponseCode;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.DNSResponseCode;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.Domain;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.Domain;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.Classic_RequestDomain;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class defining the client-side protocol operations and interactions with DNS and web servers.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
||||||
public abstract class ProtocolClient extends DefaultMethodsOverrider {
|
public abstract class ProtocolClient extends DefaultMethodsOverrider {
|
||||||
private final NetworkClient clientToDNS; // Handles everything with DNS-Connection
|
/**
|
||||||
|
* Handles everything with DNS-Connection.
|
||||||
|
*/
|
||||||
|
private final NetworkClient clientToDNS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the folder structure for client certificates.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final ClientCertificateFolderStructure folderStructure;
|
private final ClientCertificateFolderStructure folderStructure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the web connection to the destination server.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
private WebClient webClient;
|
private WebClient webClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the protocol version of the connected server.
|
||||||
|
*/
|
||||||
private ProtocolVersion serverVersion = null;
|
private ProtocolVersion serverVersion = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the ProtocolClient, setting up certificate folders and the DNS client connection.
|
||||||
|
* @throws CertificateException if there are issues with the certificates.
|
||||||
|
* @throws IOException if there are I/O issues during initialization.
|
||||||
|
*/
|
||||||
public ProtocolClient() throws CertificateException, IOException {
|
public ProtocolClient() throws CertificateException, IOException {
|
||||||
|
// Initialize and verify certificate folders and files
|
||||||
folderStructure = new ClientCertificateFolderStructure();
|
folderStructure = new ClientCertificateFolderStructure();
|
||||||
|
|
||||||
|
// Initialize connection to DNS server
|
||||||
clientToDNS = new NetworkClient.ClientBuilder().setLogger(ProtocolBridge.getInstance().getLogger()).
|
clientToDNS = new NetworkClient.ClientBuilder().setLogger(ProtocolBridge.getInstance().getLogger()).
|
||||||
setHost(ProtocolBridge.getInstance().getProtocolSettings().host).setPort(ProtocolBridge.getInstance().getProtocolSettings().port).
|
setHost(ProtocolBridge.getInstance().getProtocolSettings().host).setPort(ProtocolBridge.getInstance().getProtocolSettings().port).
|
||||||
setPacketHandler(ProtocolBridge.getInstance().getProtocolSettings().packetHandler).setEventManager(ProtocolBridge.getInstance().getProtocolSettings().eventManager).
|
setPacketHandler(ProtocolBridge.getInstance().getProtocolSettings().packetHandler).setEventManager(ProtocolBridge.getInstance().getProtocolSettings().eventManager).
|
||||||
@@ -41,52 +67,98 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
|
|||||||
build();
|
build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the DNS connection client.
|
||||||
|
* @return the NetworkClient handling the DNS connection.
|
||||||
|
*/
|
||||||
public final NetworkClient getClientDNSConnection() {
|
public final NetworkClient getClientDNSConnection() {
|
||||||
return clientToDNS;
|
return clientToDNS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a web connection to the specified domain and ports.
|
||||||
|
* @param domain the target domain for the web connection.
|
||||||
|
* @param pipelinePort the port used for the pipeline connection.
|
||||||
|
* @param webPort the port used for the web connection.
|
||||||
|
* @throws Exception if there are issues creating the web connection or if the protocol is unsupported.
|
||||||
|
*/
|
||||||
public final void createWebConnection(Domain domain, int pipelinePort, int webPort) throws Exception {
|
public final void createWebConnection(Domain domain, int pipelinePort, int webPort) throws Exception {
|
||||||
|
// Ensure the protocol supports web connections
|
||||||
if (!ProtocolBridge.getInstance().isProtocolSupported(ProtocolVersion.Protocol.OAC))
|
if (!ProtocolBridge.getInstance().isProtocolSupported(ProtocolVersion.Protocol.OAC))
|
||||||
throw new UnsupportedProtocolException();
|
throw new UnsupportedProtocolException();
|
||||||
|
|
||||||
|
// Check if web client is already connected and close it
|
||||||
if (webClient != null) {
|
if (webClient != null) {
|
||||||
try {
|
try {
|
||||||
webClient.closeConnection();
|
webClient.closeConnection();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
ProtocolBridge.getInstance().getLogger().exception("Failed to close connection to web server", e);
|
ProtocolBridge.getInstance().getLogger().exception("Failed to close connection to web server", e);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify necessary certificate files exist
|
||||||
webClient = new WebClient(domain, pipelinePort, webPort);
|
webClient = new WebClient(domain, pipelinePort, webPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
private final void checkFileExists(File folder, String prefix, String extension) throws CertificateException, IOException {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
|
// Check if folder exists
|
||||||
if (folder == null) throw new FileNotFoundException("Folder does not exist");
|
if (folder == null) throw new FileNotFoundException("Folder does not exist");
|
||||||
|
|
||||||
|
// List files in the folder
|
||||||
File[] files = folder.listFiles();
|
File[] files = folder.listFiles();
|
||||||
|
|
||||||
|
// Check if folder is empty
|
||||||
if (files == null || files.length == 0)
|
if (files == null || files.length == 0)
|
||||||
throw new FileNotFoundException("Folder " + folder.getAbsolutePath() + " is empty");
|
throw new FileNotFoundException("Folder " + folder.getAbsolutePath() + " is empty");
|
||||||
|
|
||||||
|
// Validate each file in the folder
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
if (!file.getName().startsWith(prefix) || !file.getName().endsWith(extension))
|
if (!file.getName().startsWith(prefix) || !file.getName().endsWith(extension))
|
||||||
throw new CertificateException(file.getAbsolutePath() + " is not valid");
|
throw new CertificateException(file.getAbsolutePath() + " is not valid");
|
||||||
|
|
||||||
|
// Check for specific files
|
||||||
if (!found) found = file.getName().equalsIgnoreCase(prefix + NetworkUtils.getPublicIPAddress() + extension);
|
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);
|
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() {
|
public final ProtocolVersion getServerVersion() {
|
||||||
return serverVersion == null ? ProtocolVersion.PV_1_0_0_CLASSIC : serverVersion;
|
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) {
|
public final void setServerVersion(ProtocolVersion serverVersion) {
|
||||||
if (serverVersion == null) this.serverVersion = serverVersion;
|
if (serverVersion == null) this.serverVersion = serverVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles DNS disconnection events, resetting the server version and closing the web client connection if necessary.
|
||||||
|
* @param event the ClientDisconnectedEvent triggered on DNS disconnection.
|
||||||
|
*/
|
||||||
public final void onDNSDisconnect(ClientDisconnectedEvent event) {
|
public final void onDNSDisconnect(ClientDisconnectedEvent event) {
|
||||||
|
// Reset server version on DNS disconnect
|
||||||
serverVersion = null;
|
serverVersion = null;
|
||||||
|
|
||||||
|
// Close web client connection if it exists
|
||||||
if (webClient != null) {
|
if (webClient != null) {
|
||||||
try {
|
try {
|
||||||
webClient.closeConnection();
|
webClient.closeConnection();
|
||||||
@@ -96,82 +168,167 @@ public abstract class ProtocolClient extends DefaultMethodsOverrider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the connected server is a stable server.
|
||||||
|
* @return true if the server is stable, false otherwise.
|
||||||
|
*/
|
||||||
public final boolean isStableServer() {
|
public final boolean isStableServer() {
|
||||||
|
// Check if the server version is stable
|
||||||
return !isBetaServer() && !isClassicServer();
|
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() {
|
public final boolean supportServerStable() {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version is stable
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the server version is stable
|
||||||
return isStableServer() || yes;
|
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() {
|
public final boolean isBetaServer() {
|
||||||
|
// Check if the server version is beta
|
||||||
return getServerVersion().getProtocolType() == ProtocolVersion.ProtocolType.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() {
|
public final boolean supportServerBeta() {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version is beta
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the server version is beta
|
||||||
return isBetaServer() || yes;
|
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() {
|
public final boolean isClassicServer() {
|
||||||
|
// Check if the server version is classic
|
||||||
return getServerVersion().getProtocolType() == ProtocolVersion.ProtocolType.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() {
|
public final boolean supportServerClassic() {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version is classic
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the server version is classic
|
||||||
return isClassicServer() || yes;
|
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) {
|
public final boolean supportServerPacket(OACPacket packet) {
|
||||||
|
// Check if the server supports the protocol version of the packet
|
||||||
return supportServerVersion(packet.getProtocolVersion());
|
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) {
|
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);
|
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) {
|
public final boolean supportServerProtocol(ProtocolVersion.Protocol protocol) {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getServerVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version supports the protocol
|
||||||
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
|
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the server version supports the protocol
|
||||||
return getServerVersion().getSupportedProtocols().contains(protocol) || yes;
|
return getServerVersion().getSupportedProtocols().contains(protocol) || yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the specified domain by sending a validation request to the DNS server.
|
||||||
|
* @param domain the Domain to validate.
|
||||||
|
* @throws IOException if there are I/O issues during the validation process.
|
||||||
|
* @throws ClassNotFoundException if there are issues with class loading during packet handling.
|
||||||
|
*/
|
||||||
public final void validateDomain(Domain domain) throws IOException, ClassNotFoundException {
|
public final void validateDomain(Domain domain) throws IOException, ClassNotFoundException {
|
||||||
|
// Send Classic_PingPacket if classic protocol is supported
|
||||||
Classic_PingPacket cPingPacket = new Classic_PingPacket(new Classic_RequestDomain(domain.getName(), domain.getTopLevelName(), domain.getPath()), null, false);
|
Classic_PingPacket cPingPacket = new Classic_PingPacket(new Classic_RequestDomain(domain.getName(), domain.getTopLevelName(), domain.getPath()), null, false);
|
||||||
if (ProtocolBridge.getInstance().isPacketSupported(cPingPacket)) clientToDNS.sendPacket(cPingPacket);
|
if (ProtocolBridge.getInstance().isClassicSupported()) clientToDNS.sendPacket(cPingPacket);
|
||||||
|
|
||||||
|
// Send ValidateDomainPacket
|
||||||
clientToDNS.sendPacket(new ValidateDomainPacket(domain));
|
clientToDNS.sendPacket(new ValidateDomainPacket(domain));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests the destination for the specified domain from the DNS server.
|
||||||
|
* @param domain the Domain for which to request the destination.
|
||||||
|
* @param responseCode the expected DNSResponseCode for the request.
|
||||||
|
* @throws IOException if there are I/O issues during the request process.
|
||||||
|
* @throws ClassNotFoundException if there are issues with class loading during packet handling.
|
||||||
|
*/
|
||||||
public final void requestDestination(Domain domain, DNSResponseCode responseCode) throws IOException, ClassNotFoundException {
|
public final void requestDestination(Domain domain, DNSResponseCode responseCode) throws IOException, ClassNotFoundException {
|
||||||
|
// Send Classic_DomainPacket if classic protocol is supported
|
||||||
Classic_DomainPacket cDomainPacket = new Classic_DomainPacket(0, new Classic_RequestDomain(domain.getName(), domain.getTopLevelName(), domain.getPath()), null);
|
Classic_DomainPacket cDomainPacket = new Classic_DomainPacket(0, new Classic_RequestDomain(domain.getName(), domain.getTopLevelName(), domain.getPath()), null);
|
||||||
if (ProtocolBridge.getInstance().isPacketSupported(cDomainPacket)) clientToDNS.sendPacket(cDomainPacket);
|
if (ProtocolBridge.getInstance().isClassicSupported()) clientToDNS.sendPacket(cDomainPacket);
|
||||||
|
|
||||||
|
// Send GetDestinationPacket
|
||||||
clientToDNS.sendPacket(new GetDestinationPacket(domain, responseCode));
|
clientToDNS.sendPacket(new GetDestinationPacket(domain, responseCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback method invoked when domain validation is completed.
|
||||||
|
* @param domain the Domain that was validated.
|
||||||
|
* @param responseCode the DNSResponseCode resulting from the validation.
|
||||||
|
*/
|
||||||
public abstract void validationCompleted(Domain domain, DNSResponseCode responseCode);
|
public abstract void validationCompleted(Domain domain, DNSResponseCode responseCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback method invoked when the destination retrieval is completed.
|
||||||
|
* @param domain the Domain for which the destination was requested.
|
||||||
|
* @param destination the retrieved destination as a string.
|
||||||
|
* @param validationResponse the DNSResponseCode resulting from the destination retrieval.
|
||||||
|
*/
|
||||||
public abstract void getDestinationCompleted(Domain domain, String destination, DNSResponseCode validationResponse);
|
public abstract void getDestinationCompleted(Domain domain, String destination, DNSResponseCode validationResponse);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the folder structure for client certificates.
|
||||||
|
*/
|
||||||
public final class ClientCertificateFolderStructure {
|
public final class ClientCertificateFolderStructure {
|
||||||
public final File certificatesFolder;
|
public final File certificatesFolder;
|
||||||
|
|
||||||
|
@@ -17,29 +17,89 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebClient handles secure connections to web servers through a pipeline connection.
|
||||||
|
* It manages SSL/TLS handshakes and data transmission over the established connection.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
||||||
public final class WebClient {
|
public final class WebClient {
|
||||||
private final NetworkClient clientToWebPipeline; // Handles everything with Pipeline-Connection
|
/**
|
||||||
private SSLSocket clientToWebServer; // Handles everything with Web-Connection
|
* NetworkClient instance for managing the pipeline connection to the web server.
|
||||||
private ObjectOutputStream outputStream; private final Thread receiveThread = new Thread(this::receive);
|
*/
|
||||||
|
private final NetworkClient clientToWebPipeline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSLSocket for secure communication with the web server.
|
||||||
|
*/
|
||||||
|
private SSLSocket clientToWebServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streams for object serialization over the SSL connection.
|
||||||
|
*/
|
||||||
|
private ObjectOutputStream outputStream;
|
||||||
|
/**
|
||||||
|
* Streams for object serialization over the SSL connection.
|
||||||
|
*/
|
||||||
private ObjectInputStream inputStream;
|
private ObjectInputStream inputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread for receiving data from the web server.
|
||||||
|
*/
|
||||||
|
private final Thread receiveThread = new Thread(this::receive);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a WebClient instance and establishes a secure connection to the web server.
|
||||||
|
* @param domain The domain information for the web server.
|
||||||
|
* @param pipelinePort The port for the pipeline connection.
|
||||||
|
* @param webPort The port for the web server connection.
|
||||||
|
* @throws Exception If an error occurs during connection setup.
|
||||||
|
*/
|
||||||
public WebClient(Domain domain, int pipelinePort, int webPort) throws Exception {
|
public WebClient(Domain domain, int pipelinePort, int webPort) throws Exception {
|
||||||
clientToWebPipeline = new NetworkClient.ClientBuilder().setLogger(ProtocolBridge.getInstance().getLogger()).
|
// Initialize and connect the pipeline client
|
||||||
|
clientToWebPipeline = new NetworkClient.ClientBuilder().
|
||||||
|
// Set logger from ProtocolBridge
|
||||||
|
setLogger(ProtocolBridge.getInstance().getLogger()).
|
||||||
|
// Set the destination and port for the pipeline connection
|
||||||
setHost(domain.getDestination()).setPort(pipelinePort).
|
setHost(domain.getDestination()).setPort(pipelinePort).
|
||||||
setPacketHandler(ProtocolBridge.getInstance().getProtocolSettings().packetHandler).setEventManager(ProtocolBridge.getInstance().getProtocolSettings().eventManager).
|
|
||||||
setRootCAFolder(ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().publicCAFolder).setClientCertificatesFolder(ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().publicClientFolder, ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().privateClientFolder).
|
// Configure packet handler and event manager
|
||||||
|
setPacketHandler(ProtocolBridge.getInstance().getProtocolSettings().packetHandler).
|
||||||
|
setEventManager(ProtocolBridge.getInstance().getProtocolSettings().eventManager).
|
||||||
|
|
||||||
|
// Set proxy and ssl parameters from DNS connection settings
|
||||||
|
setProxy(ProtocolBridge.getInstance().getProtocolClient().getClientDNSConnection().getProxy()).
|
||||||
|
setSSLParameters(ProtocolBridge.getInstance().getProtocolClient().getClientDNSConnection().getSocket().getSSLParameters()).
|
||||||
|
|
||||||
|
// Set certificates and folders for SSL
|
||||||
|
setRootCAFolder(ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().publicCAFolder).
|
||||||
|
setClientCertificatesFolder(ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().publicClientFolder,
|
||||||
|
ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().privateClientFolder).
|
||||||
|
|
||||||
|
|
||||||
|
// Finalize the client setup
|
||||||
build();
|
build();
|
||||||
|
|
||||||
|
// Connect to the pipeline
|
||||||
clientToWebPipeline.connect();
|
clientToWebPipeline.connect();
|
||||||
|
|
||||||
|
// Wait until the pipeline connection is established
|
||||||
while (!clientToWebPipeline.isConnected()) if (clientToWebPipeline.isConnected()) break;
|
while (!clientToWebPipeline.isConnected()) if (clientToWebPipeline.isConnected()) break;
|
||||||
|
|
||||||
SSLSocketFactory sslSocketFactory = NetworkClient.ClientBuilder.createSSLSocketFactory(ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().publicCAFolder, ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().publicClientFolder, ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().privateClientFolder);
|
// Create SSL socket factory using client certificates
|
||||||
|
SSLSocketFactory sslSocketFactory = NetworkClient.ClientBuilder.
|
||||||
|
createSSLSocketFactory(ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().publicCAFolder,
|
||||||
|
ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().publicClientFolder,
|
||||||
|
ProtocolBridge.getInstance().getProtocolClient().getFolderStructure().privateClientFolder);
|
||||||
|
|
||||||
|
// Get proxy settings from the pipeline client
|
||||||
Proxy proxy = clientToWebPipeline.getProxy();
|
Proxy proxy = clientToWebPipeline.getProxy();
|
||||||
|
|
||||||
|
// Establish SSL connection to the web server
|
||||||
SSLSocket tempSocket;
|
SSLSocket tempSocket;
|
||||||
if (sslSocketFactory == null) {
|
if (sslSocketFactory == null) {
|
||||||
throw new ConnectException("SSL socket factory not set. Client certificate required!");
|
throw new ConnectException("SSL socket factory not set. Client certificate required!");
|
||||||
} else {
|
} else {
|
||||||
|
// Create raw socket and wrap it in SSL socket
|
||||||
if (proxy != null) {
|
if (proxy != null) {
|
||||||
Socket rawSocket = new Socket(proxy);
|
Socket rawSocket = new Socket(proxy);
|
||||||
rawSocket.connect(new InetSocketAddress(domain.getDestination(), webPort), 0);
|
rawSocket.connect(new InetSocketAddress(domain.getDestination(), webPort), 0);
|
||||||
@@ -49,16 +109,20 @@ public final class WebClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientToWebServer = tempSocket;
|
clientToWebServer = tempSocket;
|
||||||
|
|
||||||
|
// Configure SSL parameters
|
||||||
SSLParameters sslParameters = clientToWebPipeline.getSocket().getSSLParameters();
|
SSLParameters sslParameters = clientToWebPipeline.getSocket().getSSLParameters();
|
||||||
|
|
||||||
if (sslParameters != null) {
|
if (sslParameters != null) {
|
||||||
clientToWebServer.setSSLParameters(sslParameters);
|
clientToWebServer.setSSLParameters(sslParameters);
|
||||||
} else {
|
} else {
|
||||||
|
// Set default to TLSv1.3 if no parameters are provided
|
||||||
SSLParameters defaultParams = clientToWebServer.getSSLParameters();
|
SSLParameters defaultParams = clientToWebServer.getSSLParameters();
|
||||||
defaultParams.setProtocols(new String[]{"TLSv1.3"});
|
defaultParams.setProtocols(new String[]{"TLSv1.3"});
|
||||||
clientToWebServer.setSSLParameters(defaultParams);
|
clientToWebServer.setSSLParameters(defaultParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure socket options
|
||||||
clientToWebServer.setTcpNoDelay(true);
|
clientToWebServer.setTcpNoDelay(true);
|
||||||
clientToWebServer.setSoTimeout(0);
|
clientToWebServer.setSoTimeout(0);
|
||||||
|
|
||||||
@@ -68,26 +132,46 @@ public final class WebClient {
|
|||||||
throw new ConnectException("Handshake failed: " + handshakeEx.getMessage());
|
throw new ConnectException("Handshake failed: " + handshakeEx.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize object streams for communication
|
||||||
this.outputStream = new ObjectOutputStream(clientToWebServer.getOutputStream());
|
this.outputStream = new ObjectOutputStream(clientToWebServer.getOutputStream());
|
||||||
this.inputStream = new ObjectInputStream(clientToWebServer.getInputStream());
|
this.inputStream = new ObjectInputStream(clientToWebServer.getInputStream());
|
||||||
|
|
||||||
|
// Start the receive thread
|
||||||
this.receiveThread.start();
|
this.receiveThread.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the NetworkClient used for the pipeline connection to the web server.
|
||||||
|
* @return The NetworkClient connected to the web server pipeline.
|
||||||
|
*/
|
||||||
public NetworkClient getClientPipelineConnection() {
|
public NetworkClient getClientPipelineConnection() {
|
||||||
return clientToWebPipeline;
|
return clientToWebPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the SSLSocket used for communication with the web server.
|
||||||
|
* @return The SSLSocket connected to the web server.
|
||||||
|
*/
|
||||||
public SSLSocket getClientWebConnection() {
|
public SSLSocket getClientWebConnection() {
|
||||||
return clientToWebServer;
|
return clientToWebServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the WebClient is currently connected to the web server.
|
||||||
|
* @return true if connected, false otherwise.
|
||||||
|
*/
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return this.clientToWebServer != null && this.clientToWebServer.isConnected() && !this.clientToWebServer.isClosed()
|
return this.clientToWebServer != null && this.clientToWebServer.isConnected() && !this.clientToWebServer.isClosed()
|
||||||
&& this.receiveThread.isAlive() && !this.receiveThread.isInterrupted() &&
|
&& this.receiveThread.isAlive() && !this.receiveThread.isInterrupted() &&
|
||||||
ProtocolBridge.getInstance().getProtocolClient().getClientDNSConnection().isConnected() && clientToWebPipeline.isConnected();
|
ProtocolBridge.getInstance().getProtocolClient().getClientDNSConnection().isConnected() && clientToWebPipeline.isConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Continuously receives data from the web server.
|
||||||
|
* This method runs in a separate thread and handles incoming objects.
|
||||||
|
* If an error occurs, it attempts to close the connection.
|
||||||
|
*/
|
||||||
private void receive() {
|
private void receive() {
|
||||||
try {
|
try {
|
||||||
while (this.isConnected()) {
|
while (this.isConnected()) {
|
||||||
@@ -102,6 +186,11 @@ public final class WebClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the connection to the web server and releases resources.
|
||||||
|
* @return true if the connection was successfully closed, false if it was already closed.
|
||||||
|
* @throws IOException If an I/O error occurs during closure.
|
||||||
|
*/
|
||||||
public synchronized boolean closeConnection() throws IOException {
|
public synchronized boolean closeConnection() throws IOException {
|
||||||
if (!this.isConnected()) {
|
if (!this.isConnected()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -109,7 +198,10 @@ public final class WebClient {
|
|||||||
clientToWebPipeline.disconnect();
|
clientToWebPipeline.disconnect();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Interrupt the receive thread
|
||||||
this.receiveThread.interrupt();
|
this.receiveThread.interrupt();
|
||||||
|
|
||||||
|
// Close streams and socket
|
||||||
if (this.outputStream != null) {
|
if (this.outputStream != null) {
|
||||||
this.outputStream.close();
|
this.outputStream.close();
|
||||||
}
|
}
|
||||||
@@ -122,6 +214,7 @@ public final class WebClient {
|
|||||||
this.clientToWebServer.close();
|
this.clientToWebServer.close();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
// Nullify references to help with garbage collection
|
||||||
this.clientToWebServer = null;
|
this.clientToWebServer = null;
|
||||||
this.outputStream = null;
|
this.outputStream = null;
|
||||||
this.inputStream = null;
|
this.inputStream = null;
|
||||||
|
@@ -4,6 +4,9 @@ import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
|||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event triggered when a client successfully connects to a DNS protocol server.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
||||||
public class ConnectedToProtocolServer extends Event {
|
public class ConnectedToProtocolDNSServerEvent extends Event {
|
||||||
}
|
}
|
@@ -6,83 +6,153 @@ import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|||||||
import org.openautonomousconnection.protocol.packets.OACPacket;
|
import org.openautonomousconnection.protocol.packets.OACPacket;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a connected protocol client on the DNS server side.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
||||||
public final class ConnectedProtocolClient {
|
public final class ConnectedProtocolClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connection handler associated with this protocol client.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final ConnectionHandler connectionHandler;
|
private final ConnectionHandler connectionHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The protocol version of the connected client.
|
||||||
|
*/
|
||||||
private ProtocolVersion clientVersion = null;
|
private ProtocolVersion clientVersion = null;
|
||||||
|
|
||||||
public ConnectedProtocolClient(ConnectionHandler connectionHandler) {
|
public ConnectedProtocolClient(ConnectionHandler connectionHandler) {
|
||||||
this.connectionHandler = connectionHandler;
|
this.connectionHandler = connectionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
public ProtocolVersion getClientVersion() {
|
||||||
return clientVersion == null ? ProtocolVersion.PV_1_0_0_CLASSIC : clientVersion;
|
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) {
|
public void setClientVersion(ProtocolVersion clientVersion) {
|
||||||
if (clientVersion == null) this.clientVersion = 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() {
|
public boolean isStableClient() {
|
||||||
|
// Check if the server version is stable
|
||||||
return !isBetaClient() && !isClassicClient();
|
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() {
|
public boolean supportClientStable() {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version is stable
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the client version is stable
|
||||||
return isStableClient() || yes;
|
return isStableClient() || yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the connected client is a beta client.
|
||||||
|
* @return True if the client is beta, false otherwise.
|
||||||
|
*/
|
||||||
public boolean isBetaClient() {
|
public boolean isBetaClient() {
|
||||||
|
// Check if the server version is beta
|
||||||
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.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() {
|
public boolean supportClientBeta() {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version is beta
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the client version is beta
|
||||||
return isBetaClient() || yes;
|
return isBetaClient() || yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the connected client is a classic client.
|
||||||
|
* @return True if the client is classic, false otherwise.
|
||||||
|
*/
|
||||||
public boolean isClassicClient() {
|
public boolean isClassicClient() {
|
||||||
|
// Check if the server version is classic
|
||||||
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.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() {
|
public boolean supportClientClassic() {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version is classic
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the client version is classic
|
||||||
return isClassicClient() || yes;
|
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) {
|
public boolean supportClientPacket(OACPacket packet) {
|
||||||
return supportClientVersion(packet.getProtocolVersion());
|
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) {
|
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);
|
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) {
|
public boolean supportClientProtocol(ProtocolVersion.Protocol protocol) {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version supports the protocol
|
||||||
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
|
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the client version supports the protocol
|
||||||
return getClientVersion().getSupportedProtocols().contains(protocol) || yes;
|
return getClientVersion().getSupportedProtocols().contains(protocol) || yes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,23 +18,50 @@ import java.security.cert.CertificateException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class representing a DNS server in the protocol.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
||||||
public abstract class ProtocolDNSServer extends DefaultMethodsOverrider {
|
public abstract class ProtocolDNSServer extends DefaultMethodsOverrider {
|
||||||
|
/**
|
||||||
|
* The network server instance.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final NetworkServer networkServer;
|
private final NetworkServer networkServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration manager for handling server configurations.
|
||||||
|
*/
|
||||||
private final ConfigurationManager configurationManager;
|
private final ConfigurationManager configurationManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of connected protocol clients.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private List<ConnectedProtocolClient> clients;
|
private List<ConnectedProtocolClient> clients;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The folder structure for server certificates.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private ServerCertificateFolderStructure folderStructure;
|
private ServerCertificateFolderStructure folderStructure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a ProtocolDNSServer with the specified configuration file.
|
||||||
|
*
|
||||||
|
* @param configFile The configuration file for the DNS server.
|
||||||
|
* @throws IOException If an I/O error occurs.
|
||||||
|
* @throws CertificateException If a certificate error occurs.
|
||||||
|
*/
|
||||||
public ProtocolDNSServer(File configFile) throws IOException, CertificateException {
|
public ProtocolDNSServer(File configFile) throws IOException, CertificateException {
|
||||||
|
// Ensure the configuration file exists
|
||||||
if (!configFile.exists()) configFile.createNewFile();
|
if (!configFile.exists()) configFile.createNewFile();
|
||||||
|
|
||||||
|
// Load the configuration properties
|
||||||
configurationManager = new ConfigurationManager(configFile);
|
configurationManager = new ConfigurationManager(configFile);
|
||||||
configurationManager.loadProperties();
|
configurationManager.loadProperties();
|
||||||
|
|
||||||
|
// Set default values for configuration properties if not already set
|
||||||
if (!configurationManager.isSet("server.site.info")) {
|
if (!configurationManager.isSet("server.site.info")) {
|
||||||
configurationManager.set("server.site.info", "DNS-SERVER INFO SITE IP");
|
configurationManager.set("server.site.info", "DNS-SERVER INFO SITE IP");
|
||||||
configurationManager.saveProperties();
|
configurationManager.saveProperties();
|
||||||
@@ -45,8 +72,10 @@ public abstract class ProtocolDNSServer extends DefaultMethodsOverrider {
|
|||||||
configurationManager.saveProperties();
|
configurationManager.saveProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the folder structure
|
||||||
folderStructure = new ServerCertificateFolderStructure();
|
folderStructure = new ServerCertificateFolderStructure();
|
||||||
|
|
||||||
|
// Check for the existence of necessary certificate files
|
||||||
checkFileExists(folderStructure.publicCAFolder, folderStructure.caPrefix, ".pem");
|
checkFileExists(folderStructure.publicCAFolder, folderStructure.caPrefix, ".pem");
|
||||||
checkFileExists(folderStructure.publicCAFolder, folderStructure.caPrefix, ".srl");
|
checkFileExists(folderStructure.publicCAFolder, folderStructure.caPrefix, ".srl");
|
||||||
checkFileExists(folderStructure.privateCAFolder, folderStructure.caPrefix, ".key");
|
checkFileExists(folderStructure.privateCAFolder, folderStructure.caPrefix, ".key");
|
||||||
@@ -54,13 +83,17 @@ public abstract class ProtocolDNSServer extends DefaultMethodsOverrider {
|
|||||||
checkFileExists(folderStructure.publicServerFolder, folderStructure.certPrefix, ".crt");
|
checkFileExists(folderStructure.publicServerFolder, folderStructure.certPrefix, ".crt");
|
||||||
checkFileExists(folderStructure.privateServerFolder, folderStructure.certPrefix, ".key");
|
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 certFile = new File(folderStructure.publicServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".crt");
|
||||||
File keyFile = new File(folderStructure.privateServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".key");
|
File keyFile = new File(folderStructure.privateServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".key");
|
||||||
|
|
||||||
|
// Initialize the protocol bridge and clients list
|
||||||
ProtocolBridge protocolBridge = ProtocolBridge.getInstance();
|
ProtocolBridge protocolBridge = ProtocolBridge.getInstance();
|
||||||
this.clients = new ArrayList<>();
|
this.clients = new ArrayList<>();
|
||||||
|
|
||||||
this.networkServer = new NetworkServer.ServerBuilder().setLogger(protocolBridge.getLogger()).
|
// Build the network server with the specified settings
|
||||||
|
this.networkServer = new NetworkServer.ServerBuilder().
|
||||||
|
setLogger(protocolBridge.getLogger()).
|
||||||
setEventManager(protocolBridge.getProtocolSettings().eventManager).
|
setEventManager(protocolBridge.getProtocolSettings().eventManager).
|
||||||
setPacketHandler(protocolBridge.getProtocolSettings().packetHandler).
|
setPacketHandler(protocolBridge.getProtocolSettings().packetHandler).
|
||||||
setPort(protocolBridge.getProtocolSettings().port).
|
setPort(protocolBridge.getProtocolSettings().port).
|
||||||
@@ -68,51 +101,126 @@ public abstract class ProtocolDNSServer extends DefaultMethodsOverrider {
|
|||||||
build();
|
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 {
|
private final void checkFileExists(File folder, String prefix, String extension) throws CertificateException, IOException {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
|
|
||||||
|
// Check if the folder exists
|
||||||
if (folder == null) throw new FileNotFoundException("Folder does not exist");
|
if (folder == null) throw new FileNotFoundException("Folder does not exist");
|
||||||
|
|
||||||
|
// List all files in the folder
|
||||||
File[] files = folder.listFiles();
|
File[] files = folder.listFiles();
|
||||||
|
|
||||||
|
// Check if the folder is empty
|
||||||
if (files == null || files.length == 0)
|
if (files == null || files.length == 0)
|
||||||
throw new FileNotFoundException("Folder " + folder.getAbsolutePath() + " is empty");
|
throw new FileNotFoundException("Folder " + folder.getAbsolutePath() + " is empty");
|
||||||
|
|
||||||
|
// Validate each file in the folder
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
if (!file.getName().startsWith(prefix) || !file.getName().endsWith(extension))
|
if (!file.getName().startsWith(prefix) || !file.getName().endsWith(extension))
|
||||||
throw new CertificateException(file.getAbsolutePath() + " is not valid");
|
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 (!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);
|
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) {
|
public final ConnectedProtocolClient getClientByID(int clientID) {
|
||||||
for (ConnectedProtocolClient client : clients)
|
for (ConnectedProtocolClient client : clients)
|
||||||
if (client.getConnectionHandler().getClientID() == clientID) return client;
|
if (client.getConnectionHandler().getClientID() == clientID) return client;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the DNS information site URL from the configuration.
|
||||||
|
* @return The DNS information site URL.
|
||||||
|
*/
|
||||||
public final String getDNSInfoSite() {
|
public final String getDNSInfoSite() {
|
||||||
return configurationManager.getString("server.site.info");
|
return configurationManager.getString("server.site.info");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the DNS registration site URL from the configuration.
|
||||||
|
* @return The DNS registration site URL.
|
||||||
|
*/
|
||||||
public final String getDNSRegisterSite() {
|
public final String getDNSRegisterSite() {
|
||||||
return configurationManager.getString("server.site.register");
|
return configurationManager.getString("server.site.register");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method to retrieve the list of domains managed by the DNS server.
|
||||||
|
* @return A list of Domain objects.
|
||||||
|
*/
|
||||||
public abstract List<Domain> getDomains();
|
public abstract List<Domain> getDomains();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Domain#getDestination()
|
||||||
|
* Abstract method to get the destination for a given domain.
|
||||||
|
* @param domain The domain to look up.
|
||||||
|
* @return The destination associated with the domain.
|
||||||
|
*/
|
||||||
public abstract String getDomainDestination(Domain domain);
|
public abstract String getDomainDestination(Domain domain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Domain#getDestination()
|
||||||
|
* Abstract method to get the destination for a given subname under a specific domain.
|
||||||
|
* @param domain The parent domain.
|
||||||
|
* @param subname The subname to look up.
|
||||||
|
* @return The destination associated with the subname.
|
||||||
|
*/
|
||||||
public abstract String getSubnameDestination(Domain domain, String subname);
|
public abstract String getSubnameDestination(Domain domain, String subname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Domain#getDestination()
|
||||||
|
* Abstract method to get the top-level domain information site URL.
|
||||||
|
* @param topLevelName The top-level domain name.
|
||||||
|
* @return The information site URL for the specified top-level domain.
|
||||||
|
*/
|
||||||
public abstract String getTLNInfoSite(String topLevelName);
|
public abstract String getTLNInfoSite(String topLevelName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method to validate a requested domain.
|
||||||
|
* @param requestedDomain The domain to validate.
|
||||||
|
* @return A DNSResponseCode indicating the result of the validation.
|
||||||
|
*/
|
||||||
public abstract DNSResponseCode validateDomain(Domain requestedDomain);
|
public abstract DNSResponseCode validateDomain(Domain requestedDomain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method called when a validation packet fails to send.
|
||||||
|
* @param domain The domain associated with the validation.
|
||||||
|
* @param client The connected protocol client.
|
||||||
|
* @param exception The exception that occurred during sending.
|
||||||
|
*/
|
||||||
public abstract void validationPacketSendFailed(Domain domain, ConnectedProtocolClient client, Exception exception);
|
public abstract void validationPacketSendFailed(Domain domain, ConnectedProtocolClient client, Exception exception);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method called when a domain destination packet fails to send.
|
||||||
|
* @param client The connected protocol client.
|
||||||
|
* @param domain The domain associated with the packet.
|
||||||
|
* @param validationResponse The DNS response code from validation.
|
||||||
|
* @param exception The exception that occurred during sending.
|
||||||
|
*/
|
||||||
public abstract void domainDestinationPacketFailedSend(ConnectedProtocolClient client, Domain domain, DNSResponseCode validationResponse, Exception exception);
|
public abstract void domainDestinationPacketFailedSend(ConnectedProtocolClient client, Domain domain, DNSResponseCode validationResponse, Exception exception);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing the folder structure for server certificates.
|
||||||
|
*/
|
||||||
public final class ServerCertificateFolderStructure {
|
public final class ServerCertificateFolderStructure {
|
||||||
public final File certificatesFolder;
|
public final File certificatesFolder;
|
||||||
|
|
||||||
|
@@ -6,6 +6,9 @@ import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|||||||
import org.openautonomousconnection.protocol.side.dns.ConnectedProtocolClient;
|
import org.openautonomousconnection.protocol.side.dns.ConnectedProtocolClient;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event triggered when a protocol client connects to the DNS server.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
||||||
public final class ConnectedProtocolClientEvent extends Event {
|
public final class ConnectedProtocolClientEvent extends Event {
|
||||||
|
|
||||||
|
@@ -18,64 +18,140 @@ import java.nio.file.Files;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a connected web client.
|
||||||
|
* Manages the connection, handles HTTP requests, and serves files.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
||||||
public final class ConnectedWebClient {
|
public final class ConnectedWebClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connection handler associated with this web client.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final ConnectionHandler pipelineConnection;
|
private final ConnectionHandler pipelineConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SSL socket for the web client connection.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private SSLSocket webSocket;
|
private SSLSocket webSocket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The output stream for sending data to the client.
|
||||||
|
*/
|
||||||
private ObjectOutputStream outputStream;
|
private ObjectOutputStream outputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The input stream for receiving data from the client.
|
||||||
|
*/
|
||||||
private ObjectInputStream inputStream;
|
private ObjectInputStream inputStream;
|
||||||
private ProtocolVersion clientVersion = null; private final Thread receiveThread = new Thread(this::receive);
|
|
||||||
|
/**
|
||||||
|
* The protocol version of the connected client.
|
||||||
|
*/
|
||||||
|
private ProtocolVersion clientVersion = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread for receiving data from the client.
|
||||||
|
*/
|
||||||
|
private final Thread receiveThread = new Thread(this::receive);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the client version has been loaded.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private boolean clientVersionLoaded = false;
|
private boolean clientVersionLoaded = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a ConnectedWebClient with the given connection handler.
|
||||||
|
* @param pipelineConnection The connection handler for the web client.
|
||||||
|
*/
|
||||||
public ConnectedWebClient(ConnectionHandler pipelineConnection) {
|
public ConnectedWebClient(ConnectionHandler pipelineConnection) {
|
||||||
this.pipelineConnection = 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 {
|
private static void sendRedirect(OutputStream out, String location, Map<String, String> cookies) throws IOException {
|
||||||
out.write(("HTTP/1.1 302 Found\r\n").getBytes());
|
// Send HTTP 302 Found response with Location header
|
||||||
|
out.write(("OAC 302 Found\r\n").getBytes());
|
||||||
out.write(("Location: " + location + "\r\n").getBytes());
|
out.write(("Location: " + location + "\r\n").getBytes());
|
||||||
|
|
||||||
|
// Set cookies if provided
|
||||||
if (cookies != null) {
|
if (cookies != null) {
|
||||||
for (var entry : cookies.entrySet()) {
|
for (var entry : cookies.entrySet()) {
|
||||||
out.write((entry.getKey() + ": " + entry.getValue() + "\r\n").getBytes());
|
out.write((entry.getKey() + ": " + entry.getValue() + "\r\n").getBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// End of headers
|
||||||
out.write("\r\n".getBytes());
|
out.write("\r\n".getBytes());
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
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));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
while (reader.ready()) {
|
while (reader.ready()) {
|
||||||
sb.append((char) reader.read());
|
sb.append((char) reader.read());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split the string into key-value pairs and decode them
|
||||||
Map<String, String> map = new HashMap<>();
|
Map<String, String> map = new HashMap<>();
|
||||||
String[] pairs = sb.toString().split("&");
|
String[] pairs = sb.toString().split("&");
|
||||||
for (String p : pairs) {
|
for (String p : pairs) {
|
||||||
|
// Split each pair into key and value
|
||||||
String[] kv = p.split("=", 2);
|
String[] kv = p.split("=", 2);
|
||||||
if (kv.length == 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));
|
map.put(URLDecoder.decode(kv[0], StandardCharsets.UTF_8), URLDecoder.decode(kv[1], StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
return map;
|
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) {
|
private static String normalizePath(String path) {
|
||||||
|
// Replace backslashes with forward slashes and remove ".." segments
|
||||||
path = path.replace("/", File.separator).replace("\\", "/");
|
path = path.replace("/", File.separator).replace("\\", "/");
|
||||||
|
// Remove any ".." segments to prevent directory traversal
|
||||||
while (path.contains("..")) path = path.replace("..", "");
|
while (path.contains("..")) path = path.replace("..", "");
|
||||||
|
|
||||||
|
// Remove leading slashes
|
||||||
if (path.startsWith("/")) path = path.substring(1);
|
if (path.startsWith("/")) path = path.substring(1);
|
||||||
|
|
||||||
return path;
|
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) {
|
private static Map<String, String> parseQueryParams(String rawPath) {
|
||||||
|
// Extract query parameters from the URL path
|
||||||
Map<String, String> map = new HashMap<>();
|
Map<String, String> map = new HashMap<>();
|
||||||
if (rawPath.contains("?")) {
|
if (rawPath.contains("?")) {
|
||||||
|
// Split the query string into key-value pairs
|
||||||
String[] params = rawPath.substring(rawPath.indexOf("?") + 1).split("&");
|
String[] params = rawPath.substring(rawPath.indexOf("?") + 1).split("&");
|
||||||
for (String p : params) {
|
for (String p : params) {
|
||||||
|
// Split each pair into key and value
|
||||||
String[] kv = p.split("=");
|
String[] kv = p.split("=");
|
||||||
if (kv.length == 2) map.put(kv[0], kv[1]);
|
if (kv.length == 2) map.put(kv[0], kv[1]);
|
||||||
}
|
}
|
||||||
@@ -83,17 +159,32 @@ public final class ConnectedWebClient {
|
|||||||
return map;
|
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) {
|
private static boolean isMultipart(Map<String, String> headers) {
|
||||||
String contentType = headers.get("content-type");
|
String contentType = headers.get("content-type");
|
||||||
return contentType != null && contentType.startsWith("multipart/form-data");
|
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 {
|
private static void handleMultipart(InputStream in, Map<String, String> headers, File uploadDir) throws IOException {
|
||||||
|
// Ensure the upload directory exists
|
||||||
if (!uploadDir.exists()) uploadDir.mkdirs();
|
if (!uploadDir.exists()) uploadDir.mkdirs();
|
||||||
|
|
||||||
|
// Extract the boundary from the Content-Type header
|
||||||
String contentType = headers.get("content-type");
|
String contentType = headers.get("content-type");
|
||||||
String boundary = "--" + contentType.split("boundary=")[1];
|
String boundary = "--" + contentType.split("boundary=")[1];
|
||||||
|
|
||||||
|
// Read the entire request body into a buffer
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
byte[] lineBuffer = new byte[8192];
|
byte[] lineBuffer = new byte[8192];
|
||||||
int read;
|
int read;
|
||||||
@@ -102,14 +193,17 @@ public final class ConnectedWebClient {
|
|||||||
if (buffer.size() > 10 * 1024 * 1024) break; // 10 MB max
|
if (buffer.size() > 10 * 1024 * 1024) break; // 10 MB max
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the multipart data
|
||||||
String data = buffer.toString(StandardCharsets.UTF_8);
|
String data = buffer.toString(StandardCharsets.UTF_8);
|
||||||
String[] parts = data.split(boundary);
|
String[] parts = data.split(boundary);
|
||||||
|
|
||||||
|
// Process each part
|
||||||
for (String part : parts) {
|
for (String part : parts) {
|
||||||
if (part.contains("Content-Disposition")) {
|
if (part.contains("Content-Disposition")) {
|
||||||
String name = null;
|
String name = null;
|
||||||
String filename = null;
|
String filename = null;
|
||||||
|
|
||||||
|
// Extract headers from the part
|
||||||
for (String headerLine : part.split("\r\n")) {
|
for (String headerLine : part.split("\r\n")) {
|
||||||
if (headerLine.startsWith("Content-Disposition")) {
|
if (headerLine.startsWith("Content-Disposition")) {
|
||||||
if (headerLine.contains("filename=\"")) {
|
if (headerLine.contains("filename=\"")) {
|
||||||
@@ -125,6 +219,7 @@ public final class ConnectedWebClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save the file if a filename is provided
|
||||||
if (filename != null && !filename.isEmpty()) {
|
if (filename != null && !filename.isEmpty()) {
|
||||||
int headerEnd = part.indexOf("\r\n\r\n");
|
int headerEnd = part.indexOf("\r\n\r\n");
|
||||||
byte[] fileData = part.substring(headerEnd + 4).getBytes(StandardCharsets.UTF_8);
|
byte[] fileData = part.substring(headerEnd + 4).getBytes(StandardCharsets.UTF_8);
|
||||||
@@ -135,54 +230,89 @@ public final class ConnectedWebClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String renderPHP(File file) throws IOException, InterruptedException {
|
/**
|
||||||
ProcessBuilder pb = new ProcessBuilder("php", file.getAbsolutePath());
|
* Sends an response to the client.
|
||||||
pb.redirectErrorStream(true);
|
* @param out
|
||||||
Process p = pb.start();
|
* @param code
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
* @param file
|
||||||
InputStream processIn = p.getInputStream();
|
* @param headers
|
||||||
byte[] buf = new byte[8192];
|
* @throws IOException
|
||||||
int read;
|
*/
|
||||||
while ((read = processIn.read(buf)) != -1) {
|
|
||||||
output.write(buf, 0, read);
|
|
||||||
}
|
|
||||||
p.waitFor();
|
|
||||||
return output.toString(StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void sendResponse(OutputStream out, int code, File file, Map<String, String> 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());
|
byte[] body = Files.readAllBytes(file.toPath());
|
||||||
sendResponse(out, code, body, "text/html", headers);
|
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 {
|
private static void sendResponse(OutputStream out, int code, File file) throws IOException {
|
||||||
sendResponse(out, code, Files.readString(file.toPath()), "text/html");
|
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 {
|
private static void sendResponse(OutputStream out, int code, String body, String contentType) throws IOException {
|
||||||
sendResponse(out, code, body.getBytes(StandardCharsets.UTF_8), contentType, null);
|
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 {
|
private static void sendResponse(OutputStream out, int code, File file, String contentType) throws IOException {
|
||||||
byte[] bytes = Files.readAllBytes(file.toPath());
|
byte[] bytes = Files.readAllBytes(file.toPath());
|
||||||
sendResponse(out, code, bytes, contentType, null);
|
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 {
|
private static void sendResponse(OutputStream out, int code, byte[] body, String contentType, Map<String, String> headers) throws IOException {
|
||||||
out.write(("HTTP/1.1 " + code + " " + getStatusText(code) + "\r\n").getBytes());
|
// 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-Type: " + contentType + "\r\n").getBytes());
|
||||||
out.write(("Content-Length: " + body.length + "\r\n").getBytes());
|
out.write(("Content-Length: " + body.length + "\r\n").getBytes());
|
||||||
|
|
||||||
|
// Write additional headers if provided
|
||||||
if (headers != null) headers.forEach((k, v) -> {
|
if (headers != null) headers.forEach((k, v) -> {
|
||||||
try {
|
try {
|
||||||
out.write((k + ": " + v + "\r\n").getBytes());
|
out.write((k + ": " + v + "\r\n").getBytes());
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// End of headers
|
||||||
out.write("\r\n".getBytes());
|
out.write("\r\n".getBytes());
|
||||||
out.write(body);
|
out.write(body);
|
||||||
out.flush();
|
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) {
|
private static String getStatusText(int code) {
|
||||||
return switch (code) {
|
return switch (code) {
|
||||||
case 200 -> "OK";
|
case 200 -> "OK";
|
||||||
@@ -197,6 +327,11 @@ public final class ConnectedWebClient {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
private static String getContentType(String name) {
|
||||||
return switch (name.substring(name.lastIndexOf('.') + 1).toLowerCase()) {
|
return switch (name.substring(name.lastIndexOf('.') + 1).toLowerCase()) {
|
||||||
case "html", "php" -> "text/html";
|
case "html", "php" -> "text/html";
|
||||||
@@ -213,11 +348,20 @@ public final class ConnectedWebClient {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
private static PHPResponse renderPHPWithCookies(File file) throws IOException, InterruptedException {
|
||||||
|
// Execute the PHP file using the PHP interpreter
|
||||||
ProcessBuilder pb = new ProcessBuilder("php", file.getAbsolutePath());
|
ProcessBuilder pb = new ProcessBuilder("php", file.getAbsolutePath());
|
||||||
pb.redirectErrorStream(true);
|
pb.redirectErrorStream(true);
|
||||||
Process p = pb.start();
|
Process p = pb.start();
|
||||||
|
|
||||||
|
// Capture the output of the PHP process
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
InputStream processIn = p.getInputStream();
|
InputStream processIn = p.getInputStream();
|
||||||
byte[] buf = new byte[8192];
|
byte[] buf = new byte[8192];
|
||||||
@@ -227,14 +371,19 @@ public final class ConnectedWebClient {
|
|||||||
}
|
}
|
||||||
p.waitFor();
|
p.waitFor();
|
||||||
|
|
||||||
|
// Parse the output to separate headers and body, and extract cookies
|
||||||
String fullOutput = output.toString(StandardCharsets.UTF_8);
|
String fullOutput = output.toString(StandardCharsets.UTF_8);
|
||||||
Map<String, String> cookies = new HashMap<>();
|
Map<String, String> cookies = new HashMap<>();
|
||||||
|
|
||||||
|
// Split headers and body
|
||||||
String[] parts = fullOutput.split("\r\n\r\n", 2);
|
String[] parts = fullOutput.split("\r\n\r\n", 2);
|
||||||
String body;
|
String body;
|
||||||
if (parts.length == 2) {
|
if (parts.length == 2) {
|
||||||
|
// Get headers and body
|
||||||
String headers = parts[0];
|
String headers = parts[0];
|
||||||
body = parts[1];
|
body = parts[1];
|
||||||
|
|
||||||
|
// Extract cookies from headers
|
||||||
for (String headerLine : headers.split("\r\n")) {
|
for (String headerLine : headers.split("\r\n")) {
|
||||||
if (headerLine.toLowerCase().startsWith("set-cookie:")) {
|
if (headerLine.toLowerCase().startsWith("set-cookie:")) {
|
||||||
String cookie = headerLine.substring("set-cookie:".length()).trim();
|
String cookie = headerLine.substring("set-cookie:".length()).trim();
|
||||||
@@ -244,114 +393,194 @@ public final class ConnectedWebClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// No headers, only body
|
||||||
body = fullOutput;
|
body = fullOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PHPResponse(body, cookies);
|
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) {
|
public void setWebSocket(SSLSocket webSocket) {
|
||||||
if (webSocket != null) this.webSocket = webSocket;
|
if (webSocket != null) this.webSocket = webSocket;
|
||||||
this.receiveThread.start();
|
this.receiveThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the web client is currently connected.
|
||||||
|
* @return True if connected, false otherwise.
|
||||||
|
*/
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return this.webSocket != null && this.webSocket.isConnected() && !this.webSocket.isClosed() && this.receiveThread.isAlive() && pipelineConnection.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() {
|
public synchronized boolean disconnect() {
|
||||||
if (!this.isConnected()) {
|
if (!this.isConnected()) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
// Disconnect the underlying connection handler
|
||||||
pipelineConnection.disconnect();
|
pipelineConnection.disconnect();
|
||||||
|
|
||||||
|
// Interrupt the receive thread if it's still alive
|
||||||
if (this.receiveThread.isAlive()) {
|
if (this.receiveThread.isAlive()) {
|
||||||
this.receiveThread.interrupt();
|
this.receiveThread.interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Close streams and the socket
|
||||||
this.outputStream.close();
|
this.outputStream.close();
|
||||||
this.inputStream.close();
|
this.inputStream.close();
|
||||||
this.webSocket.close();
|
this.webSocket.close();
|
||||||
} catch (IOException var2) {
|
} catch (IOException var2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nullify references
|
||||||
this.webSocket = null;
|
this.webSocket = null;
|
||||||
this.outputStream = null;
|
this.outputStream = null;
|
||||||
this.inputStream = null;
|
this.inputStream = null;
|
||||||
|
|
||||||
return true;
|
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() {
|
public ProtocolVersion getClientVersion() {
|
||||||
return clientVersion == null ? ProtocolVersion.PV_1_0_0_CLASSIC : clientVersion;
|
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) {
|
public void setClientVersion(ProtocolVersion clientVersion) {
|
||||||
if (!clientVersionLoaded) clientVersionLoaded = true;
|
if (!clientVersionLoaded) clientVersionLoaded = true;
|
||||||
if (clientVersion == null) this.clientVersion = 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() {
|
public boolean isStableClient() {
|
||||||
|
// Check if the server version is stable
|
||||||
return !isBetaClient() && !isClassicClient();
|
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() {
|
public boolean supportClientStable() {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version is stable
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the client version is stable
|
||||||
return isStableClient() || yes;
|
return isStableClient() || yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the connected client is a beta client.
|
||||||
|
* @return True if the client is beta, false otherwise.
|
||||||
|
*/
|
||||||
public boolean isBetaClient() {
|
public boolean isBetaClient() {
|
||||||
|
// Check if the server version is beta
|
||||||
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.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() {
|
public boolean supportClientBeta() {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version is beta
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the client version is beta
|
||||||
return isBetaClient() || yes;
|
return isBetaClient() || yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the connected client is a classic client.
|
||||||
|
* @return True if the client is classic, false otherwise.
|
||||||
|
*/
|
||||||
public boolean isClassicClient() {
|
public boolean isClassicClient() {
|
||||||
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.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() {
|
public boolean supportClientClassic() {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version is classic
|
||||||
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the client version is classic
|
||||||
return isClassicClient() || yes;
|
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) {
|
public boolean supportClientPacket(OACPacket packet) {
|
||||||
return supportClientVersion(packet.getProtocolVersion());
|
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) {
|
public boolean supportClientVersion(ProtocolVersion targetVersion) {
|
||||||
|
// Check if the client version matches the target version or is compatible
|
||||||
return getClientVersion() == targetVersion || getClientVersion().getCompatibleVersions().contains(targetVersion);
|
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) {
|
public boolean supportClientProtocol(ProtocolVersion.Protocol protocol) {
|
||||||
boolean yes = false;
|
boolean yes = false;
|
||||||
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
|
||||||
|
// Check if compatible version supports the protocol
|
||||||
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
|
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
|
||||||
if (yes) break;
|
if (yes) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the client version supports the protocol
|
||||||
return getClientVersion().getSupportedProtocols().contains(protocol) || yes;
|
return getClientVersion().getSupportedProtocols().contains(protocol) || yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives and processes requests from the client.
|
||||||
|
* Handles authentication, file serving, and PHP rendering.
|
||||||
|
*/
|
||||||
private void receive() {
|
private void receive() {
|
||||||
try {
|
try {
|
||||||
while (this.isConnected()) {
|
while (this.isConnected()) {
|
||||||
@@ -447,6 +676,9 @@ public final class ConnectedWebClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the response from a PHP script, including body and cookies.
|
||||||
|
*/
|
||||||
private static class PHPResponse {
|
private static class PHPResponse {
|
||||||
String body;
|
String body;
|
||||||
Map<String, String> cookies;
|
Map<String, String> cookies;
|
||||||
@@ -457,5 +689,4 @@ public final class ConnectedWebClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,43 +20,96 @@ import java.security.cert.CertificateException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the web server for the protocol.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
||||||
public class ProtocolWebServer {
|
public class ProtocolWebServer {
|
||||||
|
/**
|
||||||
|
* Folder for web content.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final File contentFolder;
|
private final File contentFolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Folder for error pages.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final File errorsFolder;
|
private final File errorsFolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure for server.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final ServerCertificateFolderStructure folderStructure;
|
private final ServerCertificateFolderStructure folderStructure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration manager for server settings.
|
||||||
|
*/
|
||||||
private final ConfigurationManager configurationManager;
|
private final ConfigurationManager configurationManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Certificate files for SSL.
|
||||||
|
*/
|
||||||
private final File certFile;
|
private final File certFile;
|
||||||
|
/**
|
||||||
|
* Certificate files for SSL.
|
||||||
|
*/
|
||||||
private final File keyFile;
|
private final File keyFile;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The network server handling pipeline connections.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private NetworkServer pipelineServer;
|
private NetworkServer pipelineServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SSL server socket for web connections.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private SSLServerSocket webServer;
|
private SSLServerSocket webServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of connected web clients.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private List<ConnectedWebClient> clients;
|
private List<ConnectedWebClient> clients;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) throws Exception {
|
public ProtocolWebServer(File configFile, File authFile, File rulesFile) throws Exception {
|
||||||
|
// Initialize the list of connected clients
|
||||||
this.clients = new ArrayList<>();
|
this.clients = new ArrayList<>();
|
||||||
|
|
||||||
|
// Set up folder structure for certificates
|
||||||
folderStructure = new ServerCertificateFolderStructure();
|
folderStructure = new ServerCertificateFolderStructure();
|
||||||
|
|
||||||
|
// Check for necessary certificate files
|
||||||
checkFileExists(folderStructure.publicServerFolder, folderStructure.certPrefix, ".crt");
|
checkFileExists(folderStructure.publicServerFolder, folderStructure.certPrefix, ".crt");
|
||||||
checkFileExists(folderStructure.privateServerFolder, folderStructure.certPrefix, ".key");
|
checkFileExists(folderStructure.privateServerFolder, folderStructure.certPrefix, ".key");
|
||||||
|
|
||||||
|
// Load configuration settings
|
||||||
this.configurationManager = getConfigurationManager(configFile);
|
this.configurationManager = getConfigurationManager(configFile);
|
||||||
|
|
||||||
|
// Set up content and error folders
|
||||||
contentFolder = new File("content");
|
contentFolder = new File("content");
|
||||||
errorsFolder = new File("errors");
|
errorsFolder = new File("errors");
|
||||||
|
|
||||||
|
// Create folders if they don't exist
|
||||||
if (!contentFolder.exists()) contentFolder.mkdir();
|
if (!contentFolder.exists()) contentFolder.mkdir();
|
||||||
if (!errorsFolder.exists()) errorsFolder.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.certFile = new File(folderStructure.publicServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".crt");
|
||||||
this.keyFile = new File(folderStructure.privateServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".key");
|
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()) {
|
if (!authFile.exists()) {
|
||||||
authFile.createNewFile();
|
authFile.createNewFile();
|
||||||
FileUtils.writeFile(authFile, """
|
FileUtils.writeFile(authFile, """
|
||||||
@@ -65,6 +118,7 @@ public class ProtocolWebServer {
|
|||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create default rules file if it doesn't exist
|
||||||
if (!rulesFile.exists()) {
|
if (!rulesFile.exists()) {
|
||||||
rulesFile.createNewFile();
|
rulesFile.createNewFile();
|
||||||
FileUtils.writeFile(rulesFile, """
|
FileUtils.writeFile(rulesFile, """
|
||||||
@@ -85,9 +139,11 @@ public class ProtocolWebServer {
|
|||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load authentication and rules
|
||||||
AuthManager.loadAuthFile(authFile);
|
AuthManager.loadAuthFile(authFile);
|
||||||
RuleManager.loadRules(rulesFile);
|
RuleManager.loadRules(rulesFile);
|
||||||
|
|
||||||
|
// Initialize the pipeline server
|
||||||
pipelineServer = new NetworkServer.ServerBuilder().
|
pipelineServer = new NetworkServer.ServerBuilder().
|
||||||
setPort(configurationManager.getInt("port.pipeline")).setTimeout(0).
|
setPort(configurationManager.getInt("port.pipeline")).setTimeout(0).
|
||||||
setPacketHandler(ProtocolBridge.getInstance().getProtocolSettings().packetHandler).setEventManager(ProtocolBridge.getInstance().getProtocolSettings().eventManager).
|
setPacketHandler(ProtocolBridge.getInstance().getProtocolSettings().packetHandler).setEventManager(ProtocolBridge.getInstance().getProtocolSettings().eventManager).
|
||||||
@@ -96,13 +152,26 @@ public class ProtocolWebServer {
|
|||||||
build();
|
build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a connected web client by its client ID.
|
||||||
|
* @param clientID The client ID to search for.
|
||||||
|
* @return The connected web client with the specified ID, or null if not found.
|
||||||
|
*/
|
||||||
public final ConnectedWebClient getClientByID(int clientID) {
|
public final ConnectedWebClient getClientByID(int clientID) {
|
||||||
for (ConnectedWebClient client : clients)
|
for (ConnectedWebClient client : clients)
|
||||||
if (client.getPipelineConnection().getClientID() == clientID) return client;
|
if (client.getPipelineConnection().getClientID() == clientID) return client;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the web server to accept and handle client connections.
|
||||||
|
* @throws Exception If an error occurs while starting the server.
|
||||||
|
*/
|
||||||
public final void startWebServer() throws Exception {
|
public final void startWebServer() throws Exception {
|
||||||
|
// Start the pipeline server
|
||||||
|
pipelineServer.start();
|
||||||
|
|
||||||
|
// Create the SSL server socket for web connections
|
||||||
webServer = (SSLServerSocket) NetworkServer.ServerBuilder.
|
webServer = (SSLServerSocket) NetworkServer.ServerBuilder.
|
||||||
createSSLServerSocketFactory(folderStructure.publicCAFolder, certFile, keyFile).
|
createSSLServerSocketFactory(folderStructure.publicCAFolder, certFile, keyFile).
|
||||||
createServerSocket(configurationManager.getInt("port"));
|
createServerSocket(configurationManager.getInt("port"));
|
||||||
@@ -112,8 +181,10 @@ public class ProtocolWebServer {
|
|||||||
// Stop WebServer if pipelineServer dies
|
// Stop WebServer if pipelineServer dies
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// Check if the pipeline server is still running
|
||||||
if (pipelineServer == null || !pipelineServer.getServerSocket().isBound()) {
|
if (pipelineServer == null || !pipelineServer.getServerSocket().isBound()) {
|
||||||
try {
|
try {
|
||||||
|
// Stop the web server
|
||||||
onPipelineStop();
|
onPipelineStop();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
pipelineServer.getLogger().exception("Failed to stop WebServer", e);
|
pipelineServer.getLogger().exception("Failed to stop WebServer", e);
|
||||||
@@ -122,6 +193,11 @@ public class ProtocolWebServer {
|
|||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Sleep for a while before checking again
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException ignored) {}
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
@@ -129,40 +205,68 @@ public class ProtocolWebServer {
|
|||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
|
// Accept incoming client connections
|
||||||
SSLSocket client = (SSLSocket) webServer.accept();
|
SSLSocket client = (SSLSocket) webServer.accept();
|
||||||
|
|
||||||
for (ConnectedWebClient connectedWebClient : clients) {
|
for (ConnectedWebClient connectedWebClient : clients) {
|
||||||
if (connectedWebClient.getPipelineConnection().getClientID() != -1 && connectedWebClient.isClientVersionLoaded()) {
|
if (connectedWebClient.getPipelineConnection().getClientID() != -1 && connectedWebClient.isClientVersionLoaded()) {
|
||||||
|
// Assign socket to an existing connected client
|
||||||
connectedWebClient.setWebSocket(client);
|
connectedWebClient.setWebSocket(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
pipelineServer.getLogger().exception("Failed to accept WebClient", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
}).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 {
|
private void onPipelineStop() throws IOException {
|
||||||
webServer.close();
|
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 {
|
private void checkFileExists(File folder, String prefix, String extension) throws CertificateException, IOException {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
|
|
||||||
|
// Ensure the folder exists
|
||||||
if (folder == null) throw new FileNotFoundException("Folder does not exist");
|
if (folder == null) throw new FileNotFoundException("Folder does not exist");
|
||||||
|
|
||||||
|
// List all files in the folder
|
||||||
File[] files = folder.listFiles();
|
File[] files = folder.listFiles();
|
||||||
if (files == null || files.length == 0)
|
if (files == null || files.length == 0)
|
||||||
throw new FileNotFoundException("Folder " + folder.getAbsolutePath() + " is empty");
|
throw new FileNotFoundException("Folder " + folder.getAbsolutePath() + " is empty");
|
||||||
|
|
||||||
|
// Check for the required certificate file
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
if (!file.getName().startsWith(prefix) || !file.getName().endsWith(extension))
|
if (!file.getName().startsWith(prefix) || !file.getName().endsWith(extension))
|
||||||
throw new CertificateException(file.getAbsolutePath() + " is not valid");
|
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);
|
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);
|
if (!found) throw new CertificateException("Missing " + prefix + NetworkUtils.getPublicIPAddress() + extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
private ConfigurationManager getConfigurationManager(File configFile) throws IOException {
|
||||||
if (!configFile.exists()) configFile.createNewFile();
|
if (!configFile.exists()) configFile.createNewFile();
|
||||||
|
|
||||||
@@ -192,6 +296,9 @@ public class ProtocolWebServer {
|
|||||||
return configurationManager;
|
return configurationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the folder structure for server certificates.
|
||||||
|
*/
|
||||||
public final class ServerCertificateFolderStructure {
|
public final class ServerCertificateFolderStructure {
|
||||||
public final File certificatesFolder;
|
public final File certificatesFolder;
|
||||||
|
|
||||||
|
@@ -6,9 +6,15 @@ import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
|||||||
import org.openautonomousconnection.protocol.side.web.ConnectedWebClient;
|
import org.openautonomousconnection.protocol.side.web.ConnectedWebClient;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event triggered when a web client connects to the web server.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
||||||
public final class ConnectedWebClientEvent extends Event {
|
public final class ConnectedWebClientEvent extends Event {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connected web client.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final ConnectedWebClient webClient;
|
private final ConnectedWebClient webClient;
|
||||||
|
|
||||||
|
@@ -11,16 +11,34 @@ import java.security.MessageDigest;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages authentication for web clients.
|
||||||
|
* Loads user credentials from a file and verifies login attempts.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
||||||
public class AuthManager {
|
public class AuthManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of usernames to their SHA-256 hashed passwords
|
||||||
|
*/
|
||||||
private static final Map<String, String> users = new HashMap<>();
|
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 {
|
public static void loadAuthFile(File authFile) throws IOException {
|
||||||
|
// Create the file if it doesn't exist
|
||||||
if (!authFile.exists()) authFile.createNewFile();
|
if (!authFile.exists()) authFile.createNewFile();
|
||||||
for (String line : Files.readAllLines(authFile.toPath(), StandardCharsets.UTF_8)) {
|
for (String line : Files.readAllLines(authFile.toPath(), StandardCharsets.UTF_8)) {
|
||||||
|
// Trim whitespace and ignore comments/empty lines
|
||||||
line = line.trim();
|
line = line.trim();
|
||||||
if (line.isEmpty() || line.startsWith("#")) continue;
|
if (line.isEmpty() || line.startsWith("#")) continue;
|
||||||
|
|
||||||
|
// Split the line into username and hashed password
|
||||||
String[] parts = line.split(":", 2);
|
String[] parts = line.split(":", 2);
|
||||||
if (parts.length == 2) {
|
if (parts.length == 2) {
|
||||||
users.put(parts[0], parts[1]);
|
users.put(parts[0], parts[1]);
|
||||||
@@ -28,19 +46,33 @@ public class AuthManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
public static boolean checkAuth(String login, String password) {
|
||||||
|
// Retrieve the stored hashed password for the given username
|
||||||
String storedHash = users.get(login);
|
String storedHash = users.get(login);
|
||||||
if (storedHash == null) return false;
|
if (storedHash == null) return false;
|
||||||
|
|
||||||
|
// Hash the provided password and compare it to the stored hash
|
||||||
String hash = sha256(password);
|
String hash = sha256(password);
|
||||||
return storedHash.equalsIgnoreCase(hash);
|
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.
|
||||||
|
*/
|
||||||
private static String sha256(String input) {
|
private static String sha256(String input) {
|
||||||
try {
|
try {
|
||||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||||
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
// Convert the byte array to a hexadecimal string
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (byte b : digest) sb.append(String.format("%02x", b));
|
for (byte b : digest) sb.append(String.format("%02x", b));
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
|
@@ -10,33 +10,79 @@ import java.nio.file.Files;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
||||||
public class RuleManager {
|
public class RuleManager {
|
||||||
|
/**
|
||||||
|
* Lists of path patterns for allow, deny, and auth rules
|
||||||
|
*/
|
||||||
private static List<String> allow;
|
private static List<String> allow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists of path patterns for allow, deny, and auth rules
|
||||||
|
*/
|
||||||
private static List<String> deny;
|
private static List<String> deny;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists of path patterns for allow, deny, and auth rules
|
||||||
|
*/
|
||||||
private static List<String> auth;
|
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 {
|
public static void loadRules(File rulesFile) throws Exception {
|
||||||
|
// Load and parse the JSON file
|
||||||
String json = new String(Files.readAllBytes(rulesFile.toPath()));
|
String json = new String(Files.readAllBytes(rulesFile.toPath()));
|
||||||
Map<String, List<String>> map = new Gson().fromJson(json, new TypeToken<Map<String, List<String>>>() {
|
Map<String, List<String>> map = new Gson().fromJson(json, new TypeToken<Map<String, List<String>>>() {}.getType());
|
||||||
}.getType());
|
|
||||||
|
// Default to empty lists if keys are missing
|
||||||
allow = map.getOrDefault("allow", List.of());
|
allow = map.getOrDefault("allow", List.of());
|
||||||
deny = map.getOrDefault("deny", List.of());
|
deny = map.getOrDefault("deny", List.of());
|
||||||
auth = map.getOrDefault("auth", 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) {
|
public static boolean isAllowed(String path) {
|
||||||
return allow.stream().anyMatch(p -> pathMatches(path, p));
|
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) {
|
public static boolean isDenied(String path) {
|
||||||
return deny.stream().anyMatch(p -> pathMatches(path, p));
|
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) {
|
public static boolean requiresAuth(String path) {
|
||||||
return auth.stream().anyMatch(p -> pathMatches(path, p));
|
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) {
|
private static boolean pathMatches(String path, String pattern) {
|
||||||
pattern = pattern.replace("/", File.separator).replace("*", ".*");
|
pattern = pattern.replace("/", File.separator).replace("*", ".*");
|
||||||
return path.matches(pattern);
|
return path.matches(pattern);
|
||||||
|
@@ -10,49 +10,106 @@ import java.util.Base64;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages user sessions for web clients.
|
||||||
|
* Provides methods to create, validate, and invalidate sessions.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
||||||
public class SessionManager {
|
public class SessionManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of session IDs to Session objects.
|
||||||
|
*/
|
||||||
private static final Map<String, Session> sessions = new ConcurrentHashMap<>();
|
private static final Map<String, Session> sessions = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Secure random number generator for session ID creation.
|
||||||
|
*/
|
||||||
private static final SecureRandom secureRandom = new SecureRandom();
|
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.
|
||||||
|
* @return The generated session ID.
|
||||||
|
* @throws IOException If an I/O error occurs.
|
||||||
|
*/
|
||||||
public static String create(String login, String ip, String userAgent) throws IOException {
|
public static String create(String login, String ip, String userAgent) throws IOException {
|
||||||
|
// Generate a secure random session ID
|
||||||
byte[] bytes = new byte[32];
|
byte[] bytes = new byte[32];
|
||||||
secureRandom.nextBytes(bytes);
|
secureRandom.nextBytes(bytes);
|
||||||
|
|
||||||
|
// Encode the bytes to a URL-safe Base64 string
|
||||||
String sessionId = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
|
String sessionId = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
|
||||||
|
|
||||||
|
// Create and store the new session
|
||||||
sessions.put(sessionId, new Session(login, ip, userAgent));
|
sessions.put(sessionId, new Session(login, ip, userAgent));
|
||||||
return sessionId;
|
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.
|
||||||
|
* @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) throws IOException {
|
public static boolean isValid(String sessionId, String ip, String userAgent) throws IOException {
|
||||||
|
// Retrieve the session associated with the session ID
|
||||||
Session session = sessions.get(sessionId);
|
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)) {
|
if (session == null || session.isExpired() || !session.matches(ip, userAgent)) {
|
||||||
sessions.remove(sessionId);
|
sessions.remove(sessionId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refresh the session expiration time
|
||||||
session.refresh();
|
session.refresh();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates a session, removing it from the active sessions.
|
||||||
|
* @param sessionId The session ID to invalidate.
|
||||||
|
*/
|
||||||
public static void invalidate(String sessionId) {
|
public static void invalidate(String sessionId) {
|
||||||
sessions.remove(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) {
|
public static String getUser(String sessionId) {
|
||||||
|
// Retrieve the session associated with the session ID
|
||||||
Session session = sessions.get(sessionId);
|
Session session = sessions.get(sessionId);
|
||||||
|
|
||||||
|
// Check if the session exists and is not expired
|
||||||
if (session == null || session.isExpired()) {
|
if (session == null || session.isExpired()) {
|
||||||
sessions.remove(sessionId);
|
sessions.remove(sessionId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the username associated with the session
|
||||||
return session.getLogin();
|
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() {
|
public static void cleanupExpiredSessions() {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
sessions.entrySet().removeIf(entry -> entry.getValue().isExpired());
|
sessions.entrySet().removeIf(entry -> entry.getValue().isExpired());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a user session with associated metadata.
|
||||||
|
*/
|
||||||
private static class Session {
|
private static class Session {
|
||||||
@Getter
|
@Getter
|
||||||
String login;
|
String login;
|
||||||
@@ -67,14 +124,28 @@ public class SessionManager {
|
|||||||
this.expiresAt = System.currentTimeMillis() + Main.getConfigurationManager().getInt("sessionexpireminutes") * 60 * 1000;
|
this.expiresAt = System.currentTimeMillis() + Main.getConfigurationManager().getInt("sessionexpireminutes") * 60 * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the session has expired.
|
||||||
|
* @return True if the session is expired, false otherwise.
|
||||||
|
*/
|
||||||
boolean isExpired() {
|
boolean isExpired() {
|
||||||
return System.currentTimeMillis() > expiresAt;
|
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) {
|
boolean matches(String ip, String userAgent) {
|
||||||
return this.ip.equals(ip) && this.userAgent.equals(userAgent);
|
return this.ip.equals(ip) && this.userAgent.equals(userAgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes the session's expiration time.
|
||||||
|
* @throws IOException If an I/O error occurs.
|
||||||
|
*/
|
||||||
void refresh() throws IOException {
|
void refresh() throws IOException {
|
||||||
this.expiresAt = System.currentTimeMillis() + Main.getConfigurationManager().getInt("sessionexpireminutes") * 60 * 1000;
|
this.expiresAt = System.currentTimeMillis() + Main.getConfigurationManager().getInt("sessionexpireminutes") * 60 * 1000;
|
||||||
}
|
}
|
||||||
|
@@ -7,21 +7,59 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing different protocol versions, their types, sides, and compatibility.
|
||||||
|
*/
|
||||||
public enum ProtocolVersion implements Serializable {
|
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_DNS, List.of(Protocol.HTTP)),
|
PV_1_0_0_CLASSIC("1.0.0", ProtocolType.CLASSIC, ProtocolSide.WEB_DNS, 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), PV_1_0_0_CLASSIC);
|
PV_1_0_0_BETA("1.0.0", ProtocolType.BETA, ProtocolSide.ALL, List.of(Protocol.OAC), PV_1_0_0_CLASSIC);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version string of the protocol version.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final String version;
|
private final String version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the protocol version.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final ProtocolType protocolType;
|
private final ProtocolType protocolType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The side(s) the protocol version is intended for.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final ProtocolSide protocolSide;
|
private final ProtocolSide protocolSide;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of protocol versions that are compatible with this version.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final List<ProtocolVersion> compatibleVersions;
|
private final List<ProtocolVersion> compatibleVersions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of supported protocols.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final List<Protocol> supportedProtocols;
|
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) {
|
ProtocolVersion(String version, ProtocolType protocolType, ProtocolSide protocolSide, List<Protocol> supportedProtocols, ProtocolVersion... compatibleVersions) {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.protocolType = protocolType;
|
this.protocolType = protocolType;
|
||||||
@@ -31,57 +69,123 @@ public enum ProtocolVersion implements Serializable {
|
|||||||
this.supportedProtocols = supportedProtocols;
|
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
|
@Override
|
||||||
public final String toString() {
|
public final String toString() {
|
||||||
StringBuilder compatible = new StringBuilder("[");
|
StringBuilder compatible = new StringBuilder("[");
|
||||||
StringBuilder supported = new StringBuilder("[");
|
StringBuilder supported = new StringBuilder("[");
|
||||||
|
|
||||||
for (ProtocolVersion compatibleVersion : compatibleVersions) compatible.append(compatibleVersion.buildName());
|
for (ProtocolVersion compatibleVersion : compatibleVersions) compatible.append(compatibleVersion.buildName());
|
||||||
for (Protocol supportedProtocol : supportedProtocols) supported.append(supportedProtocol.toString());
|
for (Protocol supportedProtocol : supportedProtocols) supported.append(supportedProtocol.toString());
|
||||||
|
|
||||||
compatible.append("]");
|
compatible.append("]");
|
||||||
supported.append("]");
|
supported.append("]");
|
||||||
|
|
||||||
return "{version=" + version + ";type=" + protocolType.toString() + ";side=" + protocolSide.toString() + ";supportedProtocols=" + supported + ";compatibleVersions=" + compatible + "}";
|
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() {
|
public final String buildName() {
|
||||||
return version + "-" + protocolType.toString();
|
return version + "-" + protocolType.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing different protocols.
|
||||||
|
*/
|
||||||
public enum Protocol implements Serializable {
|
public enum Protocol implements Serializable {
|
||||||
HTTP,
|
HTTP,
|
||||||
HTTPS,
|
HTTPS,
|
||||||
OAC;
|
OAC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the protocol in uppercase.
|
||||||
|
* @return the name of the protocol in uppercase.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final String toString() {
|
public final String toString() {
|
||||||
return name().toUpperCase();
|
return name().toUpperCase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing different types of protocol versions.
|
||||||
|
*/
|
||||||
public enum ProtocolType implements Serializable {
|
public enum ProtocolType implements Serializable {
|
||||||
CLASSIC, // -> See "_old" Projects https://repo.open-autonomous-connection.org/Open-Autonomous-Connection/
|
/**
|
||||||
|
* 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,
|
BETA,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stable Protocol Type, recommended for production use.
|
||||||
|
*/
|
||||||
STABLE;
|
STABLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the protocol in uppercase.
|
||||||
|
* @return the name of the protocol in uppercase.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final String toString() {
|
public final String toString() {
|
||||||
return name().toUpperCase();
|
return name().toUpperCase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing different sides where the protocol version can be used.
|
||||||
|
*/
|
||||||
public enum ProtocolSide implements Serializable {
|
public enum ProtocolSide implements Serializable {
|
||||||
|
/**
|
||||||
|
* Client Side only
|
||||||
|
*/
|
||||||
CLIENT, // Protocol version can only used on Client
|
CLIENT, // Protocol version can only used on Client
|
||||||
DNS, // Protocol version can only used on DNS Server
|
|
||||||
WEB, // Protocol version can only used on Web Server
|
|
||||||
|
|
||||||
WEB_DNS, // Protocol version can only used on DNS and WebSerber
|
/**
|
||||||
|
* DNS Server Side only
|
||||||
|
*/
|
||||||
|
DNS,
|
||||||
|
|
||||||
CLIENT_DNS, // Protocol version can only used on DNS and Client
|
/**
|
||||||
CLIENT_WEB, // Protocol version can only used on WebServer and Client
|
* Web Server Side only
|
||||||
|
*/
|
||||||
|
WEB,
|
||||||
|
|
||||||
ALL // Protocol version can used on all Sides
|
/**
|
||||||
|
* Both DNS and Web Server Side
|
||||||
|
*/
|
||||||
|
WEB_DNS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Both Client and DNS Server Side
|
||||||
|
*/
|
||||||
|
CLIENT_DNS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
@Override
|
||||||
public final String toString() {
|
public final String toString() {
|
||||||
return name().toUpperCase();
|
return name().toUpperCase();
|
||||||
|
@@ -4,42 +4,79 @@ import lombok.Getter;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing various DNS response codes and their descriptions.
|
||||||
|
*/
|
||||||
public enum DNSResponseCode implements Serializable {
|
public enum DNSResponseCode implements Serializable {
|
||||||
|
/**
|
||||||
|
* General Responses
|
||||||
|
*/
|
||||||
RESPONSE_NOT_REQUIRED(0, "Response code not required"),
|
RESPONSE_NOT_REQUIRED(0, "Response code not required"),
|
||||||
RESPONSE_INVALID_REQUEST(1, "Invalid request"),
|
RESPONSE_INVALID_REQUEST(1, "Invalid request"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication Responses
|
||||||
|
*/
|
||||||
RESPONSE_AUTH_SUCCESS(4, "Auth success"),
|
RESPONSE_AUTH_SUCCESS(4, "Auth success"),
|
||||||
RESPONSE_AUTH_FAILED(5, "Auth failed"),
|
RESPONSE_AUTH_FAILED(5, "Auth failed"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domain Responses
|
||||||
|
*/
|
||||||
RESPONSE_DOMAIN_NAME_EXIST(100, "Domainname exist"),
|
RESPONSE_DOMAIN_NAME_EXIST(100, "Domainname exist"),
|
||||||
RESPONSE_DOMAIN_NAME_NOT_EXIST(101, "Domainname does not exist"),
|
RESPONSE_DOMAIN_NAME_NOT_EXIST(101, "Domainname does not exist"),
|
||||||
RESPONSE_DOMAIN_NAME_CREATED(105, "Domainname created"),
|
RESPONSE_DOMAIN_NAME_CREATED(105, "Domainname created"),
|
||||||
RESPONSE_DOMAIN_NAME_DELETED(106, "Domainname deleted"),
|
RESPONSE_DOMAIN_NAME_DELETED(106, "Domainname deleted"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Top Level Name Responses
|
||||||
|
*/
|
||||||
RESPONSE_DOMAIN_TLN_EXIST(110, "TopLevelName exist"),
|
RESPONSE_DOMAIN_TLN_EXIST(110, "TopLevelName exist"),
|
||||||
RESPONSE_DOMAIN_TLN_NOT_EXIST(111, "TopLevelName does not exist"),
|
RESPONSE_DOMAIN_TLN_NOT_EXIST(111, "TopLevelName does not exist"),
|
||||||
RESPONSE_DOMAIN_TLN_CREATED(115, "TopLevelName created"),
|
RESPONSE_DOMAIN_TLN_CREATED(115, "TopLevelName created"),
|
||||||
RESPONSE_DOMAIN_TLN_DELETED(116, "TopLevelName deleted"),
|
RESPONSE_DOMAIN_TLN_DELETED(116, "TopLevelName deleted"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subname Responses
|
||||||
|
*/
|
||||||
RESPONSE_DOMAIN_SUBNAME_EXIST(120, "Subname exist"),
|
RESPONSE_DOMAIN_SUBNAME_EXIST(120, "Subname exist"),
|
||||||
RESPONSE_DOMAIN_SUBNAME_NOT_EXIST(121, "Subname does not exist"),
|
RESPONSE_DOMAIN_SUBNAME_NOT_EXIST(121, "Subname does not exist"),
|
||||||
RESPONSE_DOMAIN_SUBNAME_CREATED(125, "Subname created"),
|
RESPONSE_DOMAIN_SUBNAME_CREATED(125, "Subname created"),
|
||||||
RESPONSE_DOMAIN_SUBNAME_DELETED(126, "Subname deleted"),
|
RESPONSE_DOMAIN_SUBNAME_DELETED(126, "Subname deleted"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full Domain Responses
|
||||||
|
*/
|
||||||
RESPONSE_DOMAIN_FULLY_EXIST(130, "Full domain exist"),
|
RESPONSE_DOMAIN_FULLY_EXIST(130, "Full domain exist"),
|
||||||
RESPONSE_DOMAIN_FULLY_NOT_EXIST(131, "Full domain does not exist");
|
RESPONSE_DOMAIN_FULLY_NOT_EXIST(131, "Full domain does not exist");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The numeric code representing the DNS response.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final int code;
|
private final int code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A brief description of the DNS response code.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final String description;
|
private final String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for DNSResponseCode enum.
|
||||||
|
*
|
||||||
|
* @param code The numeric code of the response.
|
||||||
|
* @param description A brief description of the response.
|
||||||
|
*/
|
||||||
DNSResponseCode(int code, String description) {
|
DNSResponseCode(int code, String description) {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the DNS response code, including its code and description.
|
||||||
|
* @return a string representation of the DNS response code.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "{code=" + code + ";description=" + description + "}";
|
return "{code=" + code + ";description=" + description + "}";
|
||||||
|
@@ -9,22 +9,58 @@ import java.io.Serializable;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing a domain with its components such as subname, name, top-level name, path, query, fragment, and protocol.
|
||||||
|
*/
|
||||||
public class Domain implements Serializable {
|
public class Domain implements Serializable {
|
||||||
|
/**
|
||||||
|
* The subname of the domain (e.g., "sub" in "sub.example.com").
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final String subname;
|
private final String subname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main name of the domain (e.g., "example" in "sub.example.com").
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The top-level name of the domain (e.g., "com" in "sub.example.com").
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final String topLevelName;
|
private final String topLevelName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path component of the domain (e.g., "path/to/resource" in "example.com/path/to/resource").
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The query component of the domain (e.g., "key=value" in "example.com/path?key=value").
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private String query;
|
private String query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fragment component of the domain (e.g., "section1" in "example.com/path#section1").
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private String fragment;
|
private String fragment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The protocol of the domain (e.g., "oac" in "oac://example.com").
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private String protocol;
|
private String protocol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Domain object by parsing the provided full domain string.
|
||||||
|
*
|
||||||
|
* @param fullDomain The full domain string to parse.
|
||||||
|
* @throws IllegalArgumentException if the domain is invalid.
|
||||||
|
*/
|
||||||
public Domain(String fullDomain) {
|
public Domain(String fullDomain) {
|
||||||
// Remove protocol
|
// Remove protocol
|
||||||
String domainWithPath = fullDomain.contains("://") ? fullDomain.split("://", 2)[1] : fullDomain;
|
String domainWithPath = fullDomain.contains("://") ? fullDomain.split("://", 2)[1] : fullDomain;
|
||||||
@@ -34,17 +70,21 @@ public class Domain implements Serializable {
|
|||||||
|
|
||||||
// Cut path
|
// Cut path
|
||||||
String[] domainPartsAndPath = domainWithPath.split("/", 2);
|
String[] domainPartsAndPath = domainWithPath.split("/", 2);
|
||||||
String host = domainPartsAndPath[0]; // z.B. hello.world.com
|
|
||||||
|
// Get host and full path
|
||||||
|
String host = domainPartsAndPath[0];
|
||||||
String fullPath = domainPartsAndPath.length > 1 ? "/" + domainPartsAndPath[1] : "";
|
String fullPath = domainPartsAndPath.length > 1 ? "/" + domainPartsAndPath[1] : "";
|
||||||
|
|
||||||
// Split domain in labels
|
// Split domain in labels
|
||||||
List<String> labels = Arrays.asList(host.split("\\."));
|
List<String> labels = Arrays.asList(host.split("\\."));
|
||||||
if (labels.size() < 2) throw new IllegalArgumentException("Invalid domain: " + host);
|
if (labels.size() < 2) throw new IllegalArgumentException("Invalid domain: " + host);
|
||||||
|
|
||||||
|
// Get subname, name and top-level name
|
||||||
this.topLevelName = labels.getLast();
|
this.topLevelName = labels.getLast();
|
||||||
this.name = labels.get(labels.size() - 2);
|
this.name = labels.get(labels.size() - 2);
|
||||||
this.subname = labels.size() > 2 ? String.join(".", labels.subList(0, labels.size() - 2)) : null;
|
this.subname = labels.size() > 2 ? String.join(".", labels.subList(0, labels.size() - 2)) : null;
|
||||||
|
|
||||||
|
// Split fragment
|
||||||
if (fullPath.contains("#")) {
|
if (fullPath.contains("#")) {
|
||||||
this.fragment = "#" + Arrays.stream(fullPath.split("#")).toList().getLast();
|
this.fragment = "#" + Arrays.stream(fullPath.split("#")).toList().getLast();
|
||||||
fullPath = fullPath.substring(0, fullPath.length() - ("#" + fragment).length());
|
fullPath = fullPath.substring(0, fullPath.length() - ("#" + fragment).length());
|
||||||
@@ -60,6 +100,7 @@ public class Domain implements Serializable {
|
|||||||
this.query = "";
|
this.query = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up path, query and fragment
|
||||||
if (this.path.startsWith("/")) this.path = this.path.substring(1);
|
if (this.path.startsWith("/")) this.path = this.path.substring(1);
|
||||||
if (this.path.endsWith("/")) this.path = this.path.substring(0, this.path.length() - 1);
|
if (this.path.endsWith("/")) this.path = this.path.substring(0, this.path.length() - 1);
|
||||||
|
|
||||||
@@ -67,23 +108,41 @@ public class Domain implements Serializable {
|
|||||||
if (this.fragment.startsWith("#")) this.fragment = this.fragment.substring(1);
|
if (this.fragment.startsWith("#")) this.fragment = this.fragment.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the domain has a subname.
|
||||||
|
* @return true if the domain has a subname, false otherwise.
|
||||||
|
*/
|
||||||
public final boolean hasSubname() {
|
public final boolean hasSubname() {
|
||||||
return subname != null;
|
return subname != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this domain is equal to another object.
|
||||||
|
* Two domains are considered equal if their subname, name, top-level name, and protocol are equal (case-insensitive).
|
||||||
|
* @return true if the domains are equal, false otherwise.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final boolean equals(Object obj) {
|
public final boolean equals(Object obj) {
|
||||||
|
// Check if the object is an instance of Domain
|
||||||
if (!(obj instanceof Domain domain)) return false;
|
if (!(obj instanceof Domain domain)) return false;
|
||||||
|
|
||||||
|
// Compare subname, name, top-level name, and protocol (case-insensitive)
|
||||||
return domain.getSubname().equalsIgnoreCase(this.subname) && domain.getName().equalsIgnoreCase(this.name) &&
|
return domain.getSubname().equalsIgnoreCase(this.subname) && domain.getName().equalsIgnoreCase(this.name) &&
|
||||||
domain.getTopLevelName().equalsIgnoreCase(this.topLevelName) && domain.getProtocol().equalsIgnoreCase(this.protocol);
|
domain.getTopLevelName().equalsIgnoreCase(this.topLevelName) && domain.getProtocol().equalsIgnoreCase(this.protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the destination associated with this domain.
|
||||||
|
* The destination is determined based on the domain's components and the current protocol context.
|
||||||
|
* @return the destination as a string.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
||||||
public final String getDestination() {
|
public final String getDestination() {
|
||||||
|
// If running as client or web server, return invalid request
|
||||||
if (ProtocolBridge.getInstance().isRunningAsClient() || ProtocolBridge.getInstance().isRunningAsWebServer())
|
if (ProtocolBridge.getInstance().isRunningAsClient() || ProtocolBridge.getInstance().isRunningAsWebServer())
|
||||||
return DNSResponseCode.RESPONSE_INVALID_REQUEST.toString();
|
return DNSResponseCode.RESPONSE_INVALID_REQUEST.toString();
|
||||||
|
|
||||||
|
// Handle special default domains
|
||||||
if (this.equals(DefaultDomains.DNS_INFO_SITE))
|
if (this.equals(DefaultDomains.DNS_INFO_SITE))
|
||||||
return ProtocolBridge.getInstance().getProtocolDNSServer().getDNSInfoSite();
|
return ProtocolBridge.getInstance().getProtocolDNSServer().getDNSInfoSite();
|
||||||
if (this.equals(DefaultDomains.DNS_REGISTER_SITE))
|
if (this.equals(DefaultDomains.DNS_REGISTER_SITE))
|
||||||
@@ -91,9 +150,14 @@ public class Domain implements Serializable {
|
|||||||
if (this.name.equalsIgnoreCase("about") && this.protocol.equalsIgnoreCase("oac"))
|
if (this.name.equalsIgnoreCase("about") && this.protocol.equalsIgnoreCase("oac"))
|
||||||
return ProtocolBridge.getInstance().getProtocolDNSServer().getTLNInfoSite(topLevelName);
|
return ProtocolBridge.getInstance().getProtocolDNSServer().getTLNInfoSite(topLevelName);
|
||||||
|
|
||||||
|
// Return destination based on whether subname exists
|
||||||
return !hasSubname() ? ProtocolBridge.getInstance().getProtocolDNSServer().getDomainDestination(this) : ProtocolBridge.getInstance().getProtocolDNSServer().getSubnameDestination(this, subname);
|
return !hasSubname() ? ProtocolBridge.getInstance().getProtocolDNSServer().getDomainDestination(this) : ProtocolBridge.getInstance().getProtocolDNSServer().getSubnameDestination(this, subname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the domain, including its protocol, subname, name, top-level name, path, query, and fragment.
|
||||||
|
* @return a string representation of the domain.
|
||||||
|
*/
|
||||||
public static class DefaultDomains {
|
public static class DefaultDomains {
|
||||||
public static final Domain DNS_INFO_SITE = new Domain("oac://about.oac/");
|
public static final Domain DNS_INFO_SITE = new Domain("oac://about.oac/");
|
||||||
public static final Domain DNS_REGISTER_SITE = new Domain("oac://register.oac/");
|
public static final Domain DNS_REGISTER_SITE = new Domain("oac://register.oac/");
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
enum Classic_SiteType implements Serializable {
|
|
||||||
CLIENT("oac-client"), SERVER("oac-server"),
|
|
||||||
PUBLIC("oac"), PROTOCOL("oac-protocol"), LOCAL("oac-local");
|
|
||||||
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
Classic_SiteType(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,7 +1,19 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.events;
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||||
|
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.utils.Classic_ProtocolVersion;
|
||||||
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerDNSServer
|
||||||
|
* @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 class Classic_DomainPacketReceivedEvent extends Event {
|
public class Classic_DomainPacketReceivedEvent extends Event {
|
||||||
|
|
||||||
public final Classic_ProtocolVersion protocolVersion;
|
public final Classic_ProtocolVersion protocolVersion;
|
@@ -1,9 +1,19 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.events;
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||||
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
||||||
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
||||||
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerDNSServer
|
||||||
|
* @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 class Classic_PingPacketReceivedEvent extends Event {
|
public class Classic_PingPacketReceivedEvent extends Event {
|
||||||
|
|
||||||
public final Classic_ProtocolVersion protocolVersion;
|
public final Classic_ProtocolVersion protocolVersion;
|
||||||
public final Classic_Domain domain;
|
public final Classic_Domain domain;
|
||||||
public final Classic_RequestDomain requestDomain;
|
public final Classic_RequestDomain requestDomain;
|
@@ -1,13 +1,18 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers;
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.classic.Classic_MessagePacket;
|
import org.openautonomousconnection.protocol.packets.v1_0_0.classic.Classic_MessagePacket;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
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.site.Classic_SiteType;
|
||||||
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class defining the client-side handler for Classic protocol operations.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
|
||||||
public abstract class ClassicHandlerClient {
|
public abstract class ClassicHandlerClient {
|
||||||
|
|
@@ -1,11 +1,17 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers;
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
||||||
import org.openautonomousconnection.protocol.side.dns.ConnectedProtocolClient;
|
import org.openautonomousconnection.protocol.side.dns.ConnectedProtocolClient;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
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.utils.Classic_ProtocolVersion;
|
||||||
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class defining the DNS server-side handler for Classic protocol operations.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.DNS)
|
||||||
public abstract class ClassicHandlerDNSServer {
|
public abstract class ClassicHandlerDNSServer {
|
||||||
public abstract void handleMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion);
|
public abstract void handleMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion);
|
@@ -1,11 +1,13 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers;
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
||||||
import org.openautonomousconnection.protocol.side.dns.ConnectedProtocolClient;
|
import org.openautonomousconnection.protocol.side.dns.ConnectedProtocolClient;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
/**
|
||||||
|
* Abstract class defining the web server-side handler for Classic protocol operations.
|
||||||
|
*/
|
||||||
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
|
||||||
public abstract class ClassicHandlerWebServer {
|
public abstract class ClassicHandlerWebServer {
|
||||||
public abstract void handleMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion);
|
public abstract void handleMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion);
|
@@ -1,15 +1,46 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.Domain;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.Domain;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classic_Domain is an old representation of a domain, maintained for backward compatibility.
|
||||||
|
* It encapsulates the domain's name, top-level domain, path, and destination.
|
||||||
|
* This class is deprecated and users are encouraged to use the Domain class instead.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
||||||
public class Classic_Domain implements Serializable {
|
public class Classic_Domain implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the domain (e.g., "example" in "example.com").
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3 | Will be replaced with a getter")
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The top-level domain (e.g., "com" in "example.com").
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3 | Will be replaced with a getter")
|
||||||
public final String topLevelDomain;
|
public final String topLevelDomain;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path component of the domain (e.g., "/path/to/resource" in "example.com/path/to/resource").
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3 | Will be replaced with a getter")
|
||||||
public final String path;
|
public final String path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The destination of the domain, typically the full URL or address.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3 | Will be replaced with a getter")
|
||||||
private final String destination;
|
private final String destination;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encapsulated Domain object for modern usage.
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final Domain domain;
|
private final Domain domain;
|
||||||
|
|
@@ -1,5 +1,10 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 class Classic_LocalDomain extends Classic_Domain {
|
public class Classic_LocalDomain extends Classic_Domain {
|
||||||
public Classic_LocalDomain(String name, String endName, String path) {
|
public Classic_LocalDomain(String name, String endName, String path) {
|
||||||
super(name, endName, null, path);
|
super(name, endName, null, path);
|
@@ -1,7 +1,12 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects;
|
||||||
|
|
||||||
import java.io.Serializable;
|
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 class Classic_RequestDomain extends Classic_Domain implements Serializable {
|
public class Classic_RequestDomain extends Classic_Domain implements Serializable {
|
||||||
|
|
||||||
public Classic_RequestDomain(String name, String topLevelDomain, String path) {
|
public Classic_RequestDomain(String name, String topLevelDomain, String path) {
|
@@ -0,0 +1,44 @@
|
|||||||
|
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"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DNS 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 | Will be replaced with a getter")
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
Classic_SiteType(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,11 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.site;
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
import dev.unlegitdqrk.unlegitlibrary.utils.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 class Classic_WebsitesContent extends DefaultMethodsOverrider {
|
public class Classic_WebsitesContent extends DefaultMethodsOverrider {
|
||||||
|
|
||||||
public static final String DOMAIN_NOT_FOUND = """
|
public static final String DOMAIN_NOT_FOUND = """
|
@@ -1,23 +1,51 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils;
|
||||||
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.Domain;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.Domain;
|
||||||
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for converting between Classic protocol objects and new protocol objects.
|
||||||
|
*/
|
||||||
public class ClassicConverter {
|
public class ClassicConverter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Classic_Domain object to a Domain object.
|
||||||
|
* @param classicDomain the Classic_Domain object to convert
|
||||||
|
* @return the converted Domain object
|
||||||
|
*/
|
||||||
|
@SuppressWarnings(value = "deprecation")
|
||||||
public static Domain classicDomainToNewDomain(Classic_Domain classicDomain) {
|
public static Domain classicDomainToNewDomain(Classic_Domain classicDomain) {
|
||||||
return new Domain(classicDomain.name + "." + classicDomain.topLevelDomain + (classicDomain.path.startsWith("/") ? classicDomain.path : "/" + classicDomain.path));
|
return new Domain(classicDomain.name + "." + classicDomain.topLevelDomain + (classicDomain.path.startsWith("/") ? classicDomain.path : "/" + classicDomain.path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Domain object to a Classic_Domain object.
|
||||||
|
* @param newDomain the Domain object to convert
|
||||||
|
* @return the converted Classic_Domain object
|
||||||
|
*/
|
||||||
|
@SuppressWarnings(value = "deprecation")
|
||||||
public static Classic_Domain newDomainToClassicDomain(Domain newDomain) {
|
public static Classic_Domain newDomainToClassicDomain(Domain newDomain) {
|
||||||
return new Classic_Domain(newDomain.getName(), newDomain.getTopLevelName(), newDomain.getDestination(), newDomain.getPath());
|
return new Classic_Domain(newDomain.getName(), newDomain.getTopLevelName(), newDomain.getDestination(), newDomain.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Classic_ProtocolVersion to a ProtocolVersion.
|
||||||
|
* @param classicProtocolVersion the Classic_ProtocolVersion to convert
|
||||||
|
* @return the converted ProtocolVersion
|
||||||
|
*/
|
||||||
|
@SuppressWarnings(value = "deprecation")
|
||||||
public static ProtocolVersion classicProtocolVersionToNewProtocolVersion(Classic_ProtocolVersion classicProtocolVersion) {
|
public static ProtocolVersion classicProtocolVersionToNewProtocolVersion(Classic_ProtocolVersion classicProtocolVersion) {
|
||||||
if (classicProtocolVersion == Classic_ProtocolVersion.PV_1_0_0) return ProtocolVersion.PV_1_0_0_CLASSIC;
|
if (classicProtocolVersion == Classic_ProtocolVersion.PV_1_0_0) return ProtocolVersion.PV_1_0_0_CLASSIC;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a ProtocolVersion to a Classic_ProtocolVersion.
|
||||||
|
* @param newProtocolVersion the ProtocolVersion to convert
|
||||||
|
* @return the converted Classic_ProtocolVersion
|
||||||
|
*/
|
||||||
|
@SuppressWarnings(value = "deprecation")
|
||||||
public static Classic_ProtocolVersion newProtocolVersionToClassicProtocolVersion(ProtocolVersion newProtocolVersion) {
|
public static Classic_ProtocolVersion newProtocolVersionToClassicProtocolVersion(ProtocolVersion newProtocolVersion) {
|
||||||
return Classic_ProtocolVersion.PV_1_0_0;
|
return Classic_ProtocolVersion.PV_1_0_0;
|
||||||
}
|
}
|
@@ -1,9 +1,14 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils;
|
||||||
|
|
||||||
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 org.openautonomousconnection.protocol.ProtocolBridge;
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
import org.openautonomousconnection.protocol.packets.v1_0_0.classic.Classic_PingPacket;
|
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.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -11,48 +16,77 @@ import java.io.InputStreamReader;
|
|||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
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 DNS server
|
||||||
|
* and web content retrieval.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
|
||||||
public class Classic_ClientListener extends EventListener {
|
public class Classic_ClientListener extends EventListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the event when a domain packet is received.
|
||||||
|
* It checks if the domain exists and sends a ping request to the DNS server.
|
||||||
|
* If the domain does not exist, it handles the error accordingly.
|
||||||
|
* @param event The event containing domain information.
|
||||||
|
*/
|
||||||
@Listener
|
@Listener
|
||||||
public void onDomain(Classic_DomainPacketReceivedEvent event) {
|
public void onDomain(Classic_DomainPacketReceivedEvent event) {
|
||||||
|
// Check if the domain exists
|
||||||
boolean exists = event.domain != null;
|
boolean exists = event.domain != null;
|
||||||
|
|
||||||
if (exists) {
|
if (exists) {
|
||||||
try {
|
try {
|
||||||
|
// Send a ping request to the DNS server
|
||||||
if (!ProtocolBridge.getInstance().getProtocolClient().getClientDNSConnection().sendPacket(new Classic_PingPacket(event.requestDomain, event.domain, false))) {
|
if (!ProtocolBridge.getInstance().getProtocolClient().getClientDNSConnection().sendPacket(new Classic_PingPacket(event.requestDomain, event.domain, false))) {
|
||||||
|
// If sending the packet fails, handle the error
|
||||||
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-occurred", "html", ""),
|
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-occurred", "html", ""),
|
||||||
Classic_WebsitesContent.ERROR_OCCURRED(event.domain + "/" + event.domain.path));
|
Classic_WebsitesContent.ERROR_OCCURRED(event.domain + "/" + event.domain.path));
|
||||||
}
|
}
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
// Handle any exceptions that occur during the process
|
||||||
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-occurred", "html", ""),
|
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-occurred", "html", ""),
|
||||||
Classic_WebsitesContent.ERROR_OCCURRED(event.domain + "/" + event.domain.path + ":\n" + e.getMessage()));
|
Classic_WebsitesContent.ERROR_OCCURRED(event.domain + "/" + event.domain.path + ":\n" + e.getMessage()));
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
// If the domain does not exist, handle the error
|
||||||
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("domain-not-found", "html", ""), Classic_WebsitesContent.DOMAIN_NOT_FOUND);
|
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("domain-not-found", "html", ""), 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
|
@Listener
|
||||||
public void onPing(Classic_PingPacketReceivedEvent event) {
|
public void onPing(Classic_PingPacketReceivedEvent event) {
|
||||||
|
// If the domain is reachable, fetch the HTML content
|
||||||
if (event.reachable) {
|
if (event.reachable) {
|
||||||
String destination = event.domain.getDomain().getDestination();
|
String destination = event.domain.getDomain().getDestination();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Create a URL object
|
||||||
URL url = new URL(destination);
|
URL url = new URL(destination);
|
||||||
HttpURLConnection connection2 = (HttpURLConnection) url.openConnection();
|
HttpURLConnection connection2 = (HttpURLConnection) url.openConnection();
|
||||||
connection2.setRequestMethod("GET");
|
connection2.setRequestMethod("GET");
|
||||||
|
|
||||||
|
// Read the response
|
||||||
StringBuilder content = new StringBuilder();
|
StringBuilder content = new StringBuilder();
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection2.getInputStream()))) {
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection2.getInputStream()))) {
|
||||||
String line;
|
String line;
|
||||||
while ((line = reader.readLine()) != null) content.append(line);
|
while ((line = reader.readLine()) != null) content.append(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle the HTML content
|
||||||
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PUBLIC, event.domain, content.toString());
|
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PUBLIC, event.domain, content.toString());
|
||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
|
// Handle any exceptions that occur during the process
|
||||||
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-occurred", "html", ""),
|
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-occurred", "html", ""),
|
||||||
Classic_WebsitesContent.ERROR_OCCURRED(exception.getMessage().replace(event.domain.getDomain().getDestination(), event.domain + "/" + event.domain.path)));
|
Classic_WebsitesContent.ERROR_OCCURRED(exception.getMessage().replace(event.domain.getDomain().getDestination(), event.domain + "/" + event.domain.path)));
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
// If the domain is not reachable, handle the error
|
||||||
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-not-reached", "html", ""), Classic_WebsitesContent.DOMAIN_NOT_REACHABLE);
|
ProtocolBridge.getInstance().getClassicHandlerClient().handleHTMLContent(Classic_SiteType.PROTOCOL, new Classic_LocalDomain("error-not-reached", "html", ""), Classic_WebsitesContent.DOMAIN_NOT_REACHABLE);
|
||||||
}
|
}
|
||||||
|
|
@@ -1,14 +1,25 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils;
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
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.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
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 {
|
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 {
|
public static String getTopLevelDomain(String url) throws MalformedURLException {
|
||||||
URL uri = null;
|
URL uri = null;
|
||||||
String tldString = null;
|
String tldString = null;
|
||||||
@@ -33,6 +44,13 @@ class Classic_DomainUtils extends DefaultMethodsOverrider {
|
|||||||
return tldString;
|
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 {
|
public static String getDomainName(String url) throws URISyntaxException, MalformedURLException {
|
||||||
if (url.startsWith(Classic_SiteType.PUBLIC.name + "://"))
|
if (url.startsWith(Classic_SiteType.PUBLIC.name + "://"))
|
||||||
url = url.substring((Classic_SiteType.PUBLIC.name + "://").length());
|
url = url.substring((Classic_SiteType.PUBLIC.name + "://").length());
|
||||||
@@ -48,11 +66,14 @@ class Classic_DomainUtils extends DefaultMethodsOverrider {
|
|||||||
if (!url.startsWith("https://") && !url.startsWith("http://")) url = "https://" + url;
|
if (!url.startsWith("https://") && !url.startsWith("http://")) url = "https://" + url;
|
||||||
|
|
||||||
URI uri = new URI(url);
|
URI uri = new URI(url);
|
||||||
String domain = uri.getHost().replace("." + getTopLevelDomain(url), "");
|
return uri.getHost().replace("." + getTopLevelDomain(url), "");
|
||||||
return domain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
public static String getPath(String url) {
|
||||||
if (!url.startsWith(Classic_SiteType.PUBLIC.name + "://") && !url.startsWith(Classic_SiteType.CLIENT.name + "://") &&
|
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.SERVER.name + "://") && !url.startsWith(Classic_SiteType.PROTOCOL.name + "://") &&
|
@@ -1,7 +1,11 @@
|
|||||||
package org.openautonomousconnection.protocol.versions.v1_0_0.classic;
|
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils;
|
||||||
|
|
||||||
import java.io.Serializable;
|
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 {
|
public enum Classic_ProtocolVersion implements Serializable {
|
||||||
PV_1_0_0("1.0.0");
|
PV_1_0_0("1.0.0");
|
||||||
public final String version;
|
public final String version;
|
Reference in New Issue
Block a user