Moved Framework
This commit is contained in:
parent
6a0e320ff6
commit
f4dd642b78
15 changed files with 23 additions and 787 deletions
|
@ -3,11 +3,7 @@
|
|||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="test"/>
|
||||
<classpathentry exported="true" kind="lib" path="json-simple-1.1.1.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="mysql-connector-java-8.0.28.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="password4j-1.6.3.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="slf4j-api-2.0.6.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="jose4j-0.9.3.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
|
||||
<classpathentry kind="src" path=".apt_generated">
|
||||
<attributes>
|
||||
|
@ -16,5 +12,6 @@
|
|||
</classpathentry>
|
||||
<classpathentry kind="lib" path="Treasure.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="JDA-5.0.0-beta.8-withDependencies.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="C:/Users/jeffc/eclipse-workspace/peer-at-code-backend/PeerAtCodeFramework.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
BIN
.generated/be/jeffcheasey88/peeratcode/model/Badge.class
Normal file
BIN
.generated/be/jeffcheasey88/peeratcode/model/Badge.class
Normal file
Binary file not shown.
BIN
PeerAtCodeFramework.jar
Normal file
BIN
PeerAtCodeFramework.jar
Normal file
Binary file not shown.
|
@ -2,15 +2,8 @@ package be.jeffcheasey88.peeratcode;
|
|||
|
||||
import static be.jeffcheasey88.peeratcode.framework.RequestType.OPTIONS;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
|
||||
import be.jeffcheasey88.peeratcode.framework.Client;
|
||||
import be.jeffcheasey88.peeratcode.framework.HttpReader;
|
||||
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
|
||||
import be.jeffcheasey88.peeratcode.framework.Locker;
|
||||
|
@ -44,7 +37,8 @@ public class Main{
|
|||
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
|
||||
Router router = new Router(new DatabaseRepository(config), config.getTokenIssuer(),
|
||||
DatabaseRepository repo = new DatabaseRepository(config);
|
||||
Router router = new Router(config.getTokenIssuer(),
|
||||
config.getTokenExpiration());
|
||||
|
||||
router.setDefault((matcher, user, reader, writer) -> {
|
||||
|
@ -63,74 +57,40 @@ public class Main{
|
|||
}
|
||||
});
|
||||
|
||||
initRoutes(router, config);
|
||||
initRoutes(router, repo, config);
|
||||
|
||||
// RouteExtracter extracter = new RouteExtracter(router);
|
||||
// extracter.extract();
|
||||
|
||||
startWebServer(config, router);
|
||||
if(config.useSsl()) router.configureSSL(config.getSslKeystore(), config.getSslKeystorePasswd());
|
||||
router.listen(config.getTcpPort(), config.useSsl());
|
||||
}
|
||||
|
||||
private static void initRoutes(Router router, Configuration config){
|
||||
router.register(new ChapterElement(router.getDataBase()));
|
||||
router.register(new ChapterList(router.getDataBase()));
|
||||
router.register(new PuzzleElement(router.getDataBase()));
|
||||
router.register(new Register(router.getDataBase(), router, config.getUsersFiles()));
|
||||
router.register(new Login(router.getDataBase(), router));
|
||||
router.register(new Result(router.getDataBase()));
|
||||
router.register(new Leaderboard(router.getDataBase()));
|
||||
router.register(new PlayerDetails(router.getDataBase()));
|
||||
router.register(new BadgeDetails(router.getDataBase()));
|
||||
private static void initRoutes(Router router, DatabaseRepository repo, Configuration config){
|
||||
router.register(new ChapterElement(repo));
|
||||
router.register(new ChapterList(repo));
|
||||
router.register(new PuzzleElement(repo));
|
||||
router.register(new Register(repo, router, config.getUsersFiles()));
|
||||
router.register(new Login(repo, router));
|
||||
router.register(new Result(repo));
|
||||
router.register(new Leaderboard(repo));
|
||||
router.register(new PlayerDetails(repo));
|
||||
router.register(new BadgeDetails(repo));
|
||||
|
||||
Locker<Group> groupLock = new Locker<>();
|
||||
router.register(new GroupCreate(router.getDataBase(), groupLock, config.getGroupJoinMinutes()));
|
||||
router.register(new GroupCreate(repo, groupLock, config.getGroupJoinMinutes()));
|
||||
|
||||
DynamicLeaderboard dlb = new DynamicLeaderboard(router.getDataBase());
|
||||
DynamicLeaderboard dlb = new DynamicLeaderboard(repo);
|
||||
router.register(dlb);
|
||||
|
||||
Locker<Completion> leaderboard = dlb.getLocker();
|
||||
|
||||
router.register(new PuzzleResponse(router.getDataBase(), config.getUsersFiles(), leaderboard));
|
||||
router.register(new GroupList(router.getDataBase()));
|
||||
router.register(new GroupJoin(router.getDataBase(), config.getGroupJoinMinutes(), config.getGroupQuitMinutes(), leaderboard));
|
||||
router.register(new GroupQuit(router.getDataBase(), config.getGroupJoinMinutes(), leaderboard));
|
||||
router.register(new PuzzleResponse(repo, config.getUsersFiles(), leaderboard));
|
||||
router.register(new GroupList(repo));
|
||||
router.register(new GroupJoin(repo, config.getGroupJoinMinutes(), config.getGroupQuitMinutes(), leaderboard));
|
||||
router.register(new GroupQuit(repo, config.getGroupJoinMinutes(), leaderboard));
|
||||
|
||||
// Bot bot = new Bot(config, router.getDataBase(), groupLock);
|
||||
// Bot bot = new Bot(config, repo, groupLock);
|
||||
// bot.start();
|
||||
}
|
||||
|
||||
private static void startWebServer(Configuration config, Router router) throws IOException {
|
||||
if (config.useSsl()) { // Not needed with the use of a proxy
|
||||
SSLServerSocket server = null;
|
||||
try {
|
||||
System.setProperty("javax.net.ssl.keyStore", config.getSslKeystore());
|
||||
System.setProperty("javax.net.ssl.keyStorePassword", config.getSslKeystorePasswd());
|
||||
|
||||
SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
|
||||
server = (SSLServerSocket) ssf.createServerSocket(config.getTcpPort());
|
||||
|
||||
while (!server.isClosed()) {
|
||||
Socket socket = server.accept();
|
||||
Client client = new Client(socket, router);
|
||||
client.start();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (server != null) {
|
||||
server.close();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try (ServerSocket server = new ServerSocket(config.getTcpPort())) {
|
||||
while (!server.isClosed()) {
|
||||
Socket socket = server.accept();
|
||||
Client client = new Client(socket, router);
|
||||
client.start();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
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<String, String> 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> 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<String> readMultiPartData() throws Exception{
|
||||
List<String> 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;
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
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[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];
|
||||
}
|
||||
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
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<V>{
|
||||
|
||||
private Map<Key, BlockingQueue<V>> 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<V> get(Key key){
|
||||
return this.map.get(key);
|
||||
}
|
||||
|
||||
public void setValue(V value){
|
||||
for(Entry<Key, BlockingQueue<V>> entry : this.map.entrySet()){
|
||||
entry.getValue().add(value);
|
||||
this.unlock(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
public V getValue(Key key){
|
||||
BlockingQueue<V> queue = get(key);
|
||||
if(queue.isEmpty()) return null;
|
||||
return queue.poll();
|
||||
}
|
||||
|
||||
public void lock(Key key) throws InterruptedException{
|
||||
BlockingQueue<V> queue = get(key);
|
||||
if(queue.isEmpty()){
|
||||
synchronized(queue){
|
||||
queue.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unlock(Key key){
|
||||
BlockingQueue<V> queue = get(key);
|
||||
synchronized(queue){
|
||||
queue.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Key{ public Key(){} }
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package be.jeffcheasey88.peeratcode.framework;
|
||||
|
||||
public enum RequestType{
|
||||
|
||||
GET, POST, OPTIONS;
|
||||
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
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;
|
||||
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
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;
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
package be.jeffcheasey88.peeratcode.framework;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
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 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;
|
||||
|
||||
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
|
||||
|
||||
public class Router{
|
||||
|
||||
private Map<RequestType, Map<Response, Route>> responses;
|
||||
private Map<Response, Pattern> patterns;
|
||||
private Response noFileFound;
|
||||
private RsaJsonWebKey rsaJsonWebKey;
|
||||
private DatabaseRepository repo;
|
||||
private String token_issuer;
|
||||
private int token_expiration;
|
||||
|
||||
public Router(DatabaseRepository repo, String token_issuer, int token_expiration) throws Exception{
|
||||
this.repo = repo;
|
||||
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 DatabaseRepository getDataBase(){
|
||||
return this.repo;
|
||||
}
|
||||
|
||||
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<Response, Route> 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 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;
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
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();
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue