commit a1d35c31316c6cc0adef417aa654c1141aa7a65a
Author: jeffcheasey88 <66554203+jeffcheasey88@users.noreply.github.com>
Date: Wed Jul 5 14:34:25 2023 +0200
First Commit, FrameWork V1
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..77f334f
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..54ac269
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.settings/
+bin/
+.project
diff --git a/jose4j-0.9.3.jar b/jose4j-0.9.3.jar
new file mode 100644
index 0000000..e073555
Binary files /dev/null and b/jose4j-0.9.3.jar differ
diff --git a/json-simple-1.1.1.jar b/json-simple-1.1.1.jar
new file mode 100644
index 0000000..dfd5856
Binary files /dev/null and b/json-simple-1.1.1.jar differ
diff --git a/password4j-1.6.3.jar b/password4j-1.6.3.jar
new file mode 100644
index 0000000..4254563
Binary files /dev/null and b/password4j-1.6.3.jar differ
diff --git a/slf4j-api-2.0.6.jar b/slf4j-api-2.0.6.jar
new file mode 100644
index 0000000..a2cb802
Binary files /dev/null and b/slf4j-api-2.0.6.jar differ
diff --git a/src/be/jeffcheasey88/peeratcode/framework/Client.java b/src/be/jeffcheasey88/peeratcode/framework/Client.java
new file mode 100644
index 0000000..4c4da80
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/Client.java
@@ -0,0 +1,60 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+import java.net.Socket;
+import java.util.Arrays;
+
+import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
+import org.jose4j.jws.AlgorithmIdentifiers;
+import org.jose4j.jwt.JwtClaims;
+import org.jose4j.jwt.consumer.JwtConsumer;
+import org.jose4j.jwt.consumer.JwtConsumerBuilder;
+
+public class Client extends Thread{
+
+ private HttpReader reader;
+ private HttpWriter writer;
+ private Router router;
+
+ public Client(Socket socket, Router router) throws Exception{
+ this.reader = new HttpReader(socket);
+ this.writer = new HttpWriter(socket);
+ this.router = router;
+ }
+
+ @Override
+ public void run(){
+ try{
+ String[] headers = reader.readLine().split("\\s");
+ System.out.println(Arrays.toString(headers));
+ reader.readHeaders();
+
+ router.exec(RequestType.valueOf(headers[0]), headers[1], isLogin(reader), reader, writer);
+ writer.flush();
+ writer.close();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+
+ private User isLogin(HttpReader reader) throws Exception{
+ String auth = reader.getHeader("Authorization");
+ if(auth == null) return null;
+ auth = auth.substring(7);
+ try{
+ JwtConsumer jwtConsumer = new JwtConsumerBuilder()
+ .setRequireExpirationTime()
+ .setAllowedClockSkewInSeconds(30)
+ .setExpectedIssuer(this.router.getTokenIssuer())
+ .setVerificationKey(this.router.getWebKey().getKey())
+ .setJwsAlgorithmConstraints(ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256).build();
+
+ JwtClaims jwtClaims = jwtConsumer.processToClaims(auth);
+ return new User(jwtClaims);
+ }catch(Exception e){
+ writer.response(401, "Access-Control-Allow-Origin: *");
+ writer.flush();
+ writer.close();
+ throw e;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/peeratcode/framework/HttpReader.java b/src/be/jeffcheasey88/peeratcode/framework/HttpReader.java
new file mode 100644
index 0000000..7239e0e
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/HttpReader.java
@@ -0,0 +1,138 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.json.simple.parser.JSONParser;
+
+public class HttpReader{
+
+ private static Pattern HEADER_PATTERN = Pattern.compile("^([^:]*):\\s+(.*)$");
+
+ private Socket socket;
+ private InputStream in;
+ private BufferedReader reader;
+
+ private Map headers;
+
+ public HttpReader(Socket socket) throws Exception{
+ this.socket = socket;
+ this.in = socket.getInputStream();
+ this.reader = new BufferedReader(new InputStreamReader(in));
+ this.headers = new HashMap<>();
+ }
+
+ public HttpReader(HttpReader origin) throws Exception{
+ this.socket = origin.socket;
+ this.in = origin.in;
+ this.reader = origin.reader;
+ }
+
+ public boolean isClosed(){
+ return this.socket.isClosed();
+ }
+
+ public void readHeaders() throws Exception{
+ String line;
+ while(((line = reader.readLine()) != null) && (line.length() > 0)){
+ Matcher matcher = HEADER_PATTERN.matcher(line);
+ matcher.matches();
+ this.headers.put(matcher.group(1).toLowerCase(), matcher.group(2));
+ }
+ }
+
+ public String getHeader(String key){
+ return this.headers.get(key.toLowerCase());
+ }
+
+ public int read(byte[] buffer) throws IOException{
+ return this.in.read(buffer);
+ }
+
+ public int read(char[] buffer) throws IOException{
+ return this.reader.read(buffer);
+ }
+
+ public String readLine() throws IOException{
+ return this.reader.readLine();
+ }
+
+ public boolean ready() throws IOException{
+ return this.reader.ready();
+ }
+
+ public int readInt() throws Exception{
+ int result = 0;
+ result += this.in.read() << 24;
+ result += this.in.read() << 16;
+ result += this.in.read() << 8;
+ result += this.in.read();
+ return result;
+ }
+
+ public T readJson() throws Exception{
+ String line = "";
+ while (ready()){
+ char[] c = new char[1];
+ read(c);
+ line += c[0];
+ if (c[0] == '}'){
+ Object parse;
+ try {
+ parse = new JSONParser().parse(line);
+ if (parse != null)
+ return (T) parse;
+ }catch(Exception e){}
+ }
+ }
+ return null;
+ }
+
+ /*
+ *
+------WebKitFormBoundaryNUjiLBAMuX2dhxU7
+Content-Disposition: form-data; name="answer"
+
+12
+------WebKitFormBoundaryNUjiLBAMuX2dhxU7
+Content-Disposition: form-data; name="filename"
+
+webpack.js
+------WebKitFormBoundaryNUjiLBAMuX2dhxU7
+Content-Disposition: form-data; name="code_file"; filename="webpack.js"
+Content-Type: text/javascript
+
+
+------WebKitFormBoundaryNUjiLBAMuX2dhxU7--
+ *
+ */
+
+ public List readMultiPartData() throws Exception{
+ List list = new ArrayList<>();
+ String boundary = getHeader("content-type");
+ if(boundary == null) return list;
+ boundary = boundary.split(";")[1].split("=")[1];
+ readLine();
+
+ while(ready()){
+ String line;
+ while (((line = readLine()) != null) && (line.length() > 0));
+ String buffer = "";
+ while (((line = readLine()) != null) && (!line.startsWith("--"+boundary))){
+ buffer += line;
+ }
+ list.add(buffer);
+ }
+
+ return list;
+ }
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/peeratcode/framework/HttpWriter.java b/src/be/jeffcheasey88/peeratcode/framework/HttpWriter.java
new file mode 100644
index 0000000..24356df
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/HttpWriter.java
@@ -0,0 +1,103 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+
+public class HttpWriter{
+
+ private OutputStream out;
+ private BufferedWriter writer;
+
+ public HttpWriter(Socket socket) throws Exception{
+ this.out = socket.getOutputStream();
+ this.writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
+ }
+
+ public HttpWriter(HttpWriter origin) throws Exception{
+ this.out = origin.out;
+ this.writer = origin.writer;
+ }
+
+ public void write(byte[] buffer) throws IOException{
+ this.out.write(buffer);
+ this.out.flush();
+ }
+
+ public void write(String message) throws IOException{
+ this.writer.write(message);
+ }
+
+ public void flush() throws IOException{
+ this.writer.flush();
+ }
+
+ public void close() throws IOException{
+ this.writer.close();
+ }
+
+ public void response(int code, String... headers) throws Exception{
+ write("HTTP/1.1 "+code+codeMessage(code)+"\n");
+ for(String header : headers) write(header+"\n");
+ write("\n");
+ flush();
+ StackTraceElement[] e = Thread.currentThread().getStackTrace();
+ System.out.println(e[2]+" -> response "+code);
+ }
+
+ private static String[] HEIGHTBITS = new String[7];
+ private static String[] NINEBITS = new String[206];
+
+ static {
+ HEIGHTBITS[0] = " OK";
+ HEIGHTBITS[1] = " Created";
+ HEIGHTBITS[2] = " Accepted";
+ HEIGHTBITS[3] = " Non-Authoritative Information";
+ HEIGHTBITS[4] = " No Content";
+ HEIGHTBITS[5] = " Reset Content";
+ HEIGHTBITS[6] = " Partial Content";
+
+ NINEBITS[0] = " Multiple Choices";
+ NINEBITS[1] = " Moved Permanently";
+ NINEBITS[2] = " Temporary Redirect";
+ NINEBITS[3] = " See Other";
+ NINEBITS[4] = " Not Modified";
+ NINEBITS[5] = " Use Proxy";
+
+ NINEBITS[100] = " Bad Request";
+ NINEBITS[101] = " Unauthorized";
+ NINEBITS[102] = " Payment Required";
+ NINEBITS[103] = " Forbidden";
+ NINEBITS[104] = " Not Found";
+ NINEBITS[105] = " Method Not Allowed";
+ NINEBITS[106] = " Not Acceptable";
+ NINEBITS[107] = " Proxy Authentication Required";
+ NINEBITS[108] = " Request Time-Out";
+ NINEBITS[109] = " Conflict";
+ NINEBITS[110] = " Gone";
+ NINEBITS[111] = " Length Required";
+ NINEBITS[112] = " Precondition Failed";
+ NINEBITS[113] = " Request Entity Too Large";
+ NINEBITS[114] = " Request-URI Too Large";
+ NINEBITS[115] = " Unsupported Media Type";
+ NINEBITS[123] = " Locked";
+ NINEBITS[125] = " Too Early";
+
+ NINEBITS[200] = " Internal Server Error";
+ NINEBITS[201] = " Not Implemented";
+ NINEBITS[202] = " Bad Gateway";
+ NINEBITS[203] = " Service Unavailable";
+ NINEBITS[204] = " Gateway Timeout";
+ NINEBITS[205] = " HTTP Version Not Supported";
+ }
+
+ private static String codeMessage(int code){
+ if(code == 100) return " Continue";
+ if(code >> 8 == 0) return HEIGHTBITS[code-200];
+ return NINEBITS[code-300];
+ }
+
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/peeratcode/framework/Locker.java b/src/be/jeffcheasey88/peeratcode/framework/Locker.java
new file mode 100644
index 0000000..8dc02be
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/Locker.java
@@ -0,0 +1,59 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class Locker{
+
+ private Map> map;
+
+ public Locker(){
+ this.map = new HashMap<>();
+ }
+
+ public void init(Key key){
+ this.map.put(key, new LinkedBlockingQueue<>());
+ }
+
+ public void remove(Key key){
+ this.map.remove(key);
+ }
+
+ private BlockingQueue get(Key key){
+ return this.map.get(key);
+ }
+
+ public void setValue(V value){
+ for(Entry> entry : this.map.entrySet()){
+ entry.getValue().add(value);
+ this.unlock(entry.getKey());
+ }
+ }
+
+ public V getValue(Key key){
+ BlockingQueue queue = get(key);
+ if(queue.isEmpty()) return null;
+ return queue.poll();
+ }
+
+ public void lock(Key key) throws InterruptedException{
+ BlockingQueue queue = get(key);
+ if(queue.isEmpty()){
+ synchronized(queue){
+ queue.wait();
+ }
+ }
+ }
+
+ public void unlock(Key key){
+ BlockingQueue queue = get(key);
+ synchronized(queue){
+ queue.notify();
+ }
+ }
+
+ public static class Key{ public Key(){} }
+}
diff --git a/src/be/jeffcheasey88/peeratcode/framework/RequestType.java b/src/be/jeffcheasey88/peeratcode/framework/RequestType.java
new file mode 100644
index 0000000..f843ef6
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/RequestType.java
@@ -0,0 +1,7 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+public enum RequestType{
+
+ GET, POST, OPTIONS;
+
+}
diff --git a/src/be/jeffcheasey88/peeratcode/framework/Response.java b/src/be/jeffcheasey88/peeratcode/framework/Response.java
new file mode 100644
index 0000000..392c6f3
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/Response.java
@@ -0,0 +1,9 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+import java.util.regex.Matcher;
+
+public interface Response{
+
+ void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception;
+
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/peeratcode/framework/Route.java b/src/be/jeffcheasey88/peeratcode/framework/Route.java
new file mode 100644
index 0000000..47ede2e
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/Route.java
@@ -0,0 +1,19 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Route{
+
+ String path() default "^.*$";
+
+ RequestType type() default RequestType.GET;
+
+ boolean needLogin() default false;
+
+ boolean websocket() default false;
+}
diff --git a/src/be/jeffcheasey88/peeratcode/framework/Router.java b/src/be/jeffcheasey88/peeratcode/framework/Router.java
new file mode 100644
index 0000000..02e843e
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/Router.java
@@ -0,0 +1,212 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+import java.lang.reflect.Method;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.MessageDigest;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+
+import org.jose4j.jwk.RsaJsonWebKey;
+import org.jose4j.jwk.RsaJwkGenerator;
+import org.jose4j.jws.AlgorithmIdentifiers;
+import org.jose4j.jws.JsonWebSignature;
+import org.jose4j.jwt.JwtClaims;
+import org.jose4j.lang.JoseException;
+
+public class Router{
+
+ private Map> responses;
+ private Map patterns;
+ private Response noFileFound;
+ private RsaJsonWebKey rsaJsonWebKey;
+ private String token_issuer;
+ private int token_expiration;
+
+ public Router(String token_issuer, int token_expiration) throws Exception{
+ this.token_issuer = token_issuer;
+ this.token_expiration = token_expiration;
+ this.responses = new HashMap<>();
+ for(RequestType type : RequestType.values()) this.responses.put(type, new HashMap<>());
+ this.patterns = new HashMap<>();
+ this.rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
+ }
+
+ public void listen(int port, boolean ssl) throws Exception{
+ if (ssl) { // Not needed with the use of a proxy
+ SSLServerSocket server = null;
+ try {
+ SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+ server = (SSLServerSocket) ssf.createServerSocket(port);
+
+ while (!server.isClosed()) {
+ Socket socket = server.accept();
+ Client client = new Client(socket, this);
+ client.start();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (server != null) {
+ server.close();
+ }
+ }
+ } else {
+ try (ServerSocket server = new ServerSocket(port)) {
+ while (!server.isClosed()) {
+ Socket socket = server.accept();
+ Client client = new Client(socket, this);
+ client.start();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void register(Response response){
+ try{
+ Method method = response.getClass().getDeclaredMethod("exec",
+ Response.class.getDeclaredMethods()[0].getParameterTypes());
+ Route route = method.getAnnotation(Route.class);
+
+ this.responses.get(route.type()).put(response, route);
+ this.patterns.put(response, Pattern.compile(route.path()));
+ }catch(Exception e){
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public void setDefault(Response response){
+ this.noFileFound = response;
+ }
+
+ public void exec(RequestType type, String path, User user, HttpReader reader, HttpWriter writer) throws Exception{
+ if(type == null) return;
+ for(Entry routes : this.responses.get(type).entrySet()){
+ Matcher matcher = this.patterns.get(routes.getKey()).matcher(path);
+ if(matcher.matches()){
+ if(user == null && routes.getValue().needLogin()){
+ writer.response(401, "Access-Control-Allow-Origin: *");
+ return;
+ }
+ if(routes.getValue().websocket()){
+ switchToWebSocket(reader, writer);
+ reader = new WebSocketReader(reader);
+ writer = new WebSocketWriter(writer);
+ }
+ routes.getKey().exec(matcher, user, reader, writer);
+ return;
+ }
+ }
+ if(noFileFound != null) noFileFound.exec(null, user, reader, writer);
+ }
+
+ public RsaJsonWebKey getWebKey(){
+ return this.rsaJsonWebKey;
+ }
+
+ public String getTokenIssuer(){
+ return this.token_issuer;
+ }
+
+ public void configureSSL(String keyStore, String keyStorePassword){
+ System.setProperty("javax.net.ssl.keyStore", keyStore);
+ System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword);
+ }
+
+ public String createAuthUser(int id) throws JoseException{
+ JwtClaims claims = new JwtClaims();
+ claims.setIssuer(token_issuer); // who creates the token and signs it
+ claims.setExpirationTimeMinutesInTheFuture(token_expiration);
+ claims.setGeneratedJwtId(); // a unique identifier for the token
+ claims.setIssuedAtToNow(); // when the token was issued/created (now)
+ claims.setNotBeforeMinutesInThePast(2); // time before which the token is not yet valid (2 minutes ago)
+
+ claims.setClaim("id", id);
+
+ JsonWebSignature jws = new JsonWebSignature();
+ jws.setPayload(claims.toJson());
+ jws.setKey(rsaJsonWebKey.getPrivateKey());
+ jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId());
+ jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
+ return jws.getCompactSerialization();
+ }
+
+ private void switchToWebSocket(HttpReader reader, HttpWriter writer) throws Exception{
+ String key = reader.getHeader("Sec-WebSocket-Key");
+ if (key == null) throw new IllegalArgumentException();
+
+ writer.write("HTTP/1.1 101 Switching Protocols\n");
+ writer.write("Connection: Upgrade\n");
+ writer.write("Upgrade: websocket\n");
+ writer.write("Sec-WebSocket-Accept: " + printBase64Binary(MessageDigest.getInstance("SHA-1")
+ .digest((key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes("UTF-8"))) + "\n");
+ writer.write("\n");
+ writer.flush();
+ }
+
+
+ // From javax.xml.bind.DatatypeConverter
+ private String printBase64Binary(byte[] array){
+ char[] arrayOfChar = new char[(array.length + 2) / 3 * 4];
+ int i = _printBase64Binary(array, 0, array.length, arrayOfChar, 0);
+ assert i == arrayOfChar.length;
+ return new String(arrayOfChar);
+ }
+
+ private int _printBase64Binary(byte[] paramArrayOfbyte, int paramInt1, int paramInt2,
+ char[] paramArrayOfchar, int paramInt3){
+ int i = paramInt2;
+ int j;
+ for (j = paramInt1; i >= 3; j += 3){
+ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
+ paramArrayOfchar[paramInt3++] = encode(
+ (paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF);
+ paramArrayOfchar[paramInt3++] = encode(
+ (paramArrayOfbyte[j + 1] & 0xF) << 2 | paramArrayOfbyte[j + 2] >> 6 & 0x3);
+ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j + 2] & 0x3F);
+ i -= 3;
+ }
+ if (i == 1){
+ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
+ paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4);
+ paramArrayOfchar[paramInt3++] = '=';
+ paramArrayOfchar[paramInt3++] = '=';
+ }
+ if (i == 2){
+ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
+ paramArrayOfchar[paramInt3++] = encode(
+ (paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF);
+ paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2);
+ paramArrayOfchar[paramInt3++] = '=';
+ }
+ return paramInt3;
+ }
+
+ private char encode(int paramInt){
+ return encodeMap[paramInt & 0x3F];
+ }
+
+ private static final char[] encodeMap = initEncodeMap();
+
+ private static char[] initEncodeMap(){
+ char[] arrayOfChar = new char[64];
+ byte b;
+ for (b = 0; b < 26; b++)
+ arrayOfChar[b] = (char) (65 + b);
+ for (b = 26; b < 52; b++)
+ arrayOfChar[b] = (char) (97 + b - 26);
+ for (b = 52; b < 62; b++)
+ arrayOfChar[b] = (char) (48 + b - 52);
+ arrayOfChar[62] = '+';
+ arrayOfChar[63] = '/';
+ return arrayOfChar;
+ }
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/peeratcode/framework/User.java b/src/be/jeffcheasey88/peeratcode/framework/User.java
new file mode 100644
index 0000000..f2e107c
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/User.java
@@ -0,0 +1,27 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+import org.jose4j.jwt.JwtClaims;
+
+import be.jeffcheasey88.peeratcode.framework.Locker.Key;
+
+public class User{
+
+ private int id;
+ private Key key;
+
+ public User(JwtClaims jwtClaims){
+ this.id = ((Long) jwtClaims.getClaimValue("id")).intValue();
+ }
+
+ public void setKey(Key key){
+ this.key = key;
+ }
+
+ public Key getKey(){
+ return this.key;
+ }
+
+ public int getId(){
+ return this.id;
+ }
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/peeratcode/framework/WebSocketReader.java b/src/be/jeffcheasey88/peeratcode/framework/WebSocketReader.java
new file mode 100644
index 0000000..7007402
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/WebSocketReader.java
@@ -0,0 +1,62 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+import java.io.IOException;
+
+public class WebSocketReader extends HttpReader{
+
+ public WebSocketReader(HttpReader origin) throws Exception{
+ super(origin);
+ }
+
+
+
+ @Override
+ public String readLine() throws IOException{
+ //read websocket found on StackOverFlow
+ int buffLenth = 1024;
+ int len = 0;
+ byte[] b = new byte[buffLenth];
+ // rawIn is a Socket.getInputStream();
+ while (true){
+ len = read(b);
+ if (len != -1){
+ byte rLength = 0;
+ int rMaskIndex = 2;
+ int rDataStart = 0;
+ // b[0] is always text in my case so no need to check;
+ byte data = b[1];
+ byte op = (byte) 127;
+ rLength = (byte) (data & op);
+
+ if (rLength == (byte) 126)
+ rMaskIndex = 4;
+ if (rLength == (byte) 127)
+ rMaskIndex = 10;
+
+ byte[] masks = new byte[4];
+
+ int j = 0;
+ int i = 0;
+ for (i = rMaskIndex; i < (rMaskIndex + 4); i++){
+ masks[j] = b[i];
+ j++;
+ }
+
+ rDataStart = rMaskIndex + 4;
+
+ int messLen = len - rDataStart;
+
+ byte[] message = new byte[messLen];
+
+ for (i = rDataStart, j = 0; i < len; i++, j++){
+ message[j] = (byte) (b[i] ^ masks[j % 4]);
+ }
+
+ return new String(message);
+
+ } else
+ break;
+ }
+ return null;
+ }
+}
diff --git a/src/be/jeffcheasey88/peeratcode/framework/WebSocketWriter.java b/src/be/jeffcheasey88/peeratcode/framework/WebSocketWriter.java
new file mode 100644
index 0000000..ac093f0
--- /dev/null
+++ b/src/be/jeffcheasey88/peeratcode/framework/WebSocketWriter.java
@@ -0,0 +1,61 @@
+package be.jeffcheasey88.peeratcode.framework;
+
+import java.io.IOException;
+
+public class WebSocketWriter extends HttpWriter{
+
+ public WebSocketWriter(HttpWriter origin) throws Exception{
+ super(origin);
+ }
+
+ @Override
+ public void write(String message) throws IOException{
+ //write websocket found on StackOverFlow
+ byte[] rawData = message.getBytes();
+
+ int frameCount = 0;
+ byte[] frame = new byte[10];
+
+ frame[0] = (byte) 129;
+
+ if (rawData.length <= 125){
+ frame[1] = (byte) rawData.length;
+ frameCount = 2;
+ } else if (rawData.length >= 126 && rawData.length <= 65535){
+ frame[1] = (byte) 126;
+ int len = rawData.length;
+ frame[2] = (byte) ((len >> 8) & (byte) 255);
+ frame[3] = (byte) (len & (byte) 255);
+ frameCount = 4;
+ } else {
+ frame[1] = (byte) 127;
+ int len = rawData.length;
+ frame[2] = (byte) ((len >> 56) & (byte) 255);
+ frame[3] = (byte) ((len >> 48) & (byte) 255);
+ frame[4] = (byte) ((len >> 40) & (byte) 255);
+ frame[5] = (byte) ((len >> 32) & (byte) 255);
+ frame[6] = (byte) ((len >> 24) & (byte) 255);
+ frame[7] = (byte) ((len >> 16) & (byte) 255);
+ frame[8] = (byte) ((len >> 8) & (byte) 255);
+ frame[9] = (byte) (len & (byte) 255);
+ frameCount = 10;
+ }
+
+ int bLength = frameCount + rawData.length;
+
+ byte[] reply = new byte[bLength];
+
+ int bLim = 0;
+ for (int i = 0; i < frameCount; i++){
+ reply[bLim] = frame[i];
+ bLim++;
+ }
+ for (int i = 0; i < rawData.length; i++){
+ reply[bLim] = rawData[i];
+ bLim++;
+ }
+
+ write(reply);
+ flush();
+ }
+}