This commit is contained in:
2025-12-12 22:00:48 +01:00
commit 04d4a94b50
37 changed files with 1336 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
package erfinderlabyrinth.panel;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
public class Config {
public static String database_url;
public static void load() {
if(!Files.exists(Path.of("config.json"))) {
try(FileOutputStream out = new FileOutputStream("config.json")) {
try(InputStream in = Config.class.getClassLoader().getResourceAsStream("/default-config.json")) {
if(in != null) {
in.transferTo(out);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
try(FileReader reader = new FileReader("config.json")) {
JSONObject object = new JSONObject(new JSONTokener(reader));
database_url = object.getString("database_url");
} catch (IOException | JSONException e) {
e.printStackTrace();
}
}
}
+30
View File
@@ -0,0 +1,30 @@
package erfinderlabyrinth.panel;
import erfinderlabyrinth.panel.panel.Panel;
import erfinderlabyrinth.panel.panel.PanelSettings;
import erfinderlabyrinth.panel.panel.server.Server;
import erfinderlabyrinth.panel.panel.server.type.ServerType;
import erfinderlabyrinth.panel.website.api.APIManager;
import erfinderlabyrinth.panel.website.api.interfaces.LoginInterface;
import erfinderlabyrinth.panel.website.page.FilePage;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) throws IOException {
Config.load();
registerInterfaces();
Panel panel = new Panel(new PanelSettings());
Server server = new Server(panel, new ServerType());
server.exec("eclipse-temurin:25", new String[]{"java", "-jar", "test.jar"}).onFinished(() -> {
System.out.println("test.jar is finished");
});
}
private static void registerInterfaces() {
APIManager.registerInterface("login", new LoginInterface());
}
}
@@ -0,0 +1,26 @@
package erfinderlabyrinth.panel.database;
import erfinderlabyrinth.panel.Config;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseManager {
static Connection connection;
public static void start() throws SQLException {
connection = DriverManager.getConnection(Config.database_url);
}
public static Connection getConnection() {
return connection;
}
public void stop() {
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,64 @@
package erfinderlabyrinth.panel.database;
import erfinderlabyrinth.panel.website.api.interfaces.LoginInterface;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
public class UserDatabase {
public static void init() throws SQLException {
String sql = "CREATE TABLE IF NOT EXISTS users (name varchar(64), password varchar(64));";
Statement statement = DatabaseManager.getConnection().createStatement();
statement.execute(sql);
statement.close();
}
public static LoginInterface.User getUser(String username, String password){
try {
String sql = "SELECT * FROM users WHERE name = ? AND password = ?";
PreparedStatement statement = DatabaseManager.getConnection().prepareStatement(sql);
statement.setString(1, username);
statement.setString(2, getSHA256(password));
ResultSet result = statement.executeQuery();
LoginInterface.User user = null;
if (result.next()) {
System.err.println("User exist with name " + result.getString("name"));
user = new LoginInterface.User(result.getString("name"));
}
statement.close();
return user;
} catch (Exception e) {
System.err.println("error while getting the user");
e.printStackTrace();
return null;
}
}
public static String getSHA256(String original) {
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
byte[] hash = digest.digest(
original.getBytes(StandardCharsets.UTF_8));
final StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
final String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1)
hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
}
@@ -0,0 +1,28 @@
package erfinderlabyrinth.panel.docker;
import javax.print.Doc;
import java.io.IOException;
import java.net.StandardProtocolFamily;
import java.net.UnixDomainSocketAddress;
import java.net.http.HttpClient;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
public class DockerConnection {
public static Path DEFAULT_LINUX_DOCKER_PATH = Path.of("/unix/panel-connect");
public static DockerConnection open() throws IOException {
return open(DEFAULT_LINUX_DOCKER_PATH);
}
public static DockerConnection open(Path unixPath) throws IOException {
UnixDomainSocketAddress socketAddress = UnixDomainSocketAddress.of(unixPath);
try (SocketChannel channel = SocketChannel
.open(StandardProtocolFamily.UNIX)) {
channel.connect(socketAddress);
}
return null;
}
}
@@ -0,0 +1,61 @@
package erfinderlabyrinth.panel.panel;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.model.Container;
import com.github.dockerjava.api.model.Volume;
import com.github.dockerjava.core.DockerClientBuilder;
import erfinderlabyrinth.panel.panel.server.Server;
import erfinderlabyrinth.panel.website.Webserver;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class Panel {
public static final Map<String, String> GROUP_LABEL = Map.of("group", "customPanel");
Webserver webserver;
DockerClient dockerClient;
List<Server> servers;
public Panel(PanelSettings settings) {
webserver = new Webserver(settings.getPort(), this);
initDocker();
try {
webserver.start();
} catch (IOException e) {
e.printStackTrace();
stop();
}
}
public void initDocker() {
dockerClient = DockerClientBuilder.getInstance().build();
List<Container> containerList = dockerClient.listContainersCmd().withShowAll(true).withLabelFilter(GROUP_LABEL).exec();
for (Container container : containerList) {
dockerClient.stopContainerCmd(container.getId());
dockerClient.removeContainerCmd(container.getId()).withForce(true).exec();
}
}
public void stop() {
System.out.println("Stopping Panel");
webserver.stop();
try {
dockerClient.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public DockerClient getDockerClient() {
return dockerClient;
}
public List<Server> getServers() {
return servers;
}
}
@@ -0,0 +1,7 @@
package erfinderlabyrinth.panel.panel;
public class PanelSettings {
public int getPort() {
return 443;
}
}
@@ -0,0 +1,90 @@
package erfinderlabyrinth.panel.panel.server;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.exception.NotFoundException;
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.PullResponseItem;
import com.github.dockerjava.api.model.Volume;
import erfinderlabyrinth.panel.panel.Panel;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
public class ExecutedProcess {
CompletableFuture<Void> onFinish;
DockerClient client;
String dockerImage;
String[] command;
String containerId;
ExecutedProcess(DockerClient client, String dockerImage, String[] command) {
this.client = client;
this.dockerImage = dockerImage;
this.command = command;
execute();
}
private void execute() {
try {
client.inspectImageCmd(dockerImage).exec();
start();
} catch (NotFoundException e) {
client.pullImageCmd(dockerImage).exec(new ResultCallback<PullResponseItem>() {
@Override
public void onStart(Closeable closeable) {
}
@Override
public void onNext(PullResponseItem object) {
if (object.getProgressDetail() != null) {
System.out.println(object.getProgressDetail().getStart() + " - " + object.getProgressDetail().getCurrent() + " - " + object.getProgressDetail().getTotal());
}else {
System.out.println("ProgressDetail is null");
}
}
@Override
public void onError(Throwable throwable) {
throw new RuntimeException(throwable);
}
@Override
public void onComplete() {
start();
}
@Override
public void close() throws IOException {
}
});
}
}
private void start() {
String containerId = client.createContainerCmd(dockerImage)
.withHostConfig(HostConfig.newHostConfig()
.withBinds(new Bind("/unix", new Volume("/unix")), new Bind("/test/server1", new Volume("/server")))
)//.withAutoRemove(false))
.withLabels(Panel.GROUP_LABEL)
.withCmd(command)
.withWorkingDir("/server")
.exec().getId();
client.startContainerCmd(containerId).exec();
}
public void onFinished(Runnable runnable) {
if (onFinish == null) {
onFinish = CompletableFuture.runAsync(() -> {
try {
client.waitContainerCmd(containerId).start().awaitCompletion();
} catch (InterruptedException ignored) {}
});
}
onFinish.thenAccept(ignored -> runnable.run());
}
}
@@ -0,0 +1,49 @@
package erfinderlabyrinth.panel.panel.server;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.exception.NotFoundException;
import com.github.dockerjava.api.model.*;
import erfinderlabyrinth.panel.panel.Panel;
import erfinderlabyrinth.panel.panel.server.type.ServerType;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.function.Supplier;
public class Server {
Panel panel;
String name;
ServerType type;
File directory;
public Server(Panel panel, ServerType type) {
this.panel = panel;
this.type = type;
}
public void install(boolean deleteAllFiles) {
if (deleteAllFiles) {
for (File file : directory.listFiles()) {
deleteFile(file);
}
}
type.install(this);
}
private void deleteFile(File file) {
if (file.isDirectory()) {
for (File file2 : file.listFiles()) {
deleteFile(file2);
}
}
file.delete();
}
public ExecutedProcess exec(String dockerImage, String[] command) {
return new ExecutedProcess(panel.getDockerClient(), dockerImage, command);
}
}
@@ -0,0 +1,13 @@
package erfinderlabyrinth.panel.panel.server.type;
import erfinderlabyrinth.panel.panel.server.Server;
public class ServerType {
public String getDockerImage() {
return "eclipse-temurin:25";
}
public void install(Server server) {
}
}
@@ -0,0 +1,13 @@
package erfinderlabyrinth.panel.panel.server.type.install;
import erfinderlabyrinth.panel.panel.server.Server;
public class ExecutionStep implements InstallStep {
String dockerImage;
String[] command;
@Override
public void execute(Server server) {
server.exec(dockerImage, command);
}
}
@@ -0,0 +1,7 @@
package erfinderlabyrinth.panel.panel.server.type.install;
import erfinderlabyrinth.panel.panel.server.Server;
public interface InstallStep {
void execute(Server server);
}
@@ -0,0 +1,93 @@
package erfinderlabyrinth.panel.website;
import erfinderlabyrinth.panel.panel.Panel;
import erfinderlabyrinth.panel.website.api.APIManager;
import erfinderlabyrinth.panel.website.page.FilePage;
import erfinderlabyrinth.panel.website.page.Page;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class Connection {
Socket s;
Panel panel;
public Connection(Socket s, Panel panel) {
this.s = s;
this.panel = panel;
}
public void start() throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line;
ConnectionType type = null;
String path = "";
String host = "";
int post_length = 0;
System.out.println("start reading");
while (!(line = reader.readLine()).isEmpty()) {
System.out.println("Input Line: " + line);
if (line.startsWith("GET")) {
type = ConnectionType.GET;
path = line.split(" ")[1];
}else if (line.startsWith("POST")) {
type = ConnectionType.POST;
path = line.split(" ")[1];
}else if (line.startsWith("OPTIONS")) {
type = ConnectionType.OPTIONS;
path = line.split(" ")[1];
} else if (line.startsWith("Host: ")) {
host = line.substring(6);
} else if (line.startsWith("Content-Length: ")) {
post_length = Integer.parseInt(line.substring(16));
}
}
System.out.println("Finished reading");
if (type == null) {
s.close();
return;
}
byte[] data = null;
if (type == ConnectionType.POST) {
System.out.println("Read Data: " + post_length + " Bytes");
data = new byte[post_length];
for (int i = 0; i < post_length; i++) {
data[i] = (byte)reader.read();
}
}
if (path.startsWith("/")) {
path = path.substring(1);
}
OutputStream output = s.getOutputStream();
if (!path.startsWith("api/")) {
Page page;
page = FilePage.load(path);
if (page == null) {
output.write(("HTTP/1.0 404 UNKNOWN_PAGE\n\n").getBytes());
}else {
output.write(("HTTP/1.0 200 OK\n\n").getBytes());
output.write(page.getPageData());
}
}else {
path = path.substring("api/".length());
APIManager.call(path, type, data, output, panel);
}
output.flush();
s.close();
System.out.println("Written");
}
public enum ConnectionType {
GET, POST, OPTIONS
}
}
@@ -0,0 +1,44 @@
package erfinderlabyrinth.panel.website;
import org.json.JSONObject;
public class Response {
int code;
JSONObject json;
public Response(int code, JSONObject json) {
this.code = code;
this.json = json;
}
public static Response ok(JSONObject json) {
return new Response(200, json);
}
public static Response missing(JSONObject json) {
return new Response(404, json);
}
public static Response unauthorized(JSONObject json) {
return new Response(401, json);
}
public static Response wrongConnectionType(JSONObject json) {
return new Response(405, json);
}
public static Response wrongData(JSONObject json) {
return new Response(400, json);
}
public static Response noContent(JSONObject json) {
return new Response(204, json);
}
public int getResponseCode() {
return code;
}
public JSONObject getJson() {
return json;
}
}
@@ -0,0 +1,100 @@
package erfinderlabyrinth.panel.website;
import erfinderlabyrinth.panel.panel.Panel;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.SecureRandom;
public class Webserver {
int port;
Thread thread;
boolean running = true;
SSLServerSocket serverSocket;
Panel panel;
public Webserver(int port, Panel panel) {
this.port = port;
this.panel = panel;
}
public void start() throws IOException {
byte[] passBytes;
try(FileInputStream in = new FileInputStream("pw.txt")) {
passBytes = in.readAllBytes();
} catch (IOException | NullPointerException e) {
System.err.println("Missing Password. Couldn't find the server keystore pass");
e.printStackTrace();
return;
}
ByteBuffer byteBuf = ByteBuffer.wrap(passBytes);
CharBuffer charBuf = StandardCharsets.UTF_8.decode(byteBuf);
char[] pass = charBuf.array();
try {
KeyStore store = KeyStore.getInstance("jks");
store.load(new FileInputStream("cert.jks"), pass);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(store, pass);
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
SSLContext context = SSLContext.getInstance("SSL");
context.init(keyManagers, null, new SecureRandom());
SSLServerSocketFactory factory = context.getServerSocketFactory();
serverSocket = (SSLServerSocket) factory.createServerSocket(port);
serverSocket.setNeedClientAuth(false);
serverSocket.setWantClientAuth(false);
} catch (IllegalArgumentException e) {
System.out.println("Port " + port + "is invalid.");
} catch (IOException e) {
System.out.println("An error occured while opening the ServerSocket:");
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (serverSocket != null) {
thread = new Thread(() -> {
while(running) {
System.out.println("Server is running");
try {
Socket s = serverSocket.accept();
System.out.println("accepted");
Connection connection = new Connection(s, panel);
new Thread(() -> {
try {
connection.start();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
public void stop() {
running = false;
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
thread.join();
} catch (InterruptedException ignored) {
}
}
}
@@ -0,0 +1,9 @@
package erfinderlabyrinth.panel.website.api;
import erfinderlabyrinth.panel.panel.Panel;
import erfinderlabyrinth.panel.website.Connection;
import erfinderlabyrinth.panel.website.Response;
public interface APIInterface {
Response onCall(String path, Connection.ConnectionType connectionType, byte[] data, Panel panel);
}
@@ -0,0 +1,62 @@
package erfinderlabyrinth.panel.website.api;
import erfinderlabyrinth.panel.panel.Panel;
import erfinderlabyrinth.panel.website.Connection;
import erfinderlabyrinth.panel.website.Response;
import erfinderlabyrinth.panel.website.api.interfaces.LoginInterface;
import org.json.JSONObject;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
public class APIManager {
public static HashMap<String, LoginInterface.Session> sessions = new HashMap<>();
static HashMap<String, APIInterface> interfaces = new HashMap<>();
public static void call(String path, Connection.ConnectionType connectionType, byte[] data, OutputStream output, Panel panel) throws IOException {
String mainCall = path.split("/")[0];
Response response = null;
if (connectionType == Connection.ConnectionType.OPTIONS) {
response = Response.noContent(new JSONObject());
}else {
APIInterface apiInterface = interfaces.get(mainCall);
if (apiInterface != null) {
response = apiInterface.onCall(path, connectionType, data, panel);
}
if (response == null) {
response = Response.missing(null);
}
}
output.write(("HTTP/1.0 " + response.getResponseCode() + " " + getDescription(response.getResponseCode()) + "\n").getBytes());
output.write(("""
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: *
""").getBytes());
JSONObject json = response.getJson();
if (json == null) {
json = new JSONObject();
}
json.put("success", response.getJson() != null);
output.write(json.toString().getBytes());
output.flush();
output.close();
}
public static void registerInterface(String path, APIInterface apiInterface) {
interfaces.put(path, apiInterface);
}
private static String getDescription(int responseCode) {
return switch (responseCode) {
case 200 -> "OK";
case 204 -> "NO CONTENT";
case 404 -> "UNKNOWN_API_CALL";
case 401 -> "UNAUTHORIZED";
case 405 -> "WRONG_METHODE";
case 400 -> "WRONG_DATA";
default -> "MISSING_DESCRIPTION";
};
}
}
@@ -0,0 +1,32 @@
package erfinderlabyrinth.panel.website.api;
import com.fasterxml.jackson.core.JsonParser;
import erfinderlabyrinth.panel.panel.Panel;
import erfinderlabyrinth.panel.website.Connection;
import erfinderlabyrinth.panel.website.Response;
import erfinderlabyrinth.panel.website.api.interfaces.LoginInterface;
import org.json.JSONObject;
public interface LoginRequireAPIInterface extends APIInterface{
@Override
default Response onCall(String path, Connection.ConnectionType connectionType, byte[] data, Panel panel) {
try {
JSONObject json = new JSONObject(new String(data));
String token = json.getString("token");
LoginInterface.Session session = APIManager.sessions.get(token);
if (session != null) {
return onLoggedinCall(path, connectionType, data, session, panel);
}
return onNotLoggedinCall(path, connectionType, data, panel);
}catch (IllegalStateException|NullPointerException e) {
return Response.wrongData(null);
}
}
Response onLoggedinCall(String path, Connection.ConnectionType connectionType, byte[] data, LoginInterface.Session session, Panel panel);
default Response onNotLoggedinCall(String path, Connection.ConnectionType connectionType, byte[] data, Panel panel) {
return Response.unauthorized(null);
}
}
@@ -0,0 +1,92 @@
package erfinderlabyrinth.panel.website.api.interfaces;
import erfinderlabyrinth.panel.database.UserDatabase;
import erfinderlabyrinth.panel.panel.Panel;
import erfinderlabyrinth.panel.website.Connection;
import erfinderlabyrinth.panel.website.Response;
import erfinderlabyrinth.panel.website.api.APIInterface;
import erfinderlabyrinth.panel.website.api.APIManager;
import org.json.JSONObject;
import java.security.SecureRandom;
public class LoginInterface implements APIInterface {
@Override
public Response onCall(String path, Connection.ConnectionType connectionType, byte[] data, Panel panel) {
if (path.equals("login/") || path.equals("login")) {
if (connectionType == Connection.ConnectionType.POST) {
try {
JSONObject json = new JSONObject(new String(data));
String name = json.getString("name");
String password = json.getString("password");
User user = UserDatabase.getUser(name, password);
//if (name.equals("root") && UserDatabase.getSHA256(password).equals("2a7044b477960dd525b7f5990a3746a097cd189769603e670b7a5040ec797ffd")) {
// user = new User("root");
//}
if (user == null) {
return Response.ok(null);
}
Session session = new Session(user);
APIManager.sessions.put(session.getToken(), session);
JSONObject response = new JSONObject();
response.put("token", session.getToken());
response.put("user", session.getUser().getName());
return Response.ok(response);
}catch (IllegalStateException|NullPointerException e) {
return Response.wrongData(null);
}
}
return Response.wrongConnectionType(null);
}
return Response.missing(null);
}
public static class Session{
User user;
long sessionCreated;
String token;
Session(User user) {
this.user = user;
this.sessionCreated = System.currentTimeMillis();
this.token = generateToken();
}
public String getToken() {
return token;
}
public User getUser() {
return user;
}
private String generateToken() {
SecureRandom random = new SecureRandom();
long randomLong1 = random.nextLong();
long randomLong2 = random.nextLong();
return Long.toHexString(randomLong1) + Long.toHexString(randomLong2);
}
}
public static class User{
String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
}
@@ -0,0 +1,25 @@
package erfinderlabyrinth.panel.website.api.interfaces;
import erfinderlabyrinth.panel.panel.Panel;
import erfinderlabyrinth.panel.panel.server.Server;
import erfinderlabyrinth.panel.website.Connection;
import erfinderlabyrinth.panel.website.Response;
import erfinderlabyrinth.panel.website.api.LoginRequireAPIInterface;
import org.json.JSONArray;
import org.json.JSONObject;
public class RequestServerListInterface implements LoginRequireAPIInterface {
@Override
public Response onLoggedinCall(String path, Connection.ConnectionType connectionType, byte[] data, LoginInterface.Session session, Panel panel) {
JSONObject object = new JSONObject();
JSONArray serverList = new JSONArray();
object.append("servers", serverList);
for (Server server : panel.getServers()) {
}
return Response.ok(object);
}
}
@@ -0,0 +1,24 @@
package erfinderlabyrinth.panel.website.api.interfaces;
import erfinderlabyrinth.panel.website.Connection;
import erfinderlabyrinth.panel.website.Response;
import erfinderlabyrinth.panel.website.api.APIInterface;
import java.util.HashMap;
public class SubInterface implements APIInterface {
static HashMap<String, APIInterface> subInterfaces = new HashMap<>();
@Override
public Response onCall(String path, Connection.ConnectionType connectionType, byte[] data) {
String secondPath = path.split("/")[1];
if (subInterfaces.containsKey(secondPath)) {
return subInterfaces.get(secondPath).onCall(path, connectionType, data);
}else {
return Response.missing(null);
}
}
public void registerSubInterface(String path, APIInterface apiInterface) {
subInterfaces.put(path, apiInterface);
}
}
@@ -0,0 +1,5 @@
package erfinderlabyrinth.panel.website.api.interfaces;
public class SubInterfaces {
public static final SubInterface PLAYER = new SubInterface();
}
@@ -0,0 +1,22 @@
package erfinderlabyrinth.panel.website.api.interfaces;
import erfinderlabyrinth.panel.panel.Panel;
import erfinderlabyrinth.panel.website.Connection;
import erfinderlabyrinth.panel.website.Response;
import erfinderlabyrinth.panel.website.api.LoginRequireAPIInterface;
import org.json.JSONObject;
public class TokenCheckInterface implements LoginRequireAPIInterface {
@Override
public Response onLoggedinCall(String path, Connection.ConnectionType connectionType, byte[] data, LoginInterface.Session session, Panel panel) {
JSONObject object = new JSONObject();
object.put("username", session.getUser().getName());
return Response.ok(object);
}
@Override
public Response onNotLoggedinCall(String path, Connection.ConnectionType connectionType, byte[] data, Panel panel) {
return Response.ok(null);
}
}
@@ -0,0 +1,35 @@
package erfinderlabyrinth.panel.website.command;
import erfinderlabyrinth.panel.website.page.PageParser;
import erfinderlabyrinth.panel.website.page.RequestContext;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
public class FileCommand implements PageParser.PageCommand {
public static final String FILE_PATH_START = "insert/";
@Override
public String apply(String args, RequestContext context) {
Path path = Path.of(FILE_PATH_START, args);
path = path.normalize();
if(path.startsWith(FILE_PATH_START)) {
try (InputStream in = getClass().getClassLoader().getResourceAsStream(FILE_PATH_START + args.replace("..", ""))) {
if (in != null) {
return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
} catch (IOException e) {
e.printStackTrace();
}
}
return "";
}
@Override
public boolean needsEscaping() {
return false;
}
}
@@ -0,0 +1,37 @@
package erfinderlabyrinth.panel.website.page;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
public class FilePage implements Page{
byte[] data;
public FilePage(byte[] data) {
this.data = data;
}
public static FilePage load(String path) {
try (InputStream input = FilePage.class.getResourceAsStream("/website/" + path.replace("..", ""))) {
if (input != null) {
byte[] bytes = input.readAllBytes();
if(path.endsWith(".html")) {
String text = new String(bytes, StandardCharsets.UTF_8);
String parsed = PageParser.parsePage(text, new RequestContext());
bytes = parsed.getBytes(StandardCharsets.UTF_8);
}
return new FilePage(bytes);
}
} catch (IOException ignored) {
}
return null;
}
@Override
public byte[] getPageData() {
return data;
}
}
@@ -0,0 +1,5 @@
package erfinderlabyrinth.panel.website.page;
public interface Page {
byte[] getPageData();
}
@@ -0,0 +1,94 @@
package erfinderlabyrinth.panel.website.page;
import erfinderlabyrinth.panel.website.command.FileCommand;
import org.apache.commons.text.StringEscapeUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class PageParser {
private static final Map<String, PageCommand> commands = new HashMap<>(
Map.of(
"file", new FileCommand()
)
);
public static String parsePage(String original, RequestContext context) {
int exclamationCount = 0;
StringBuilder output = new StringBuilder();
StringBuilder command = null;
boolean wasInTag = false;
boolean inTag = false;
for(int i = 0; i < original.length(); i++) {
char c = original.charAt(i);
if(c == '!') {
exclamationCount++;
if(exclamationCount == 3) {
inTag = !inTag;
if(inTag) {
command = new StringBuilder();
} else {
output.append(interpretCommand(command.toString(), context));
}
}
} else {
if(!inTag && !wasInTag && exclamationCount > 0) {
for(int x = 0; x < exclamationCount; x++) {
output.append('!');
}
}
exclamationCount = 0;
if(inTag) {
command.append(c);
} else {
output.append(c);
}
wasInTag = inTag;
}
}
return output.toString();
}
public static String interpretCommand(String command, RequestContext context) {
int firstSpace = command.indexOf(' ');
String name = command.substring(0, firstSpace);
String cmdArgs = command.substring(firstSpace + 1, command.length() - 1);
PageCommand pageCommand = commands.get(name);
if(pageCommand == null) {
throw new RuntimeException("Command not found " + name);
}
String out = pageCommand.apply(cmdArgs, context);
if(pageCommand.needsEscaping()) {
return StringEscapeUtils.escapeHtml4(out);
} else {
return out;
}
}
public interface PageCommand {
String apply(String args, RequestContext context);
default boolean needsEscaping() {
return true;
}
}
public static void main(String[] args) {
System.out.println(parsePage("fjjalöfjjwm!!f!kwsöqwlsd2,!!!p95!!!fjdqkpk47 ßz8dkß2kqla4qoj9cf69p576aop! ah faöohfaöh !!!testcommand1!!!", new RequestContext()));
}
}
@@ -0,0 +1,4 @@
package erfinderlabyrinth.panel.website.page;
public class RequestContext {
}