Capture Request Exception

This commit is contained in:
2023-05-21 19:50:23 +08:00
parent f19c4b8e77
commit 82477321d1
3 changed files with 260 additions and 248 deletions

View File

@ -50,133 +50,137 @@ public final class OpenCommandHandler implements Router {
public static void handle(Context context) {
var plugin = OpenCommandPlugin.getInstance();
var config = plugin.getConfig();
var data = plugin.getData();
var now = new Date();
// Trigger cleanup action
cleanupExpiredCodes();
data.removeExpiredClients();
try {
var config = plugin.getConfig();
var data = plugin.getData();
var now = new Date();
// Trigger cleanup action
cleanupExpiredCodes();
data.removeExpiredClients();
var req = context.bodyAsClass(JsonRequest.class);
if (req.action.equals("sendCode")) {
int playerId = (int) req.data;
var player = plugin.getServer().getPlayerByUid(playerId);
if (player == null) {
context.json(new JsonResponse(404, "Player Not Found."));
} else {
if (codeExpireTime.containsKey(playerId)) {
var expireTime = codeExpireTime.get(playerId);
if (now.before(expireTime)) {
context.json(new JsonResponse(403, "Requests are too frequent"));
return;
var req = context.bodyAsClass(JsonRequest.class);
if (req.action.equals("sendCode")) {
int playerId = (int) req.data;
var player = plugin.getServer().getPlayerByUid(playerId);
if (player == null) {
context.json(new JsonResponse(404, "Player Not Found."));
} else {
if (codeExpireTime.containsKey(playerId)) {
var expireTime = codeExpireTime.get(playerId);
if (now.before(expireTime)) {
context.json(new JsonResponse(403, "Requests are too frequent"));
return;
}
}
String token = req.token;
if (token == null || token.isEmpty())
token = Utils.bytesToHex(Crypto.createSessionKey(32));
int code = Utils.randomRange(1000, 9999);
codeExpireTime.put(playerId, new Date(now.getTime() + config.codeExpirationTime_S * 1000L));
codes.put(token, code);
data.addClient(new Client(token, playerId, new Date(now.getTime() + config.tempTokenExpirationTime_S * 1000L)));
player.dropMessage("[Open Command] Verification code: " + code);
context.json(new JsonResponse(token));
}
String token = req.token;
if (token == null || token.isEmpty())
token = Utils.bytesToHex(Crypto.createSessionKey(32));
int code = Utils.randomRange(1000, 9999);
codeExpireTime.put(playerId, new Date(now.getTime() + config.codeExpirationTime_S * 1000L));
codes.put(token, code);
data.addClient(new Client(token, playerId, new Date(now.getTime() + config.tempTokenExpirationTime_S * 1000L)));
player.dropMessage("[Open Command] Verification code: " + code);
context.json(new JsonResponse(token));
}
return;
} else if (req.action.equals("ping")) {
context.json(new JsonResponse());
return;
} else if (req.action.equals("online")) {
var p = new ArrayList<String>();
plugin.getServer().getPlayers().forEach((uid, player) -> p.add(player.getNickname()));
context.json(new JsonResponse(200, "Success", new SocketData.OnlinePlayer(p)));
return;
}
// token is required
if (req.token == null || req.token.isEmpty()) {
context.json(new JsonResponse(401, "Unauthorized"));
return;
}
var isConsole = req.token.equals(config.consoleToken);
var client = data.getClientByToken(req.token);
if (!isConsole && client == null) {
context.json(new JsonResponse(401, "Unauthorized"));
return;
}
if (isConsole) {
if (req.action.equals("verify")) {
return;
} else if (req.action.equals("ping")) {
context.json(new JsonResponse());
return;
} else if (req.action.equals("command")) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (plugin) {
try {
plugin.getLogger().info(String.format("IP: %s run command in console > %s", context.ip(), req.data));
var resultCollector = new StringBuilder();
EventListeners.setConsoleMessageHandler(resultCollector);
CommandMap.getInstance().invoke(null, null, req.data.toString());
context.json(new JsonResponse(resultCollector.toString()));
} catch (Exception e) {
plugin.getLogger().warn("Run command failed.", e);
EventListeners.setConsoleMessageHandler(null);
context.json(new JsonResponse(500, "error", e.getLocalizedMessage()));
}
}
return;
} else if (req.action.equals("runmode")) {
context.json(new JsonResponse(200, "Success", 0));
} else if (req.action.equals("online")) {
var p = new ArrayList<String>();
plugin.getServer().getPlayers().forEach((uid, player) -> p.add(player.getNickname()));
context.json(new JsonResponse(200, "Success", new SocketData.OnlinePlayer(p)));
return;
}
} else if (codes.containsKey(req.token)) {
if (req.action.equals("verify")) {
if (codes.get(req.token).equals(req.data)) {
codes.remove(req.token);
// update token expire time
client.tokenExpireTime = new Date(now.getTime() + config.tokenLastUseExpirationTime_H * 60L * 60L * 1000L);
// token is required
if (req.token == null || req.token.isEmpty()) {
context.json(new JsonResponse(401, "Unauthorized"));
return;
}
var isConsole = req.token.equals(config.consoleToken);
var client = data.getClientByToken(req.token);
if (!isConsole && client == null) {
context.json(new JsonResponse(401, "Unauthorized"));
return;
}
if (isConsole) {
if (req.action.equals("verify")) {
context.json(new JsonResponse());
plugin.getLogger().info(String.format("Player %d has passed the verification, ip: %s", client.playerId, context.ip()));
plugin.saveData();
} else {
context.json(new JsonResponse(400, "Verification failed"));
}
return;
}
} else {
if (req.action.equals("command")) {
// update token expire time
client.tokenExpireTime = new Date(now.getTime() + config.tokenLastUseExpirationTime_H * 60L * 60L * 1000L);
var player = plugin.getServer().getPlayerByUid(client.playerId);
var command = req.data.toString();
if (player == null) {
context.json(new JsonResponse(404, "Player not found"));
return;
} else if (req.action.equals("command")) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (plugin) {
try {
plugin.getLogger().info(String.format("IP: %s run command in console > %s", context.ip(), req.data));
var resultCollector = new StringBuilder();
EventListeners.setConsoleMessageHandler(resultCollector);
CommandMap.getInstance().invoke(null, null, req.data.toString());
context.json(new JsonResponse(resultCollector.toString()));
} catch (Exception e) {
plugin.getLogger().warn("Run command failed.", e);
EventListeners.setConsoleMessageHandler(null);
context.json(new JsonResponse(500, "error", e.getLocalizedMessage()));
}
}
return;
} else if (req.action.equals("runmode")) {
context.json(new JsonResponse(200, "Success", 0));
return;
}
// Player MessageHandler do not support concurrency
var handler = playerMessageHandlers.get(player.getUid());
if (handler == null) {
handler = new MessageHandler();
playerMessageHandlers.put(player.getUid(), handler);
}
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (handler) {
try {
handler.setMessage("");
player.setMessageHandler(handler);
CommandMap.getInstance().invoke(player, player, command);
context.json(new JsonResponse(handler.getMessage()));
} catch (Exception e) {
plugin.getLogger().warn("Run command failed.", e);
context.json(new JsonResponse(500, "error", e.getLocalizedMessage()));
} finally {
player.setMessageHandler(null);
} else if (codes.containsKey(req.token)) {
if (req.action.equals("verify")) {
if (codes.get(req.token).equals(req.data)) {
codes.remove(req.token);
// update token expire time
client.tokenExpireTime = new Date(now.getTime() + config.tokenLastUseExpirationTime_H * 60L * 60L * 1000L);
context.json(new JsonResponse());
plugin.getLogger().info(String.format("Player %d has passed the verification, ip: %s", client.playerId, context.ip()));
plugin.saveData();
} else {
context.json(new JsonResponse(400, "Verification failed"));
}
return;
}
} else {
if (req.action.equals("command")) {
// update token expire time
client.tokenExpireTime = new Date(now.getTime() + config.tokenLastUseExpirationTime_H * 60L * 60L * 1000L);
var player = plugin.getServer().getPlayerByUid(client.playerId);
var command = req.data.toString();
if (player == null) {
context.json(new JsonResponse(404, "Player not found"));
return;
}
// Player MessageHandler do not support concurrency
var handler = playerMessageHandlers.get(player.getUid());
if (handler == null) {
handler = new MessageHandler();
playerMessageHandlers.put(player.getUid(), handler);
}
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (handler) {
try {
handler.setMessage("");
player.setMessageHandler(handler);
CommandMap.getInstance().invoke(player, player, command);
context.json(new JsonResponse(handler.getMessage()));
} catch (Exception e) {
plugin.getLogger().warn("Run command failed.", e);
context.json(new JsonResponse(500, "error", e.getLocalizedMessage()));
} finally {
player.setMessageHandler(null);
}
}
return;
}
return;
}
context.json(new JsonResponse(403, "forbidden"));
} catch (Throwable ex) {
plugin.getLogger().error("[OpenCommand] handler error.", ex);
}
context.json(new JsonResponse(403, "forbidden"));
}
private static void cleanupExpiredCodes() {

View File

@ -51,155 +51,159 @@ public final class OpenCommandOnlyHttpHandler implements Router {
public static void handle(Context context) {
var plugin = OpenCommandPlugin.getInstance();
var config = plugin.getConfig();
var data = plugin.getData();
var now = new Date();
// Trigger cleanup action
cleanupExpiredCodes();
data.removeExpiredClients();
try {
var config = plugin.getConfig();
var data = plugin.getData();
var now = new Date();
// Trigger cleanup action
cleanupExpiredCodes();
data.removeExpiredClients();
var req = context.bodyAsClass(JsonRequest.class);
if (req.action.equals("sendCode")) {
int playerId = (int) req.data;
var player = SocketData.getPlayer(playerId);
if (player == null) {
context.json(new JsonResponse(404, "Player Not Found."));
} else {
if (codeExpireTime.containsKey(playerId)) {
var expireTime = codeExpireTime.get(playerId);
if (now.before(expireTime)) {
context.json(new JsonResponse(403, "Requests are too frequent"));
return;
var req = context.bodyAsClass(JsonRequest.class);
if (req.action.equals("sendCode")) {
int playerId = (int) req.data;
var player = SocketData.getPlayer(playerId);
if (player == null) {
context.json(new JsonResponse(404, "Player Not Found."));
} else {
if (codeExpireTime.containsKey(playerId)) {
var expireTime = codeExpireTime.get(playerId);
if (now.before(expireTime)) {
context.json(new JsonResponse(403, "Requests are too frequent"));
return;
}
}
String token = req.token;
if (token == null || token.isEmpty())
token = Utils.bytesToHex(Crypto.createSessionKey(32));
int code = Utils.randomRange(1000, 9999);
codeExpireTime.put(playerId, new Date(now.getTime() + config.codeExpirationTime_S * 1000L));
codes.put(token, code);
data.addClient(new Client(token, playerId, new Date(now.getTime() + config.tempTokenExpirationTime_S * 1000L)));
Player.dropMessage(playerId, "[Open Command] Verification code: " + code);
context.json(new JsonResponse(token));
}
String token = req.token;
if (token == null || token.isEmpty())
token = Utils.bytesToHex(Crypto.createSessionKey(32));
int code = Utils.randomRange(1000, 9999);
codeExpireTime.put(playerId, new Date(now.getTime() + config.codeExpirationTime_S * 1000L));
codes.put(token, code);
data.addClient(new Client(token, playerId, new Date(now.getTime() + config.tempTokenExpirationTime_S * 1000L)));
Player.dropMessage(playerId, "[Open Command] Verification code: " + code);
context.json(new JsonResponse(token));
}
return;
} else if (req.action.equals("ping")) {
context.json(new JsonResponse());
return;
} else if (req.action.equals("online")) {
context.json(new JsonResponse(200, "Success", SocketData.getOnlinePlayer()));
return;
}
// token is required
if (req.token == null || req.token.isEmpty()) {
context.json(new JsonResponse(401, "Unauthorized"));
return;
}
var isConsole = req.token.equals(config.consoleToken);
var client = data.getClientByToken(req.token);
if (!isConsole && client == null) {
context.json(new JsonResponse(401, "Unauthorized"));
return;
}
if (isConsole) {
if (req.action.equals("verify")) {
return;
} else if (req.action.equals("ping")) {
context.json(new JsonResponse());
return;
} else if (req.action.equals("command")) {
var server = SocketServer.getClientInfoByUuid(req.server);
if (server == null) {
context.json(new JsonResponse(404, "Server Not Found."));
return;
}
plugin.getLogger().info(String.format("IP: %s run command in console > %s", context.ip(), req.data));
var wait = new SocketDataWait<HttpPacket>(2000L) {
@Override
public void run() {
}
@Override
public HttpPacket initData(HttpPacket data) {
return data;
}
@Override
public void timeout() {
}
};
SocketServer.sendPacketAndWait(server.ip, new RunConsoleCommand(req.data.toString()), wait);
var packet = wait.getData();
if (packet == null) {
context.json(new JsonResponse(408, "Timeout"));
return;
}
context.json(new JsonResponse(packet.code, packet.message, packet.data));
return;
} else if (req.action.equals("server")) {
context.json(new JsonResponse(200, "Success", SocketServer.getOnlineClient()));
return;
} else if (req.action.equals("runmode")) {
context.json(new JsonResponse(200, "Success", 1));
} else if (req.action.equals("online")) {
context.json(new JsonResponse(200, "Success", SocketData.getOnlinePlayer()));
return;
}
} else if (codes.containsKey(req.token)) {
if (req.action.equals("verify")) {
if (codes.get(req.token).equals(req.data)) {
codes.remove(req.token);
// token is required
if (req.token == null || req.token.isEmpty()) {
context.json(new JsonResponse(401, "Unauthorized"));
return;
}
var isConsole = req.token.equals(config.consoleToken);
var client = data.getClientByToken(req.token);
if (!isConsole && client == null) {
context.json(new JsonResponse(401, "Unauthorized"));
return;
}
if (isConsole) {
if (req.action.equals("verify")) {
context.json(new JsonResponse());
return;
} else if (req.action.equals("command")) {
var server = SocketServer.getClientInfoByUuid(req.server);
if (server == null) {
context.json(new JsonResponse(404, "Server Not Found."));
return;
}
plugin.getLogger().info(String.format("IP: %s run command in console > %s", context.ip(), req.data));
var wait = new SocketDataWait<HttpPacket>(2000L) {
@Override
public void run() {
}
@Override
public HttpPacket initData(HttpPacket data) {
return data;
}
@Override
public void timeout() {
}
};
SocketServer.sendPacketAndWait(server.ip, new RunConsoleCommand(req.data.toString()), wait);
var packet = wait.getData();
if (packet == null) {
context.json(new JsonResponse(408, "Timeout"));
return;
}
context.json(new JsonResponse(packet.code, packet.message, packet.data));
return;
} else if (req.action.equals("server")) {
context.json(new JsonResponse(200, "Success", SocketServer.getOnlineClient()));
return;
} else if (req.action.equals("runmode")) {
context.json(new JsonResponse(200, "Success", 1));
return;
}
} else if (codes.containsKey(req.token)) {
if (req.action.equals("verify")) {
if (codes.get(req.token).equals(req.data)) {
codes.remove(req.token);
// update token expire time
client.tokenExpireTime = new Date(now.getTime() + config.tokenLastUseExpirationTime_H * 60L * 60L * 1000L);
context.json(new JsonResponse());
plugin.getLogger().info(String.format("Player %d has passed the verification, ip: %s", client.playerId, context.ip()));
plugin.saveData();
} else {
context.json(new JsonResponse(400, "Verification failed"));
}
return;
}
} else {
if (req.action.equals("command")) {
SocketDataWait<HttpPacket> socketDataWait = new SocketDataWait<>(1000L * 10L) {
@Override
public void run() {
}
@Override
public HttpPacket initData(HttpPacket data) {
return data;
}
@Override
public void timeout() {
}
};
// update token expire time
client.tokenExpireTime = new Date(now.getTime() + config.tokenLastUseExpirationTime_H * 60L * 60L * 1000L);
context.json(new JsonResponse());
plugin.getLogger().info(String.format("Player %d has passed the verification, ip: %s", client.playerId, context.ip()));
plugin.saveData();
} else {
context.json(new JsonResponse(400, "Verification failed"));
}
return;
}
} else {
if (req.action.equals("command")) {
SocketDataWait<HttpPacket> socketDataWait = new SocketDataWait<>(1000L * 10L) {
@Override
public void run() {
var command = req.data.toString();
var player = new Player();
player.uid = client.playerId;
player.type = PlayerEnum.RunCommand;
player.data = command;
if (!SocketServer.sendUidPacketAndWait(client.playerId, player, socketDataWait)) {
context.json(new JsonResponse(404, "Player Not Found."));
return;
}
@Override
public HttpPacket initData(HttpPacket data) {
return data;
HttpPacket httpPacket = socketDataWait.getData();
if (httpPacket == null) {
context.json(new JsonResponse(500, "error", "Wait timeout"));
return;
}
@Override
public void timeout() {
}
};
// update token expire time
client.tokenExpireTime = new Date(now.getTime() + config.tokenLastUseExpirationTime_H * 60L * 60L * 1000L);
var command = req.data.toString();
var player = new Player();
player.uid = client.playerId;
player.type = PlayerEnum.RunCommand;
player.data = command;
if (!SocketServer.sendUidPacketAndWait(client.playerId, player, socketDataWait)) {
context.json(new JsonResponse(404, "Player Not Found."));
context.json(new JsonResponse(httpPacket.code, httpPacket.message));
return;
}
HttpPacket httpPacket = socketDataWait.getData();
if (httpPacket == null) {
context.json(new JsonResponse(500, "error", "Wait timeout"));
return;
}
context.json(new JsonResponse(httpPacket.code, httpPacket.message));
return;
}
context.json(new JsonResponse(403, "forbidden"));
} catch (Exception ex) {
plugin.getLogger().error("[OpenCommand] handler error.", ex);
}
context.json(new JsonResponse(403, "forbidden"));
}
private static void cleanupExpiredCodes() {

View File

@ -111,9 +111,11 @@ public final class OpenCommandPlugin extends Plugin {
config = JsonUtils.decode(Files.readString(configFile.toPath(), StandardCharsets.UTF_8),
OpenCommandConfig.class);
} catch (Exception exception) {
config = new OpenCommandConfig();
getLogger().error("[OpenCommand] There was an error while trying to load the configuration from config.json. Please make sure that there are no syntax errors. If you want to start with a default configuration, delete your existing config.json.");
}
if (config == null) {
config = new OpenCommandConfig();
}
}
try {
runMode = Grasscutter.getConfig().server.runMode;
@ -132,9 +134,11 @@ public final class OpenCommandPlugin extends Plugin {
data = JsonUtils.decode(Files.readString(dataFile.toPath(), StandardCharsets.UTF_8),
OpenCommandData.class);
} catch (Exception exception) {
data = new OpenCommandData();
getLogger().error("[OpenCommand] There was an error while trying to load the data from data.json. Please make sure that there are no syntax errors. If you want to start with a default data, delete your existing data.json.");
}
if (data == null) {
data = new OpenCommandData();
}
}
}