diff --git a/src/be/jeffcheasey88/peeratcode/Main.java b/src/be/jeffcheasey88/peeratcode/Main.java index 716a12e..84e808f 100644 --- a/src/be/jeffcheasey88/peeratcode/Main.java +++ b/src/be/jeffcheasey88/peeratcode/Main.java @@ -10,7 +10,6 @@ import java.util.regex.Pattern; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; -import javax.net.ssl.SSLSocket; import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; import org.jose4j.jwk.JsonWebKey; @@ -31,6 +30,7 @@ import be.jeffcheasey88.peeratcode.routes.ChapterElement; import be.jeffcheasey88.peeratcode.routes.ChapterList; import be.jeffcheasey88.peeratcode.routes.Login; import be.jeffcheasey88.peeratcode.routes.PuzzleElement; +import be.jeffcheasey88.peeratcode.routes.PuzzleResponse; import be.jeffcheasey88.peeratcode.routes.Register; import be.jeffcheasey88.peeratcode.routes.Result; import be.jeffcheasey88.peeratcode.webserver.Client; @@ -42,78 +42,10 @@ import be.jeffcheasey88.peeratcode.webserver.Router; import be.jeffcheasey88.peeratcode.webserver.User; public class Main { - // Define SSL Protocol parameters - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Exception { Configuration config = new Configuration("config.txt"); config.load(); - - /*try - { - JwtClaims claims = new JwtClaims(); - claims.setIssuer("Issuer"); // who creates the token and signs it - claims.setAudience("Audience"); // to whom the token is intended to be sent - claims.setExpirationTimeMinutesInTheFuture(10); // time when the token will expire (10 minutes from now) - 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("username","USERNAME"); - JsonWebSignature jws = new JsonWebSignature(); - - jws.setPayload(claims.toJson()); - - jws.setKey(rsaJsonWebKey.getPrivateKey()); - - jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId()); - - jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); - - String jwt = jws.getCompactSerialization(); - - System.out.println("jwt token = " + jwt); - - - JwtConsumer jwtConsumer = new JwtConsumerBuilder() - .setRequireExpirationTime() // the JWT must have an expiration time - .setAllowedClockSkewInSeconds(30) // allow some leeway in validating time based claims to account for clock skew - .setRequireSubject() // the JWT must have a subject claim - .setExpectedIssuer("Issuer") // whom the JWT needs to have been issued by - .setExpectedAudience("Audience") // to whom the JWT is intended for - .setVerificationKey(rsaJsonWebKey.getKey()) // verify the signature with the public key - .setJwsAlgorithmConstraints( // only allow the expected signature algorithm(s) in the given context - ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256) // which is only RS256 here - .build(); // create the JwtConsumer instance - - // Validate the JWT and process it to the Claims - JwtClaims jwtClaims = jwtConsumer.processToClaims(jwt); - System.out.println("JWT validation = " + jwtClaims); - } - catch (InvalidJwtException e) - { - // InvalidJwtException will be thrown, if the JWT failed processing or validation in anyway. - // Hopefully with meaningful explanations(s) about what went wrong. - System.out.println("Invalid JWT! " + e); - - // Programmatic access to (some) specific reasons for JWT invalidity is also possible - // should you want different error handling behavior for certain conditions. - - // Whether or not the JWT has expired being one common reason for invalidity - if (e.hasExpired()) - { - System.out.println("JWT expired"); - } - - // Or maybe the audience was invalid - if (e.hasErrorCode(ErrorCodes.AUDIENCE_INVALID)) - { - System.out.println("JWT had wrong audience"); - } - } catch (JoseException e) { - e.printStackTrace(); - }*/ - - Class.forName("com.mysql.cj.jdbc.Driver"); Router router = new Router(); @@ -146,6 +78,7 @@ public class Main { router.register(new Register(repo)); router.register(new Login(repo)); router.register(new Result(repo)); + router.register(new PuzzleResponse(repo)); } private static void startWebServer(Configuration config, Router router) throws IOException { diff --git a/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java b/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java index 2f6c829..b233f3d 100644 --- a/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java +++ b/src/be/jeffcheasey88/peeratcode/repository/DatabaseRepository.java @@ -24,6 +24,12 @@ public class DatabaseRepository { private static final String REGISTER_QUERY = "INSERT INTO players (pseudo, email, passwd, firstname, lastname, description, sgroup, avatar) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; private static final String CHECK_PASSWORD = "SELECT passwd FROM players WHERE pseudo=?"; private static final String SCORE = "SELECT score FROM completions WHERE fk_player = ? AND fk_puzzle = ?"; + private static final String GET_PUZZLE_SOLUTION = "SELECT soluce FROM puzzles WHERE id_puzzle=?"; + private static final String GET_PUZZLE_SCORE_MAX = "SELECT score_max FROM puzzles WHERE id_puzzle=?"; + private static final String GET_PLAYER_ID_BY_PSEUDO = "SELECT id_player FROM players WHERE pseudo=?"; + private static final String GET_PUZZLE_NB_TRIES_AND_SCORE_BY_PLAYER = "SELECT tries, score FROM completions WHERE fk_puzzle = ? AND fk_player = ?"; + private static final String INSERT_COMPLETION = "INSERT INTO completions (fk_puzzle, fk_player, tries, code, fileName, score) values (?, ?, ?, ?, ?, ?)"; + private static final String UPDATE_COMPLETION = "UPDATE completions SET tries = ?, code = ?, filename = ?, score = ?"; private Connection con; private Configuration config; @@ -228,4 +234,91 @@ public class DatabaseRepository { } return false; } + + public byte[] getPuzzleSolution(int puzzleId) { + try { + PreparedStatement puzzleStmt = con.prepareStatement(GET_PUZZLE_SOLUTION); + puzzleStmt.setInt(1, puzzleId); + ResultSet result = puzzleStmt.executeQuery(); + if (result.next()) { + return result.getBytes("soluce"); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + public int insertOrUpdatePuzzleResponse(int puzzleId, String pseudo, String fileName, byte[] code) { + try { + ensureConnection(); + int[] triesAndScore = getPuzzleNbTriesAndScore(puzzleId, pseudo); + int playerId = getPlayerIdByPseudo(pseudo); + int puzzleScoreMax = getPuzzleScoreMax(puzzleId); + if (triesAndScore[0] < 0) { + // Insert completions + PreparedStatement statement = con.prepareStatement(INSERT_COMPLETION); + statement.setInt(1, puzzleId); + statement.setInt(2, playerId); + statement.setInt(3, 0); + statement.setBytes(4, code); + statement.setString(5, fileName); + statement.setInt(6, puzzleScoreMax); + return puzzleScoreMax; + } else { + // Update completions + int score = puzzleScoreMax * (((triesAndScore[0]-1)*10)/100); + PreparedStatement statement = con.prepareStatement(UPDATE_COMPLETION); + statement.setInt(1, triesAndScore[0]+1); + statement.setBytes(2, code); + statement.setString(3, fileName); + statement.setInt(4, score); + return score; + } + } catch (SQLException e) { + e.printStackTrace(); + } + return -1; + } + public int getPuzzleScoreMax(int puzzleId) { + try { + PreparedStatement puzzleStmt = con.prepareStatement(GET_PUZZLE_SCORE_MAX); + puzzleStmt.setInt(1, puzzleId); + ResultSet result = puzzleStmt.executeQuery(); + if (result.next()) { + return result.getInt("score_max"); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return -1; + } + public int[] getPuzzleNbTriesAndScore(int puzzleId, String pseudo) { + try { + PreparedStatement puzzleStmt = con.prepareStatement(GET_PUZZLE_NB_TRIES_AND_SCORE_BY_PLAYER); + puzzleStmt.setInt(1, puzzleId); + ResultSet result = puzzleStmt.executeQuery(); + int[] res = new int[2]; + if (result.next()) { + res[0] = result.getInt("tries"); + res[1] = result.getInt("score"); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + private int getPlayerIdByPseudo(String pseudo) { + try { + PreparedStatement puzzleStmt = con.prepareStatement(GET_PLAYER_ID_BY_PSEUDO); + puzzleStmt.setString(1, pseudo); + ResultSet result = puzzleStmt.executeQuery(); + if (result.next()) { + return result.getInt("id_player"); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return -1; + } } \ No newline at end of file diff --git a/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java b/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java new file mode 100644 index 0000000..4742433 --- /dev/null +++ b/src/be/jeffcheasey88/peeratcode/routes/PuzzleResponse.java @@ -0,0 +1,79 @@ +package be.jeffcheasey88.peeratcode.routes; + +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.json.simple.JSONObject; + +import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; +import be.jeffcheasey88.peeratcode.webserver.HttpReader; +import be.jeffcheasey88.peeratcode.webserver.HttpUtil; +import be.jeffcheasey88.peeratcode.webserver.HttpWriter; +import be.jeffcheasey88.peeratcode.webserver.Response; + +public class PuzzleResponse implements Response { + private final DatabaseRepository databaseRepo; + + public PuzzleResponse(DatabaseRepository databaseRepo) { + this.databaseRepo = databaseRepo; + } + + @Override + public void exec(Matcher matcher, HttpReader reader, HttpWriter writer) throws Exception { + HttpUtil.skipHeaders(reader); + + int puzzleId = Integer.parseInt(matcher.group(1)); + byte[] response; + byte[] fileName; + byte[] sourceCode; + + // Response + int hSize = reader.readInt(); + response = new byte[hSize]; + if (hSize == reader.read(response)) { + // File Name + hSize = reader.readInt(); + fileName = new byte[hSize]; + if (hSize == reader.read(fileName)) { + // Source Code + hSize = reader.readInt(); + sourceCode = new byte[hSize]; + if (hSize == reader.read(sourceCode)) { + int score = databaseRepo.insertOrUpdatePuzzleResponse(puzzleId, "Pseudo", fileName.toString(), sourceCode); + if (Arrays.equals(response, databaseRepo.getPuzzleSolution(puzzleId))) { + HttpUtil.responseHeaders(writer, 200, + "Access-Control-Allow-Origin: *", + "Content-Type: application/json"); + JSONObject responseJSON = new JSONObject(); + responseJSON.put("id", puzzleId); + responseJSON.put("score", score); + writer.write(responseJSON.toJSONString()); + writer.flush(); + writer.close(); + } else { + HttpUtil.responseHeaders(writer, 406, "Access-Control-Allow-Origin: *"); + } + } + else { + HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); + } + } + else { + HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); + } + + } + HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); + } + + @Override + public Pattern getPattern() { + return Pattern.compile("^\\/puzzleResponse\\/([0-9]+)$"); + } + + @Override + public String getType() { + return "POST"; + } +} diff --git a/src/be/jeffcheasey88/peeratcode/webserver/HttpReader.java b/src/be/jeffcheasey88/peeratcode/webserver/HttpReader.java index b124d2f..031b9ee 100644 --- a/src/be/jeffcheasey88/peeratcode/webserver/HttpReader.java +++ b/src/be/jeffcheasey88/peeratcode/webserver/HttpReader.java @@ -38,4 +38,12 @@ public class HttpReader { 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; + } } \ No newline at end of file