Impl new auth method to avoid using sessionKey

This commit is contained in:
mingjun97 2022-05-18 20:33:31 -07:00
parent 57e7ac5436
commit cc0cb2fd81
5 changed files with 119 additions and 34 deletions

View File

@ -0,0 +1,53 @@
package com.mojo.consoleplus;
import java.security.MessageDigest;
import java.util.UUID;
import com.mojo.consoleplus.ConsolePlus;
public class AuthHandler {
public static String signatureStub;
public AuthHandler(){
try {
signatureStub = UUID.randomUUID().toString();
} catch (Exception e) {
e.printStackTrace();
}
}
public AuthHandler(String stub) {
signatureStub = stub;
}
public Boolean auth(int uid, long expire, String dg) {
return digestUid(uid+":"+expire).equals(dg);
}
public String genKey(int uid, long expire){
String part1 = uid +":"+expire;
return part1 + ":" + digestUid(part1);
}
private String digestUid(String payload) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("SHA-256");
return bytesToHex(digest.digest((payload + ":" + signatureStub).getBytes("UTF-8")));
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
private static String bytesToHex(byte[] hash) {
StringBuilder hexString = new StringBuilder(2 * hash.length);
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if(hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
}

View File

@ -22,6 +22,7 @@ import com.mojo.consoleplus.config.MojoConfig;
public class ConsolePlus extends Plugin{ public class ConsolePlus extends Plugin{
public static MojoConfig config = MojoConfig.loadConfig(); public static MojoConfig config = MojoConfig.loadConfig();
public static String versionTag; public static String versionTag;
public static AuthHandler authHandler;
@Override @Override
public void onLoad() { public void onLoad() {
@ -58,7 +59,7 @@ public class ConsolePlus extends Plugin{
Grasscutter.getHttpServer().addRouter(RequestHandler.class); Grasscutter.getHttpServer().addRouter(RequestHandler.class);
CommandMap.getInstance().registerCommand("mojoconsole", new PluginCommand()); CommandMap.getInstance().registerCommand("mojoconsole", new PluginCommand());
this.getLogger().info("[MojoConsole] enabled. Version: " + versionTag); this.getLogger().info("[MojoConsole] enabled. Version: " + versionTag);
authHandler = new AuthHandler();
} }
@Override @Override

View File

@ -1,5 +1,8 @@
package com.mojo.consoleplus; package com.mojo.consoleplus;
import static java.lang.Integer.parseInt;
import static java.lang.Long.parseLong;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
@ -34,43 +37,61 @@ public final class RequestHandler implements Router {
public static void processRequest(Request req, Response res) throws IOException { public static void processRequest(Request req, Response res) throws IOException {
RequestJson request = req.body(RequestJson.class); RequestJson request = req.body(RequestJson.class);
res.type("application/json"); res.type("application/json");
if (request.k != null) { Player player = null;
if (request.k != null) { // version 1 token
Account account = DatabaseHelper.getAccountBySessionKey(request.k); Account account = DatabaseHelper.getAccountBySessionKey(request.k);
Map<Integer, Player> playersMap = Grasscutter.getGameServer().getPlayers(); Map<Integer, Player> playersMap = Grasscutter.getGameServer().getPlayers();
Player player = null;
// String invokeResult = ""; // String invokeResult = "";
MessageHandler resultCollector = new MessageHandler();
if (account != null) { if (account != null) {
for (int playerid: playersMap.keySet()) { for (int playerid: playersMap.keySet()) {
if (playersMap.get(playerid).getUid() == account.getPlayerUid()) { if (playersMap.get(playerid).getUid() == account.getPlayerUid()) {
player = playersMap.get(playerid); player = playersMap.get(playerid);
} }
} }
if (player != null) { }
// player.setInvokeResult("[MojoConsole]"); }
player.setMessageHandler(resultCollector); // hook the message
switch (request.request){ if (request.k2 != null) { // version 2 token
case "invoke": int uid;
try{ long expire;
// TODO: Enable execut commands to third party String hashDigest;
CommandMap.getInstance().invoke(player, player, request.payload); uid = parseInt(request.k2.split(":")[0]);
} catch (Exception e) { expire = parseLong(request.k2.split(":")[1]);
res.json(new ResponseJson("error", 500, e.getStackTrace().toString())); hashDigest = request.k2.split(":")[2];
break; if (ConsolePlus.authHandler.auth(uid, expire, hashDigest)){
} Map<Integer, Player> playersMap = Grasscutter.getGameServer().getPlayers();
case "ping": for (int playerid: playersMap.keySet()) {
// res.json(new ResponseJson("success", 200)); if (playersMap.get(playerid).getUid() == uid) {
res.json(new ResponseJson("success", 200, resultCollector.getMessage())); player = playersMap.get(playerid);
break;
default:
res.json(new ResponseJson("400 Bad Request", 400));
break;
} }
player.setMessageHandler(null);
return;
} }
} }
} }
if (player != null) {
MessageHandler resultCollector = new MessageHandler();
player.setMessageHandler(resultCollector); // hook the message
switch (request.request){
case "invoke":
try{
// TODO: Enable execut commands to third party
CommandMap.getInstance().invoke(player, player, request.payload);
} catch (Exception e) {
res.json(new ResponseJson("error", 500, e.getStackTrace().toString()));
break;
}
case "ping":
// res.json(new ResponseJson("success", 200));
res.json(new ResponseJson("success", 200, resultCollector.getMessage()));
break;
default:
res.json(new ResponseJson("400 Bad Request", 400));
break;
}
player.setMessageHandler(null);
return;
}
res.json(new ResponseJson("403 Forbidden", 403)); res.json(new ResponseJson("403 Forbidden", 403));
} }
} }

View File

@ -1,6 +1,7 @@
package com.mojo.consoleplus.command; package com.mojo.consoleplus.command;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List; import java.util.List;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
@ -17,24 +18,27 @@ import com.google.gson.Gson;
"mojo" }, permission = "mojo.console") "mojo" }, permission = "mojo.console")
public class PluginCommand implements CommandHandler { public class PluginCommand implements CommandHandler {
static class HashParams{ static class HashParams{
public String k; // session key public String k2; // session key
public String d; // mojo backend url public String d; // mojo backend url
} }
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
Mail mail = new Mail(); Mail mail = new Mail();
String link = getServerURL(targetPlayer.getAccount().getSessionKey()); String authKey = ConsolePlus.authHandler.genKey(sender.getUid(), System.currentTimeMillis() / 1000 + ConsolePlus.config.mail.expireHour * 3600);
String link = getServerURL(authKey);
String link_type = "webview"; String link_type = "webview";
Grasscutter.getLogger().info(link); Grasscutter.getLogger().info(link);
if (args.size() > 0 && args.get(0).equals("o")) { if (args.size() > 0) {
link_type = "browser"; if (args.get(0).equals("o")){
link_type = "browser";
}
} }
mail.mailContent.title = ConsolePlus.config.mail.title; mail.mailContent.title = ConsolePlus.config.mail.title;
mail.mailContent.sender = ConsolePlus.config.mail.author; mail.mailContent.sender = ConsolePlus.config.mail.author;
mail.mailContent.content = ConsolePlus.config.mail.content.replace("{{ LINK }}", "<type=\""+ link_type + "\" text=\"Mojo Console\" href=\"" + link + "\"/>"); mail.mailContent.content = ConsolePlus.config.mail.content.replace("{{ LINK }}", "<type=\""+ link_type + "\" text=\"Mojo Console\" href=\"" + link + "\"/>");
mail.expireTime = System.currentTimeMillis() / 1000 + 3600 * ConsolePlus.config.mail.expireHour; mail.expireTime = System.currentTimeMillis() / 1000 + 3600 * ConsolePlus.config.mail.expireHour;
targetPlayer.sendMail(mail); sender.sendMail(mail);
CommandHandler.sendMessage(sender, ConsolePlus.config.responseMessage); CommandHandler.sendMessage(sender, ConsolePlus.config.responseMessage);
} }
@ -42,16 +46,21 @@ public class PluginCommand implements CommandHandler {
if (ConsolePlus.config.UseCDN){ if (ConsolePlus.config.UseCDN){
Gson gson = new Gson(); Gson gson = new Gson();
HashParams hp = new HashParams(); HashParams hp = new HashParams();
hp.k = sessionKey; hp.k2 = sessionKey;
hp.d = getMojoBackendURL(); hp.d = getMojoBackendURL();
try {
sessionKey = URLEncoder.encode(sessionKey, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
try{ try{
return ConsolePlus.config.CDNLink + "#" + URLEncoder.encode(gson.toJson(hp), "utf-8"); return ConsolePlus.config.CDNLink + "#" + URLEncoder.encode(gson.toJson(hp), "utf-8");
} catch (Exception e){ } catch (Exception e){
e.printStackTrace(); e.printStackTrace();
return ConsolePlus.config.CDNLink + "?k=" + sessionKey; return ConsolePlus.config.CDNLink + "?k2=" + sessionKey;
} }
} else { } else {
return getMojoBackendURL() + ConsolePlus.config.interfacePath + "?k=" + sessionKey; return getMojoBackendURL() + ConsolePlus.config.interfacePath + "?k2=" + sessionKey;
} }
} }

View File

@ -1,7 +1,8 @@
package com.mojo.consoleplus.forms; package com.mojo.consoleplus.forms;
public final class RequestJson { public final class RequestJson {
public String k = ""; public String k;
public String k2;
public String request = ""; public String request = "";
public String payload = ""; public String payload = "";
} }