From 1a54476cbe469de9c7b73b4994cbb46b409ba304 Mon Sep 17 00:00:00 2001 From: yoyosource Date: Sun, 29 May 2022 21:37:31 +0200 Subject: [PATCH] Add initial WebAPI --- build.gradle | 2 + src/de/steamwar/bungeecore/api/EndPoint.java | 24 +++ src/de/steamwar/bungeecore/api/Token.java | 162 ++++++++++++++++++ src/de/steamwar/bungeecore/api/WebAPI.java | 35 ++++ .../api/v1/ServerStatusEndPoint.java | 42 +++++ .../bungeecore/api/v1/ServerTeamEndPoint.java | 49 ++++++ .../steamwar/bungeecore/sql/SteamwarUser.java | 11 ++ 7 files changed, 325 insertions(+) create mode 100644 src/de/steamwar/bungeecore/api/EndPoint.java create mode 100644 src/de/steamwar/bungeecore/api/Token.java create mode 100644 src/de/steamwar/bungeecore/api/WebAPI.java create mode 100644 src/de/steamwar/bungeecore/api/v1/ServerStatusEndPoint.java create mode 100644 src/de/steamwar/bungeecore/api/v1/ServerTeamEndPoint.java diff --git a/build.gradle b/build.gradle index 7b1f7967..6435d368 100644 --- a/build.gradle +++ b/build.gradle @@ -99,6 +99,8 @@ dependencies { exclude module: 'opus-java' } + implementation "com.sparkjava:spark-core:2.9.3" + implementation project(":CommonCore") } diff --git a/src/de/steamwar/bungeecore/api/EndPoint.java b/src/de/steamwar/bungeecore/api/EndPoint.java new file mode 100644 index 00000000..02304f82 --- /dev/null +++ b/src/de/steamwar/bungeecore/api/EndPoint.java @@ -0,0 +1,24 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.api; + +public interface EndPoint { + void ignite(); +} diff --git a/src/de/steamwar/bungeecore/api/Token.java b/src/de/steamwar/bungeecore/api/Token.java new file mode 100644 index 00000000..5acb2326 --- /dev/null +++ b/src/de/steamwar/bungeecore/api/Token.java @@ -0,0 +1,162 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.api; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonWriter; +import de.steamwar.bungeecore.sql.SteamwarUser; + +import javax.crypto.Cipher; +import java.io.*; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.DSAPublicKeySpec; +import java.util.Base64; +import java.util.UUID; + +public class Token { + + private static KeyPair pair; + + private static KeyPair getKeyPair() { + if (pair != null) return pair; + + File publicKeyFile = new File("~/token_dsa.pub"); + File privateKeyFile = new File("~/token_dsa"); + + if (publicKeyFile.exists() && privateKeyFile.exists()) { + PublicKey publicKey = null; + try { + JsonObject jsonObject = JsonParser.parseReader(new BufferedReader(new InputStreamReader(new FileInputStream(publicKeyFile)))).getAsJsonObject(); + BigInteger y = jsonObject.get("y").getAsBigInteger(); + BigInteger p = jsonObject.get("p").getAsBigInteger(); + BigInteger q = jsonObject.get("q").getAsBigInteger(); + BigInteger g = jsonObject.get("g").getAsBigInteger(); + KeyFactory keyFactory = KeyFactory.getInstance("DSA"); + publicKey = keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g)); + } catch (Exception e) { + // Ignore + } + PrivateKey privateKey = null; + try { + JsonObject jsonObject = JsonParser.parseReader(new BufferedReader(new InputStreamReader(new FileInputStream(privateKeyFile)))).getAsJsonObject(); + BigInteger x = jsonObject.get("x").getAsBigInteger(); + BigInteger p = jsonObject.get("p").getAsBigInteger(); + BigInteger q = jsonObject.get("q").getAsBigInteger(); + BigInteger g = jsonObject.get("g").getAsBigInteger(); + KeyFactory keyFactory = KeyFactory.getInstance("DSA"); + privateKey = keyFactory.generatePrivate(new DSAPrivateKeySpec(x, p, q, g)); + } catch (Exception e) { + // Ignore + } + pair = new KeyPair(publicKey, privateKey); + return pair; + } + try { + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA"); + keyPairGen.initialize(2048); + pair = keyPairGen.generateKeyPair(); + saveKeyPair(); + return pair; + } catch (Exception e) { + throw new SecurityException(e.getMessage(), e); + } + } + + private static void saveKeyPair() { + File publicKeyFile = new File("~/token_dsa.pub"); + File privateKeyFile = new File("~/token_dsa"); + + try { + publicKeyFile.createNewFile(); + KeyFactory keyFactory = KeyFactory.getInstance(pair.getPrivate().getAlgorithm()); + DSAPublicKeySpec dsaPublicKeySpec = keyFactory.getKeySpec(pair.getPublic(), DSAPublicKeySpec.class); + + JsonObject privateKey = new JsonObject(); + privateKey.addProperty("y", dsaPublicKeySpec.getY()); + privateKey.addProperty("p", dsaPublicKeySpec.getP()); + privateKey.addProperty("q", dsaPublicKeySpec.getQ()); + privateKey.addProperty("g", dsaPublicKeySpec.getG()); + new JsonWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(publicKeyFile)))).close(); + } catch (Exception e) { + + } + + try { + privateKeyFile.createNewFile(); + KeyFactory keyFactory = KeyFactory.getInstance(pair.getPrivate().getAlgorithm()); + DSAPrivateKeySpec dsaPrivateKeySpec = keyFactory.getKeySpec(pair.getPrivate(), DSAPrivateKeySpec.class); + + JsonObject privateKey = new JsonObject(); + privateKey.addProperty("x", dsaPrivateKeySpec.getX()); + privateKey.addProperty("p", dsaPrivateKeySpec.getP()); + privateKey.addProperty("q", dsaPrivateKeySpec.getQ()); + privateKey.addProperty("g", dsaPrivateKeySpec.getG()); + new JsonWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(privateKeyFile)))).close(); + } catch (Exception e) { + + } + } + + private UUID uuid; + private long creationDate; + + public Token(SteamwarUser steamwarUser) { + uuid = steamwarUser.getUuid(); + creationDate = System.currentTimeMillis(); + } + + public Token(JsonObject jsonObject) { + uuid = UUID.fromString(jsonObject.get("uuid").getAsString()); + creationDate = jsonObject.get("creationDate").getAsLong(); + } + + public JsonObject toJSON() { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("uuid", uuid.toString()); + jsonObject.addProperty("creationDate", creationDate); + return jsonObject; + } + + public String encrypt() { + try { + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, getKeyPair().getPublic()); + return Base64.getEncoder().encodeToString(cipher.doFinal(toJSON().toString().getBytes(StandardCharsets.UTF_8))); + } catch (Exception e) { + throw new SecurityException(e.getMessage(), e); + } + } + + public static Token decrypt(String s) { + try { + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, getKeyPair().getPrivate()); + byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(s)); + JsonObject jsonObject = JsonParser.parseReader(new InputStreamReader(new ByteArrayInputStream(bytes))).getAsJsonObject(); + return new Token(jsonObject); + } catch (Exception e) { + throw new SecurityException(e.getMessage(), e); + } + } +} diff --git a/src/de/steamwar/bungeecore/api/WebAPI.java b/src/de/steamwar/bungeecore/api/WebAPI.java new file mode 100644 index 00000000..830bb1f7 --- /dev/null +++ b/src/de/steamwar/bungeecore/api/WebAPI.java @@ -0,0 +1,35 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.api; + +import de.steamwar.bungeecore.api.v1.ServerStatusEndPoint; +import de.steamwar.bungeecore.api.v1.ServerTeamEndPoint; + +import static spark.Spark.port; + +public class WebAPI { + + public static void start() { + port(1024); + + new ServerStatusEndPoint().ignite(); + new ServerTeamEndPoint().ignite(); + } +} diff --git a/src/de/steamwar/bungeecore/api/v1/ServerStatusEndPoint.java b/src/de/steamwar/bungeecore/api/v1/ServerStatusEndPoint.java new file mode 100644 index 00000000..b21d70e4 --- /dev/null +++ b/src/de/steamwar/bungeecore/api/v1/ServerStatusEndPoint.java @@ -0,0 +1,42 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.api.v1; + +import com.google.gson.JsonObject; +import de.steamwar.bungeecore.api.EndPoint; +import net.md_5.bungee.BungeeCord; + +import static spark.Spark.post; + +public class ServerStatusEndPoint implements EndPoint { + + @Override + public void ignite() { + post("/v1/serverstatus", (request, response) -> { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("players", BungeeCord.getInstance().getPlayers().size()); + jsonObject.addProperty("maxPlayers", BungeeCord.getInstance().getConfig().getPlayerLimit()); + + response.type("application/json"); + response.status(200); + return jsonObject.toString(); + }); + } +} diff --git a/src/de/steamwar/bungeecore/api/v1/ServerTeamEndPoint.java b/src/de/steamwar/bungeecore/api/v1/ServerTeamEndPoint.java new file mode 100644 index 00000000..a0599e8f --- /dev/null +++ b/src/de/steamwar/bungeecore/api/v1/ServerTeamEndPoint.java @@ -0,0 +1,49 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.api.v1; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import de.steamwar.bungeecore.api.EndPoint; +import de.steamwar.bungeecore.sql.SteamwarUser; + +import static spark.Spark.post; + +public class ServerTeamEndPoint implements EndPoint { + + @Override + public void ignite() { + post("/v1/serverteam", (request, response) -> { + JsonObject jsonObject = new JsonObject(); + JsonArray jsonArray = new JsonArray(); + SteamwarUser.getServerTeam().forEach(steamwarUser -> { + JsonObject user = new JsonObject(); + user.addProperty("name", steamwarUser.getUserName()); + user.addProperty("rank", steamwarUser.getUserGroup().name()); + jsonArray.add(user); + }); + jsonObject.add("", jsonArray); + + response.type("application/json"); + response.status(200); + return jsonObject.toString(); + }); + } +} diff --git a/src/de/steamwar/bungeecore/sql/SteamwarUser.java b/src/de/steamwar/bungeecore/sql/SteamwarUser.java index 901c2197..772f9d72 100644 --- a/src/de/steamwar/bungeecore/sql/SteamwarUser.java +++ b/src/de/steamwar/bungeecore/sql/SteamwarUser.java @@ -59,6 +59,8 @@ public class SteamwarUser { private static final Statement getPlaytime = new Statement("SELECT SUM(UNIX_TIMESTAMP(EndTime) - UNIX_TIMESTAMP(StartTime)) as Playtime FROM Session WHERE UserID = ?"); private static final Statement getFirstjoin = new Statement("SELECT MIN(StartTime) AS FirstJoin FROM Session WHERE UserID = ?"); + private static final Statement getServerTeam = new Statement("SELECT * FROM UserData WHERE UserGroup != 'Member' AND UserGroup != 'YouTuber'"); + private static final Map usersByName = new HashMap<>(); private static final Map usersByUUID = new HashMap<>(); private static final Map usersById = new HashMap<>(); @@ -390,4 +392,13 @@ public class SteamwarUser { updateLocale.update(locale.toLanguageTag(), manualLocale, id); new LocaleInvalidationPacket(id).send(getPlayer()); } + + public static List getServerTeam() { + return getServerTeam.select(rs -> { + List users = new ArrayList<>(); + while(rs.next()) + users.add(new SteamwarUser(rs)); + return users; + }); + } }