mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-04-19 18:46:43 +00:00
Websocket auth up and running
This commit is contained in:
parent
dc034d1437
commit
113aa50d87
@ -6,6 +6,7 @@ import net.simon987.server.web.AlertMessage;
|
|||||||
import net.simon987.server.web.AlertType;
|
import net.simon987.server.web.AlertType;
|
||||||
import net.simon987.server.websocket.SocketServer;
|
import net.simon987.server.websocket.SocketServer;
|
||||||
import org.apache.velocity.app.VelocityEngine;
|
import org.apache.velocity.app.VelocityEngine;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
import spark.ModelAndView;
|
import spark.ModelAndView;
|
||||||
import spark.Spark;
|
import spark.Spark;
|
||||||
import spark.template.velocity.VelocityTemplateEngine;
|
import spark.template.velocity.VelocityTemplateEngine;
|
||||||
@ -153,11 +154,52 @@ public class Main {
|
|||||||
request.session().attribute("messages", messages);
|
request.session().attribute("messages", messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
response.redirect("/account");
|
response.redirect("/account");
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Spark.get("/server_info", (request, response) -> {
|
||||||
|
|
||||||
|
//TODO put that in a constructor somewhere
|
||||||
|
String address;
|
||||||
|
if (GameServer.INSTANCE.getConfig().getInt("use_ssl") == 0) {
|
||||||
|
address = "ws://" +
|
||||||
|
GameServer.INSTANCE.getConfig().getString("mar_address") + ":" +
|
||||||
|
GameServer.INSTANCE.getConfig().getString("mar_port") + "/socket";
|
||||||
|
} else {
|
||||||
|
address = "wss://" +
|
||||||
|
GameServer.INSTANCE.getConfig().getString("mar_address") + ":" +
|
||||||
|
GameServer.INSTANCE.getConfig().getString("mar_port") + "/socket";
|
||||||
|
}
|
||||||
|
String serverName = GameServer.INSTANCE.getConfig().getString("server_name");
|
||||||
|
int tickLength = GameServer.INSTANCE.getConfig().getInt("tick_length");
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
|
||||||
|
String username = request.session().attribute("username");
|
||||||
|
|
||||||
|
if (username != null) {
|
||||||
|
String token = GameServer.INSTANCE.getUserManager().generateAndGetToken(username);
|
||||||
|
|
||||||
|
json.put("token", token);
|
||||||
|
json.put("username", username);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
json.put("token", "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
|
||||||
|
json.put("username", "guest");
|
||||||
|
}
|
||||||
|
|
||||||
|
json.put("address", address);
|
||||||
|
json.put("serverName", serverName);
|
||||||
|
json.put("tickLength", tickLength);
|
||||||
|
|
||||||
|
response.header("Content-Type", "application/json");
|
||||||
|
|
||||||
|
return json.toJSONString();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
Spark.after((request, response) -> response.header("Content-Encoding", "gzip"));
|
Spark.after((request, response) -> response.header("Content-Encoding", "gzip"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,10 +23,10 @@ public class RandomStringGenerator {
|
|||||||
return new String(buf);
|
return new String(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String UPPER_ALPHA_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
static final String UPPER_ALPHA_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
public static final String LOWER_ALPHA_CHARSET = UPPER_ALPHA_CHARSET.toLowerCase(Locale.ROOT);
|
static final String LOWER_ALPHA_CHARSET = UPPER_ALPHA_CHARSET.toLowerCase(Locale.ROOT);
|
||||||
public static final String NUMERIC_CHARSET = "0123456789";
|
static final String NUMERIC_CHARSET = "0123456789";
|
||||||
public static final String ALPHANUMERIC_CHARSET = UPPER_ALPHA_CHARSET + LOWER_ALPHA_CHARSET + NUMERIC_CHARSET;
|
static final String ALPHANUMERIC_CHARSET = UPPER_ALPHA_CHARSET + LOWER_ALPHA_CHARSET + NUMERIC_CHARSET;
|
||||||
|
|
||||||
private final Random random;
|
private final Random random;
|
||||||
|
|
||||||
|
@ -19,12 +19,14 @@ public class User implements MongoSerialisable {
|
|||||||
|
|
||||||
private String userCode;
|
private String userCode;
|
||||||
private String password;
|
private String password;
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
private CPU cpu;
|
private CPU cpu;
|
||||||
|
|
||||||
private ControllableUnit controlledUnit;
|
private ControllableUnit controlledUnit;
|
||||||
|
|
||||||
private boolean guest;
|
private boolean guest = false;
|
||||||
|
private boolean moderator = false;
|
||||||
|
|
||||||
public User() throws CancelledException {
|
public User() throws CancelledException {
|
||||||
GameEvent event = new UserCreationEvent(this);
|
GameEvent event = new UserCreationEvent(this);
|
||||||
@ -33,7 +35,6 @@ public class User implements MongoSerialisable {
|
|||||||
throw new CancelledException();
|
throw new CancelledException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public User(ControllableUnit unit) {
|
public User(ControllableUnit unit) {
|
||||||
@ -51,6 +52,7 @@ public class User implements MongoSerialisable {
|
|||||||
dbObject.put("controlledUnit", controlledUnit.getObjectId());
|
dbObject.put("controlledUnit", controlledUnit.getObjectId());
|
||||||
dbObject.put("cpu", cpu.mongoSerialise());
|
dbObject.put("cpu", cpu.mongoSerialise());
|
||||||
dbObject.put("password", password);
|
dbObject.put("password", password);
|
||||||
|
dbObject.put("moderator", moderator);
|
||||||
|
|
||||||
return dbObject;
|
return dbObject;
|
||||||
|
|
||||||
@ -62,6 +64,7 @@ public class User implements MongoSerialisable {
|
|||||||
user.username = (String) obj.get("username");
|
user.username = (String) obj.get("username");
|
||||||
user.userCode = (String) obj.get("code");
|
user.userCode = (String) obj.get("code");
|
||||||
user.password = (String) obj.get("password");
|
user.password = (String) obj.get("password");
|
||||||
|
user.moderator = (boolean) obj.get("moderator");
|
||||||
|
|
||||||
user.getControlledUnit().setParent(user);
|
user.getControlledUnit().setParent(user);
|
||||||
|
|
||||||
@ -114,4 +117,20 @@ public class User implements MongoSerialisable {
|
|||||||
public void setPassword(String password) {
|
public void setPassword(String password) {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getAccessToken() {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccessToken(String accessToken) {
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isModerator() {
|
||||||
|
return moderator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModerator(boolean moderator) {
|
||||||
|
this.moderator = moderator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package net.simon987.server.user;
|
|||||||
import com.mongodb.*;
|
import com.mongodb.*;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.assembly.exception.CancelledException;
|
import net.simon987.server.assembly.exception.CancelledException;
|
||||||
|
import net.simon987.server.crypto.RandomStringGenerator;
|
||||||
|
import net.simon987.server.logging.LogManager;
|
||||||
import org.springframework.security.crypto.bcrypt.BCrypt;
|
import org.springframework.security.crypto.bcrypt.BCrypt;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -91,4 +93,42 @@ public class UserManager {
|
|||||||
|
|
||||||
userCollection.save(user.mongoSerialise()); //Save new password immediately
|
userCollection.save(user.mongoSerialise()); //Save new password immediately
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate and save a access token for websocket auth
|
||||||
|
*
|
||||||
|
* @param username Username
|
||||||
|
* @return The generated token
|
||||||
|
*/
|
||||||
|
public String generateAndGetToken(String username) {
|
||||||
|
|
||||||
|
User user = GameServer.INSTANCE.getGameUniverse().getUser(username);
|
||||||
|
|
||||||
|
if (user == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomStringGenerator generator = new RandomStringGenerator(128);
|
||||||
|
String token = generator.nextString();
|
||||||
|
|
||||||
|
user.setAccessToken(token);
|
||||||
|
|
||||||
|
LogManager.LOGGER.fine("(Web) Generated access token for " + username);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User validateAuthToken(String token) {
|
||||||
|
|
||||||
|
for (User user : GameServer.INSTANCE.getGameUniverse().getUsers()) {
|
||||||
|
|
||||||
|
if (user.getAccessToken().equals(token)) {
|
||||||
|
user.setAccessToken("");
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ public class CodeRequestHandler implements MessageHandler {
|
|||||||
|
|
||||||
LogManager.LOGGER.fine("(WS) Code request from " + user.getUser().getUsername());
|
LogManager.LOGGER.fine("(WS) Code request from " + user.getUser().getUsername());
|
||||||
|
|
||||||
if (user.isGuest()) {
|
if (user.getUser().isGuest()) {
|
||||||
|
|
||||||
JSONObject response = new JSONObject();
|
JSONObject response = new JSONObject();
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ public class CodeUploadHandler implements MessageHandler {
|
|||||||
|
|
||||||
LogManager.LOGGER.fine("(WS) Code upload from " + user.getUser().getUsername());
|
LogManager.LOGGER.fine("(WS) Code upload from " + user.getUser().getUsername());
|
||||||
|
|
||||||
if (user.isGuest()) {
|
if (user.getUser().isGuest()) {
|
||||||
//Ignore
|
//Ignore
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -10,7 +10,7 @@ public class DebugCommandHandler implements MessageHandler {
|
|||||||
public void handle(OnlineUser user, JSONObject json) {
|
public void handle(OnlineUser user, JSONObject json) {
|
||||||
|
|
||||||
|
|
||||||
if (json.get("t").equals("debug") && user.isModerator()) {
|
if (json.get("t").equals("debug") && user.getUser().isModerator()) {
|
||||||
|
|
||||||
DebugCommandEvent e = new DebugCommandEvent(json, user);
|
DebugCommandEvent e = new DebugCommandEvent(json, user);
|
||||||
GameServer.INSTANCE.getEventDispatcher().dispatch(e); //Ignore cancellation
|
GameServer.INSTANCE.getEventDispatcher().dispatch(e); //Ignore cancellation
|
||||||
|
@ -15,7 +15,7 @@ public class FloppyHandler implements MessageHandler {
|
|||||||
|
|
||||||
LogManager.LOGGER.fine("(WS) Floppy download request from " + user.getUser().getUsername());
|
LogManager.LOGGER.fine("(WS) Floppy download request from " + user.getUser().getUsername());
|
||||||
|
|
||||||
if (user.isGuest()) {
|
if (user.getUser().isGuest()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ public class KeypressHandler implements MessageHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(OnlineUser user, JSONObject json) {
|
public void handle(OnlineUser user, JSONObject json) {
|
||||||
|
|
||||||
if (!user.isGuest()) {
|
if (!user.getUser().isGuest()) {
|
||||||
if (json.get("t").equals("k")) {
|
if (json.get("t").equals("k")) {
|
||||||
|
|
||||||
//LogManager.LOGGER.fine("(WS) Received keypress");
|
//LogManager.LOGGER.fine("(WS) Received keypress");
|
||||||
|
@ -10,10 +10,6 @@ public class OnlineUser {
|
|||||||
|
|
||||||
private Session webSocket;
|
private Session webSocket;
|
||||||
|
|
||||||
private boolean guest;
|
|
||||||
|
|
||||||
private boolean moderator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associated game user (if authenticated)
|
* Associated game user (if authenticated)
|
||||||
*/
|
*/
|
||||||
@ -44,20 +40,4 @@ public class OnlineUser {
|
|||||||
this.authenticated = authenticated;
|
this.authenticated = authenticated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGuest(boolean guest) {
|
|
||||||
this.guest = guest;
|
|
||||||
user.setGuest(guest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isGuest() {
|
|
||||||
return guest;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isModerator() {
|
|
||||||
return moderator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setModerator(boolean moderator) {
|
|
||||||
this.moderator = moderator;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package net.simon987.server.websocket;
|
package net.simon987.server.websocket;
|
||||||
|
|
||||||
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.game.ControllableUnit;
|
import net.simon987.server.game.ControllableUnit;
|
||||||
import net.simon987.server.logging.LogManager;
|
import net.simon987.server.logging.LogManager;
|
||||||
|
import net.simon987.server.user.User;
|
||||||
import org.eclipse.jetty.websocket.api.Session;
|
import org.eclipse.jetty.websocket.api.Session;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||||
@ -57,14 +59,46 @@ public class SocketServer {
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
LogManager.LOGGER.info("(WS) Received message from unauthenticated user " + session.getRemoteAddress());
|
LogManager.LOGGER.info("(WS) Received message from unauthenticated user " + session.getRemoteAddress());
|
||||||
//todo
|
|
||||||
|
|
||||||
|
if (message.length() == 128) {
|
||||||
|
|
||||||
|
User user = GameServer.INSTANCE.getUserManager().validateAuthToken(message);
|
||||||
|
|
||||||
|
if (user != null) {
|
||||||
|
|
||||||
|
LogManager.LOGGER.info("(WS) User was successfully authenticated: " + user.getUsername());
|
||||||
|
|
||||||
|
onlineUser.setUser(user);
|
||||||
|
onlineUser.setAuthenticated(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
session.getRemote().sendString("{\"t\":\"auth\", \"m\":\"ok\"}");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
User guestUser = GameServer.INSTANCE.getGameUniverse().getOrCreateUser(GameServer.INSTANCE.getGameUniverse().getGuestUsername(), false);
|
||||||
|
onlineUser.setUser(guestUser);
|
||||||
|
onlineUser.setAuthenticated(true);
|
||||||
|
onlineUser.getUser().setGuest(true);
|
||||||
|
|
||||||
|
LogManager.LOGGER.info("(WS) Created guest user " +
|
||||||
|
onlineUser.getUser().getUsername() + session.getRemoteAddress());
|
||||||
|
|
||||||
|
try {
|
||||||
|
session.getRemote().sendString("{\"t\":\"auth\", \"m\":\"ok\"}");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
LogManager.LOGGER.severe("(WS) FIXME: SocketServer:onMessage");
|
LogManager.LOGGER.severe("(WS) FIXME: SocketServer:onMessage");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +115,7 @@ public class SocketServer {
|
|||||||
|
|
||||||
if (user.getWebSocket().isOpen()) {
|
if (user.getWebSocket().isOpen()) {
|
||||||
|
|
||||||
if (user.isGuest()) {
|
if (user.getUser().isGuest()) {
|
||||||
|
|
||||||
json.remove("c");
|
json.remove("c");
|
||||||
try {
|
try {
|
||||||
|
@ -18,7 +18,7 @@ public class UserInfoRequestHandler implements MessageHandler {
|
|||||||
LogManager.LOGGER.fine("(WS) User info request from " + user.getUser().getUsername());
|
LogManager.LOGGER.fine("(WS) User info request from " + user.getUser().getUsername());
|
||||||
JSONObject json = new JSONObject();
|
JSONObject json = new JSONObject();
|
||||||
|
|
||||||
if (user.isGuest()) {
|
if (user.getUser().isGuest()) {
|
||||||
json.put("worldX", GameServer.INSTANCE.getConfig().getInt("new_user_worldX"));
|
json.put("worldX", GameServer.INSTANCE.getConfig().getInt("new_user_worldX"));
|
||||||
json.put("worldY", GameServer.INSTANCE.getConfig().getInt("new_user_worldY"));
|
json.put("worldY", GameServer.INSTANCE.getConfig().getInt("new_user_worldY"));
|
||||||
json.put("dimension", GameServer.INSTANCE.getConfig().getString("new_user_dimension"));
|
json.put("dimension", GameServer.INSTANCE.getConfig().getString("new_user_dimension"));
|
||||||
|
@ -8,12 +8,11 @@ mysql_url=jdbc:mysql://localhost:3306/mar?useSSL=false
|
|||||||
save_interval=5
|
save_interval=5
|
||||||
log_limit=2000000
|
log_limit=2000000
|
||||||
log_count=10
|
log_count=10
|
||||||
# Web server port
|
use_ssl=0
|
||||||
webSocket_port=8887
|
|
||||||
webSocket_host=0.0.0.0
|
|
||||||
|
|
||||||
use_secure_webSocket=0
|
|
||||||
cert_path=certificates
|
cert_path=certificates
|
||||||
|
mar_port=4567
|
||||||
|
mar_address=localhost
|
||||||
|
server_name=Official MAR server
|
||||||
# ----------------------------------------------
|
# ----------------------------------------------
|
||||||
|
|
||||||
# Length of a tick in ms
|
# Length of a tick in ms
|
||||||
@ -86,7 +85,6 @@ wg_minCopperCount=0
|
|||||||
# Maximum copper tile count for the WorldGenerator
|
# Maximum copper tile count for the WorldGenerator
|
||||||
wg_maxCopperCount=2
|
wg_maxCopperCount=2
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------
|
# ----------------------------------------------
|
||||||
# Maximum execution time of user code in ms
|
# Maximum execution time of user code in ms
|
||||||
user_timeout=100
|
user_timeout=100
|
||||||
|
@ -695,7 +695,7 @@ var GameClient = (function () {
|
|||||||
console.log("[MAR] Getting server info... ");
|
console.log("[MAR] Getting server info... ");
|
||||||
}
|
}
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open("GET", "./getServerInfo.php", true);
|
xhr.open("GET", "./server_info", true);
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -374,7 +374,7 @@ class GameClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest();
|
||||||
xhr.open("GET", "./getServerInfo.php", true);
|
xhr.open("GET", "./server_info", true);
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user