This commit is contained in:
jeffcheasey88 2023-04-09 17:57:27 +02:00
commit 0585e073e5
30 changed files with 859 additions and 694 deletions

View file

@ -20,33 +20,37 @@ public class Configuration {
private String ssl_keystore; private String ssl_keystore;
private String ssl_keystorePasswd; private String ssl_keystorePasswd;
private String users_files;
private String token_issuer; private String token_issuer;
private int token_expiration; private int token_expiration;
private File _file; private File _file;
public Configuration(String path){ public Configuration(String path) {
this._file = new File(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{ public void load() throws Exception {
if(!this._file.exists()) return; if (!this._file.exists())
return;
BufferedReader reader = new BufferedReader(new FileReader(this._file)); BufferedReader reader = new BufferedReader(new FileReader(this._file));
String line; String line;
while((line = reader.readLine()) != null){ while ((line = reader.readLine()) != null) {
String[] split = line.split("="); String[] split = line.split("=");
Field field = getClass().getDeclaredField(split[0]); Field field = getClass().getDeclaredField(split[0]);
if(field == null) continue; if (field == null)
continue;
field.setAccessible(true); field.setAccessible(true);
injectValue(field, split[1]); injectValue(field, split[1]);
} }
reader.close(); reader.close();
} }
private void injectValue(Field field, String value) throws IllegalAccessException{ private void injectValue(Field field, String value) throws IllegalAccessException {
if(field.getType().isPrimitive()){ if (field.getType().isPrimitive()) {
switch(field.getType().getName()){ switch (field.getType().getName()) {
case "boolean": case "boolean":
field.setBoolean(this, Boolean.parseBoolean(value)); field.setBoolean(this, Boolean.parseBoolean(value));
break; break;
@ -71,76 +75,85 @@ public class Configuration {
case "short": case "short":
field.setShort(this, Short.parseShort(value)); field.setShort(this, Short.parseShort(value));
break; break;
default: throw new IllegalArgumentException(value); default:
throw new IllegalArgumentException(value);
} }
return; return;
} }
if(field.getType().equals(String.class)){ if (field.getType().equals(String.class)) {
field.set(this, value); field.set(this, value);
return; return;
} }
throw new IllegalArgumentException(value); throw new IllegalArgumentException(value);
} }
public void save() throws Exception{ public void save() throws Exception {
if(!_file.exists()){ if (!_file.exists()) {
File parent = _file.getParentFile(); File parent = _file.getParentFile();
if(!parent.exists()) parent.mkdirs(); if (!parent.exists())
parent.mkdirs();
_file.createNewFile(); _file.createNewFile();
} }
Field[] fields = getClass().getDeclaredFields(); Field[] fields = getClass().getDeclaredFields();
BufferedWriter writer = new BufferedWriter(new FileWriter(_file)); BufferedWriter writer = new BufferedWriter(new FileWriter(_file));
for(Field field : fields){ for (Field field : fields) {
field.setAccessible(true); field.setAccessible(true);
if(field.getName().startsWith("_")) continue; if (field.getName().startsWith("_"))
continue;
Object value = field.get(this); Object value = field.get(this);
writer.write(field.getName()+"="+value); writer.write(field.getName() + "=" + value);
} }
writer.flush(); writer.flush();
writer.close(); writer.close();
} }
public String getDbHost(){ public String getDbHost() {
return this.db_host; return this.db_host;
} }
public int getDbPort(){ public int getDbPort() {
return this.db_port; return this.db_port;
} }
public String getDbUser(){ public String getDbUser() {
return this.db_user; return this.db_user;
} }
public String getDbDatabase(){ public String getDbDatabase() {
return this.db_database; return this.db_database;
} }
public String getDbPassword(){ public String getDbPassword() {
return this.db_password; return this.db_password;
} }
public String getSslKeystore(){ public String getSslKeystore() {
return this.ssl_keystore; return this.ssl_keystore;
} }
public String getTokenIssuer(){ public String getTokenIssuer() {
return this.token_issuer; return this.token_issuer;
} }
public int getTokenExpiration(){ public int getTokenExpiration() {
return this.token_expiration; return this.token_expiration;
} }
public String getSslKeystorePasswd(){ public String getSslKeystorePasswd() {
return this.ssl_keystorePasswd; return this.ssl_keystorePasswd;
} }
public int getTcpPort(){ public int getTcpPort() {
return this.tcp_port; return this.tcp_port;
} }
public boolean useSsl(){ public boolean useSsl() {
return this.use_ssl; return this.use_ssl;
} }
public String getUsersFiles() {
if (users_files == null || users_files.trim().isEmpty())
users_files = "/tmp/users_files";
return users_files;
} }
}

View file

@ -40,9 +40,10 @@ public class Main {
Class.forName("com.mysql.cj.jdbc.Driver"); 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 @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
HttpUtil.responseHeaders(writer, 404, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 404, "Access-Control-Allow-Origin: *");
@ -52,30 +53,28 @@ public class Main {
} }
}); });
router.register(new Response(){ router.register(new Response() {
@Route(path = "^(.*)$", type = "OPTIONS") @Route(path = "^(.*)$", type = "OPTIONS")
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
HttpUtil.responseHeaders(writer, 200, HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *",
"Access-Control-Allow-Origin: *", "Access-Control-Allow-Methods: *", "Access-Control-Allow-Headers: *");
"Access-Control-Allow-Methods: *",
"Access-Control-Allow-Headers: *");
} }
}); });
initRoutes(router); initRoutes(router, config);
startWebServer(config, router); 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 ChapterElement(router.getDataBase()));
router.register(new ChapterList(router.getDataBase())); router.register(new ChapterList(router.getDataBase()));
router.register(new PuzzleElement(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 Login(router.getDataBase(), router));
router.register(new Result(router.getDataBase())); 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 Leaderboard(router.getDataBase()));
router.register(new PlayerDetails(router.getDataBase())); router.register(new PlayerDetails(router.getDataBase()));
router.register(new BadgeDetails(router.getDataBase())); router.register(new BadgeDetails(router.getDataBase()));
@ -85,7 +84,7 @@ public class Main {
} }
private static void startWebServer(Configuration config, Router router) throws IOException { 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; SSLServerSocket server = null;
try { try {
System.setProperty("javax.net.ssl.keyStore", config.getSslKeystore()); System.setProperty("javax.net.ssl.keyStore", config.getSslKeystore());
@ -106,17 +105,15 @@ public class Main {
server.close(); server.close();
} }
} }
} } else {
else { try (ServerSocket server = new ServerSocket(config.getTcpPort())) {
try (ServerSocket server = new ServerSocket(config.getTcpPort())){ while (!server.isClosed()) {
while(!server.isClosed()){
Socket socket = server.accept(); Socket socket = server.accept();
RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048); RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
Client client = new Client(socket, router, rsaJsonWebKey); Client client = new Client(socket, router, rsaJsonWebKey);
client.start(); client.start();
} }
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }

View file

@ -5,20 +5,19 @@ import java.util.Arrays;
import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
import org.jose4j.jwk.RsaJsonWebKey; import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jwk.RsaJwkGenerator;
import org.jose4j.jws.AlgorithmIdentifiers; import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jwt.JwtClaims; import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.JwtConsumer; import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder; import org.jose4j.jwt.consumer.JwtConsumerBuilder;
public class Client extends Thread{ public class Client extends Thread {
private HttpReader reader; private HttpReader reader;
private HttpWriter writer; private HttpWriter writer;
private Router router; private Router router;
private RsaJsonWebKey key; private RsaJsonWebKey key; // Really needed ?
public Client(Socket socket, Router router, RsaJsonWebKey key) throws Exception{ public Client(Socket socket, Router router, RsaJsonWebKey key) throws Exception {
this.reader = new HttpReader(socket); this.reader = new HttpReader(socket);
this.writer = new HttpWriter(socket); this.writer = new HttpWriter(socket);
this.router = router; this.router = router;
@ -26,7 +25,7 @@ public class Client extends Thread{
} }
@Override @Override
public void run(){ public void run() {
try { try {
String[] headers = reader.readLine().split("\\s"); String[] headers = reader.readLine().split("\\s");
System.out.println(Arrays.toString(headers)); 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); router.exec(headers[0], headers[1], isLogin(reader), reader, writer);
writer.flush(); writer.flush();
writer.close(); writer.close();
} catch (Exception e){ } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
private User isLogin(HttpReader reader) throws Exception{ private User isLogin(HttpReader reader) throws Exception {
String auth = HttpUtil.readAuthorization(reader); String auth = HttpUtil.readAuthorization(reader);
if(auth == null) return null; if (auth == null)
return null;
try { try {
JwtConsumer jwtConsumer = new JwtConsumerBuilder() JwtConsumer jwtConsumer = new JwtConsumerBuilder().setRequireExpirationTime()
.setRequireExpirationTime() .setAllowedClockSkewInSeconds(30).setExpectedIssuer(this.router.getTokenIssuer())
.setAllowedClockSkewInSeconds(30)
.setExpectedIssuer(this.router.getTokenIssuer())
.setVerificationKey(this.router.getWebKey().getKey()) .setVerificationKey(this.router.getWebKey().getKey())
.setJwsAlgorithmConstraints( .setJwsAlgorithmConstraints(ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256).build();
ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256)
.build();
JwtClaims jwtClaims = jwtConsumer.processToClaims(auth); JwtClaims jwtClaims = jwtConsumer.processToClaims(auth);
return new User(jwtClaims); return new User(jwtClaims);
}catch(Exception e){ } catch (Exception e) {
HttpUtil.responseHeaders(writer, 401, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 401, "Access-Control-Allow-Origin: *");
writer.flush(); writer.flush();
writer.close(); writer.close();

View file

@ -12,17 +12,17 @@ public class HttpReader {
private InputStream in; private InputStream in;
private BufferedReader reader; private BufferedReader reader;
public HttpReader(Socket socket) throws Exception{ public HttpReader(Socket socket) throws Exception {
this.socket = socket; this.socket = socket;
this.in = socket.getInputStream(); this.in = socket.getInputStream();
this.reader = new BufferedReader(new InputStreamReader(in)); this.reader = new BufferedReader(new InputStreamReader(in));
} }
public boolean isClosed(){ public boolean isClosed() {
return this.socket.isClosed(); return this.socket.isClosed();
} }
public int read(byte[] buffer) throws IOException{ public int read(byte[] buffer) throws IOException {
return this.in.read(buffer); return this.in.read(buffer);
} }
@ -30,20 +30,20 @@ public class HttpReader {
return this.reader.read(buffer); return this.reader.read(buffer);
} }
public String readLine() throws IOException{ public String readLine() throws IOException {
return this.reader.readLine(); return this.reader.readLine();
} }
public boolean ready() throws IOException{ public boolean ready() throws IOException {
return this.reader.ready(); return this.reader.ready();
} }
public int readInt() throws Exception{ public int readInt() throws Exception {
int result = 0; int result = 0;
result+=this.in.read() << 24; result += this.in.read() << 24;
result+=this.in.read() << 16; result += this.in.read() << 16;
result+=this.in.read() << 8; result += this.in.read() << 8;
result+=this.in.read(); result += this.in.read();
return result; return result;
} }
} }

View file

@ -10,33 +10,36 @@ import org.json.simple.parser.JSONParser;
public class HttpUtil { public class HttpUtil {
private HttpUtil(){} private HttpUtil() {
}
public static void responseHeaders(HttpWriter writer, int code, String... headers) throws Exception{ public static void responseHeaders(HttpWriter writer, int code, String... headers) throws Exception {
writer.write("HTTP/1.1 "+code+" "+codeMessage(code)+"\n"); writer.write("HTTP/1.1 " + code + " " + codeMessage(code) + "\n");
for(String header : headers) writer.write(header+"\n"); for (String header : headers)
writer.write(header + "\n");
writer.write("\n"); writer.write("\n");
writer.flush(); writer.flush();
} }
public static void skipHeaders(HttpReader reader) throws Exception{ public static void skipHeaders(HttpReader reader) throws Exception {
String line; String line;
while(((line = reader.readLine()) != null) && (line.length() > 0)); while (((line = reader.readLine()) != null) && (line.length() > 0))
;
} }
public static List<String> readMultiPartData(HttpReader reader) throws Exception{ public static List<String> readMultiPartData(HttpReader reader) throws Exception {
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
reader.readLine(); reader.readLine();
while(reader.ready()){ while (reader.ready()) {
String line; String line;
while(((line = reader.readLine()) != null) && (line.length() > 0)){ while (((line = reader.readLine()) != null) && (line.length() > 0)) {
} }
String buffer = ""; String buffer = "";
while(((line = reader.readLine()) != null) && (!line.startsWith("------WebKitFormBoundary"))){ while (((line = reader.readLine()) != null) && (!line.startsWith("------WebKitFormBoundary"))) {
buffer+=line; buffer += line;
} }
list.add(buffer); list.add(buffer);
} }
@ -44,17 +47,16 @@ public class HttpUtil {
return list; 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); 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("HTTP/1.1 101 Switching Protocols\n");
writer.write("Connection: Upgrade\n"); writer.write("Connection: Upgrade\n");
writer.write("Upgrade: websocket\n"); writer.write("Upgrade: websocket\n");
writer.write("Sec-WebSocket-Accept: "+ writer.write("Sec-WebSocket-Accept: " + printBase64Binary(MessageDigest.getInstance("SHA-1")
printBase64Binary( .digest((key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes("UTF-8"))) + "\n");
MessageDigest.getInstance("SHA-1").
digest((key+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes("UTF-8")))+"\n");
writer.write("\n"); writer.write("\n");
writer.flush(); writer.flush();
} }
@ -64,12 +66,13 @@ public class HttpUtil {
public static String readWebSocketKey(HttpReader reader) throws Exception { public static String readWebSocketKey(HttpReader reader) throws Exception {
String line; String line;
String key = null; String key = null;
while(((line = reader.readLine()) != null) && (line.length() > 0)){ while (((line = reader.readLine()) != null) && (line.length() > 0)) {
if(key != null){ if (key != null) {
continue; continue;
} }
Matcher matcher = WEBSOCKET_KEY.matcher(line); Matcher matcher = WEBSOCKET_KEY.matcher(line);
if(matcher.matches()) key = matcher.group(1); if (matcher.matches())
key = matcher.group(1);
} }
return key; return key;
} }
@ -79,9 +82,9 @@ public class HttpUtil {
public static String readAuthorization(HttpReader reader) throws Exception { public static String readAuthorization(HttpReader reader) throws Exception {
String line; String line;
String key = null; String key = null;
while(((line = reader.readLine()) != null) && (line.length() > 0)){ while (((line = reader.readLine()) != null) && (line.length() > 0)) {
Matcher matcher = AUTORIZATION.matcher(line); Matcher matcher = AUTORIZATION.matcher(line);
if(matcher.matches()){ if (matcher.matches()) {
key = matcher.group(1); key = matcher.group(1);
break; break;
} }
@ -89,48 +92,52 @@ public class HttpUtil {
return key; return key;
} }
public static Object readJson(HttpReader reader) throws Exception{ public static Object readJson(HttpReader reader) throws Exception {
String line = ""; String line = "";
while(reader.ready()){ while (reader.ready()) {
char[] c = new char[1]; char[] c = new char[1];
reader.read(c); reader.read(c);
line+=c[0]; line += c[0];
if(c[0] == '}'){ if (c[0] == '}') {
Object parse; Object parse;
try { try {
parse = new JSONParser().parse(line); parse = new JSONParser().parse(line);
if(parse != null) return parse; if (parse != null)
}catch(Exception e){} return parse;
} catch (Exception e) {
}
} }
} }
return null; return null;
} }
//I found this code on StackOverFlow !!!!! (and the write too) // I found this code on StackOverFlow !!!!! (and the write too)
public static String readWebSocket(HttpReader reader) throws Exception{ public static String readWebSocket(HttpReader reader) throws Exception {
int buffLenth = 1024; int buffLenth = 1024;
int len = 0; int len = 0;
byte[] b = new byte[buffLenth]; byte[] b = new byte[buffLenth];
//rawIn is a Socket.getInputStream(); // rawIn is a Socket.getInputStream();
while(true){ while (true) {
len = reader.read(b); len = reader.read(b);
if(len!=-1){ if (len != -1) {
byte rLength = 0; byte rLength = 0;
int rMaskIndex = 2; int rMaskIndex = 2;
int rDataStart = 0; int rDataStart = 0;
//b[0] is always text in my case so no need to check; // b[0] is always text in my case so no need to check;
byte data = b[1]; byte data = b[1];
byte op = (byte) 127; byte op = (byte) 127;
rLength = (byte) (data & op); rLength = (byte) (data & op);
if(rLength==(byte)126) rMaskIndex=4; if (rLength == (byte) 126)
if(rLength==(byte)127) rMaskIndex=10; rMaskIndex = 4;
if (rLength == (byte) 127)
rMaskIndex = 10;
byte[] masks = new byte[4]; byte[] masks = new byte[4];
int j=0; int j = 0;
int i=0; int i = 0;
for(i=rMaskIndex;i<(rMaskIndex+4);i++){ for (i = rMaskIndex; i < (rMaskIndex + 4); i++) {
masks[j] = b[i]; masks[j] = b[i];
j++; j++;
} }
@ -141,18 +148,19 @@ public class HttpUtil {
byte[] message = new byte[messLen]; byte[] message = new byte[messLen];
for(i=rDataStart, j=0; i<len; i++, j++){ for (i = rDataStart, j = 0; i < len; i++, j++) {
message[j] = (byte) (b[i] ^ masks[j % 4]); message[j] = (byte) (b[i] ^ masks[j % 4]);
} }
return new String(message); return new String(message);
}else break; } else
break;
} }
return null; return null;
} }
public static void sendWebSocket(HttpWriter writer, String message) throws Exception{ public static void sendWebSocket(HttpWriter writer, String message) throws Exception {
byte[] rawData = message.getBytes(); byte[] rawData = message.getBytes();
int frameCount = 0; int frameCount = 0;
@ -160,26 +168,26 @@ public class HttpUtil {
frame[0] = (byte) 129; frame[0] = (byte) 129;
if(rawData.length <= 125){ if (rawData.length <= 125) {
frame[1] = (byte) rawData.length; frame[1] = (byte) rawData.length;
frameCount = 2; frameCount = 2;
}else if(rawData.length >= 126 && rawData.length <= 65535){ } else if (rawData.length >= 126 && rawData.length <= 65535) {
frame[1] = (byte) 126; frame[1] = (byte) 126;
int len = rawData.length; int len = rawData.length;
frame[2] = (byte)((len >> 8 ) & (byte)255); frame[2] = (byte) ((len >> 8) & (byte) 255);
frame[3] = (byte)(len & (byte)255); frame[3] = (byte) (len & (byte) 255);
frameCount = 4; frameCount = 4;
}else{ } else {
frame[1] = (byte) 127; frame[1] = (byte) 127;
int len = rawData.length; int len = rawData.length;
frame[2] = (byte)((len >> 56 ) & (byte)255); frame[2] = (byte) ((len >> 56) & (byte) 255);
frame[3] = (byte)((len >> 48 ) & (byte)255); frame[3] = (byte) ((len >> 48) & (byte) 255);
frame[4] = (byte)((len >> 40 ) & (byte)255); frame[4] = (byte) ((len >> 40) & (byte) 255);
frame[5] = (byte)((len >> 32 ) & (byte)255); frame[5] = (byte) ((len >> 32) & (byte) 255);
frame[6] = (byte)((len >> 24 ) & (byte)255); frame[6] = (byte) ((len >> 24) & (byte) 255);
frame[7] = (byte)((len >> 16 ) & (byte)255); frame[7] = (byte) ((len >> 16) & (byte) 255);
frame[8] = (byte)((len >> 8 ) & (byte)255); frame[8] = (byte) ((len >> 8) & (byte) 255);
frame[9] = (byte)(len & (byte)255); frame[9] = (byte) (len & (byte) 255);
frameCount = 10; frameCount = 10;
} }
@ -188,11 +196,11 @@ public class HttpUtil {
byte[] reply = new byte[bLength]; byte[] reply = new byte[bLength];
int bLim = 0; int bLim = 0;
for(int i=0; i<frameCount;i++){ for (int i = 0; i < frameCount; i++) {
reply[bLim] = frame[i]; reply[bLim] = frame[i];
bLim++; bLim++;
} }
for(int i=0; i<rawData.length;i++){ for (int i = 0; i < rawData.length; i++) {
reply[bLim] = rawData[i]; reply[bLim] = rawData[i];
bLim++; bLim++;
} }
@ -279,22 +287,24 @@ public class HttpUtil {
return " "; return " ";
} }
// From javax.xml.bind.DatatypeConverter
//From javax.xml.bind.DatatypeConverter private static String printBase64Binary(byte[] array) {
private static String printBase64Binary(byte[] array){
char[] arrayOfChar = new char[(array.length + 2) / 3 * 4]; char[] arrayOfChar = new char[(array.length + 2) / 3 * 4];
int i = _printBase64Binary(array, 0, array.length, arrayOfChar, 0); int i = _printBase64Binary(array, 0, array.length, arrayOfChar, 0);
assert i == arrayOfChar.length; assert i == arrayOfChar.length;
return new String(arrayOfChar); return new String(arrayOfChar);
} }
private static int _printBase64Binary(byte[] paramArrayOfbyte, int paramInt1, int paramInt2, char[] paramArrayOfchar, int paramInt3) { private static int _printBase64Binary(byte[] paramArrayOfbyte, int paramInt1, int paramInt2,
char[] paramArrayOfchar, int paramInt3) {
int i = paramInt2; int i = paramInt2;
int j; int j;
for (j = paramInt1; i >= 3; j += 3) { for (j = paramInt1; i >= 3; j += 3) {
paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF); paramArrayOfchar[paramInt3++] = encode(
paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2 | paramArrayOfbyte[j + 2] >> 6 & 0x3); (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); paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j + 2] & 0x3F);
i -= 3; i -= 3;
} }
@ -306,7 +316,8 @@ public class HttpUtil {
} }
if (i == 2) { if (i == 2) {
paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF); paramArrayOfchar[paramInt3++] = encode(
(paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF);
paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2); paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2);
paramArrayOfchar[paramInt3++] = '='; paramArrayOfchar[paramInt3++] = '=';
} }
@ -316,17 +327,18 @@ public class HttpUtil {
private static char encode(int paramInt) { private static char encode(int paramInt) {
return encodeMap[paramInt & 0x3F]; return encodeMap[paramInt & 0x3F];
} }
private static final char[] encodeMap = initEncodeMap(); private static final char[] encodeMap = initEncodeMap();
private static char[] initEncodeMap() { private static char[] initEncodeMap() {
char[] arrayOfChar = new char[64]; char[] arrayOfChar = new char[64];
byte b; byte b;
for (b = 0; b < 26; b++) for (b = 0; b < 26; b++)
arrayOfChar[b] = (char)(65 + b); arrayOfChar[b] = (char) (65 + b);
for (b = 26; b < 52; b++) for (b = 26; b < 52; b++)
arrayOfChar[b] = (char)(97 + b - 26); arrayOfChar[b] = (char) (97 + b - 26);
for (b = 52; b < 62; b++) for (b = 52; b < 62; b++)
arrayOfChar[b] = (char)(48 + b - 52); arrayOfChar[b] = (char) (48 + b - 52);
arrayOfChar[62] = '+'; arrayOfChar[62] = '+';
arrayOfChar[63] = '/'; arrayOfChar[63] = '/';
return arrayOfChar; return arrayOfChar;

View file

@ -7,30 +7,30 @@ import java.io.OutputStreamWriter;
import java.net.Socket; import java.net.Socket;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
public class HttpWriter{ public class HttpWriter {
private OutputStream out; private OutputStream out;
private BufferedWriter writer; private BufferedWriter writer;
public HttpWriter(Socket socket) throws Exception{ public HttpWriter(Socket socket) throws Exception {
this.out = socket.getOutputStream(); this.out = socket.getOutputStream();
this.writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)); 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.write(buffer);
this.out.flush(); this.out.flush();
} }
public void write(String message) throws IOException{ public void write(String message) throws IOException {
this.writer.write(message); this.writer.write(message);
} }
public void flush() throws IOException{ public void flush() throws IOException {
this.writer.flush(); this.writer.flush();
} }
public void close() throws IOException{ public void close() throws IOException {
this.writer.close(); this.writer.close();
} }
} }

View file

@ -1,10 +1,9 @@
package be.jeffcheasey88.peeratcode.framework; package be.jeffcheasey88.peeratcode.framework;
import java.util.regex.Matcher; 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;
} }

View file

@ -10,7 +10,9 @@ import java.lang.annotation.Target;
public @interface Route { public @interface Route {
String path() default "^.*$"; String path() default "^.*$";
String type() default "GET"; String type() default "GET";
boolean needLogin() default false; boolean needLogin() default false;
} }

View file

@ -16,7 +16,7 @@ import org.jose4j.lang.JoseException;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class Router{ public class Router {
private Map<Response, Route> responses; private Map<Response, Route> responses;
private Map<Response, Pattern> patterns; private Map<Response, Pattern> patterns;
@ -26,7 +26,7 @@ public class Router{
private String token_issuer; private String token_issuer;
private int token_expiration; 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.repo = repo;
this.token_issuer = token_issuer; this.token_issuer = token_issuer;
this.token_expiration = token_expiration; this.token_expiration = token_expiration;
@ -35,49 +35,52 @@ public class Router{
this.rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048); this.rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
} }
public DatabaseRepository getDataBase(){ public DatabaseRepository getDataBase() {
return this.repo; return this.repo;
} }
public void register(Response response){ public void register(Response response) {
try { 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); Route route = method.getAnnotation(Route.class);
this.responses.put(response, route); this.responses.put(response, route);
this.patterns.put(response, Pattern.compile(route.path())); this.patterns.put(response, Pattern.compile(route.path()));
} catch (Exception e){ } catch (Exception e) {
throw new IllegalArgumentException(e); throw new IllegalArgumentException(e);
} }
} }
public void setDefault(Response response){ public void setDefault(Response response) {
this.noFileFound = response; this.noFileFound = response;
} }
public void exec(String type, String path, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(String type, String path, User user, HttpReader reader, HttpWriter writer) throws Exception {
for(Entry<Response, Route> routes : this.responses.entrySet()){ for (Entry<Response, Route> routes : this.responses.entrySet()) {
if(routes.getValue().type().equals(type)){ if (routes.getValue().type().equals(type)) {
Matcher matcher = this.patterns.get(routes.getKey()).matcher(path); Matcher matcher = this.patterns.get(routes.getKey()).matcher(path);
if(matcher.matches()){ if (matcher.matches()) {
if(user == null && routes.getValue().needLogin()) return; if (user == null && routes.getValue().needLogin())
return;
routes.getKey().exec(matcher, user, reader, writer); routes.getKey().exec(matcher, user, reader, writer);
return; 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; return this.rsaJsonWebKey;
} }
public String getTokenIssuer(){ public String getTokenIssuer() {
return this.token_issuer; return this.token_issuer;
} }
public String createAuthUser(int id) throws JoseException{ public String createAuthUser(int id) throws JoseException {
JwtClaims claims = new JwtClaims(); JwtClaims claims = new JwtClaims();
claims.setIssuer(token_issuer); // who creates the token and signs it claims.setIssuer(token_issuer); // who creates the token and signs it
claims.setExpirationTimeMinutesInTheFuture(token_expiration); claims.setExpirationTimeMinutesInTheFuture(token_expiration);

View file

@ -6,11 +6,11 @@ public class User {
private int id; private int id;
public User(JwtClaims jwtClaims){ public User(JwtClaims jwtClaims) {
this.id = ((Long)jwtClaims.getClaimValue("id")).intValue(); this.id = ((Long) jwtClaims.getClaimValue("id")).intValue();
} }
public int getId(){ public int getId() {
return this.id; return this.id;
} }
} }

View file

@ -9,10 +9,6 @@ public class Badge {
private byte[] logo; private byte[] logo;
private int level; private int level;
public Badge(String name, int level) {
this(name, null, level);
}
public Badge(String name, byte[] logo, int level) { public Badge(String name, byte[] logo, int level) {
this.name = name; this.name = name;
this.logo = logo; this.logo = logo;
@ -23,24 +19,11 @@ public class Badge {
return name; return name;
} }
public void setName(String name) {
this.name = name;
}
public byte[] getLogo() { public byte[] getLogo() {
return logo; return logo;
} }
public void setLogo(byte[] logo) {
this.logo = logo;
}
public int getLevel() { public int getLevel() {
return level; return level;
} }
public void setLevel(int level) {
this.level = level;
}
} }

View file

@ -1,7 +1,6 @@
package be.jeffcheasey88.peeratcode.model; package be.jeffcheasey88.peeratcode.model;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
public class Chapter { public class Chapter {
@ -23,18 +22,10 @@ public class Chapter {
return id; return id;
} }
public void setId(int id) {
this.id = id;
}
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) {
this.name = name;
}
public List<Puzzle> getPuzzles() { public List<Puzzle> getPuzzles() {
return puzzles; return puzzles;
} }
@ -52,10 +43,12 @@ public class Chapter {
} }
@Override @Override
public boolean equals(Object object){ public boolean equals(Object object) {
if(this == object) return true; if (this == object)
if(!(object instanceof Chapter)) return false; return true;
return this.id == (((Chapter)object).id); if (!(object instanceof Chapter))
return false;
return this.id == (((Chapter) object).id);
} }
@Override @Override

View file

@ -12,10 +12,6 @@ public class Completion {
this(playerId, puzzleId, -1, 1, fileName, score, null); 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, public Completion(int playerId, int puzzleId, int idCompletion, int tries, String fileName, int score,
byte[] file) { byte[] file) {
this.playerId = playerId; this.playerId = playerId;
@ -42,9 +38,10 @@ public class Completion {
this.tries++; this.tries++;
updateScore(); updateScore();
} }
private void updateScore() { private void updateScore() {
if (tries > 1) { if (tries > 1) {
score = score * (1-((tries-1)/10)); score = score * (1 - ((tries - 1) / 10));
} }
} }

View file

@ -1,16 +1,24 @@
package be.jeffcheasey88.peeratcode.model; package be.jeffcheasey88.peeratcode.model;
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; import org.json.simple.JSONObject;
public class Group { public class Group implements Comparable<Group> {
private String name; private String name;
private int linkToChapter; private int linkToChapter;
private int linkToPuzzle; private int linkToPuzzle;
private List<Player> players;
public Group(JSONObject json){ public Group(JSONObject json) {
this.name = (String)json.get("name"); this.name = (String) json.get("name");
this.linkToChapter = ((Number)json.get("chapter")).intValue(); this.linkToChapter = ((Number) json.get("chapter")).intValue();
this.linkToPuzzle = ((Number)json.get("puzzle")).intValue(); this.linkToPuzzle = ((Number) json.get("puzzle")).intValue();
} }
public Group(String name, int initChap, int initPuzz) { public Group(String name, int initChap, int initPuzz) {
@ -19,35 +27,112 @@ public class Group {
this.linkToPuzzle = initPuzz; this.linkToPuzzle = initPuzz;
} }
public String getName() { public void addPlayer(Player newPlayer) {
return name; if (newPlayer != null) {
if (players == null)
players = new ArrayList<Player>();
int pPosition = players.indexOf(newPlayer);
if (pPosition < 0) {
players.add(newPlayer);
} else {
players.get(pPosition).addScore(newPlayer.getTotalScore(), newPlayer.getTotalTries());
}
}
} }
public void setName(String name) { public int getScore() {
this.name = name; 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;
} }
public int getLinkToChapter() { public int getLinkToChapter() {
return linkToChapter; return linkToChapter;
} }
public void setLinkToChapter(int linkToChapter) {
this.linkToChapter = linkToChapter;
}
public int getLinkToPuzzle() { public int getLinkToPuzzle() {
return linkToPuzzle; return linkToPuzzle;
} }
public void setLinkToPuzzle(int linkToPuzzle) { public JSONObject toJson() {
this.linkToPuzzle = linkToPuzzle; return this.toJson(null);
} }
public JSONObject toJson() { public JSONObject toJson(Integer rank) {
JSONObject groupJSON = new JSONObject(); JSONObject groupJSON = new JSONObject();
groupJSON.put("name", name); groupJSON.put("name", name);
if (linkToChapter > 0) groupJSON.put("chapter", linkToChapter); if (rank != null)
if (linkToPuzzle > 0) groupJSON.put("puzzle", linkToPuzzle); 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) {
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; 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);
}
} }

View file

@ -9,8 +9,6 @@ import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
public class Player implements Comparable<Player> { public class Player implements Comparable<Player> {
public static final String PATH_TO_CODE = "/home/%s/peer-at-source/";
private String pseudo; private String pseudo;
private String email; private String email;
private String firstname; private String firstname;
@ -38,6 +36,18 @@ public class Player implements Comparable<Player> {
totalTries = 0; 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() { public String getPseudo() {
return this.pseudo; return this.pseudo;
} }
@ -62,11 +72,6 @@ public class Player implements Comparable<Player> {
return groups; return groups;
} }
/**
* SEE SET_TAGS IN PUZZLE
*
* @return DEATH
*/
public JSONArray getJsonGroups() { public JSONArray getJsonGroups() {
if (groups != null) { if (groups != null) {
JSONArray groupsJSON = new JSONArray(); JSONArray groupsJSON = new JSONArray();
@ -94,10 +99,6 @@ public class Player implements Comparable<Player> {
avatar = newAvatar; avatar = newAvatar;
} }
public String getPathToSourceCode() {
return String.format(PATH_TO_CODE, pseudo);
}
public int getRank() { public int getRank() {
return rank; return rank;
} }
@ -114,6 +115,12 @@ public class Player implements Comparable<Player> {
this.totalScore = totalScore; this.totalScore = totalScore;
} }
public void addScore(int addScore, int tries) {
totalScore = totalScore + addScore;
totalTries = totalTries + tries;
totalCompletion++;
}
public int getTotalCompletion() { public int getTotalCompletion() {
return totalCompletion; return totalCompletion;
} }
@ -134,11 +141,6 @@ public class Player implements Comparable<Player> {
return badges; return badges;
} }
/**
* SEE SET_TAGS IN PUZZLE
*
* @return DEATH
*/
public JSONArray getJsonBadges() { public JSONArray getJsonBadges() {
if (badges == null) if (badges == null)
return null; return null;

View file

@ -18,10 +18,8 @@ public class Puzzle {
private Set<String> tags; private Set<String> tags;
private int depend; private int depend;
public Puzzle(int id, String name, String content, byte[] soluce, String verify, int scoreMax, String tags){ 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); int depend) {
}
public Puzzle(int id, String name, String content, byte[] soluce, String verify, int scoreMax, String tags, int depend){
this.id = id; this.id = id;
this.name = name; this.name = name;
this.content = content; this.content = content;
@ -36,63 +34,36 @@ public class Puzzle {
return id; return id;
} }
public void setId(int id) {
this.id = id;
}
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) {
this.name = name;
}
public String getContent() { public String getContent() {
return content; return content;
} }
public void setContent(String content) { public byte[] getSoluce() {
this.content = content;
}
public byte[] getSoluce(){
return this.soluce; return this.soluce;
} }
public void setSoluce(byte[] array){ public int getScoreMax() {
this.soluce = array;
}
public String getVerify(){
return this.verify;
}
public void setVerify(String regex){
this.verify = regex;
}
public int getScoreMax(){
return this.scoreMax; return this.scoreMax;
} }
public void setScoreMax(int max){ public Set<String> getTags() {
this.scoreMax = max;
}
public Set<String> getTags(){
return this.tags; return this.tags;
} }
/** /**
* DO NOT EVER EVER SHOW TO MISTER LUDWIG XD * DO NOT EVER EVER SHOW TO MISTER LUDWIG XD
*
* @return DEATH * @return DEATH
*/ */
public JSONArray getJsonTags() { public JSONArray getJsonTags() {
if (tags == null) if (tags == null)
return null; return null;
JSONArray tagsJSON = new JSONArray(); JSONArray tagsJSON = new JSONArray();
for (String tag: tags) { for (String tag : tags) {
JSONObject tagJSON = new JSONObject(); JSONObject tagJSON = new JSONObject();
tagJSON.put("name", tag); tagJSON.put("name", tag);
tagsJSON.add(tagJSON); tagsJSON.add(tagJSON);
@ -100,26 +71,24 @@ public class Puzzle {
return tagsJSON; return tagsJSON;
} }
public void setTags(String tags){ public void setTags(String tags) {
if (tags == null || tags.isEmpty()) if (tags == null || tags.isEmpty())
this.tags = null; this.tags = null;
else else
this.tags = new HashSet<String>(Arrays.asList(tags.split(","))); this.tags = new HashSet<String>(Arrays.asList(tags.split(",")));
} }
public int getDepend(){ public int getDepend() {
return this.depend; return this.depend;
} }
public void setDepend(int depend){
this.depend = depend;
}
@Override @Override
public boolean equals(Object object) { public boolean equals(Object object) {
if(this == object) return true; if (this == object)
if(!(object instanceof Puzzle)) return false; return true;
return this.id == (((Puzzle)object).id); if (!(object instanceof Puzzle))
return false;
return this.id == (((Puzzle) object).id);
} }
@Override @Override

View file

@ -5,46 +5,72 @@ import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
public enum DatabaseQuery { public enum DatabaseQuery {
// 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"),
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"), // CHAPTERS
SPECIFIC_CHAPTER_QUERY("SELECT * FROM chapters WHERE id_chapter = ?"), 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_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"), // 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_PSEUDO_AVAILABLE_QUERY("SELECT * FROM players WHERE pseudo = ?"),
CHECK_EMAIL_AVAILABLE_QUERY("SELECT * FROM players WHERE email = ?"), CHECK_EMAIL_AVAILABLE_QUERY("SELECT * FROM players WHERE email = ?"),
REGISTER_QUERY("INSERT INTO players (pseudo, email, passwd, firstname, lastname, description, avatar) VALUES (?, ?, ?, ?, ?, ?, ?)"), REGISTER_QUERY(
REGISTER_PLAYER_IN_EXISTING_GROUP("INSERT INTO containsGroups (fk_player, fk_group) VALUES (?, (SELECT id_group FROM groups WHERE name = ?));"), "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=?"), 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 = ?"), 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_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(
GET_PLAYER_DETAILS_BY_ID(GET_PLAYER_DETAILS," p.id_player = ? ORDER BY g.fk_chapter, g.fk_puzzle;"), "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_PSEUDO(GET_PLAYER_DETAILS,"p.pseudo = ? ORDER BY g.fk_chapter, g.fk_puzzle;"), GET_PLAYER_DETAILS_BY_ID(GET_PLAYER_DETAILS, " p.id_player = ? ORDER BY g.fk_chapter, g.fk_puzzle;"),
GET_BADGE("SELECT * FROM badges WHERE id_badge = ?"), GET_PLAYER_DETAILS_BY_PSEUDO(GET_PLAYER_DETAILS, "p.pseudo = ? ORDER BY g.fk_chapter, g.fk_puzzle;"),
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 (?, ?, ?, ?, ?, ?)"), // BADGES
INSERT_GROUP("INSERT INTO groups (name, fk_chapter, fk_puzzle) VALUES (?,?,?)"), GET_BADGE("SELECT * FROM badges WHERE id_badge = ?"), GET_BADGES_OF_PLAYER(
UPDATE_COMPLETION("UPDATE completions SET tries = ?, filename = ?, score = ? WHERE fk_puzzle = ? AND fk_player = ?"); "SELECT * FROM badges b LEFT JOIN containsBadges cb ON cb.fk_badge = b.id_badge WHERE cb.fk_player = ?");
private String request; private String request;
DatabaseQuery(DatabaseQuery parent, String request){ DatabaseQuery(DatabaseQuery parent, String request) {
this.request = parent.request+request; this.request = parent.request + request;
} }
DatabaseQuery(String request){ DatabaseQuery(String request) {
this.request = request; this.request = request;
} }
public PreparedStatement prepare(Connection con) throws SQLException{ public PreparedStatement prepare(Connection con) throws SQLException {
return con.prepareStatement(this.request); return con.prepareStatement(this.request);
} }
@Override @Override
public String toString(){ public String toString() {
return this.request; return this.request;
} }
} }

View file

@ -82,6 +82,9 @@ public class DatabaseRepository {
private Group makeGroup(ResultSet result) throws SQLException { private Group makeGroup(ResultSet result) throws SQLException {
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"));
}
private Badge makeBadge(ResultSet rs) throws SQLException { private Badge makeBadge(ResultSet rs) throws SQLException {
return new Badge(rs.getString("name"), rs.getBytes("logo"), rs.getInt("level")); return new Badge(rs.getString("name"), rs.getBytes("logo"), rs.getInt("level"));
@ -91,8 +94,9 @@ public class DatabaseRepository {
// Found on StackOverflow // Found on StackOverflow
ResultSetMetaData rsmd = rs.getMetaData(); ResultSetMetaData rsmd = rs.getMetaData();
int columns = rsmd.getColumnCount(); int columns = rsmd.getColumnCount();
for(int x = 1; x <= columns; x++){ for (int x = 1; x <= columns; x++) {
if(columnName.equals(rsmd.getColumnName(x))) return true; if (columnName.equals(rsmd.getColumnName(x)))
return true;
} }
return false; return false;
} }
@ -238,6 +242,33 @@ public class DatabaseRepository {
return null; return null;
} }
public SortedSet<Group> 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<Group> groups = new ArrayList<Group>();
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<Group>(groups);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public Badge getBadge(int badgeId) { public Badge getBadge(int badgeId) {
try { try {
ensureConnection(); ensureConnection();
@ -380,7 +411,8 @@ public class DatabaseRepository {
ResultSet inserted = playerStatement.getGeneratedKeys(); ResultSet inserted = playerStatement.getGeneratedKeys();
if (inserted.next()) { if (inserted.next()) {
int newPlayerId = inserted.getInt(1); 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.setInt(1, newPlayerId);
containsGroupsStatement.setString(2, sgroup); containsGroupsStatement.setString(2, sgroup);
containsGroupsStatement.executeUpdate(); containsGroupsStatement.executeUpdate();
@ -390,8 +422,7 @@ public class DatabaseRepository {
} }
} }
} }
} } catch (SQLException e) {
catch (SQLException e) {
con.rollback(); con.rollback();
con.setAutoCommit(true); con.setAutoCommit(true);
} }
@ -454,7 +485,7 @@ public class DatabaseRepository {
statement.executeUpdate(); statement.executeUpdate();
} }
public boolean insertGroup(Group group){ public boolean insertGroup(Group group) {
try { try {
ensureConnection(); ensureConnection();
PreparedStatement statement = DatabaseQuery.INSERT_GROUP.prepare(this.con); PreparedStatement statement = DatabaseQuery.INSERT_GROUP.prepare(this.con);
@ -462,7 +493,8 @@ public class DatabaseRepository {
statement.setInt(2, group.getLinkToChapter()); statement.setInt(2, group.getLinkToChapter());
statement.setInt(3, group.getLinkToPuzzle()); statement.setInt(3, group.getLinkToPuzzle());
return statement.executeUpdate() >= 0; return statement.executeUpdate() >= 0;
}catch(Exception e){} } catch (Exception e) {
}
return false; return false;
} }

View file

@ -1,5 +1,10 @@
package be.jeffcheasey88.peeratcode.routes; package be.jeffcheasey88.peeratcode.routes;
import java.util.Base64;
import java.util.regex.Matcher;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.framework.HttpReader; import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpUtil; import be.jeffcheasey88.peeratcode.framework.HttpUtil;
import be.jeffcheasey88.peeratcode.framework.HttpWriter; import be.jeffcheasey88.peeratcode.framework.HttpWriter;
@ -9,11 +14,6 @@ import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Badge; import be.jeffcheasey88.peeratcode.model.Badge;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
import org.json.simple.JSONObject;
import java.util.Base64;
import java.util.regex.Matcher;
public class BadgeDetails implements Response { public class BadgeDetails implements Response {
private final DatabaseRepository databaseRepo; private final DatabaseRepository databaseRepo;
@ -22,22 +22,22 @@ public class BadgeDetails implements Response {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
} }
@Route(path = "^\\/badge\\/([0-9]+)$") @Route(path = "^\\/badge\\/([0-9]+)$", needLogin = true)
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { 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) { if (matcher.groupCount() > 0) {
int badgeId = Integer.parseInt(matcher.group(1)); int badgeId = Integer.parseInt(matcher.group(1));
Badge badge = databaseRepo.getBadge(badgeId); Badge badge = databaseRepo.getBadge(badgeId);
JSONObject badgeJSON = new JSONObject(); JSONObject badgeJSON = new JSONObject();
if (badge != null) { if (badge != null) {
badgeJSON.put("name", badge.getName()); 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()); badgeJSON.put("level", badge.getLevel());
} }
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *");
writer.write(badgeJSON.toJSONString().replace("\\", "")); writer.write(badgeJSON.toJSONString().replace("\\", ""));
} } else {
else {
HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *");
} }
} }

View file

@ -1,5 +1,10 @@
package be.jeffcheasey88.peeratcode.routes; package be.jeffcheasey88.peeratcode.routes;
import java.util.regex.Matcher;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.framework.HttpReader; import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpUtil; import be.jeffcheasey88.peeratcode.framework.HttpUtil;
import be.jeffcheasey88.peeratcode.framework.HttpWriter; import be.jeffcheasey88.peeratcode.framework.HttpWriter;
@ -10,11 +15,6 @@ import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Puzzle; import be.jeffcheasey88.peeratcode.model.Puzzle;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.util.regex.Matcher;
public class ChapterElement implements Response { public class ChapterElement implements Response {
private final DatabaseRepository databaseRepo; private final DatabaseRepository databaseRepo;
@ -23,27 +23,32 @@ public class ChapterElement implements Response {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
} }
@Route(path = "^\\/chapter\\/([0-9]+)$") @Route(path = "^\\/chapter\\/([0-9]+)$", needLogin = true)
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { 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)); Chapter chapter = databaseRepo.getChapter(extractId(matcher));
if (chapter != null) { if (chapter != null) {
JSONObject chapterJSON = new JSONObject(); JSONObject chapterJSON = new JSONObject();
chapterJSON.put("id", chapter.getId()); chapterJSON.put("id", chapter.getId());
chapterJSON.put("name", chapter.getName()); chapterJSON.put("name", chapter.getName());
if (chapter.getStartDate() != null) chapterJSON.put("startDate", chapter.getStartDate().toString()); if (chapter.getStartDate() != null)
if (chapter.getEndDate() != null) chapterJSON.put("endDate", chapter.getEndDate().toString()); chapterJSON.put("startDate", chapter.getStartDate().toString());
if (chapter.getEndDate() != null)
chapterJSON.put("endDate", chapter.getEndDate().toString());
JSONArray puzzles = new JSONArray(); JSONArray puzzles = new JSONArray();
for (Puzzle puzzle : chapter.getPuzzles()) { for (Puzzle puzzle : chapter.getPuzzles()) {
JSONObject puzzleJSON = new JSONObject(); JSONObject puzzleJSON = new JSONObject();
puzzleJSON.put("id", puzzle.getId()); puzzleJSON.put("id", puzzle.getId());
puzzleJSON.put("name", puzzle.getName()); 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); puzzles.add(puzzleJSON);
} }
chapterJSON.put("puzzles", puzzles); chapterJSON.put("puzzles", puzzles);
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *");
writer.write(chapterJSON.toJSONString()); writer.write(chapterJSON.toJSONString());
} else {
HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *");
} }
} }

View file

@ -23,10 +23,9 @@ public class ChapterList implements Response {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
} }
@Route(path = "^\\/chapters$") @Route(path = "^\\/chapters$", needLogin = true)
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *");
List<Chapter> allChapters = databaseRepo.getAllChapters(); List<Chapter> allChapters = databaseRepo.getAllChapters();
if (allChapters != null) { if (allChapters != null) {
JSONArray chaptersJSON = new JSONArray(); JSONArray chaptersJSON = new JSONArray();
@ -34,11 +33,16 @@ public class ChapterList implements Response {
JSONObject chapterJSON = new JSONObject(); JSONObject chapterJSON = new JSONObject();
chapterJSON.put("id", chapter.getId()); chapterJSON.put("id", chapter.getId());
chapterJSON.put("name", chapter.getName()); chapterJSON.put("name", chapter.getName());
if (chapter.getStartDate() != null) chapterJSON.put("startDate", chapter.getStartDate().toString()); if (chapter.getStartDate() != null)
if (chapter.getEndDate() != null) chapterJSON.put("endDate", chapter.getEndDate().toString()); chapterJSON.put("startDate", chapter.getStartDate().toString());
if (chapter.getEndDate() != null)
chapterJSON.put("endDate", chapter.getEndDate().toString());
chaptersJSON.add(chapterJSON); chaptersJSON.add(chapterJSON);
} }
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *");
writer.write(chaptersJSON.toJSONString()); writer.write(chaptersJSON.toJSONString());
} else {
HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *");
} }
} }

View file

@ -1,5 +1,6 @@
package be.jeffcheasey88.peeratcode.routes; package be.jeffcheasey88.peeratcode.routes;
import java.io.IOException;
import java.util.Base64; import java.util.Base64;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -13,6 +14,8 @@ import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response; import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route; import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User; import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.model.Player; import be.jeffcheasey88.peeratcode.model.Player;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
@ -24,18 +27,59 @@ public class Leaderboard implements Response {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
} }
@Route(path = "^\\/leaderboard$") @Route(path = "^\\/leaderboard\\/?(\\d+)?$")
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); 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 {
Chapter chInfo = databaseRepo.getChapter(chapterId);
SortedSet<Group> 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;
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;
}
}
leaderboardJSON.put("groups", groupsJSON);
writer.write(leaderboardJSON.toJSONString().replace("\\", ""));
}
private void playersLeaderboard(HttpWriter writer) throws IOException {
SortedSet<Player> allPlayers = databaseRepo.getAllPlayerForLeaderboard(); SortedSet<Player> allPlayers = databaseRepo.getAllPlayerForLeaderboard();
JSONArray playersJSON = new JSONArray(); JSONArray playersJSON = new JSONArray();
if (allPlayers != null) { if (allPlayers != null) {
for (Player player : allPlayers) { for (Player player : allPlayers) {
JSONObject playerJSON = new JSONObject(); JSONObject playerJSON = new JSONObject();
playerJSON.put("pseudo", player.getPseudo()); playerJSON.put("pseudo", player.getPseudo());
if (player.getGroups() != null) playerJSON.put("groups", player.getJsonGroups()); if (player.getGroups() != null)
if(player.getAvatar() != null) playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar())); playerJSON.put("groups", player.getJsonGroups());
if (player.getAvatar() != null)
playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar()));
playerJSON.put("rank", player.getRank()); playerJSON.put("rank", player.getRank());
playerJSON.put("score", player.getTotalScore()); playerJSON.put("score", player.getTotalScore());
playerJSON.put("completions", player.getTotalCompletion()); playerJSON.put("completions", player.getTotalCompletion());

View file

@ -1,12 +1,7 @@
package be.jeffcheasey88.peeratcode.routes; package be.jeffcheasey88.peeratcode.routes;
import java.util.regex.Matcher; 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 org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.framework.HttpReader; import be.jeffcheasey88.peeratcode.framework.HttpReader;
@ -23,7 +18,7 @@ public class Login implements Response {
private DatabaseRepository databaseRepo; private DatabaseRepository databaseRepo;
private Router router; private Router router;
public Login(DatabaseRepository databaseRepo, Router router){ public Login(DatabaseRepository databaseRepo, Router router) {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
this.router = router; this.router = router;
} }
@ -31,8 +26,8 @@ public class Login implements Response {
@Route(path = "^\\/login$", type = "POST") @Route(path = "^\\/login$", type = "POST")
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
if(user != null){ if (user != null) {
HttpUtil.responseHeaders(writer, 403,"Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *");
return; return;
} }
JSONObject informations = (JSONObject) HttpUtil.readJson(reader); JSONObject informations = (JSONObject) HttpUtil.readJson(reader);
@ -40,15 +35,14 @@ public class Login implements Response {
String pseudo = (String) informations.get("pseudo"); String pseudo = (String) informations.get("pseudo");
String password = (String) informations.get("passwd"); String password = (String) informations.get("passwd");
int id; int id;
if ((id = databaseRepo.login(pseudo, password)) >= 0){ if ((id = databaseRepo.login(pseudo, password)) >= 0) {
HttpUtil.responseHeaders(writer, 200, HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *",
"Access-Control-Allow-Origin: *",
"Access-Control-Expose-Headers: Authorization", "Access-Control-Expose-Headers: Authorization",
"Authorization: Bearer "+this.router.createAuthUser(id)); "Authorization: Bearer " + this.router.createAuthUser(id));
return;
} }
} else {
HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *");
} }
HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *");
} }
} }

View file

@ -22,30 +22,33 @@ public class PlayerDetails implements Response {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
} }
@Route(path = "^\\/player\\/?(.+)?$") @Route(path = "^\\/player\\/?(.+)?$", needLogin = true)
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
Player player; Player player;
if (matcher.group(1) != null){ if (matcher.group(1) != null) {
player = databaseRepo.getPlayerDetails(matcher.group(1)); player = databaseRepo.getPlayerDetails(matcher.group(1));
} else { } else {
player = databaseRepo.getPlayerDetails(user.getId()); player = databaseRepo.getPlayerDetails(user.getId());
} }
JSONObject playerJSON = new JSONObject(); JSONObject playerJSON = new JSONObject();
if (player != null) { if (player != null) {
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *");
playerJSON.put("pseudo", player.getPseudo()); playerJSON.put("pseudo", player.getPseudo());
playerJSON.put("email", player.getEmail()); playerJSON.put("email", player.getEmail());
playerJSON.put("firstname", player.getFirstname()); playerJSON.put("firstname", player.getFirstname());
playerJSON.put("lastname", player.getLastname()); playerJSON.put("lastname", player.getLastname());
playerJSON.put("description", player.getDescription()); 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("rank", player.getRank());
playerJSON.put("score", player.getTotalScore()); playerJSON.put("score", player.getTotalScore());
playerJSON.put("completions", player.getTotalCompletion()); playerJSON.put("completions", player.getTotalCompletion());
playerJSON.put("tries", player.getTotalTries()); playerJSON.put("tries", player.getTotalTries());
if (player.getBadges() != null) playerJSON.put("badges", player.getJsonBadges()); if (player.getBadges() != null)
if(player.getAvatar() != null) playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar())); 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("\\", "")); writer.write(playerJSON.toJSONString().replace("\\", ""));
} else { } else {
HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *");

View file

@ -1,11 +1,7 @@
package be.jeffcheasey88.peeratcode.routes; package be.jeffcheasey88.peeratcode.routes;
import java.nio.charset.Charset;
import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jose4j.json.internal.json_simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.framework.HttpReader; import be.jeffcheasey88.peeratcode.framework.HttpReader;
@ -25,20 +21,25 @@ public class PuzzleElement implements Response {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
} }
@Route(path = "^\\/puzzle\\/([0-9]+)$") @Route(path = "^\\/puzzle\\/([0-9]+)$", needLogin = true)
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { 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)); Puzzle puzzle = databaseRepo.getPuzzle(extractId(matcher));
if (puzzle != null) { if (puzzle != null) {
JSONObject puzzleJSON = new JSONObject(); JSONObject puzzleJSON = new JSONObject();
puzzleJSON.put("id", puzzle.getId()); puzzleJSON.put("id", puzzle.getId());
puzzleJSON.put("name", puzzle.getName()); puzzleJSON.put("name", puzzle.getName());
puzzleJSON.put("content", puzzle.getContent()); puzzleJSON.put("content", puzzle.getContent());
if (puzzle.getTags() != null) puzzleJSON.put("tags", puzzle.getJsonTags()); if (puzzle.getTags() != null)
if (puzzle.getDepend() > 0) puzzleJSON.put("depend", puzzle.getDepend()); 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()); writer.write(puzzleJSON.toJSONString());
} }
else {
HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *");
}
} }
private int extractId(Matcher matcher) { private int extractId(Matcher matcher) {

View file

@ -22,9 +22,11 @@ import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class PuzzleResponse implements Response { public class PuzzleResponse implements Response {
private final DatabaseRepository databaseRepo; private final DatabaseRepository databaseRepo;
private final String usersFilesPath;
public PuzzleResponse(DatabaseRepository databaseRepo) { public PuzzleResponse(DatabaseRepository databaseRepo, String initUsersFilesPath) {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
usersFilesPath = initUsersFilesPath;
} }
@Route(path = "^\\/puzzleResponse\\/([0-9]+)$", type = "POST", needLogin = true) @Route(path = "^\\/puzzleResponse\\/([0-9]+)$", type = "POST", needLogin = true)
@ -45,14 +47,15 @@ public class PuzzleResponse implements Response {
HttpUtil.responseHeaders(writer, 406, "Access-Control-Allow-Origin: *", "Content-Type: application/json"); HttpUtil.responseHeaders(writer, 406, "Access-Control-Allow-Origin: *", "Content-Type: application/json");
responseJSON.put("tries", completion.getTries()); responseJSON.put("tries", completion.getTries());
} else { } else {
HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *");
return; return;
} }
writer.write(responseJSON.toJSONString()); writer.write(responseJSON.toJSONString());
} }
private void saveSourceCode(ReceivedResponse received, Player player) throws IOException { 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()); Files.write(path, received.getSourceCode());
} }

View file

@ -4,7 +4,6 @@ import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
@ -15,24 +14,25 @@ import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route; import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.Router; import be.jeffcheasey88.peeratcode.framework.Router;
import be.jeffcheasey88.peeratcode.framework.User; import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Player;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class Register implements Response { public class Register implements Response {
private DatabaseRepository databaseRepo; private DatabaseRepository databaseRepo;
private Router router; private Router router;
private String usersFilesPath;
public Register(DatabaseRepository databaseRepo, Router router) { public Register(DatabaseRepository databaseRepo, Router router, String initUsersFilesPath) {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
this.router = router; this.router = router;
usersFilesPath = initUsersFilesPath;
} }
@Route(path = "^\\/register$", type = "POST") @Route(path = "^\\/register$", type = "POST")
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
if(user != null){ if (user != null) {
HttpUtil.responseHeaders(writer, 403,"Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *");
return; return;
} }
JSONObject informations = (JSONObject) HttpUtil.readJson(reader); JSONObject informations = (JSONObject) HttpUtil.readJson(reader);
@ -60,27 +60,28 @@ public class Register implements Response {
int id; int id;
if ((id = databaseRepo.register(pseudo, email, password, firstname, lastname, description, group, if ((id = databaseRepo.register(pseudo, email, password, firstname, lastname, description, group,
avatar)) >= 0) { avatar)) >= 0) {
HttpUtil.responseHeaders(writer, 200, HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *",
"Access-Control-Allow-Origin: *",
"Access-Control-Expose-Headers: Authorization", "Access-Control-Expose-Headers: Authorization",
"Authorization: Bearer " + this.router.createAuthUser(id)); "Authorization: Bearer " + this.router.createAuthUser(id));
createFolderToSaveSourceCode(pseudo); createFolderToSaveSourceCode(pseudo);
return; return;
} }
} else { } else {
HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 400, "Access-Control-Allow-Origin: *");
JSONObject error = new JSONObject(); JSONObject error = new JSONObject();
error.put("username_valid", pseudoAvailable); error.put("username_valid", pseudoAvailable);
error.put("email_valid", emailAvailable); error.put("email_valid", emailAvailable);
writer.write(error.toJSONString()); writer.write(error.toJSONString());
return; 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 { 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)));
} }
} }

View file

@ -10,11 +10,11 @@ import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User; import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class Result implements Response{ public class Result implements Response {
private DatabaseRepository repo; private DatabaseRepository repo;
public Result(DatabaseRepository repo){ public Result(DatabaseRepository repo) {
this.repo = repo; this.repo = repo;
} }
@ -24,11 +24,11 @@ public class Result implements Response{
int puzzle = Integer.parseInt(matcher.group(1)); int puzzle = Integer.parseInt(matcher.group(1));
int score = this.repo.getScore(user.getId(), puzzle); int score = this.repo.getScore(user.getId(), puzzle);
if(score < 0) { if (score < 0) {
HttpUtil.responseHeaders(writer, 425, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 425, "Access-Control-Allow-Origin: *");
}else{ } else {
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *");
writer.write(score+""); writer.write(score + "");
} }
} }

View file

@ -13,11 +13,11 @@ import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Group; import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class CreateGroup implements Response{ public class CreateGroup implements Response {
private DatabaseRepository repo; private DatabaseRepository repo;
public CreateGroup(DatabaseRepository repo){ public CreateGroup(DatabaseRepository repo) {
this.repo = repo; this.repo = repo;
} }
@ -26,9 +26,9 @@ public class CreateGroup implements Response{
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
HttpUtil.skipHeaders(reader); 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: *"); HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *");
}else{ } else {
HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *");
} }
} }

View file

@ -13,11 +13,11 @@ import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Group; import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class GroupList implements Response{ public class GroupList implements Response {
private DatabaseRepository repo; private DatabaseRepository repo;
public GroupList(DatabaseRepository repo){ public GroupList(DatabaseRepository repo) {
this.repo = repo; this.repo = repo;
} }
@ -26,7 +26,8 @@ public class GroupList implements Response{
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *");
JSONArray result = new JSONArray(); 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()); writer.write(result.toJSONString());
} }