From e5794f382d0c22405f05e9fd60faa9d5837c47b4 Mon Sep 17 00:00:00 2001 From: Francois G Date: Sat, 8 Apr 2023 10:22:12 +0200 Subject: [PATCH 1/5] add config line for users files path --- src/be/jeffcheasey88/peeratcode/Configuration.java | 8 ++++++++ src/be/jeffcheasey88/peeratcode/Main.java | 8 ++++---- src/be/jeffcheasey88/peeratcode/model/Player.java | 6 ------ .../jeffcheasey88/peeratcode/routes/PuzzleResponse.java | 6 ++++-- src/be/jeffcheasey88/peeratcode/routes/Register.java | 7 +++++-- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/be/jeffcheasey88/peeratcode/Configuration.java b/src/be/jeffcheasey88/peeratcode/Configuration.java index 2e7a691..a5700a7 100644 --- a/src/be/jeffcheasey88/peeratcode/Configuration.java +++ b/src/be/jeffcheasey88/peeratcode/Configuration.java @@ -19,6 +19,8 @@ public class Configuration { private boolean use_ssl; private String ssl_keystore; private String ssl_keystorePasswd; + + private String users_files; private String token_issuer; private int token_expiration; @@ -143,4 +145,10 @@ public class Configuration { public boolean useSsl(){ return this.use_ssl; } + + public String getUsersFiles(){ + if (users_files == null || users_files.trim().isEmpty()) + users_files = "/tmp/users_files"; + return users_files; + } } \ No newline at end of file diff --git a/src/be/jeffcheasey88/peeratcode/Main.java b/src/be/jeffcheasey88/peeratcode/Main.java index 2ec0190..74dbe24 100644 --- a/src/be/jeffcheasey88/peeratcode/Main.java +++ b/src/be/jeffcheasey88/peeratcode/Main.java @@ -63,19 +63,19 @@ public class Main { } }); - initRoutes(router); + initRoutes(router, config); startWebServer(config, router); } - private static void initRoutes(Router router) { + private static void initRoutes(Router router, Configuration config) { router.register(new ChapterElement(router.getDataBase())); router.register(new ChapterList(router.getDataBase())); router.register(new PuzzleElement(router.getDataBase())); - router.register(new Register(router.getDataBase(), router)); + router.register(new Register(router.getDataBase(), router, config.getUsersFiles())); router.register(new Login(router.getDataBase(), router)); router.register(new Result(router.getDataBase())); - router.register(new PuzzleResponse(router.getDataBase())); + router.register(new PuzzleResponse(router.getDataBase(), config.getUsersFiles())); router.register(new Leaderboard(router.getDataBase())); router.register(new PlayerDetails(router.getDataBase())); router.register(new BadgeDetails(router.getDataBase())); diff --git a/src/be/jeffcheasey88/peeratcode/model/Player.java b/src/be/jeffcheasey88/peeratcode/model/Player.java index 278f5e9..59677f6 100644 --- a/src/be/jeffcheasey88/peeratcode/model/Player.java +++ b/src/be/jeffcheasey88/peeratcode/model/Player.java @@ -16,8 +16,6 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; public class Player implements Comparable { - public static final String PATH_TO_CODE = "/home/%s/peer-at-source/"; - private String pseudo; private String email; private String firstname; @@ -101,10 +99,6 @@ public class Player implements Comparable { avatar = newAvatar; } - public String getPathToSourceCode() { - return String.format(PATH_TO_CODE, pseudo); - } - public int getRank() { return rank; } diff --git a/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java b/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java index 2280102..2dda965 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java +++ b/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java @@ -22,9 +22,11 @@ import be.jeffcheasey88.peeratcode.webserver.User; public class PuzzleResponse implements Response { private final DatabaseRepository databaseRepo; + private final String usersFilesPath; - public PuzzleResponse(DatabaseRepository databaseRepo) { + public PuzzleResponse(DatabaseRepository databaseRepo, String initUsersFilesPath) { this.databaseRepo = databaseRepo; + usersFilesPath = initUsersFilesPath; } @Route(path = "^\\/puzzleResponse\\/([0-9]+)$", type = "POST", needLogin = true) @@ -52,7 +54,7 @@ public class PuzzleResponse implements Response { } private void saveSourceCode(ReceivedResponse received, Player player) throws IOException { - Path path = Paths.get(String.format("%s/puz%04d-%s", player.getPathToSourceCode(), received.getPuzzleId(), received.getFileName())); + Path path = Paths.get(String.format("%s/%s/puz%04d-%s", usersFilesPath, player.getPseudo(), received.getPuzzleId(), received.getFileName())); Files.write(path, received.getSourceCode()); } diff --git a/src/be/jeffcheasey88/peeratcode/routes/Register.java b/src/be/jeffcheasey88/peeratcode/routes/Register.java index 5e65bf4..1e3c4cd 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/Register.java +++ b/src/be/jeffcheasey88/peeratcode/routes/Register.java @@ -22,10 +22,12 @@ public class Register implements Response { private DatabaseRepository databaseRepo; private Router router; + private String usersFilesPath; - public Register(DatabaseRepository databaseRepo, Router router) { + public Register(DatabaseRepository databaseRepo, Router router, String initUsersFilesPath) { this.databaseRepo = databaseRepo; this.router = router; + usersFilesPath = initUsersFilesPath; } @Route(path = "^\\/register$", type = "POST") @@ -80,7 +82,8 @@ public class Register implements Response { } private void createFolderToSaveSourceCode(String pseudo) throws IOException { - Files.createDirectories(Paths.get(String.format(Player.PATH_TO_CODE, pseudo))); + + Files.createDirectories(Paths.get(String.format("%s/%s", usersFilesPath, pseudo))); } } From 14905a489a0cfdba95fb14d78a81abf5b2869eb8 Mon Sep 17 00:00:00 2001 From: Francois G Date: Sat, 8 Apr 2023 17:33:19 +0200 Subject: [PATCH 2/5] Add route for groups leaderboard --- .../jeffcheasey88/peeratcode/model/Group.java | 109 +++++++++++++++++- .../peeratcode/model/Player.java | 25 ++-- .../peeratcode/repository/DatabaseQuery.java | 3 + .../repository/DatabaseRepository.java | 57 +++++++-- .../peeratcode/routes/Leaderboard.java | 35 +++++- 5 files changed, 206 insertions(+), 23 deletions(-) diff --git a/src/be/jeffcheasey88/peeratcode/model/Group.java b/src/be/jeffcheasey88/peeratcode/model/Group.java index e41f30b..a73a4bc 100644 --- a/src/be/jeffcheasey88/peeratcode/model/Group.java +++ b/src/be/jeffcheasey88/peeratcode/model/Group.java @@ -1,11 +1,17 @@ package be.jeffcheasey88.peeratcode.model; +import java.sql.Timestamp; +import java.util.*; + +import org.json.simple.JSONArray; import org.json.simple.JSONObject; -public class Group { +public class Group implements Comparable { private String name; private int linkToChapter; private int linkToPuzzle; + private List players; + private Timestamp endDate; public Group(JSONObject json){ this.name = (String)json.get("name"); @@ -14,11 +20,55 @@ public class Group { } public Group(String name, int initChap, int initPuzz) { + this(name, initChap, initPuzz, null); + } + public Group(String name, int initChap, int initPuzz, Timestamp initEnd) { this.name = name; this.linkToChapter = initChap; this.linkToPuzzle = initPuzz; + this.endDate = initEnd; } - + + public void addPlayer(Player newPlayer) { + if (newPlayer != null) { + if (players == null) + players = new ArrayList(); + + int pPosition = players.indexOf(newPlayer); + if (pPosition < 0) { + players.add(newPlayer); + } + else { + players.get(pPosition).addScore(newPlayer.getTotalScore(), newPlayer.getTotalTries()); + } + } + } + public SortedSet getPlayers() { + return new TreeSet(players); + } + + public int getScore() { + int score = 0; + + if (players != null) { + for (Player p: players) { + score = score + p.getTotalScore(); + } + } + return score; + } + + public int getTries() { + int tries = 0; + + if (players != null) { + for (Player p: players) { + tries = tries + p.getTotalTries(); + } + } + return tries; + } + public String getName() { return name; } @@ -44,10 +94,61 @@ public class Group { } public JSONObject toJson() { + return this.toJson(null); + } + public JSONObject toJson(Integer rank) { JSONObject groupJSON = new JSONObject(); groupJSON.put("name", name); - if (linkToChapter > 0) groupJSON.put("chapter", linkToChapter); - if (linkToPuzzle > 0) groupJSON.put("puzzle", linkToPuzzle); + if (rank != null) groupJSON.put("rank", rank); + else if (linkToChapter > 0) groupJSON.put("chapter", linkToChapter); + else if (linkToPuzzle > 0) groupJSON.put("puzzle", linkToPuzzle); + if (endDate != null) groupJSON.put("end_date", endDate.toString()); + if (players != null) { + JSONArray groupsPlayerJSON = new JSONArray(); + for (Player p:players) { + JSONObject playerJSON = new JSONObject(); + playerJSON.put("pseudo", p.getPseudo()); + playerJSON.put("score", p.getTotalScore()); + playerJSON.put("completion", p.getTotalCompletion()); + playerJSON.put("tries", p.getTotalTries()); + groupsPlayerJSON.add(playerJSON); + } + groupJSON.put("players", groupsPlayerJSON); + } return groupJSON; } + + @Override + public int compareTo(Group arg0) { + int comparo = arg0.getScore() - getScore(); + if (comparo == 0) { + comparo = players.size() - arg0.players.size(); + if (comparo == 0) { + comparo = getTries() - arg0.getTries(); + if (comparo == 0) { + comparo = name.compareTo(arg0.name); + } + } + } + return comparo; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Group other = (Group) obj; + return Objects.equals(name, other.name); + } + + } diff --git a/src/be/jeffcheasey88/peeratcode/model/Player.java b/src/be/jeffcheasey88/peeratcode/model/Player.java index 59677f6..1d701a9 100644 --- a/src/be/jeffcheasey88/peeratcode/model/Player.java +++ b/src/be/jeffcheasey88/peeratcode/model/Player.java @@ -1,16 +1,9 @@ package be.jeffcheasey88.peeratcode.model; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Base64; import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; import java.util.Objects; import java.util.Set; -import java.util.SortedSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -43,6 +36,18 @@ public class Player implements Comparable { totalTries = 0; } + public Player(String pseudo, int score, int tries) { + // For groups leaderboard + this.pseudo = pseudo; + totalScore = score; + totalTries = tries; + if (totalTries > 0) + totalCompletion = totalTries; + else + totalCompletion = 0; + email = ""; // TO make compareTo and equals works as usual + } + public String getPseudo() { return this.pseudo; } @@ -115,6 +120,12 @@ public class Player implements Comparable { this.totalScore = totalScore; } + public void addScore(int addScore, int tries) { + totalScore = totalScore + addScore; + totalTries = totalTries + tries; + totalCompletion++; + } + public int getTotalCompletion() { return totalCompletion; } diff --git a/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java b/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java index 9689439..9e74f10 100644 --- a/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java +++ b/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java @@ -11,7 +11,10 @@ public enum DatabaseQuery { PUZZLES_IN_CHAPTER_QUERY("SELECT p.*, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE fk_chapter = ? GROUP BY p.id_puzzle"), ALL_CHAPTERS_QUERY("SELECT * FROM chapters WHERE id_chapter > 0"), ALL_GROUPS("SELCT * FROM groups"), + ALL_PLAYERS_FOR_LEADERBOARD("select p.*, scores.*, g.* from players p ,(SELECT fk_player, SUM(c.score) AS score, COUNT(c.id_completion) AS completions, SUM(c.tries) AS tries, rank() over(ORDER BY score DESC) AS rank FROM completions c GROUP BY c.fk_player) AS scores LEFT JOIN containsGroups cg ON scores.fk_player = cg.fk_player LEFT JOIN groups g ON cg.fk_group = g.id_group WHERE p.id_player = scores.fk_player ORDER BY g.fk_chapter, g.fk_puzzle"), + ALL_GROUP_FOR_CHAPTER_LEADERBOARD("SELECT g.*, pl.pseudo, co.score, co.tries, ch.end_date FROM groups g LEFT JOIN containsGroups cg ON g.id_group = cg.fk_group LEFT JOIN players pl ON cg.fk_player = pl.id_player LEFT JOIN completions co ON pl.id_player = co.fk_player LEFT JOIN chapters ch ON g.fk_chapter = ch.id_chapter WHERE fk_chapter = ? AND (co.fk_puzzle IN (SELECT id_puzzle FROM puzzles puz WHERE puz.fk_chapter = g.fk_chapter) OR co.score IS NULL);"), + CHECK_PSEUDO_AVAILABLE_QUERY("SELECT * FROM players WHERE pseudo = ?"), CHECK_EMAIL_AVAILABLE_QUERY("SELECT * FROM players WHERE email = ?"), REGISTER_QUERY("INSERT INTO players (pseudo, email, passwd, firstname, lastname, description, avatar) VALUES (?, ?, ?, ?, ?, ?, ?)"), diff --git a/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java b/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java index a26fad3..0b1c085 100644 --- a/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java +++ b/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java @@ -80,7 +80,13 @@ public class DatabaseRepository { } private Group makeGroup(ResultSet result) throws SQLException { - return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle")); + if (hasColumn(result, "end_date")) + return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle"), result.getTimestamp("end_date")); + else + return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle")); + } + private Player makeGroupPlayer(ResultSet result) throws SQLException { + return new Player(result.getString("pseudo"), result.getInt("score"), result.getInt("tries")); } private Badge makeBadge(ResultSet rs) throws SQLException { @@ -91,8 +97,9 @@ public class DatabaseRepository { // Found on StackOverflow ResultSetMetaData rsmd = rs.getMetaData(); int columns = rsmd.getColumnCount(); - for(int x = 1; x <= columns; x++){ - if(columnName.equals(rsmd.getColumnName(x))) return true; + for (int x = 1; x <= columns; x++) { + if (columnName.equals(rsmd.getColumnName(x))) + return true; } return false; } @@ -238,6 +245,33 @@ public class DatabaseRepository { return null; } + public SortedSet getAllGroupForChapterLeaderboard(int chapterId) { + try { + ensureConnection(); + PreparedStatement groupsStmt = DatabaseQuery.ALL_GROUP_FOR_CHAPTER_LEADERBOARD.prepare(this.con); + groupsStmt.setInt(1, chapterId); + ResultSet result = groupsStmt.executeQuery(); + List groups = new ArrayList(); + Group tmpGroup; + while (result.next()) { + tmpGroup = makeGroup(result); + if (tmpGroup != null) { + int gPosition = groups.indexOf(tmpGroup); + if (gPosition < 0) { + tmpGroup.addPlayer(makeGroupPlayer(result)); + groups.add(tmpGroup); + } else { + groups.get(gPosition).addPlayer(makeGroupPlayer(result)); + } + } + } + return new TreeSet(groups); + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + public Badge getBadge(int badgeId) { try { ensureConnection(); @@ -380,7 +414,8 @@ public class DatabaseRepository { ResultSet inserted = playerStatement.getGeneratedKeys(); if (inserted.next()) { int newPlayerId = inserted.getInt(1); - try (PreparedStatement containsGroupsStatement = con.prepareStatement(DatabaseQuery.REGISTER_PLAYER_IN_EXISTING_GROUP.toString())) { + try (PreparedStatement containsGroupsStatement = con + .prepareStatement(DatabaseQuery.REGISTER_PLAYER_IN_EXISTING_GROUP.toString())) { containsGroupsStatement.setInt(1, newPlayerId); containsGroupsStatement.setString(2, sgroup); containsGroupsStatement.executeUpdate(); @@ -390,10 +425,9 @@ public class DatabaseRepository { } } } - } - catch (SQLException e) { - con.rollback(); - con.setAutoCommit(true); + } catch (SQLException e) { + con.rollback(); + con.setAutoCommit(true); } } catch (SQLException e) { e.printStackTrace(); @@ -453,8 +487,8 @@ public class DatabaseRepository { statement.setInt(6, newCompletion.getScore()); statement.executeUpdate(); } - - public boolean insertGroup(Group group){ + + public boolean insertGroup(Group group) { try { ensureConnection(); PreparedStatement statement = DatabaseQuery.INSERT_GROUP.prepare(this.con); @@ -462,7 +496,8 @@ public class DatabaseRepository { statement.setInt(2, group.getLinkToChapter()); statement.setInt(3, group.getLinkToPuzzle()); return statement.executeUpdate() >= 0; - }catch(Exception e){} + } catch (Exception e) { + } return false; } diff --git a/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java b/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java index 0230787..4ec7307 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java +++ b/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java @@ -1,5 +1,6 @@ package be.jeffcheasey88.peeratcode.routes; +import java.io.IOException; import java.util.Base64; import java.util.SortedSet; import java.util.regex.Matcher; @@ -7,6 +8,7 @@ import java.util.regex.Matcher; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import be.jeffcheasey88.peeratcode.model.Group; import be.jeffcheasey88.peeratcode.model.Player; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.webserver.HttpReader; @@ -24,10 +26,41 @@ public class Leaderboard implements Response { this.databaseRepo = databaseRepo; } - @Route(path = "^\\/leaderboard$") + @Route(path = "^\\/leaderboard\\/?(\\d+)?$") @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); + if (matcher.group(1) != null){ + groupsLeaderboard(Integer.parseInt(matcher.group(1)), writer); + } else { + playersLeaderboard(writer); + } + } + + private void groupsLeaderboard(int chapterId, HttpWriter writer) throws IOException { + SortedSet allGroupsForChapter = databaseRepo.getAllGroupForChapterLeaderboard(chapterId); + JSONArray groupsJSON = new JSONArray(); + if (allGroupsForChapter != null) { + int rank = 1; + int sameRankCount = 1; + Group previousGroup = null; + for (Group g: allGroupsForChapter) { + if (previousGroup != null) { + if (g.compareTo(previousGroup) == 0) { + sameRankCount++; + } else { + rank = rank + sameRankCount; + sameRankCount = 1; + } + } + groupsJSON.add(g.toJson(rank)); + previousGroup = g; + } + } + writer.write(groupsJSON.toJSONString().replace("\\", "")); + } + + private void playersLeaderboard(HttpWriter writer) throws IOException { SortedSet allPlayers = databaseRepo.getAllPlayerForLeaderboard(); JSONArray playersJSON = new JSONArray(); if (allPlayers != null) { From 611b45a5bd6f2e777b36cc0a2b8e47be63fccf24 Mon Sep 17 00:00:00 2001 From: Francois G Date: Sat, 8 Apr 2023 18:09:58 +0200 Subject: [PATCH 3/5] change date system to match UI attends that I didn't understand well at first --- src/be/jeffcheasey88/peeratcode/model/Group.java | 6 ------ .../peeratcode/repository/DatabaseQuery.java | 2 +- .../peeratcode/repository/DatabaseRepository.java | 5 +---- src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java | 9 ++++++++- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/be/jeffcheasey88/peeratcode/model/Group.java b/src/be/jeffcheasey88/peeratcode/model/Group.java index a73a4bc..e3e1eca 100644 --- a/src/be/jeffcheasey88/peeratcode/model/Group.java +++ b/src/be/jeffcheasey88/peeratcode/model/Group.java @@ -11,7 +11,6 @@ public class Group implements Comparable { private int linkToChapter; private int linkToPuzzle; private List players; - private Timestamp endDate; public Group(JSONObject json){ this.name = (String)json.get("name"); @@ -20,13 +19,9 @@ public class Group implements Comparable { } public Group(String name, int initChap, int initPuzz) { - this(name, initChap, initPuzz, null); - } - public Group(String name, int initChap, int initPuzz, Timestamp initEnd) { this.name = name; this.linkToChapter = initChap; this.linkToPuzzle = initPuzz; - this.endDate = initEnd; } public void addPlayer(Player newPlayer) { @@ -102,7 +97,6 @@ public class Group implements Comparable { if (rank != null) groupJSON.put("rank", rank); else if (linkToChapter > 0) groupJSON.put("chapter", linkToChapter); else if (linkToPuzzle > 0) groupJSON.put("puzzle", linkToPuzzle); - if (endDate != null) groupJSON.put("end_date", endDate.toString()); if (players != null) { JSONArray groupsPlayerJSON = new JSONArray(); for (Player p:players) { diff --git a/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java b/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java index 9e74f10..60ab08b 100644 --- a/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java +++ b/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java @@ -13,7 +13,7 @@ public enum DatabaseQuery { ALL_GROUPS("SELCT * FROM groups"), ALL_PLAYERS_FOR_LEADERBOARD("select p.*, scores.*, g.* from players p ,(SELECT fk_player, SUM(c.score) AS score, COUNT(c.id_completion) AS completions, SUM(c.tries) AS tries, rank() over(ORDER BY score DESC) AS rank FROM completions c GROUP BY c.fk_player) AS scores LEFT JOIN containsGroups cg ON scores.fk_player = cg.fk_player LEFT JOIN groups g ON cg.fk_group = g.id_group WHERE p.id_player = scores.fk_player ORDER BY g.fk_chapter, g.fk_puzzle"), - ALL_GROUP_FOR_CHAPTER_LEADERBOARD("SELECT g.*, pl.pseudo, co.score, co.tries, ch.end_date FROM groups g LEFT JOIN containsGroups cg ON g.id_group = cg.fk_group LEFT JOIN players pl ON cg.fk_player = pl.id_player LEFT JOIN completions co ON pl.id_player = co.fk_player LEFT JOIN chapters ch ON g.fk_chapter = ch.id_chapter WHERE fk_chapter = ? AND (co.fk_puzzle IN (SELECT id_puzzle FROM puzzles puz WHERE puz.fk_chapter = g.fk_chapter) OR co.score IS NULL);"), + ALL_GROUP_FOR_CHAPTER_LEADERBOARD("SELECT g.*, pl.pseudo, co.score, co.tries FROM groups g LEFT JOIN containsGroups cg ON g.id_group = cg.fk_group LEFT JOIN players pl ON cg.fk_player = pl.id_player LEFT JOIN completions co ON pl.id_player = co.fk_player WHERE fk_chapter = ? AND (co.fk_puzzle IN (SELECT id_puzzle FROM puzzles puz WHERE puz.fk_chapter = g.fk_chapter) OR co.score IS NULL);"), CHECK_PSEUDO_AVAILABLE_QUERY("SELECT * FROM players WHERE pseudo = ?"), CHECK_EMAIL_AVAILABLE_QUERY("SELECT * FROM players WHERE email = ?"), diff --git a/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java b/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java index 0b1c085..45b840e 100644 --- a/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java +++ b/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java @@ -80,10 +80,7 @@ public class DatabaseRepository { } private Group makeGroup(ResultSet result) throws SQLException { - if (hasColumn(result, "end_date")) - return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle"), result.getTimestamp("end_date")); - else - return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle")); + return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle")); } private Player makeGroupPlayer(ResultSet result) throws SQLException { return new Player(result.getString("pseudo"), result.getInt("score"), result.getInt("tries")); diff --git a/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java b/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java index 4ec7307..a537941 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java +++ b/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java @@ -8,6 +8,7 @@ import java.util.regex.Matcher; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import be.jeffcheasey88.peeratcode.model.Chapter; import be.jeffcheasey88.peeratcode.model.Group; import be.jeffcheasey88.peeratcode.model.Player; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; @@ -38,7 +39,12 @@ public class Leaderboard implements Response { } private void groupsLeaderboard(int chapterId, HttpWriter writer) throws IOException { + Chapter chInfo = databaseRepo.getChapter(chapterId); + SortedSet allGroupsForChapter = databaseRepo.getAllGroupForChapterLeaderboard(chapterId); + JSONObject leaderboardJSON = new JSONObject(); + if (chInfo.getStartDate() != null) leaderboardJSON.put("start_date", chInfo.getStartDate().toString()); + if (chInfo.getEndDate() != null) leaderboardJSON.put("end_date", chInfo.getEndDate().toString()); JSONArray groupsJSON = new JSONArray(); if (allGroupsForChapter != null) { int rank = 1; @@ -57,7 +63,8 @@ public class Leaderboard implements Response { previousGroup = g; } } - writer.write(groupsJSON.toJSONString().replace("\\", "")); + leaderboardJSON.put("groups", groupsJSON); + writer.write(leaderboardJSON.toJSONString().replace("\\", "")); } private void playersLeaderboard(HttpWriter writer) throws IOException { From 109ab984b300d8895ad200563169a193a2f5017c Mon Sep 17 00:00:00 2001 From: Francois G Date: Sun, 9 Apr 2023 08:40:13 +0200 Subject: [PATCH 4/5] Remove unused method, organize imports and format all files --- .../peeratcode/Configuration.java | 153 +++--- src/be/jeffcheasey88/peeratcode/Main.java | 29 +- .../jeffcheasey88/peeratcode/model/Badge.java | 17 - .../peeratcode/model/Chapter.java | 25 +- .../peeratcode/model/Completion.java | 9 +- .../jeffcheasey88/peeratcode/model/Group.java | 70 ++- .../peeratcode/model/Player.java | 10 - .../peeratcode/model/Puzzle.java | 71 +-- .../peeratcode/repository/DatabaseQuery.java | 81 ++- .../peeratcode/routes/BadgeDetails.java | 16 +- .../peeratcode/routes/ChapterElement.java | 19 +- .../peeratcode/routes/ChapterList.java | 6 +- .../peeratcode/routes/Leaderboard.java | 20 +- .../peeratcode/routes/Login.java | 18 +- .../peeratcode/routes/PlayerDetails.java | 11 +- .../peeratcode/routes/PuzzleElement.java | 10 +- .../peeratcode/routes/PuzzleResponse.java | 9 +- .../peeratcode/routes/Register.java | 11 +- .../peeratcode/routes/Result.java | 19 +- .../peeratcode/routes/groups/CreateGroup.java | 14 +- .../peeratcode/routes/groups/GroupList.java | 12 +- .../peeratcode/webserver/Client.java | 42 +- .../peeratcode/webserver/HttpReader.java | 42 +- .../peeratcode/webserver/HttpUtil.java | 502 +++++++++--------- .../peeratcode/webserver/HttpWriter.java | 22 +- .../peeratcode/webserver/Response.java | 7 +- .../peeratcode/webserver/Route.java | 4 +- .../peeratcode/webserver/Router.java | 81 +-- .../peeratcode/webserver/User.java | 10 +- 29 files changed, 650 insertions(+), 690 deletions(-) diff --git a/src/be/jeffcheasey88/peeratcode/Configuration.java b/src/be/jeffcheasey88/peeratcode/Configuration.java index a5700a7..eb6672d 100644 --- a/src/be/jeffcheasey88/peeratcode/Configuration.java +++ b/src/be/jeffcheasey88/peeratcode/Configuration.java @@ -8,147 +8,152 @@ import java.io.FileWriter; import java.lang.reflect.Field; public class Configuration { - + private String db_host; private int db_port; private String db_user; private String db_database; private String db_password; - + private int tcp_port; private boolean use_ssl; private String ssl_keystore; private String ssl_keystorePasswd; - + private String users_files; private String token_issuer; private int token_expiration; - + private File _file; - - public Configuration(String path){ + + public Configuration(String path) { this._file = new File(path); - System.out.println("Config on "+_file.getAbsolutePath()); + System.out.println("Config on " + _file.getAbsolutePath()); } - - public void load() throws Exception{ - if(!this._file.exists()) return; + + public void load() throws Exception { + if (!this._file.exists()) + return; BufferedReader reader = new BufferedReader(new FileReader(this._file)); String line; - while((line = reader.readLine()) != null){ + while ((line = reader.readLine()) != null) { String[] split = line.split("="); Field field = getClass().getDeclaredField(split[0]); - if(field == null) continue; + if (field == null) + continue; field.setAccessible(true); injectValue(field, split[1]); } reader.close(); } - - private void injectValue(Field field, String value) throws IllegalAccessException{ - if(field.getType().isPrimitive()){ - switch(field.getType().getName()){ - case "boolean": - field.setBoolean(this, Boolean.parseBoolean(value)); - break; - case "byte": - field.setByte(this, Byte.parseByte(value)); - break; - case "char": - field.setChar(this, value.charAt(0)); - break; - case "double": - field.setDouble(this, Double.parseDouble(value)); - break; - case "float": - field.setFloat(this, Float.parseFloat(value)); - break; - case "int": - field.setInt(this, Integer.parseInt(value)); - break; - case "long": - field.setLong(this, Long.parseLong(value)); - break; - case "short": - field.setShort(this, Short.parseShort(value)); - break; - default: throw new IllegalArgumentException(value); + + private void injectValue(Field field, String value) throws IllegalAccessException { + if (field.getType().isPrimitive()) { + switch (field.getType().getName()) { + case "boolean": + field.setBoolean(this, Boolean.parseBoolean(value)); + break; + case "byte": + field.setByte(this, Byte.parseByte(value)); + break; + case "char": + field.setChar(this, value.charAt(0)); + break; + case "double": + field.setDouble(this, Double.parseDouble(value)); + break; + case "float": + field.setFloat(this, Float.parseFloat(value)); + break; + case "int": + field.setInt(this, Integer.parseInt(value)); + break; + case "long": + field.setLong(this, Long.parseLong(value)); + break; + case "short": + field.setShort(this, Short.parseShort(value)); + break; + default: + throw new IllegalArgumentException(value); } return; } - if(field.getType().equals(String.class)){ + if (field.getType().equals(String.class)) { field.set(this, value); return; } throw new IllegalArgumentException(value); } - - public void save() throws Exception{ - if(!_file.exists()){ + + public void save() throws Exception { + if (!_file.exists()) { File parent = _file.getParentFile(); - if(!parent.exists()) parent.mkdirs(); + if (!parent.exists()) + parent.mkdirs(); _file.createNewFile(); } Field[] fields = getClass().getDeclaredFields(); BufferedWriter writer = new BufferedWriter(new FileWriter(_file)); - for(Field field : fields){ + for (Field field : fields) { field.setAccessible(true); - if(field.getName().startsWith("_")) continue; + if (field.getName().startsWith("_")) + continue; Object value = field.get(this); - writer.write(field.getName()+"="+value); + writer.write(field.getName() + "=" + value); } writer.flush(); writer.close(); } - - public String getDbHost(){ + + public String getDbHost() { return this.db_host; } - - public int getDbPort(){ + + public int getDbPort() { return this.db_port; } - - public String getDbUser(){ + + public String getDbUser() { return this.db_user; } - - public String getDbDatabase(){ + + public String getDbDatabase() { return this.db_database; } - - public String getDbPassword(){ + + public String getDbPassword() { return this.db_password; } - - public String getSslKeystore(){ + + public String getSslKeystore() { return this.ssl_keystore; } - - public String getTokenIssuer(){ + + public String getTokenIssuer() { return this.token_issuer; } - - public int getTokenExpiration(){ + + public int getTokenExpiration() { return this.token_expiration; } - - public String getSslKeystorePasswd(){ + + public String getSslKeystorePasswd() { return this.ssl_keystorePasswd; } - - public int getTcpPort(){ + + public int getTcpPort() { return this.tcp_port; } - - public boolean useSsl(){ + + public boolean useSsl() { return this.use_ssl; } - - public String getUsersFiles(){ + + public String getUsersFiles() { if (users_files == null || users_files.trim().isEmpty()) users_files = "/tmp/users_files"; return users_files; } - } \ No newline at end of file +} \ No newline at end of file diff --git a/src/be/jeffcheasey88/peeratcode/Main.java b/src/be/jeffcheasey88/peeratcode/Main.java index 74dbe24..9afabfb 100644 --- a/src/be/jeffcheasey88/peeratcode/Main.java +++ b/src/be/jeffcheasey88/peeratcode/Main.java @@ -40,9 +40,10 @@ public class Main { Class.forName("com.mysql.cj.jdbc.Driver"); - Router router = new Router(new DatabaseRepository(config), config.getTokenIssuer(), config.getTokenExpiration()); + Router router = new Router(new DatabaseRepository(config), config.getTokenIssuer(), + config.getTokenExpiration()); - router.setDefault(new Response(){ + router.setDefault(new Response() { @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { HttpUtil.responseHeaders(writer, 404, "Access-Control-Allow-Origin: *"); @@ -51,15 +52,13 @@ public class Main { writer.close(); } }); - - router.register(new Response(){ + + router.register(new Response() { @Route(path = "^(.*)$", type = "OPTIONS") @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { - HttpUtil.responseHeaders(writer, 200, - "Access-Control-Allow-Origin: *", - "Access-Control-Allow-Methods: *", - "Access-Control-Allow-Headers: *"); + HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *", + "Access-Control-Allow-Methods: *", "Access-Control-Allow-Headers: *"); } }); @@ -79,13 +78,13 @@ public class Main { router.register(new Leaderboard(router.getDataBase())); router.register(new PlayerDetails(router.getDataBase())); router.register(new BadgeDetails(router.getDataBase())); - + router.register(new GroupList(router.getDataBase())); router.register(new CreateGroup(router.getDataBase())); } private static void startWebServer(Configuration config, Router router) throws IOException { - if (config.useSsl()) { + if (config.useSsl()) { // Not needed with the use of a proxy SSLServerSocket server = null; try { System.setProperty("javax.net.ssl.keyStore", config.getSslKeystore()); @@ -106,17 +105,15 @@ public class Main { server.close(); } } - } - else { - try (ServerSocket server = new ServerSocket(config.getTcpPort())){ - while(!server.isClosed()){ + } else { + try (ServerSocket server = new ServerSocket(config.getTcpPort())) { + while (!server.isClosed()) { Socket socket = server.accept(); RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048); Client client = new Client(socket, router, rsaJsonWebKey); client.start(); } - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } } diff --git a/src/be/jeffcheasey88/peeratcode/model/Badge.java b/src/be/jeffcheasey88/peeratcode/model/Badge.java index 55f6834..48f54f6 100644 --- a/src/be/jeffcheasey88/peeratcode/model/Badge.java +++ b/src/be/jeffcheasey88/peeratcode/model/Badge.java @@ -5,10 +5,6 @@ public class Badge { private byte[] logo; private int level; - public Badge(String name, int level) { - this(name, null, level); - } - public Badge(String name, byte[] logo, int level) { this.name = name; this.logo = logo; @@ -19,24 +15,11 @@ public class Badge { return name; } - public void setName(String name) { - this.name = name; - } - public byte[] getLogo() { return logo; } - public void setLogo(byte[] logo) { - this.logo = logo; - } - public int getLevel() { return level; } - - public void setLevel(int level) { - this.level = level; - } - } diff --git a/src/be/jeffcheasey88/peeratcode/model/Chapter.java b/src/be/jeffcheasey88/peeratcode/model/Chapter.java index f286ae3..0e1b3b1 100644 --- a/src/be/jeffcheasey88/peeratcode/model/Chapter.java +++ b/src/be/jeffcheasey88/peeratcode/model/Chapter.java @@ -1,11 +1,10 @@ package be.jeffcheasey88.peeratcode.model; import java.sql.Timestamp; -import java.time.LocalDateTime; import java.util.List; public class Chapter { - + private int id; private String name; private List puzzles; @@ -23,18 +22,10 @@ public class Chapter { return id; } - public void setId(int id) { - this.id = id; - } - public String getName() { return name; } - public void setName(String name) { - this.name = name; - } - public List getPuzzles() { return puzzles; } @@ -42,20 +33,22 @@ public class Chapter { public void setPuzzles(List puzzles) { this.puzzles = puzzles; } - + public Timestamp getStartDate() { return startDate; } - + public Timestamp getEndDate() { return endDate; } @Override - public boolean equals(Object object){ - if(this == object) return true; - if(!(object instanceof Chapter)) return false; - return this.id == (((Chapter)object).id); + public boolean equals(Object object) { + if (this == object) + return true; + if (!(object instanceof Chapter)) + return false; + return this.id == (((Chapter) object).id); } @Override diff --git a/src/be/jeffcheasey88/peeratcode/model/Completion.java b/src/be/jeffcheasey88/peeratcode/model/Completion.java index 2259136..f36e813 100644 --- a/src/be/jeffcheasey88/peeratcode/model/Completion.java +++ b/src/be/jeffcheasey88/peeratcode/model/Completion.java @@ -11,10 +11,6 @@ public class Completion { public Completion(int playerId, int puzzleId, String fileName, int score) { this(playerId, puzzleId, -1, 1, fileName, score, null); } - - public Completion(int playerId, int puzzleId, int idCompletion, int tries, String fileName, int score) { - this(playerId, puzzleId, idCompletion, tries, fileName, score, null); - } public Completion(int playerId, int puzzleId, int idCompletion, int tries, String fileName, int score, byte[] file) { @@ -25,7 +21,7 @@ public class Completion { this.score = score; this.code = file; } - + public int getPuzzleId() { return puzzleId; } @@ -42,9 +38,10 @@ public class Completion { this.tries++; updateScore(); } + private void updateScore() { if (tries > 1) { - score = score * (1-((tries-1)/10)); + score = score * (1 - ((tries - 1) / 10)); } } diff --git a/src/be/jeffcheasey88/peeratcode/model/Group.java b/src/be/jeffcheasey88/peeratcode/model/Group.java index e3e1eca..74a7c7b 100644 --- a/src/be/jeffcheasey88/peeratcode/model/Group.java +++ b/src/be/jeffcheasey88/peeratcode/model/Group.java @@ -1,7 +1,10 @@ package be.jeffcheasey88.peeratcode.model; -import java.sql.Timestamp; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.SortedSet; +import java.util.TreeSet; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -11,95 +14,83 @@ public class Group implements Comparable { private int linkToChapter; private int linkToPuzzle; private List players; - - public Group(JSONObject json){ - this.name = (String)json.get("name"); - this.linkToChapter = ((Number)json.get("chapter")).intValue(); - this.linkToPuzzle = ((Number)json.get("puzzle")).intValue(); + + public Group(JSONObject json) { + this.name = (String) json.get("name"); + this.linkToChapter = ((Number) json.get("chapter")).intValue(); + this.linkToPuzzle = ((Number) json.get("puzzle")).intValue(); } - + public Group(String name, int initChap, int initPuzz) { this.name = name; this.linkToChapter = initChap; this.linkToPuzzle = initPuzz; } - + public void addPlayer(Player newPlayer) { if (newPlayer != null) { if (players == null) players = new ArrayList(); - + int pPosition = players.indexOf(newPlayer); if (pPosition < 0) { players.add(newPlayer); - } - else { + } else { players.get(pPosition).addScore(newPlayer.getTotalScore(), newPlayer.getTotalTries()); } } } - public SortedSet getPlayers() { - return new TreeSet(players); - } - + public int getScore() { int score = 0; - + if (players != null) { - for (Player p: players) { + for (Player p : players) { score = score + p.getTotalScore(); } } return score; } - + public int getTries() { int tries = 0; - + if (players != null) { - for (Player p: players) { + for (Player p : players) { tries = tries + p.getTotalTries(); } } return tries; } - + public String getName() { return name; } - public void setName(String name) { - this.name = name; - } - public int getLinkToChapter() { return linkToChapter; } - public void setLinkToChapter(int linkToChapter) { - this.linkToChapter = linkToChapter; - } - public int getLinkToPuzzle() { return linkToPuzzle; } - public void setLinkToPuzzle(int linkToPuzzle) { - this.linkToPuzzle = linkToPuzzle; - } - public JSONObject toJson() { return this.toJson(null); } + public JSONObject toJson(Integer rank) { JSONObject groupJSON = new JSONObject(); groupJSON.put("name", name); - if (rank != null) groupJSON.put("rank", rank); - else if (linkToChapter > 0) groupJSON.put("chapter", linkToChapter); - else if (linkToPuzzle > 0) groupJSON.put("puzzle", linkToPuzzle); + if (rank != null) + groupJSON.put("rank", rank); + else if (linkToChapter > 0) + groupJSON.put("chapter", linkToChapter); + else if (linkToPuzzle > 0) + groupJSON.put("puzzle", linkToPuzzle); if (players != null) { JSONArray groupsPlayerJSON = new JSONArray(); - for (Player p:players) { + for (Player p : players) { JSONObject playerJSON = new JSONObject(); playerJSON.put("pseudo", p.getPseudo()); playerJSON.put("score", p.getTotalScore()); @@ -143,6 +134,5 @@ public class Group implements Comparable { Group other = (Group) obj; return Objects.equals(name, other.name); } - - + } diff --git a/src/be/jeffcheasey88/peeratcode/model/Player.java b/src/be/jeffcheasey88/peeratcode/model/Player.java index 1d701a9..328d07b 100644 --- a/src/be/jeffcheasey88/peeratcode/model/Player.java +++ b/src/be/jeffcheasey88/peeratcode/model/Player.java @@ -72,11 +72,6 @@ public class Player implements Comparable { return groups; } - /** - * SEE SET_TAGS IN PUZZLE - * - * @return DEATH - */ public JSONArray getJsonGroups() { if (groups != null) { JSONArray groupsJSON = new JSONArray(); @@ -146,11 +141,6 @@ public class Player implements Comparable { return badges; } - /** - * SEE SET_TAGS IN PUZZLE - * - * @return DEATH - */ public JSONArray getJsonBadges() { if (badges == null) return null; diff --git a/src/be/jeffcheasey88/peeratcode/model/Puzzle.java b/src/be/jeffcheasey88/peeratcode/model/Puzzle.java index 192fab2..75e6427 100644 --- a/src/be/jeffcheasey88/peeratcode/model/Puzzle.java +++ b/src/be/jeffcheasey88/peeratcode/model/Puzzle.java @@ -8,7 +8,7 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; public class Puzzle { - + private int id; private String name; private String content; @@ -18,10 +18,8 @@ public class Puzzle { private Set tags; private int depend; - public Puzzle(int id, String name, String content, byte[] soluce, String verify, int scoreMax, String tags){ - this(id, name, content, soluce, verify, scoreMax, tags, -1); - } - public Puzzle(int id, String name, String content, byte[] soluce, String verify, int scoreMax, String tags, int depend){ + public Puzzle(int id, String name, String content, byte[] soluce, String verify, int scoreMax, String tags, + int depend) { this.id = id; this.name = name; this.content = content; @@ -36,90 +34,61 @@ public class Puzzle { return id; } - public void setId(int id) { - this.id = id; - } - public String getName() { return name; } - public void setName(String name) { - this.name = name; - } - public String getContent() { return content; } - public void setContent(String content) { - this.content = content; - } - - public byte[] getSoluce(){ + public byte[] getSoluce() { return this.soluce; } - - public void setSoluce(byte[] array){ - this.soluce = array; - } - - public String getVerify(){ - return this.verify; - } - - public void setVerify(String regex){ - this.verify = regex; - } - - public int getScoreMax(){ + + public int getScoreMax() { return this.scoreMax; } - - public void setScoreMax(int max){ - this.scoreMax = max; - } - - public Set getTags(){ + + public Set getTags() { return this.tags; } - + /** * DO NOT EVER EVER SHOW TO MISTER LUDWIG XD + * * @return DEATH */ public JSONArray getJsonTags() { if (tags == null) return null; JSONArray tagsJSON = new JSONArray(); - for (String tag: tags) { + for (String tag : tags) { JSONObject tagJSON = new JSONObject(); tagJSON.put("name", tag); tagsJSON.add(tagJSON); } return tagsJSON; } - - public void setTags(String tags){ + + public void setTags(String tags) { if (tags == null || tags.isEmpty()) this.tags = null; else this.tags = new HashSet(Arrays.asList(tags.split(","))); } - - public int getDepend(){ + + public int getDepend() { return this.depend; } - - public void setDepend(int depend){ - this.depend = depend; - } @Override public boolean equals(Object object) { - if(this == object) return true; - if(!(object instanceof Puzzle)) return false; - return this.id == (((Puzzle)object).id); + if (this == object) + return true; + if (!(object instanceof Puzzle)) + return false; + return this.id == (((Puzzle) object).id); } @Override diff --git a/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java b/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java index 60ab08b..fe876a5 100644 --- a/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java +++ b/src/be/jeffcheasey88/peeratcode/repository/DatabaseQuery.java @@ -5,49 +5,72 @@ import java.sql.PreparedStatement; import java.sql.SQLException; public enum DatabaseQuery { - - SPECIFIC_PUZZLE_QUERY("SELECT p.*, np.origin, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN nextPart np ON p.id_puzzle = np.next LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE p.id_puzzle = ? GROUP BY p.id_puzzle"), + // PUZZLES + SPECIFIC_PUZZLE_QUERY( + "SELECT p.*, np.origin, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN nextPart np ON p.id_puzzle = np.next LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE p.id_puzzle = ? GROUP BY p.id_puzzle"), + PUZZLES_IN_CHAPTER_QUERY( + "SELECT p.*, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE fk_chapter = ? GROUP BY p.id_puzzle"), + + // CHAPTERS SPECIFIC_CHAPTER_QUERY("SELECT * FROM chapters WHERE id_chapter = ?"), - PUZZLES_IN_CHAPTER_QUERY("SELECT p.*, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE fk_chapter = ? GROUP BY p.id_puzzle"), ALL_CHAPTERS_QUERY("SELECT * FROM chapters WHERE id_chapter > 0"), - ALL_GROUPS("SELCT * FROM groups"), - - ALL_PLAYERS_FOR_LEADERBOARD("select p.*, scores.*, g.* from players p ,(SELECT fk_player, SUM(c.score) AS score, COUNT(c.id_completion) AS completions, SUM(c.tries) AS tries, rank() over(ORDER BY score DESC) AS rank FROM completions c GROUP BY c.fk_player) AS scores LEFT JOIN containsGroups cg ON scores.fk_player = cg.fk_player LEFT JOIN groups g ON cg.fk_group = g.id_group WHERE p.id_player = scores.fk_player ORDER BY g.fk_chapter, g.fk_puzzle"), - ALL_GROUP_FOR_CHAPTER_LEADERBOARD("SELECT g.*, pl.pseudo, co.score, co.tries FROM groups g LEFT JOIN containsGroups cg ON g.id_group = cg.fk_group LEFT JOIN players pl ON cg.fk_player = pl.id_player LEFT JOIN completions co ON pl.id_player = co.fk_player WHERE fk_chapter = ? AND (co.fk_puzzle IN (SELECT id_puzzle FROM puzzles puz WHERE puz.fk_chapter = g.fk_chapter) OR co.score IS NULL);"), - + + // GROUPS + ALL_GROUPS("SELCT * FROM groups"), INSERT_GROUP("INSERT INTO groups (name, fk_chapter, fk_puzzle) VALUES (?,?,?)"), + UPDATE_COMPLETION( + "UPDATE completions SET tries = ?, filename = ?, score = ? WHERE fk_puzzle = ? AND fk_player = ?"), + + // LEADERBOARD + ALL_PLAYERS_FOR_LEADERBOARD( + "select p.*, scores.*, g.* from players p ,(SELECT fk_player, SUM(c.score) AS score, COUNT(c.id_completion) AS completions, SUM(c.tries) AS tries, rank() over(ORDER BY score DESC) AS rank FROM completions c GROUP BY c.fk_player) AS scores LEFT JOIN containsGroups cg ON scores.fk_player = cg.fk_player LEFT JOIN groups g ON cg.fk_group = g.id_group WHERE p.id_player = scores.fk_player ORDER BY g.fk_chapter, g.fk_puzzle"), + ALL_GROUP_FOR_CHAPTER_LEADERBOARD( + "SELECT g.*, pl.pseudo, co.score, co.tries FROM groups g LEFT JOIN containsGroups cg ON g.id_group = cg.fk_group LEFT JOIN players pl ON cg.fk_player = pl.id_player LEFT JOIN completions co ON pl.id_player = co.fk_player WHERE fk_chapter = ? AND (co.fk_puzzle IN (SELECT id_puzzle FROM puzzles puz WHERE puz.fk_chapter = g.fk_chapter) OR co.score IS NULL);"), + + // REGISTER CHECK_PSEUDO_AVAILABLE_QUERY("SELECT * FROM players WHERE pseudo = ?"), CHECK_EMAIL_AVAILABLE_QUERY("SELECT * FROM players WHERE email = ?"), - REGISTER_QUERY("INSERT INTO players (pseudo, email, passwd, firstname, lastname, description, avatar) VALUES (?, ?, ?, ?, ?, ?, ?)"), - REGISTER_PLAYER_IN_EXISTING_GROUP("INSERT INTO containsGroups (fk_player, fk_group) VALUES (?, (SELECT id_group FROM groups WHERE name = ?));"), + REGISTER_QUERY( + "INSERT INTO players (pseudo, email, passwd, firstname, lastname, description, avatar) VALUES (?, ?, ?, ?, ?, ?, ?)"), + REGISTER_PLAYER_IN_EXISTING_GROUP( + "INSERT INTO containsGroups (fk_player, fk_group) VALUES (?, (SELECT id_group FROM groups WHERE name = ?));"), + + // LOGIN CHECK_PASSWORD("SELECT id_player, passwd FROM players WHERE pseudo=?"), + + // COMPLETIONS + GET_COMPLETION( + "SELECT id_completion, tries, fileName, score FROM completions WHERE fk_puzzle = ? AND fk_player = ?"), + INSERT_COMPLETION( + "INSERT INTO completions (fk_puzzle, fk_player, tries, code, fileName, score) values (?, ?, ?, ?, ?, ?)"), SCORE("SELECT score FROM completions WHERE fk_player = ? AND fk_puzzle = ?"), - GET_COMPLETION("SELECT id_completion, tries, fileName, score FROM completions WHERE fk_puzzle = ? AND fk_player = ?"), + + // PLAYERS GET_PLAYER_SIMPLE("SELECT pseudo, email, firstname, lastname, description FROM players WHERE id_player = ?"), - GET_PLAYER_DETAILS("SELECT p.*, scores.score, scores.completions, scores.tries, scores.rank, g.* FROM players p, (SELECT fk_player, SUM(c.score) AS score, COUNT(c.id_completion) AS completions, SUM(c.tries) AS tries, rank() over(ORDER BY score DESC) AS rank FROM completions c GROUP BY c.fk_player) AS scores LEFT JOIN containsGroups cg ON scores.fk_player = cg.fk_player LEFT JOIN groups g ON cg.fk_group = g.id_group WHERE p.id_player = scores.fk_player AND "), - GET_PLAYER_DETAILS_BY_ID(GET_PLAYER_DETAILS," p.id_player = ? ORDER BY g.fk_chapter, g.fk_puzzle;"), - GET_PLAYER_DETAILS_BY_PSEUDO(GET_PLAYER_DETAILS,"p.pseudo = ? ORDER BY g.fk_chapter, g.fk_puzzle;"), - GET_BADGE("SELECT * FROM badges WHERE id_badge = ?"), - GET_BADGES_OF_PLAYER("SELECT * FROM badges b LEFT JOIN containsBadges cb ON cb.fk_badge = b.id_badge WHERE cb.fk_player = ?"), - INSERT_COMPLETION("INSERT INTO completions (fk_puzzle, fk_player, tries, code, fileName, score) values (?, ?, ?, ?, ?, ?)"), - INSERT_GROUP("INSERT INTO groups (name, fk_chapter, fk_puzzle) VALUES (?,?,?)"), - UPDATE_COMPLETION("UPDATE completions SET tries = ?, filename = ?, score = ? WHERE fk_puzzle = ? AND fk_player = ?"); - + GET_PLAYER_DETAILS( + "SELECT p.*, scores.score, scores.completions, scores.tries, scores.rank, g.* FROM players p, (SELECT fk_player, SUM(c.score) AS score, COUNT(c.id_completion) AS completions, SUM(c.tries) AS tries, rank() over(ORDER BY score DESC) AS rank FROM completions c GROUP BY c.fk_player) AS scores LEFT JOIN containsGroups cg ON scores.fk_player = cg.fk_player LEFT JOIN groups g ON cg.fk_group = g.id_group WHERE p.id_player = scores.fk_player AND "), + GET_PLAYER_DETAILS_BY_ID(GET_PLAYER_DETAILS, " p.id_player = ? ORDER BY g.fk_chapter, g.fk_puzzle;"), + GET_PLAYER_DETAILS_BY_PSEUDO(GET_PLAYER_DETAILS, "p.pseudo = ? ORDER BY g.fk_chapter, g.fk_puzzle;"), + + // BADGES + GET_BADGE("SELECT * FROM badges WHERE id_badge = ?"), GET_BADGES_OF_PLAYER( + "SELECT * FROM badges b LEFT JOIN containsBadges cb ON cb.fk_badge = b.id_badge WHERE cb.fk_player = ?"); + private String request; - - DatabaseQuery(DatabaseQuery parent, String request){ - this.request = parent.request+request; + + DatabaseQuery(DatabaseQuery parent, String request) { + this.request = parent.request + request; } - - DatabaseQuery(String request){ + + DatabaseQuery(String request) { this.request = request; } - - public PreparedStatement prepare(Connection con) throws SQLException{ + + public PreparedStatement prepare(Connection con) throws SQLException { return con.prepareStatement(this.request); } - + @Override - public String toString(){ + public String toString() { return this.request; } } diff --git a/src/be/jeffcheasey88/peeratcode/routes/BadgeDetails.java b/src/be/jeffcheasey88/peeratcode/routes/BadgeDetails.java index e96aa5e..4633acb 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/BadgeDetails.java +++ b/src/be/jeffcheasey88/peeratcode/routes/BadgeDetails.java @@ -1,5 +1,10 @@ package be.jeffcheasey88.peeratcode.routes; +import java.util.Base64; +import java.util.regex.Matcher; + +import org.json.simple.JSONObject; + import be.jeffcheasey88.peeratcode.model.Badge; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.webserver.HttpReader; @@ -9,11 +14,6 @@ import be.jeffcheasey88.peeratcode.webserver.Response; import be.jeffcheasey88.peeratcode.webserver.Route; import be.jeffcheasey88.peeratcode.webserver.User; -import org.json.simple.JSONObject; - -import java.util.Base64; -import java.util.regex.Matcher; - public class BadgeDetails implements Response { private final DatabaseRepository databaseRepo; @@ -32,12 +32,12 @@ public class BadgeDetails implements Response { JSONObject badgeJSON = new JSONObject(); if (badge != null) { badgeJSON.put("name", badge.getName()); - if(badge.getLogo() != null) badgeJSON.put("logo", Base64.getEncoder().encodeToString(badge.getLogo())); + if (badge.getLogo() != null) + badgeJSON.put("logo", Base64.getEncoder().encodeToString(badge.getLogo())); badgeJSON.put("level", badge.getLevel()); } writer.write(badgeJSON.toJSONString().replace("\\", "")); - } - else { + } else { HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); } } diff --git a/src/be/jeffcheasey88/peeratcode/routes/ChapterElement.java b/src/be/jeffcheasey88/peeratcode/routes/ChapterElement.java index 8931419..ea0a70e 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/ChapterElement.java +++ b/src/be/jeffcheasey88/peeratcode/routes/ChapterElement.java @@ -1,5 +1,10 @@ package be.jeffcheasey88.peeratcode.routes; +import java.util.regex.Matcher; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + import be.jeffcheasey88.peeratcode.model.Chapter; import be.jeffcheasey88.peeratcode.model.Puzzle; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; @@ -10,11 +15,6 @@ import be.jeffcheasey88.peeratcode.webserver.Response; import be.jeffcheasey88.peeratcode.webserver.Route; import be.jeffcheasey88.peeratcode.webserver.User; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import java.util.regex.Matcher; - public class ChapterElement implements Response { private final DatabaseRepository databaseRepo; @@ -32,14 +32,17 @@ public class ChapterElement implements Response { JSONObject chapterJSON = new JSONObject(); chapterJSON.put("id", chapter.getId()); chapterJSON.put("name", chapter.getName()); - if (chapter.getStartDate() != null) chapterJSON.put("startDate", chapter.getStartDate().toString()); - if (chapter.getEndDate() != null) chapterJSON.put("endDate", chapter.getEndDate().toString()); + if (chapter.getStartDate() != null) + chapterJSON.put("startDate", chapter.getStartDate().toString()); + if (chapter.getEndDate() != null) + chapterJSON.put("endDate", chapter.getEndDate().toString()); JSONArray puzzles = new JSONArray(); for (Puzzle puzzle : chapter.getPuzzles()) { JSONObject puzzleJSON = new JSONObject(); puzzleJSON.put("id", puzzle.getId()); puzzleJSON.put("name", puzzle.getName()); - if (puzzle.getTags() != null) puzzleJSON.put("tags", puzzle.getJsonTags()); + if (puzzle.getTags() != null) + puzzleJSON.put("tags", puzzle.getJsonTags()); puzzles.add(puzzleJSON); } chapterJSON.put("puzzles", puzzles); diff --git a/src/be/jeffcheasey88/peeratcode/routes/ChapterList.java b/src/be/jeffcheasey88/peeratcode/routes/ChapterList.java index a12e9d1..30b092a 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/ChapterList.java +++ b/src/be/jeffcheasey88/peeratcode/routes/ChapterList.java @@ -34,8 +34,10 @@ public class ChapterList implements Response { JSONObject chapterJSON = new JSONObject(); chapterJSON.put("id", chapter.getId()); chapterJSON.put("name", chapter.getName()); - if (chapter.getStartDate() != null) chapterJSON.put("startDate", chapter.getStartDate().toString()); - if (chapter.getEndDate() != null) chapterJSON.put("endDate", chapter.getEndDate().toString()); + if (chapter.getStartDate() != null) + chapterJSON.put("startDate", chapter.getStartDate().toString()); + if (chapter.getEndDate() != null) + chapterJSON.put("endDate", chapter.getEndDate().toString()); chaptersJSON.add(chapterJSON); } writer.write(chaptersJSON.toJSONString()); diff --git a/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java b/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java index a537941..9b29237 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java +++ b/src/be/jeffcheasey88/peeratcode/routes/Leaderboard.java @@ -31,7 +31,7 @@ public class Leaderboard implements Response { @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); - if (matcher.group(1) != null){ + if (matcher.group(1) != null) { groupsLeaderboard(Integer.parseInt(matcher.group(1)), writer); } else { playersLeaderboard(writer); @@ -40,17 +40,19 @@ public class Leaderboard implements Response { private void groupsLeaderboard(int chapterId, HttpWriter writer) throws IOException { Chapter chInfo = databaseRepo.getChapter(chapterId); - + SortedSet allGroupsForChapter = databaseRepo.getAllGroupForChapterLeaderboard(chapterId); JSONObject leaderboardJSON = new JSONObject(); - if (chInfo.getStartDate() != null) leaderboardJSON.put("start_date", chInfo.getStartDate().toString()); - if (chInfo.getEndDate() != null) leaderboardJSON.put("end_date", chInfo.getEndDate().toString()); + if (chInfo.getStartDate() != null) + leaderboardJSON.put("start_date", chInfo.getStartDate().toString()); + if (chInfo.getEndDate() != null) + leaderboardJSON.put("end_date", chInfo.getEndDate().toString()); JSONArray groupsJSON = new JSONArray(); if (allGroupsForChapter != null) { int rank = 1; int sameRankCount = 1; - Group previousGroup = null; - for (Group g: allGroupsForChapter) { + Group previousGroup = null; + for (Group g : allGroupsForChapter) { if (previousGroup != null) { if (g.compareTo(previousGroup) == 0) { sameRankCount++; @@ -74,8 +76,10 @@ public class Leaderboard implements Response { for (Player player : allPlayers) { JSONObject playerJSON = new JSONObject(); playerJSON.put("pseudo", player.getPseudo()); - if (player.getGroups() != null) playerJSON.put("groups", player.getJsonGroups()); - if(player.getAvatar() != null) playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar())); + if (player.getGroups() != null) + playerJSON.put("groups", player.getJsonGroups()); + if (player.getAvatar() != null) + playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar())); playerJSON.put("rank", player.getRank()); playerJSON.put("score", player.getTotalScore()); playerJSON.put("completions", player.getTotalCompletion()); diff --git a/src/be/jeffcheasey88/peeratcode/routes/Login.java b/src/be/jeffcheasey88/peeratcode/routes/Login.java index ae33b8d..2e06a67 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/Login.java +++ b/src/be/jeffcheasey88/peeratcode/routes/Login.java @@ -1,12 +1,7 @@ package be.jeffcheasey88.peeratcode.routes; import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.jose4j.jwk.RsaJsonWebKey; -import org.jose4j.jws.AlgorithmIdentifiers; -import org.jose4j.jws.JsonWebSignature; -import org.jose4j.jwt.JwtClaims; import org.json.simple.JSONObject; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; @@ -23,7 +18,7 @@ public class Login implements Response { private DatabaseRepository databaseRepo; private Router router; - public Login(DatabaseRepository databaseRepo, Router router){ + public Login(DatabaseRepository databaseRepo, Router router) { this.databaseRepo = databaseRepo; this.router = router; } @@ -31,8 +26,8 @@ public class Login implements Response { @Route(path = "^\\/login$", type = "POST") @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { - if(user != null){ - HttpUtil.responseHeaders(writer, 403,"Access-Control-Allow-Origin: *"); + if (user != null) { + HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); return; } JSONObject informations = (JSONObject) HttpUtil.readJson(reader); @@ -40,11 +35,10 @@ public class Login implements Response { String pseudo = (String) informations.get("pseudo"); String password = (String) informations.get("passwd"); int id; - if ((id = databaseRepo.login(pseudo, password)) >= 0){ - HttpUtil.responseHeaders(writer, 200, - "Access-Control-Allow-Origin: *", + if ((id = databaseRepo.login(pseudo, password)) >= 0) { + HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *", "Access-Control-Expose-Headers: Authorization", - "Authorization: Bearer "+this.router.createAuthUser(id)); + "Authorization: Bearer " + this.router.createAuthUser(id)); return; } } diff --git a/src/be/jeffcheasey88/peeratcode/routes/PlayerDetails.java b/src/be/jeffcheasey88/peeratcode/routes/PlayerDetails.java index 7307ad2..377967c 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/PlayerDetails.java +++ b/src/be/jeffcheasey88/peeratcode/routes/PlayerDetails.java @@ -26,7 +26,7 @@ public class PlayerDetails implements Response { @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { Player player; - if (matcher.group(1) != null){ + if (matcher.group(1) != null) { player = databaseRepo.getPlayerDetails(matcher.group(1)); } else { player = databaseRepo.getPlayerDetails(user.getId()); @@ -39,13 +39,16 @@ public class PlayerDetails implements Response { playerJSON.put("firstname", player.getFirstname()); playerJSON.put("lastname", player.getLastname()); playerJSON.put("description", player.getDescription()); - if (player.getGroups() != null) playerJSON.put("groups", player.getJsonGroups()); + if (player.getGroups() != null) + playerJSON.put("groups", player.getJsonGroups()); playerJSON.put("rank", player.getRank()); playerJSON.put("score", player.getTotalScore()); playerJSON.put("completions", player.getTotalCompletion()); playerJSON.put("tries", player.getTotalTries()); - if (player.getBadges() != null) playerJSON.put("badges", player.getJsonBadges()); - if(player.getAvatar() != null) playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar())); + if (player.getBadges() != null) + playerJSON.put("badges", player.getJsonBadges()); + if (player.getAvatar() != null) + playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar())); writer.write(playerJSON.toJSONString().replace("\\", "")); } else { HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); diff --git a/src/be/jeffcheasey88/peeratcode/routes/PuzzleElement.java b/src/be/jeffcheasey88/peeratcode/routes/PuzzleElement.java index 6db30f9..066ab08 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/PuzzleElement.java +++ b/src/be/jeffcheasey88/peeratcode/routes/PuzzleElement.java @@ -1,11 +1,7 @@ package be.jeffcheasey88.peeratcode.routes; -import java.nio.charset.Charset; -import java.util.Set; import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.jose4j.json.internal.json_simple.JSONArray; import org.json.simple.JSONObject; import be.jeffcheasey88.peeratcode.model.Puzzle; @@ -35,8 +31,10 @@ public class PuzzleElement implements Response { puzzleJSON.put("id", puzzle.getId()); puzzleJSON.put("name", puzzle.getName()); puzzleJSON.put("content", puzzle.getContent()); - if (puzzle.getTags() != null) puzzleJSON.put("tags", puzzle.getJsonTags()); - if (puzzle.getDepend() > 0) puzzleJSON.put("depend", puzzle.getDepend()); + if (puzzle.getTags() != null) + puzzleJSON.put("tags", puzzle.getJsonTags()); + if (puzzle.getDepend() > 0) + puzzleJSON.put("depend", puzzle.getDepend()); writer.write(puzzleJSON.toJSONString()); } } diff --git a/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java b/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java index 2dda965..9ed1add 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java +++ b/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java @@ -54,15 +54,16 @@ public class PuzzleResponse implements Response { } private void saveSourceCode(ReceivedResponse received, Player player) throws IOException { - Path path = Paths.get(String.format("%s/%s/puz%04d-%s", usersFilesPath, player.getPseudo(), received.getPuzzleId(), received.getFileName())); + Path path = Paths.get(String.format("%s/%s/puz%04d-%s", usersFilesPath, player.getPseudo(), + received.getPuzzleId(), received.getFileName())); Files.write(path, received.getSourceCode()); - + } } class ReceivedResponse { - + private int puzzleId; private byte[] response; private String fileName; @@ -73,7 +74,7 @@ class ReceivedResponse { public ReceivedResponse(Matcher matcher, HttpReader reader) throws Exception { this.reader = reader; puzzleId = Integer.parseInt(matcher.group(1)); - + List multiPartData = HttpUtil.readMultiPartData(reader); this.response = multiPartData.get(0).getBytes(); this.fileName = multiPartData.get(1); diff --git a/src/be/jeffcheasey88/peeratcode/routes/Register.java b/src/be/jeffcheasey88/peeratcode/routes/Register.java index 1e3c4cd..fc69479 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/Register.java +++ b/src/be/jeffcheasey88/peeratcode/routes/Register.java @@ -4,11 +4,9 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.json.simple.JSONObject; -import be.jeffcheasey88.peeratcode.model.Player; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.webserver.HttpReader; import be.jeffcheasey88.peeratcode.webserver.HttpUtil; @@ -33,8 +31,8 @@ public class Register implements Response { @Route(path = "^\\/register$", type = "POST") @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { - if(user != null){ - HttpUtil.responseHeaders(writer, 403,"Access-Control-Allow-Origin: *"); + if (user != null) { + HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); return; } JSONObject informations = (JSONObject) HttpUtil.readJson(reader); @@ -62,8 +60,7 @@ public class Register implements Response { int id; if ((id = databaseRepo.register(pseudo, email, password, firstname, lastname, description, group, avatar)) >= 0) { - HttpUtil.responseHeaders(writer, 200, - "Access-Control-Allow-Origin: *", + HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *", "Access-Control-Expose-Headers: Authorization", "Authorization: Bearer " + this.router.createAuthUser(id)); createFolderToSaveSourceCode(pseudo); @@ -82,7 +79,7 @@ public class Register implements Response { } private void createFolderToSaveSourceCode(String pseudo) throws IOException { - + Files.createDirectories(Paths.get(String.format("%s/%s", usersFilesPath, pseudo))); } diff --git a/src/be/jeffcheasey88/peeratcode/routes/Result.java b/src/be/jeffcheasey88/peeratcode/routes/Result.java index 787d842..6f77df0 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/Result.java +++ b/src/be/jeffcheasey88/peeratcode/routes/Result.java @@ -1,7 +1,6 @@ package be.jeffcheasey88.peeratcode.routes; import java.util.regex.Matcher; -import java.util.regex.Pattern; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.webserver.HttpReader; @@ -11,25 +10,25 @@ import be.jeffcheasey88.peeratcode.webserver.Response; import be.jeffcheasey88.peeratcode.webserver.Route; import be.jeffcheasey88.peeratcode.webserver.User; -public class Result implements Response{ - +public class Result implements Response { + private DatabaseRepository repo; - - public Result(DatabaseRepository repo){ + + public Result(DatabaseRepository repo) { this.repo = repo; } - + @Route(path = "^\\/result\\/(\\d+)$", needLogin = true) @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { int puzzle = Integer.parseInt(matcher.group(1)); - + int score = this.repo.getScore(user.getId(), puzzle); - if(score < 0) { + if (score < 0) { HttpUtil.responseHeaders(writer, 425, "Access-Control-Allow-Origin: *"); - }else{ + } else { HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); - writer.write(score+""); + writer.write(score + ""); } } diff --git a/src/be/jeffcheasey88/peeratcode/routes/groups/CreateGroup.java b/src/be/jeffcheasey88/peeratcode/routes/groups/CreateGroup.java index 2c96332..d550223 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/groups/CreateGroup.java +++ b/src/be/jeffcheasey88/peeratcode/routes/groups/CreateGroup.java @@ -13,11 +13,11 @@ import be.jeffcheasey88.peeratcode.webserver.Response; import be.jeffcheasey88.peeratcode.webserver.Route; import be.jeffcheasey88.peeratcode.webserver.User; -public class CreateGroup implements Response{ - +public class CreateGroup implements Response { + private DatabaseRepository repo; - - public CreateGroup(DatabaseRepository repo){ + + public CreateGroup(DatabaseRepository repo) { this.repo = repo; } @@ -25,10 +25,10 @@ public class CreateGroup implements Response{ @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { HttpUtil.skipHeaders(reader); - - if(this.repo.insertGroup(new Group((JSONObject)HttpUtil.readJson(reader)))){ + + if (this.repo.insertGroup(new Group((JSONObject) HttpUtil.readJson(reader)))) { HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); - }else{ + } else { HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); } } diff --git a/src/be/jeffcheasey88/peeratcode/routes/groups/GroupList.java b/src/be/jeffcheasey88/peeratcode/routes/groups/GroupList.java index 17038be..8458497 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/groups/GroupList.java +++ b/src/be/jeffcheasey88/peeratcode/routes/groups/GroupList.java @@ -3,7 +3,6 @@ package be.jeffcheasey88.peeratcode.routes.groups; import java.util.regex.Matcher; import org.json.simple.JSONArray; -import org.json.simple.JSONObject; import be.jeffcheasey88.peeratcode.model.Group; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; @@ -14,11 +13,11 @@ import be.jeffcheasey88.peeratcode.webserver.Response; import be.jeffcheasey88.peeratcode.webserver.Route; import be.jeffcheasey88.peeratcode.webserver.User; -public class GroupList implements Response{ - +public class GroupList implements Response { + private DatabaseRepository repo; - - public GroupList(DatabaseRepository repo){ + + public GroupList(DatabaseRepository repo) { this.repo = repo; } @@ -27,7 +26,8 @@ public class GroupList implements Response{ public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); JSONArray result = new JSONArray(); - for(Group group : this.repo.getAllGroups()) result.add(group.toJson()); + for (Group group : this.repo.getAllGroups()) + result.add(group.toJson()); writer.write(result.toJSONString()); } diff --git a/src/be/jeffcheasey88/peeratcode/webserver/Client.java b/src/be/jeffcheasey88/peeratcode/webserver/Client.java index 692fa58..9f68d14 100644 --- a/src/be/jeffcheasey88/peeratcode/webserver/Client.java +++ b/src/be/jeffcheasey88/peeratcode/webserver/Client.java @@ -5,20 +5,19 @@ import java.util.Arrays; import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; import org.jose4j.jwk.RsaJsonWebKey; -import org.jose4j.jwk.RsaJwkGenerator; import org.jose4j.jws.AlgorithmIdentifiers; import org.jose4j.jwt.JwtClaims; import org.jose4j.jwt.consumer.JwtConsumer; import org.jose4j.jwt.consumer.JwtConsumerBuilder; -public class Client extends Thread{ - +public class Client extends Thread { + private HttpReader reader; private HttpWriter writer; private Router router; - private RsaJsonWebKey key; - - public Client(Socket socket, Router router, RsaJsonWebKey key) throws Exception{ + private RsaJsonWebKey key; // Really needed ? + + public Client(Socket socket, Router router, RsaJsonWebKey key) throws Exception { this.reader = new HttpReader(socket); this.writer = new HttpWriter(socket); this.router = router; @@ -26,7 +25,7 @@ public class Client extends Thread{ } @Override - public void run(){ + public void run() { try { String[] headers = reader.readLine().split("\\s"); System.out.println(Arrays.toString(headers)); @@ -34,27 +33,24 @@ public class Client extends Thread{ router.exec(headers[0], headers[1], isLogin(reader), reader, writer); writer.flush(); writer.close(); - } catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); } } - - private User isLogin(HttpReader reader) throws Exception{ + + private User isLogin(HttpReader reader) throws Exception { String auth = HttpUtil.readAuthorization(reader); - if(auth == null) return null; + if (auth == null) + return null; try { - JwtConsumer jwtConsumer = new JwtConsumerBuilder() - .setRequireExpirationTime() - .setAllowedClockSkewInSeconds(30) - .setExpectedIssuer(this.router.getTokenIssuer()) - .setVerificationKey(this.router.getWebKey().getKey()) - .setJwsAlgorithmConstraints( - ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256) - .build(); - - JwtClaims jwtClaims = jwtConsumer.processToClaims(auth); - return new User(jwtClaims); - }catch(Exception e){ + JwtConsumer jwtConsumer = new JwtConsumerBuilder().setRequireExpirationTime() + .setAllowedClockSkewInSeconds(30).setExpectedIssuer(this.router.getTokenIssuer()) + .setVerificationKey(this.router.getWebKey().getKey()) + .setJwsAlgorithmConstraints(ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256).build(); + + JwtClaims jwtClaims = jwtConsumer.processToClaims(auth); + return new User(jwtClaims); + } catch (Exception e) { HttpUtil.responseHeaders(writer, 401, "Access-Control-Allow-Origin: *"); writer.flush(); writer.close(); diff --git a/src/be/jeffcheasey88/peeratcode/webserver/HttpReader.java b/src/be/jeffcheasey88/peeratcode/webserver/HttpReader.java index 031b9ee..6fe32cb 100644 --- a/src/be/jeffcheasey88/peeratcode/webserver/HttpReader.java +++ b/src/be/jeffcheasey88/peeratcode/webserver/HttpReader.java @@ -7,43 +7,43 @@ import java.io.InputStreamReader; import java.net.Socket; public class HttpReader { - + private Socket socket; private InputStream in; private BufferedReader reader; - - public HttpReader(Socket socket) throws Exception{ + + public HttpReader(Socket socket) throws Exception { this.socket = socket; this.in = socket.getInputStream(); this.reader = new BufferedReader(new InputStreamReader(in)); } - - public boolean isClosed(){ + + public boolean isClosed() { return this.socket.isClosed(); } - - public int read(byte[] buffer) throws IOException{ + + public int read(byte[] buffer) throws IOException { return this.in.read(buffer); } - + public int read(char[] buffer) throws IOException { return this.reader.read(buffer); } - - public String readLine() throws IOException{ + + public String readLine() throws IOException { return this.reader.readLine(); } - - public boolean ready() throws IOException{ + + public boolean ready() throws IOException { return this.reader.ready(); } - - public int readInt() throws Exception{ - int result = 0; - result+=this.in.read() << 24; - result+=this.in.read() << 16; - result+=this.in.read() << 8; - result+=this.in.read(); - return result; - } + + public int readInt() throws Exception { + int result = 0; + result += this.in.read() << 24; + result += this.in.read() << 16; + result += this.in.read() << 8; + result += this.in.read(); + return result; + } } \ No newline at end of file diff --git a/src/be/jeffcheasey88/peeratcode/webserver/HttpUtil.java b/src/be/jeffcheasey88/peeratcode/webserver/HttpUtil.java index ad880a9..416ea78 100644 --- a/src/be/jeffcheasey88/peeratcode/webserver/HttpUtil.java +++ b/src/be/jeffcheasey88/peeratcode/webserver/HttpUtil.java @@ -9,326 +9,338 @@ import java.util.regex.Pattern; import org.json.simple.parser.JSONParser; public class HttpUtil { - - private HttpUtil(){} - - public static void responseHeaders(HttpWriter writer, int code, String... headers) throws Exception{ - writer.write("HTTP/1.1 "+code+" "+codeMessage(code)+"\n"); - for(String header : headers) writer.write(header+"\n"); + + private HttpUtil() { + } + + public static void responseHeaders(HttpWriter writer, int code, String... headers) throws Exception { + writer.write("HTTP/1.1 " + code + " " + codeMessage(code) + "\n"); + for (String header : headers) + writer.write(header + "\n"); writer.write("\n"); writer.flush(); } - - public static void skipHeaders(HttpReader reader) throws Exception{ + + public static void skipHeaders(HttpReader reader) throws Exception { String line; - while(((line = reader.readLine()) != null) && (line.length() > 0)); + while (((line = reader.readLine()) != null) && (line.length() > 0)) + ; } - - public static List readMultiPartData(HttpReader reader) throws Exception{ + + public static List readMultiPartData(HttpReader reader) throws Exception { List list = new ArrayList<>(); - + reader.readLine(); - - while(reader.ready()){ + + while (reader.ready()) { String line; - while(((line = reader.readLine()) != null) && (line.length() > 0)){ - + while (((line = reader.readLine()) != null) && (line.length() > 0)) { + } String buffer = ""; - while(((line = reader.readLine()) != null) && (!line.startsWith("------WebKitFormBoundary"))){ - buffer+=line; + while (((line = reader.readLine()) != null) && (!line.startsWith("------WebKitFormBoundary"))) { + buffer += line; } list.add(buffer); } - + return list; } - - public static void switchToWebSocket(HttpReader reader, HttpWriter writer) throws Exception{ + + public static void switchToWebSocket(HttpReader reader, HttpWriter writer) throws Exception { String key = readWebSocketKey(reader); - if(key == null) throw new IllegalArgumentException(); - + if (key == null) + throw new IllegalArgumentException(); + writer.write("HTTP/1.1 101 Switching Protocols\n"); writer.write("Connection: Upgrade\n"); writer.write("Upgrade: websocket\n"); - writer.write("Sec-WebSocket-Accept: "+ - printBase64Binary( - MessageDigest.getInstance("SHA-1"). - digest((key+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes("UTF-8")))+"\n"); + writer.write("Sec-WebSocket-Accept: " + printBase64Binary(MessageDigest.getInstance("SHA-1") + .digest((key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes("UTF-8"))) + "\n"); writer.write("\n"); writer.flush(); } - + private static Pattern WEBSOCKET_KEY = Pattern.compile("Sec-WebSocket-Key: (.*)"); - + public static String readWebSocketKey(HttpReader reader) throws Exception { String line; String key = null; - while(((line = reader.readLine()) != null) && (line.length() > 0)){ - if(key != null){ + while (((line = reader.readLine()) != null) && (line.length() > 0)) { + if (key != null) { continue; } Matcher matcher = WEBSOCKET_KEY.matcher(line); - if(matcher.matches()) key = matcher.group(1); + if (matcher.matches()) + key = matcher.group(1); } return key; } - + private static Pattern AUTORIZATION = Pattern.compile("Authorization: Bearer (.*)"); - + public static String readAuthorization(HttpReader reader) throws Exception { String line; String key = null; - while(((line = reader.readLine()) != null) && (line.length() > 0)){ + while (((line = reader.readLine()) != null) && (line.length() > 0)) { Matcher matcher = AUTORIZATION.matcher(line); - if(matcher.matches()){ + if (matcher.matches()) { key = matcher.group(1); break; } } return key; } - - public static Object readJson(HttpReader reader) throws Exception{ + + public static Object readJson(HttpReader reader) throws Exception { String line = ""; - while(reader.ready()){ + while (reader.ready()) { char[] c = new char[1]; reader.read(c); - line+=c[0]; - if(c[0] == '}'){ + line += c[0]; + if (c[0] == '}') { Object parse; try { parse = new JSONParser().parse(line); - if(parse != null) return parse; - }catch(Exception e){} + if (parse != null) + return parse; + } catch (Exception e) { + } } } return null; } - - //I found this code on StackOverFlow !!!!! (and the write too) - public static String readWebSocket(HttpReader reader) throws Exception{ + + // I found this code on StackOverFlow !!!!! (and the write too) + public static String readWebSocket(HttpReader reader) throws Exception { int buffLenth = 1024; - int len = 0; - byte[] b = new byte[buffLenth]; - //rawIn is a Socket.getInputStream(); - while(true){ - len = reader.read(b); - if(len!=-1){ - byte rLength = 0; - int rMaskIndex = 2; - int rDataStart = 0; - //b[0] is always text in my case so no need to check; - byte data = b[1]; - byte op = (byte) 127; - rLength = (byte) (data & op); + int len = 0; + byte[] b = new byte[buffLenth]; + // rawIn is a Socket.getInputStream(); + while (true) { + len = reader.read(b); + if (len != -1) { + byte rLength = 0; + int rMaskIndex = 2; + int rDataStart = 0; + // b[0] is always text in my case so no need to check; + byte data = b[1]; + byte op = (byte) 127; + rLength = (byte) (data & op); - if(rLength==(byte)126) rMaskIndex=4; - if(rLength==(byte)127) rMaskIndex=10; + if (rLength == (byte) 126) + rMaskIndex = 4; + if (rLength == (byte) 127) + rMaskIndex = 10; - byte[] masks = new byte[4]; + byte[] masks = new byte[4]; - int j=0; - int i=0; - for(i=rMaskIndex;i<(rMaskIndex+4);i++){ - masks[j] = b[i]; - j++; - } + int j = 0; + int i = 0; + for (i = rMaskIndex; i < (rMaskIndex + 4); i++) { + masks[j] = b[i]; + j++; + } - rDataStart = rMaskIndex + 4; + rDataStart = rMaskIndex + 4; - int messLen = len - rDataStart; + int messLen = len - rDataStart; - byte[] message = new byte[messLen]; + byte[] message = new byte[messLen]; - for(i=rDataStart, j=0; i= 126 && rawData.length <= 65535){ - frame[1] = (byte) 126; - int len = rawData.length; - frame[2] = (byte)((len >> 8 ) & (byte)255); - frame[3] = (byte)(len & (byte)255); - frameCount = 4; - }else{ - frame[1] = (byte) 127; - int len = rawData.length; - frame[2] = (byte)((len >> 56 ) & (byte)255); - frame[3] = (byte)((len >> 48 ) & (byte)255); - frame[4] = (byte)((len >> 40 ) & (byte)255); - frame[5] = (byte)((len >> 32 ) & (byte)255); - frame[6] = (byte)((len >> 24 ) & (byte)255); - frame[7] = (byte)((len >> 16 ) & (byte)255); - frame[8] = (byte)((len >> 8 ) & (byte)255); - frame[9] = (byte)(len & (byte)255); - frameCount = 10; - } + if (rawData.length <= 125) { + frame[1] = (byte) rawData.length; + frameCount = 2; + } else if (rawData.length >= 126 && rawData.length <= 65535) { + frame[1] = (byte) 126; + int len = rawData.length; + frame[2] = (byte) ((len >> 8) & (byte) 255); + frame[3] = (byte) (len & (byte) 255); + frameCount = 4; + } else { + frame[1] = (byte) 127; + int len = rawData.length; + frame[2] = (byte) ((len >> 56) & (byte) 255); + frame[3] = (byte) ((len >> 48) & (byte) 255); + frame[4] = (byte) ((len >> 40) & (byte) 255); + frame[5] = (byte) ((len >> 32) & (byte) 255); + frame[6] = (byte) ((len >> 24) & (byte) 255); + frame[7] = (byte) ((len >> 16) & (byte) 255); + frame[8] = (byte) ((len >> 8) & (byte) 255); + frame[9] = (byte) (len & (byte) 255); + frameCount = 10; + } - int bLength = frameCount + rawData.length; + int bLength = frameCount + rawData.length; - byte[] reply = new byte[bLength]; + byte[] reply = new byte[bLength]; - int bLim = 0; - for(int i=0; i= 3; j += 3) { - paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); - paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF); - paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2 | paramArrayOfbyte[j + 2] >> 6 & 0x3); - paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j + 2] & 0x3F); - i -= 3; - } - if (i == 1) { - paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); - paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4); - paramArrayOfchar[paramInt3++] = '='; - paramArrayOfchar[paramInt3++] = '='; - } - if (i == 2) { - paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); - paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF); - paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2); - paramArrayOfchar[paramInt3++] = '='; - } - return paramInt3; - } - + + // From javax.xml.bind.DatatypeConverter + private static String printBase64Binary(byte[] array) { + char[] arrayOfChar = new char[(array.length + 2) / 3 * 4]; + int i = _printBase64Binary(array, 0, array.length, arrayOfChar, 0); + assert i == arrayOfChar.length; + return new String(arrayOfChar); + } + + private static int _printBase64Binary(byte[] paramArrayOfbyte, int paramInt1, int paramInt2, + char[] paramArrayOfchar, int paramInt3) { + int i = paramInt2; + int j; + for (j = paramInt1; i >= 3; j += 3) { + paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); + paramArrayOfchar[paramInt3++] = encode( + (paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF); + paramArrayOfchar[paramInt3++] = encode( + (paramArrayOfbyte[j + 1] & 0xF) << 2 | paramArrayOfbyte[j + 2] >> 6 & 0x3); + paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j + 2] & 0x3F); + i -= 3; + } + if (i == 1) { + paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); + paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4); + paramArrayOfchar[paramInt3++] = '='; + paramArrayOfchar[paramInt3++] = '='; + } + if (i == 2) { + paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); + paramArrayOfchar[paramInt3++] = encode( + (paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF); + paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2); + paramArrayOfchar[paramInt3++] = '='; + } + return paramInt3; + } + private static char encode(int paramInt) { - return encodeMap[paramInt & 0x3F]; - } + return encodeMap[paramInt & 0x3F]; + } + private static final char[] encodeMap = initEncodeMap(); - + private static char[] initEncodeMap() { - char[] arrayOfChar = new char[64]; - byte b; - for (b = 0; b < 26; b++) - arrayOfChar[b] = (char)(65 + b); - for (b = 26; b < 52; b++) - arrayOfChar[b] = (char)(97 + b - 26); - for (b = 52; b < 62; b++) - arrayOfChar[b] = (char)(48 + b - 52); - arrayOfChar[62] = '+'; - arrayOfChar[63] = '/'; - return arrayOfChar; - } + char[] arrayOfChar = new char[64]; + byte b; + for (b = 0; b < 26; b++) + arrayOfChar[b] = (char) (65 + b); + for (b = 26; b < 52; b++) + arrayOfChar[b] = (char) (97 + b - 26); + for (b = 52; b < 62; b++) + arrayOfChar[b] = (char) (48 + b - 52); + arrayOfChar[62] = '+'; + arrayOfChar[63] = '/'; + return arrayOfChar; + } } diff --git a/src/be/jeffcheasey88/peeratcode/webserver/HttpWriter.java b/src/be/jeffcheasey88/peeratcode/webserver/HttpWriter.java index 5546719..20fa494 100644 --- a/src/be/jeffcheasey88/peeratcode/webserver/HttpWriter.java +++ b/src/be/jeffcheasey88/peeratcode/webserver/HttpWriter.java @@ -7,30 +7,30 @@ import java.io.OutputStreamWriter; import java.net.Socket; import java.nio.charset.StandardCharsets; -public class HttpWriter{ - +public class HttpWriter { + private OutputStream out; private BufferedWriter writer; - - public HttpWriter(Socket socket) throws Exception{ + + public HttpWriter(Socket socket) throws Exception { this.out = socket.getOutputStream(); this.writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)); } - - public void write(byte[] buffer) throws IOException{ + + public void write(byte[] buffer) throws IOException { this.out.write(buffer); this.out.flush(); } - public void write(String message) throws IOException{ + public void write(String message) throws IOException { this.writer.write(message); } - - public void flush() throws IOException{ + + public void flush() throws IOException { this.writer.flush(); } - - public void close() throws IOException{ + + public void close() throws IOException { this.writer.close(); } } \ No newline at end of file diff --git a/src/be/jeffcheasey88/peeratcode/webserver/Response.java b/src/be/jeffcheasey88/peeratcode/webserver/Response.java index 2d7eec6..2c51825 100644 --- a/src/be/jeffcheasey88/peeratcode/webserver/Response.java +++ b/src/be/jeffcheasey88/peeratcode/webserver/Response.java @@ -1,10 +1,9 @@ package be.jeffcheasey88.peeratcode.webserver; import java.util.regex.Matcher; -import java.util.regex.Pattern; -public interface Response{ +public interface Response { + + void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception; - void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception ; - } \ No newline at end of file diff --git a/src/be/jeffcheasey88/peeratcode/webserver/Route.java b/src/be/jeffcheasey88/peeratcode/webserver/Route.java index fcfea70..71f3834 100644 --- a/src/be/jeffcheasey88/peeratcode/webserver/Route.java +++ b/src/be/jeffcheasey88/peeratcode/webserver/Route.java @@ -8,9 +8,11 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Route { - + String path() default "^.*$"; + String type() default "GET"; + boolean needLogin() default false; } diff --git a/src/be/jeffcheasey88/peeratcode/webserver/Router.java b/src/be/jeffcheasey88/peeratcode/webserver/Router.java index bb9236c..e6bc073 100644 --- a/src/be/jeffcheasey88/peeratcode/webserver/Router.java +++ b/src/be/jeffcheasey88/peeratcode/webserver/Router.java @@ -16,8 +16,8 @@ import org.jose4j.lang.JoseException; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; -public class Router{ - +public class Router { + private Map responses; private Map patterns; private Response noFileFound; @@ -25,73 +25,76 @@ public class Router{ private DatabaseRepository repo; private String token_issuer; private int token_expiration; - - public Router(DatabaseRepository repo, String token_issuer, int token_expiration) throws Exception{ + + public Router(DatabaseRepository repo, String token_issuer, int token_expiration) throws Exception { this.repo = repo; - this.token_issuer = token_issuer; + this.token_issuer = token_issuer; this.token_expiration = token_expiration; this.responses = new HashMap<>(); this.patterns = new HashMap<>(); this.rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048); } - - public DatabaseRepository getDataBase(){ + + public DatabaseRepository getDataBase() { return this.repo; } - - public void register(Response response){ + + public void register(Response response) { try { - Method method = response.getClass().getDeclaredMethod("exec", Response.class.getDeclaredMethods()[0].getParameterTypes()); + Method method = response.getClass().getDeclaredMethod("exec", + Response.class.getDeclaredMethods()[0].getParameterTypes()); Route route = method.getAnnotation(Route.class); - + this.responses.put(response, route); this.patterns.put(response, Pattern.compile(route.path())); - } catch (Exception e){ + } catch (Exception e) { throw new IllegalArgumentException(e); } } - - public void setDefault(Response response){ + + public void setDefault(Response response) { this.noFileFound = response; } public void exec(String type, String path, User user, HttpReader reader, HttpWriter writer) throws Exception { - for(Entry routes : this.responses.entrySet()){ - if(routes.getValue().type().equals(type)){ + for (Entry routes : this.responses.entrySet()) { + if (routes.getValue().type().equals(type)) { Matcher matcher = this.patterns.get(routes.getKey()).matcher(path); - if(matcher.matches()){ - if(user == null && routes.getValue().needLogin()) return; + if (matcher.matches()) { + if (user == null && routes.getValue().needLogin()) + return; routes.getKey().exec(matcher, user, reader, writer); return; } } } - if(noFileFound != null) noFileFound.exec(null, user, reader, writer); + if (noFileFound != null) + noFileFound.exec(null, user, reader, writer); } - - public RsaJsonWebKey getWebKey(){ + + public RsaJsonWebKey getWebKey() { return this.rsaJsonWebKey; } - - public String getTokenIssuer(){ + + public String getTokenIssuer() { return this.token_issuer; } - - public String createAuthUser(int id) throws JoseException{ + + public String createAuthUser(int id) throws JoseException { JwtClaims claims = new JwtClaims(); - claims.setIssuer(token_issuer); // who creates the token and signs it - claims.setExpirationTimeMinutesInTheFuture(token_expiration); - claims.setGeneratedJwtId(); // a unique identifier for the token - claims.setIssuedAtToNow(); // when the token was issued/created (now) - claims.setNotBeforeMinutesInThePast(2); // time before which the token is not yet valid (2 minutes ago) - - claims.setClaim("id", id); - - JsonWebSignature jws = new JsonWebSignature(); - jws.setPayload(claims.toJson()); - jws.setKey(rsaJsonWebKey.getPrivateKey()); - jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId()); - jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); - return jws.getCompactSerialization(); + claims.setIssuer(token_issuer); // who creates the token and signs it + claims.setExpirationTimeMinutesInTheFuture(token_expiration); + claims.setGeneratedJwtId(); // a unique identifier for the token + claims.setIssuedAtToNow(); // when the token was issued/created (now) + claims.setNotBeforeMinutesInThePast(2); // time before which the token is not yet valid (2 minutes ago) + + claims.setClaim("id", id); + + JsonWebSignature jws = new JsonWebSignature(); + jws.setPayload(claims.toJson()); + jws.setKey(rsaJsonWebKey.getPrivateKey()); + jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId()); + jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); + return jws.getCompactSerialization(); } } \ No newline at end of file diff --git a/src/be/jeffcheasey88/peeratcode/webserver/User.java b/src/be/jeffcheasey88/peeratcode/webserver/User.java index 0967426..949bc12 100644 --- a/src/be/jeffcheasey88/peeratcode/webserver/User.java +++ b/src/be/jeffcheasey88/peeratcode/webserver/User.java @@ -5,12 +5,12 @@ import org.jose4j.jwt.JwtClaims; public class User { private int id; - - public User(JwtClaims jwtClaims){ - this.id = ((Long)jwtClaims.getClaimValue("id")).intValue(); + + public User(JwtClaims jwtClaims) { + this.id = ((Long) jwtClaims.getClaimValue("id")).intValue(); } - - public int getId(){ + + public int getId() { return this.id; } } \ No newline at end of file From 87c4fd8bc1c2da0d4e144c3e11685a43419170ab Mon Sep 17 00:00:00 2001 From: Francois G Date: Sun, 9 Apr 2023 17:10:49 +0200 Subject: [PATCH 5/5] Secure route needing login and update some http errors codes --- src/be/jeffcheasey88/peeratcode/routes/BadgeDetails.java | 4 ++-- src/be/jeffcheasey88/peeratcode/routes/ChapterElement.java | 6 ++++-- src/be/jeffcheasey88/peeratcode/routes/ChapterList.java | 6 ++++-- src/be/jeffcheasey88/peeratcode/routes/Login.java | 4 ++-- src/be/jeffcheasey88/peeratcode/routes/PlayerDetails.java | 4 ++-- src/be/jeffcheasey88/peeratcode/routes/PuzzleElement.java | 7 +++++-- src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java | 2 +- src/be/jeffcheasey88/peeratcode/routes/Register.java | 5 +++-- 8 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/be/jeffcheasey88/peeratcode/routes/BadgeDetails.java b/src/be/jeffcheasey88/peeratcode/routes/BadgeDetails.java index 4633acb..89c3302 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/BadgeDetails.java +++ b/src/be/jeffcheasey88/peeratcode/routes/BadgeDetails.java @@ -22,10 +22,9 @@ public class BadgeDetails implements Response { this.databaseRepo = databaseRepo; } - @Route(path = "^\\/badge\\/([0-9]+)$") + @Route(path = "^\\/badge\\/([0-9]+)$", needLogin = true) @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { - HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); if (matcher.groupCount() > 0) { int badgeId = Integer.parseInt(matcher.group(1)); Badge badge = databaseRepo.getBadge(badgeId); @@ -36,6 +35,7 @@ public class BadgeDetails implements Response { badgeJSON.put("logo", Base64.getEncoder().encodeToString(badge.getLogo())); badgeJSON.put("level", badge.getLevel()); } + HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); writer.write(badgeJSON.toJSONString().replace("\\", "")); } else { HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); diff --git a/src/be/jeffcheasey88/peeratcode/routes/ChapterElement.java b/src/be/jeffcheasey88/peeratcode/routes/ChapterElement.java index ea0a70e..2bd05a0 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/ChapterElement.java +++ b/src/be/jeffcheasey88/peeratcode/routes/ChapterElement.java @@ -23,10 +23,9 @@ public class ChapterElement implements Response { this.databaseRepo = databaseRepo; } - @Route(path = "^\\/chapter\\/([0-9]+)$") + @Route(path = "^\\/chapter\\/([0-9]+)$", needLogin = true) @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { - HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); Chapter chapter = databaseRepo.getChapter(extractId(matcher)); if (chapter != null) { JSONObject chapterJSON = new JSONObject(); @@ -46,7 +45,10 @@ public class ChapterElement implements Response { puzzles.add(puzzleJSON); } chapterJSON.put("puzzles", puzzles); + HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); writer.write(chapterJSON.toJSONString()); + } else { + HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); } } diff --git a/src/be/jeffcheasey88/peeratcode/routes/ChapterList.java b/src/be/jeffcheasey88/peeratcode/routes/ChapterList.java index 30b092a..63f514b 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/ChapterList.java +++ b/src/be/jeffcheasey88/peeratcode/routes/ChapterList.java @@ -23,10 +23,9 @@ public class ChapterList implements Response { this.databaseRepo = databaseRepo; } - @Route(path = "^\\/chapters$") + @Route(path = "^\\/chapters$", needLogin = true) @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { - HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); List allChapters = databaseRepo.getAllChapters(); if (allChapters != null) { JSONArray chaptersJSON = new JSONArray(); @@ -40,7 +39,10 @@ public class ChapterList implements Response { chapterJSON.put("endDate", chapter.getEndDate().toString()); chaptersJSON.add(chapterJSON); } + HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); writer.write(chaptersJSON.toJSONString()); + } else { + HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); } } diff --git a/src/be/jeffcheasey88/peeratcode/routes/Login.java b/src/be/jeffcheasey88/peeratcode/routes/Login.java index 2e06a67..877b73d 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/Login.java +++ b/src/be/jeffcheasey88/peeratcode/routes/Login.java @@ -39,10 +39,10 @@ public class Login implements Response { HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *", "Access-Control-Expose-Headers: Authorization", "Authorization: Bearer " + this.router.createAuthUser(id)); - return; } + } else { + HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); } - HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); } } diff --git a/src/be/jeffcheasey88/peeratcode/routes/PlayerDetails.java b/src/be/jeffcheasey88/peeratcode/routes/PlayerDetails.java index 377967c..d7e2b11 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/PlayerDetails.java +++ b/src/be/jeffcheasey88/peeratcode/routes/PlayerDetails.java @@ -22,7 +22,7 @@ public class PlayerDetails implements Response { this.databaseRepo = databaseRepo; } - @Route(path = "^\\/player\\/?(.+)?$") + @Route(path = "^\\/player\\/?(.+)?$", needLogin = true) @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { Player player; @@ -33,7 +33,6 @@ public class PlayerDetails implements Response { } JSONObject playerJSON = new JSONObject(); if (player != null) { - HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); playerJSON.put("pseudo", player.getPseudo()); playerJSON.put("email", player.getEmail()); playerJSON.put("firstname", player.getFirstname()); @@ -49,6 +48,7 @@ public class PlayerDetails implements Response { playerJSON.put("badges", player.getJsonBadges()); if (player.getAvatar() != null) playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar())); + HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); writer.write(playerJSON.toJSONString().replace("\\", "")); } else { HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); diff --git a/src/be/jeffcheasey88/peeratcode/routes/PuzzleElement.java b/src/be/jeffcheasey88/peeratcode/routes/PuzzleElement.java index 066ab08..ef642b7 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/PuzzleElement.java +++ b/src/be/jeffcheasey88/peeratcode/routes/PuzzleElement.java @@ -21,10 +21,9 @@ public class PuzzleElement implements Response { this.databaseRepo = databaseRepo; } - @Route(path = "^\\/puzzle\\/([0-9]+)$") + @Route(path = "^\\/puzzle\\/([0-9]+)$", needLogin = true) @Override public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { - HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *", "Content-Type: application/json"); Puzzle puzzle = databaseRepo.getPuzzle(extractId(matcher)); if (puzzle != null) { JSONObject puzzleJSON = new JSONObject(); @@ -35,8 +34,12 @@ public class PuzzleElement implements Response { puzzleJSON.put("tags", puzzle.getJsonTags()); if (puzzle.getDepend() > 0) puzzleJSON.put("depend", puzzle.getDepend()); + HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *", "Content-Type: application/json"); writer.write(puzzleJSON.toJSONString()); } + else { + HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); + } } private int extractId(Matcher matcher) { diff --git a/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java b/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java index 9ed1add..457bab5 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java +++ b/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java @@ -47,7 +47,7 @@ public class PuzzleResponse implements Response { HttpUtil.responseHeaders(writer, 406, "Access-Control-Allow-Origin: *", "Content-Type: application/json"); responseJSON.put("tries", completion.getTries()); } else { - HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); + HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); return; } writer.write(responseJSON.toJSONString()); diff --git a/src/be/jeffcheasey88/peeratcode/routes/Register.java b/src/be/jeffcheasey88/peeratcode/routes/Register.java index fc69479..a3e7b5f 100644 --- a/src/be/jeffcheasey88/peeratcode/routes/Register.java +++ b/src/be/jeffcheasey88/peeratcode/routes/Register.java @@ -67,15 +67,16 @@ public class Register implements Response { return; } } else { - HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); + HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); JSONObject error = new JSONObject(); error.put("username_valid", pseudoAvailable); error.put("email_valid", emailAvailable); writer.write(error.toJSONString()); return; } + } else { + HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); } - HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); } private void createFolderToSaveSourceCode(String pseudo) throws IOException {