package dev.peerat.framework; import java.lang.reflect.Method; import java.net.ServerSocket; import java.net.Socket; import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Pattern; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; 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.jwt.consumer.JwtConsumer; import org.jose4j.jwt.consumer.JwtConsumerBuilder; import org.jose4j.lang.JoseException; public class Router{ public static void main(String[] args) { } private Locker logger; private RouteMapper[] mappers; private Response noFileFound; private RsaJsonWebKey rsaJsonWebKey; private JwtConsumer jwtConsumer; private Consumer claims; private Function userCreator; private String[][] headers; private ServerSocket serverSocket; public Router() throws Exception{ this.logger = new Locker<>(); int types = RequestType.values().length; this.mappers = new RouteMapper[types]; for(RequestType type : RequestType.values()) this.mappers[type.ordinal()] = new RouteMapper(); this.rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048); this.headers = new String[types][0]; } public Router configureJwt(Consumer consumer, Consumer claims, Function userCreator){ JwtConsumerBuilder builder = new JwtConsumerBuilder() .setRequireExpirationTime() .setAllowedClockSkewInSeconds(30) .setVerificationKey(rsaJsonWebKey.getKey()) .setJwsAlgorithmConstraints(ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256); consumer.accept(builder); this.jwtConsumer = builder.build(); this.claims = claims; this.userCreator = userCreator; return this; } public Router addDefaultHeaders(RequestType type, String... headers){ String[] origin = this.headers[type.ordinal()]; String[] copy = new String[origin.length+headers.length]; System.arraycopy(origin, 0, copy, 0, origin.length); System.arraycopy(headers, 0, copy, origin.length, headers.length); this.headers[type.ordinal()] = copy; return this; } public Router register(Response response){ try{ Method method = response.getClass().getDeclaredMethod("exec", Response.class.getDeclaredMethods()[0].getParameterTypes()); Route route = method.getAnnotation(Route.class); this.mappers[route.type().ordinal()].register(response, route, Pattern.compile(route.path())); }catch(Exception e){ throw new IllegalArgumentException(e); } return this; } public Router setDefault(Response response){ this.noFileFound = response; return this; } public Router activeReOrdering(){ for(RouteMapper mapper : this.mappers) mapper.activeReOrdering(); return this; } String[] getDefaultHeaders(RequestType type){ return this.headers[type.ordinal()]; } void exec(Context context, HttpReader reader, HttpWriter writer) throws Exception{ if(this.mappers[context.getType().ordinal()].exec(context, reader, writer)) return; if(noFileFound != null) noFileFound.exec(null, context, reader, writer); } public Router configureSSL(String keyStore, String keyStorePassword){ System.setProperty("javax.net.ssl.keyStore", keyStore); System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword); return this; } public U getUser(String token) throws Exception{ return this.userCreator.apply(this.jwtConsumer.processToClaims(token)); } public String createAuthUser(U user) throws JoseException{ JwtClaims claims = new JwtClaims(); 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) this.claims.accept(claims); user.write(claims); 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(); } public Locker getLogger(){ return this.logger; } public void listen(int port, boolean ssl) throws Exception{ if (ssl) { // Not needed with the use of a proxy try { SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); serverSocket = (SSLServerSocket) ssf.createServerSocket(port); while (!serverSocket.isClosed()) { Socket socket = serverSocket.accept(); Client client = new Client<>(socket, this); client.start(); } } catch (Exception e) { e.printStackTrace(); } finally { stop(); } } else { try{ serverSocket = new ServerSocket(port); while (!serverSocket.isClosed()) { Socket socket = serverSocket.accept(); Client client = new Client<>(socket, this); client.start(); } } catch (Exception e) { e.printStackTrace(); } finally { stop(); } } } public void stop(){ if(serverSocket == null) return; try { serverSocket.close(); serverSocket = null; }catch(Exception e){ e.printStackTrace(); } } }