Merge remote-tracking branch 'origin/getPuzzleResponse'

This commit is contained in:
jeffcheasey88 2023-02-23 16:11:19 +01:00
commit 688ff3cedd
4 changed files with 183 additions and 70 deletions

View file

@ -10,7 +10,6 @@ import java.util.regex.Pattern;
import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
import org.jose4j.jwk.JsonWebKey; 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.ChapterList;
import be.jeffcheasey88.peeratcode.routes.Login; import be.jeffcheasey88.peeratcode.routes.Login;
import be.jeffcheasey88.peeratcode.routes.PuzzleElement; import be.jeffcheasey88.peeratcode.routes.PuzzleElement;
import be.jeffcheasey88.peeratcode.routes.PuzzleResponse;
import be.jeffcheasey88.peeratcode.routes.Register; import be.jeffcheasey88.peeratcode.routes.Register;
import be.jeffcheasey88.peeratcode.routes.Result; import be.jeffcheasey88.peeratcode.routes.Result;
import be.jeffcheasey88.peeratcode.webserver.Client; import be.jeffcheasey88.peeratcode.webserver.Client;
@ -42,78 +42,10 @@ import be.jeffcheasey88.peeratcode.webserver.Router;
import be.jeffcheasey88.peeratcode.webserver.User; import be.jeffcheasey88.peeratcode.webserver.User;
public class Main { 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"); Configuration config = new Configuration("config.txt");
config.load(); 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"); Class.forName("com.mysql.cj.jdbc.Driver");
Router router = new Router(); Router router = new Router();
@ -146,6 +78,7 @@ public class Main {
router.register(new Register(repo)); router.register(new Register(repo));
router.register(new Login(repo)); router.register(new Login(repo));
router.register(new Result(repo)); router.register(new Result(repo));
router.register(new PuzzleResponse(repo));
} }
private static void startWebServer(Configuration config, Router router) throws IOException { private static void startWebServer(Configuration config, Router router) throws IOException {

View file

@ -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 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 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 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 Connection con;
private Configuration config; private Configuration config;
@ -228,4 +234,91 @@ public class DatabaseRepository {
} }
return false; 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;
}
} }

View file

@ -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";
}
}

View file

@ -38,4 +38,12 @@ public class HttpReader {
return this.reader.ready(); 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;
}
} }