diff --git a/.gitignore b/.gitignore
index 7d0ab85..d6ecfc9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -218,3 +218,5 @@ TheButtonAutoFlair/out/artifacts/Autoflair/Autoflair.jar
*.name
.idea/compiler.xml
*.xml
+
+upload_key
diff --git a/.travis.yml b/.travis.yml
index 6f1ca80..c822f5d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,3 +14,5 @@ deploy:
on:
branch: master
skip_cleanup: true
+notifications:
+ webhooks: https://server.figytuna.com:8080/build_notifications
diff --git a/src/buttondevteam/website/io/IOHelper.java b/src/buttondevteam/website/io/IOHelper.java
index faae178..ba0ba46 100644
--- a/src/buttondevteam/website/io/IOHelper.java
+++ b/src/buttondevteam/website/io/IOHelper.java
@@ -76,13 +76,15 @@ public class IOHelper {
public static void LoginUser(HttpExchange exchange, WebUser user) {
Bukkit.getLogger().fine("Logging in user: " + user);
user.sessionID().set(UUID.randomUUID());
+ user.save();
new Cookies(2).add(new Cookie("user_id", user.getUUID() + ""))
- .add(new Cookie("session_id", user.sessionID().get().toString())).SendHeaders(exchange);
+ .add(new Cookie("session_id", user.sessionID().getOrDefault(null).toString())).SendHeaders(exchange);
Bukkit.getLogger().fine("Logged in user.");
}
public static void LogoutUser(HttpExchange exchange, WebUser user) {
user.sessionID().set(new UUID(0, 0));
+ user.save();
SendLogoutHeaders(exchange);
}
@@ -125,7 +127,7 @@ public class IOHelper {
}
/**
- * Get logged in user. It may also send logout headers if the cookies are invalid, or login headers to keep the user logged in.
+ * Get logged in user. It may also send logout headers if the cookies are invalid, or login headers to keep the user logged in. Make sure to save the user data.
*
* @param exchange
* @return The logged in user or null if not logged in.
@@ -137,7 +139,7 @@ public class IOHelper {
return null;
WebUser user = ChromaGamerBase.getUser(cookies.get("user_id").getValue(), WebUser.class);
if (user != null && cookies.get("session_id") != null
- && cookies.get("session_id").getValue().equals(user.sessionID().get())) {
+ && cookies.get("session_id").getValue().equals(user.sessionID().getOrDefault(null))) {
if (cookies.getExpireTimeParsed().minusYears(1).isBefore(ZonedDateTime.now(ZoneId.of("GMT"))))
LoginUser(exchange, user);
return user;
@@ -174,4 +176,22 @@ public class IOHelper {
}
return result;
}
+
+ public static HashMap GetPOSTKeyValues(HttpExchange exchange) {
+ try {
+ String[] content = GetPOST(exchange).split("\\&");
+ HashMap vars = new HashMap<>();
+ for (String var : content) {
+ String[] spl = var.split("\\=");
+ if (spl.length == 1)
+ vars.put(spl[0], "");
+ else
+ vars.put(spl[0], spl[1]);
+ }
+ return vars;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return new HashMap<>();
+ }
+ }
}
diff --git a/src/buttondevteam/website/page/BuildNotificationsPage.java b/src/buttondevteam/website/page/BuildNotificationsPage.java
new file mode 100644
index 0000000..ddd5864
--- /dev/null
+++ b/src/buttondevteam/website/page/BuildNotificationsPage.java
@@ -0,0 +1,86 @@
+package buttondevteam.website.page;
+
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.List;
+import java.util.function.Supplier;
+
+import com.google.gson.*;
+import com.sun.net.httpserver.HttpExchange;
+
+import buttondevteam.lib.TBMCCoreAPI;
+import buttondevteam.website.io.IOHelper;
+import buttondevteam.website.io.Response;
+
+public class BuildNotificationsPage extends Page {
+
+ @Override
+ public String GetName() {
+ return "build_notifications";
+ }
+
+ private static final String signature = ((Supplier) () -> {
+ try {
+ return fromString(TBMCCoreAPI.DownloadString("https://api.travis-ci.org/config"),
+ "config.notifications.webhook.public_key").getAsString();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }).get();
+
+ @Override
+ public Response handlePage(HttpExchange exchange) {
+ HashMap post = IOHelper.GetPOSTKeyValues(exchange);
+ try {
+ final List signatures = exchange.getRequestHeaders().get("Signature");
+ if (signatures.size() > 0 && post.containsKey("payload")
+ && verifySignature(Base64.getDecoder().decode(post.get("payload")),
+ Base64.getDecoder().decode(signatures.get(0)), signature)) {
+ // TODO: Send event
+ return new Response(200, "All right", exchange);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return new Response(400, "Verification failed", exchange);
+ }
+
+ // Method for signature verification that initializes with the Public Key,
+ // updates the data to be verified and then verifies them using the signature
+ private boolean verifySignature(byte[] data, byte[] signature, String keystr) throws Exception {
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ sig.initVerify(getPublic(keystr));
+ sig.update(data);
+
+ return sig.verify(signature);
+ }
+
+ // Method to retrieve the Public Key from a file
+ public PublicKey getPublic(String keystr) throws Exception {
+ byte[] keyBytes = Base64.getDecoder().decode(keystr);
+ X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ return kf.generatePublic(spec);
+ }
+
+ public static JsonElement fromString(String json, String path) throws JsonSyntaxException {
+ JsonObject obj = new GsonBuilder().create().fromJson(json, JsonObject.class);
+ String[] seg = path.split("\\.");
+ for (String element : seg) {
+ if (obj != null) {
+ JsonElement ele = obj.get(element);
+ if (!ele.isJsonObject())
+ return ele;
+ else
+ obj = ele.getAsJsonObject();
+ } else {
+ return null;
+ }
+ }
+ return obj;
+ }
+}