diff --git a/.gitignore b/.gitignore index 1c91930..56f044f 100644 --- a/.gitignore +++ b/.gitignore @@ -97,6 +97,7 @@ $RECYCLE.BIN/ *.lnk target/ +test-setver/ pom.xml.tag pom.xml.releaseBackup diff --git a/README.md b/README.md index 5ad702d..b9db0d0 100644 --- a/README.md +++ b/README.md @@ -3,5 +3,28 @@ ## 功能介绍 (TODO List) +### 外置登录服务器 +- [x] 用户登录 +- [x] 刷新令牌 +- [x] 验证令牌 +- [x] 吊销令牌 +- [x] 客户端进入服务器 +- [x] 服务端验证客户端 +- [x] 查询角色属性 +- [x] 按名称批量查询 +- [ ] 材质(皮肤)上传/删除 +- [ ] 多角色支持 + +### Web服务器 + +- [x] 用户注册 +- [ ] 邀请码生成 +- [ ] 实名认证白名单 +- [ ] 用户管理 +- [ ] 用户登录 +- [ ] 密码修改 +- [ ] 用户信息修改 +- [ ] 材质(皮肤)上传/删除 +- [ ] 多角色创建删除 diff --git a/pom.xml b/pom.xml index 7aba170..9ce6f15 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,26 @@ + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + + + install + install + + + + + + + + run + + + + @@ -75,24 +95,27 @@ org.xerial sqlite-jdbc - 3.39.4.1 + 3.40.0.0 com.alibaba fastjson - 2.0.19 + 2.0.20 - javax.mail mail 1.4.7 - javax.activation activation 1.1.1 + + org.apache.directory.studio + org.apache.commons.codec + 1.8 + diff --git a/src/main/java/site/deercloud/identityverification/Controller/ConfigManager.java b/src/main/java/site/deercloud/identityverification/Controller/ConfigManager.java index f1c7cac..200b052 100644 --- a/src/main/java/site/deercloud/identityverification/Controller/ConfigManager.java +++ b/src/main/java/site/deercloud/identityverification/Controller/ConfigManager.java @@ -149,8 +149,6 @@ public class ConfigManager { } public void setSignaturePublicKey(String signaturePublicKey) { m_SignaturePublicKey = signaturePublicKey; - config.set("Yggdrasil.SignaturePublicKey", signaturePublicKey); - plugin.saveConfig(); } public void setPublicKeyFileName(String signaturePublicKey) { m_RsaPublicKeyFileName = signaturePublicKey; @@ -166,8 +164,6 @@ public class ConfigManager { } public void setSignaturePrivateKey(String signaturePrivateKey) { m_SignaturePrivateKey = signaturePrivateKey; - config.set("Yggdrasil.SignaturePrivateKey", signaturePrivateKey); - plugin.saveConfig(); } public void setPrivateKeyFileName(String signaturePrivateKey) { m_RsaPrivateKeyFileName = signaturePrivateKey; diff --git a/src/main/java/site/deercloud/identityverification/Controller/EmailCodeCache.java b/src/main/java/site/deercloud/identityverification/Controller/EmailCodeCache.java index 7751a8f..f9c4273 100644 --- a/src/main/java/site/deercloud/identityverification/Controller/EmailCodeCache.java +++ b/src/main/java/site/deercloud/identityverification/Controller/EmailCodeCache.java @@ -1,6 +1,7 @@ package site.deercloud.identityverification.Controller; import site.deercloud.identityverification.HttpServer.model.EmailCode; +import site.deercloud.identityverification.IdentityVerification; import java.util.Map; import java.util.Optional; @@ -22,10 +23,12 @@ public class EmailCodeCache { } public static boolean isEmailCodeExpired(String email) { + if (IdentityVerification.getInstance().getConfigManager().getDebug()) return false; return getEmailCode(email).map(EmailCode::isExpired).orElse(true); } public static boolean isEmailCodeValid(String email, String code) { + if (IdentityVerification.getInstance().getConfigManager().getDebug()) return true; return getEmailCode(email).map(emailCode -> emailCode.code.equals(code)).orElse(false); } } diff --git a/src/main/java/site/deercloud/identityverification/Controller/InviteCodeManager.java b/src/main/java/site/deercloud/identityverification/Controller/InviteCodeManager.java index a5dd551..c450251 100644 --- a/src/main/java/site/deercloud/identityverification/Controller/InviteCodeManager.java +++ b/src/main/java/site/deercloud/identityverification/Controller/InviteCodeManager.java @@ -28,7 +28,7 @@ public class InviteCodeManager { if (sender.isOp()) { Connection connection = SqlManager.getConnection(); try { - User console = UserDAO.selectByEmail(connection, "console@mc.com"); + User console = UserDAO.selectByUuid(connection, ((Player) sender).getUniqueId().toString()); InviteCodeDAO.insert(connection, code, console.uuid, false, 0); } catch (SQLException e) { throw new RuntimeException(e); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Ban.java b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Ban.java index d43a8f8..04871ae 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Ban.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Ban.java @@ -8,6 +8,7 @@ import site.deercloud.identityverification.Utils.MyLogger; import java.io.IOException; import java.util.Map; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; import static site.deercloud.identityverification.HttpServer.HttpServerManager.jsonResponse; import static site.deercloud.identityverification.Utils.Utils.*; @@ -21,7 +22,7 @@ public class Ban implements HttpHandler { return; } - JSONObject jsonObject = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject jsonObject = getBody(exchange); String uuid = jsonObject.getString("uuid"); String reason = jsonObject.getString("reason"); Integer time = jsonObject.getInteger("time"); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Api/GetInviter.java b/src/main/java/site/deercloud/identityverification/HttpServer/Api/GetInviter.java index be6f341..2afe0d0 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Api/GetInviter.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Api/GetInviter.java @@ -13,6 +13,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.Map; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getQuery; import static site.deercloud.identityverification.HttpServer.HttpServerManager.jsonResponse; import static site.deercloud.identityverification.SQLite.SqlManager.getConnection; import static site.deercloud.identityverification.Utils.Utils.*; @@ -28,8 +29,7 @@ public class GetInviter implements HttpHandler { return; } - String query = exchange.getRequestURI().getQuery(); - Map params = ParseQueryString(query); + Map params = getQuery(exchange); Connection connection = getConnection(); String uuid = params.get("uuid"); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Api/GetProfiles.java b/src/main/java/site/deercloud/identityverification/HttpServer/Api/GetProfiles.java index 253fcad..476304d 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Api/GetProfiles.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Api/GetProfiles.java @@ -14,6 +14,9 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBodyArray; + public class GetProfiles implements HttpHandler { @Override public void handle(HttpExchange exchange) { @@ -23,7 +26,7 @@ public class GetProfiles implements HttpHandler { Response.err_method_not_allowed(exchange); return; } - JSONArray profiles_json = JSONArray.parseArray(exchange.getRequestBody().toString()); + JSONArray profiles_json = getBodyArray(exchange); if (profiles_json.size() > 5) { Response.success_no_content(exchange); return; diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Login.java b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Login.java index a66b8d0..e0ad382 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Login.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Login.java @@ -13,6 +13,7 @@ import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; import static site.deercloud.identityverification.HttpServer.HttpServerManager.jsonResponse; public class Login implements HttpHandler { @@ -25,7 +26,7 @@ public class Login implements HttpHandler { Response.err_method_not_allowed(exchange); return; } - JSONObject request = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject request = getBody(exchange); String username = request.getString("username"); String password = request.getString("password"); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/SendEmailCode.java b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/GetEmailCode.java similarity index 80% rename from src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/SendEmailCode.java rename to src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/GetEmailCode.java index 4139bb5..cd3df97 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/SendEmailCode.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/GetEmailCode.java @@ -10,9 +10,10 @@ import site.deercloud.identityverification.Utils.RandomCode; import java.io.IOException; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; import static site.deercloud.identityverification.HttpServer.HttpServerManager.jsonResponse; -public class SendEmailCode implements HttpHandler { +public class GetEmailCode implements HttpHandler { @Override public void handle(HttpExchange exchange) { try { @@ -21,7 +22,7 @@ public class SendEmailCode implements HttpHandler { jsonResponse(exchange, 405, "Method Not Allowed", null); return; } - JSONObject request = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject request = getBody(exchange); String email = request.getString("email"); if (!EmailCodeCache.isEmailCodeExpired(email)) { @@ -30,7 +31,10 @@ public class SendEmailCode implements HttpHandler { } String code = RandomCode.NewCodeOnlyNumber(6); - EmailSender.sendCodeEmail(email, code); + if(!EmailSender.sendCodeEmail(email, code)) { + jsonResponse(exchange, 500, "邮件发送失败!", null); + return; + } EmailCodeCache.addEmailCode(email, code); jsonResponse(exchange, 200, "发送成功,请在五分钟内完成注册。", null); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/GetOnlineProfile.java b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/GetOnlineProfile.java index 6aca242..bdd1d52 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/GetOnlineProfile.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/GetOnlineProfile.java @@ -8,6 +8,7 @@ import site.deercloud.identityverification.Utils.MyLogger; import java.io.IOException; import java.util.Map; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getQuery; import static site.deercloud.identityverification.HttpServer.HttpServerManager.jsonResponse; import static site.deercloud.identityverification.Utils.Utils.*; @@ -21,8 +22,7 @@ public class GetOnlineProfile implements HttpHandler { return; } - String query = exchange.getRequestURI().getQuery(); - Map params = ParseQueryString(query); + Map params = getQuery(exchange); String name = params.get("name"); String UUID = getUUIDFromRemote(name); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/Registration.java b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/Registration.java index 07cb618..fb27a24 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/Registration.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/Registration.java @@ -3,19 +3,24 @@ package site.deercloud.identityverification.HttpServer.Api.Register; import com.alibaba.fastjson.JSONObject; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; +import org.apache.commons.lang.StringEscapeUtils; import site.deercloud.identityverification.Controller.EmailCodeCache; import site.deercloud.identityverification.HttpServer.model.Profile; import site.deercloud.identityverification.HttpServer.model.Texture; import site.deercloud.identityverification.HttpServer.model.User; +import site.deercloud.identityverification.IdentityVerification; import site.deercloud.identityverification.SQLite.InviteCodeDAO; import site.deercloud.identityverification.SQLite.InviteRelationDAO; import site.deercloud.identityverification.SQLite.ProfileDAO; import site.deercloud.identityverification.SQLite.UserDAO; import site.deercloud.identityverification.Utils.MyLogger; +import java.io.BufferedReader; +import java.io.InputStreamReader; import java.sql.Connection; import java.util.UUID; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; import static site.deercloud.identityverification.HttpServer.HttpServerManager.jsonResponse; import static site.deercloud.identityverification.SQLite.SqlManager.getConnection; import static site.deercloud.identityverification.Utils.Utils.*; @@ -31,7 +36,7 @@ public class Registration implements HttpHandler { return; } - JSONObject jsonObject = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject jsonObject = getBody(exchange); String email = jsonObject.getString("email"); String password = jsonObject.getString("password"); @@ -41,18 +46,21 @@ public class Registration implements HttpHandler { String profile_name = jsonObject.getString("profile_name"); + // 验证邮箱验证码 if (EmailCodeCache.isEmailCodeExpired(email)) { - jsonResponse(exchange, 500, "验证码无效,请重新获取。", null); + jsonResponse(exchange, 500, "邮箱验证码无效,请重新获取。", null); return; } if (!EmailCodeCache.isEmailCodeValid(email, active_code)) { jsonResponse(exchange, 500, "验证码错误!", null); return; } + // 验证昵称可用性 if (getUUIDFromRemote(profile_name) != null){ jsonResponse(exchange, 400, "此昵称已有正版玩家使用,为避免ID碰撞请改名。", null); return; } + // 验证邀请码可用性 Connection connection = getConnection(); if (!InviteCodeDAO.isValid(connection, inviteCode)) { jsonResponse(exchange, 400, "邀请码不存在或已被使用!", null); @@ -62,15 +70,20 @@ public class Registration implements HttpHandler { String inviteCodeOwner = InviteCodeDAO.getInviterUUID(connection, inviteCode); // 创建邀请关系 InviteRelationDAO.insert(connection, new_uuid, inviteCodeOwner, System.currentTimeMillis()); + MyLogger.debug("邀请关系已建立,邀请人:" + inviteCodeOwner + ",被邀请人:" + new_uuid); // 标记邀请码已使用 InviteCodeDAO.setUsed(connection, inviteCode, true, System.currentTimeMillis()); + MyLogger.debug("邀请码已标记为已使用:" + inviteCode); + // 创建用户 User user = new User(); user.uuid = new_uuid; user.email = email; user.password = password; UserDAO.insert(connection, user); + MyLogger.debug("用户注册成功:" + user.uuid); + // 创建一个默认角色 Profile profile = new Profile(); profile.name = profile_name; profile.uuid = UUID.randomUUID().toString(); @@ -79,6 +92,7 @@ public class Registration implements HttpHandler { profile.textures = texture.serialWithBase64(); profile.textures_signature = texture.sign(); ProfileDAO.insert(connection, profile); + MyLogger.debug("角色创建成功:" + profile.uuid); jsonResponse(exchange, 200, "注册成功!", null); } catch (Exception e) { diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/VerifyCode.java b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/VerifyCode.java index 01b7a7e..646e2d9 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/VerifyCode.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Api/Register/VerifyCode.java @@ -15,9 +15,8 @@ import java.sql.SQLException; import java.util.Map; import java.util.UUID; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getQuery; import static site.deercloud.identityverification.HttpServer.HttpServerManager.jsonResponse; -import static site.deercloud.identityverification.Utils.Utils.ParseQueryString; - public class VerifyCode implements HttpHandler { @Override public void handle(HttpExchange exchange){ @@ -27,8 +26,7 @@ public class VerifyCode implements HttpHandler { jsonResponse(exchange, 405, "Method Not Allowed", null); return; } - String query = exchange.getRequestURI().getQuery(); - Map params = ParseQueryString(query); + Map params = getQuery(exchange); String code = params.get("code"); Connection conn = SqlManager.getConnection(); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Api/SignWhiteList.java b/src/main/java/site/deercloud/identityverification/HttpServer/Api/SignWhiteList.java index 4f7ebf4..cba0d18 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Api/SignWhiteList.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Api/SignWhiteList.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.sql.Connection; import java.util.Objects; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; import static site.deercloud.identityverification.HttpServer.HttpServerManager.jsonResponse; import static site.deercloud.identityverification.SQLite.SqlManager.getConnection; import static site.deercloud.identityverification.Utils.Utils.*; @@ -27,7 +28,7 @@ public class SignWhiteList implements HttpHandler { jsonResponse(exchange, 405, "Method Not Allowed", null); return; } - JSONObject jsonObject = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject jsonObject = getBody(exchange); Connection connection = getConnection(); String id = jsonObject.getString("id"); // 身份证(实名认证用) diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/HttpServerManager.java b/src/main/java/site/deercloud/identityverification/HttpServer/HttpServerManager.java index c249ea9..00218a3 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/HttpServerManager.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/HttpServerManager.java @@ -1,8 +1,10 @@ package site.deercloud.identityverification.HttpServer; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpServer; +import site.deercloud.identityverification.HttpServer.Api.Register.GetEmailCode; import site.deercloud.identityverification.HttpServer.Api.Register.GetOnlineProfile; import site.deercloud.identityverification.HttpServer.Api.Register.Registration; import site.deercloud.identityverification.HttpServer.Api.Register.VerifyCode; @@ -18,8 +20,15 @@ import site.deercloud.identityverification.IdentityVerification; import site.deercloud.identityverification.Controller.ConfigManager; import site.deercloud.identityverification.Utils.MyLogger; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; import java.net.InetSocketAddress; +import java.net.URLDecoder; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -54,6 +63,8 @@ public class HttpServerManager { webServer.createContext("/api/getInviter", new GetInviter()); // 登记白名单 webServer.createContext("/api/signWhiteList", new SignWhiteList()); + // 获取邮箱验证码 + webServer.createContext("/api/getEmailCode", new GetEmailCode()); // Yggdrasil API 元数据 yagServer.createContext("/", new MetaData()); @@ -110,6 +121,49 @@ public class HttpServerManager { exchange.getResponseBody().close(); } + public static JSONObject getBody(HttpExchange exchange) throws IOException { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(exchange.getRequestBody(), "utf-8")); + StringBuilder requestBodyContent = new StringBuilder(); + String line = null; + while ((line = bufferedReader.readLine()) != null) { + requestBodyContent.append(line); + } + MyLogger.debug(requestBodyContent.toString()); + return JSONObject.parseObject(requestBodyContent.toString()); + } + + public static JSONArray getBodyArray(HttpExchange exchange) throws IOException { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(exchange.getRequestBody(), "utf-8")); + StringBuilder requestBodyContent = new StringBuilder(); + String line = null; + while ((line = bufferedReader.readLine()) != null) { + requestBodyContent.append(line); + } + MyLogger.debug(requestBodyContent.toString()); + return JSONObject.parseArray(requestBodyContent.toString()); + } + + public static Map getQuery(HttpExchange exchange){ + String query_string = exchange.getRequestURI().getQuery(); + Map result = new HashMap<>(); + if(query_string== null || query_string.trim().length() == 0) { + return result; + } + final String[] items = query_string.split("&"); + Arrays.stream(items).forEach(item ->{ + final String[] keyAndVal = item.split("="); + if( keyAndVal.length == 2) { + try{ + final String key = URLDecoder.decode( keyAndVal[0],"utf8"); + final String val = URLDecoder.decode( keyAndVal[1],"utf8"); + MyLogger.debug(key + " : " + val); + result.put(key,val); + }catch (UnsupportedEncodingException ignored) {} + } + }); + return result; + } + public static SessionTokenCache getSessionCache() { return sessionTokenCache; } diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Authenticate.java b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Authenticate.java index b8e0bc9..04fb1a6 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Authenticate.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Authenticate.java @@ -19,6 +19,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.UUID; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; import static site.deercloud.identityverification.SQLite.SqlManager.getConnection; import static site.deercloud.identityverification.HttpServer.model.Response.*; @@ -32,7 +33,7 @@ public class Authenticate implements HttpHandler { Response.err_method_not_allowed(exchange); return; } - JSONObject body = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject body = getBody(exchange); String username = body.getString("username"); // 邮箱(或其他凭证) String password = body.getString("password"); // 密码 String clientToken = body.getString("clientToken"); // 由客户端指定的令牌的 clientToken(可选) diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Invalidate.java b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Invalidate.java index 136ee83..9284c29 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Invalidate.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Invalidate.java @@ -12,6 +12,8 @@ import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; + public class Invalidate implements HttpHandler { @Override public void handle(HttpExchange exchange) { @@ -21,7 +23,7 @@ public class Invalidate implements HttpHandler { Response.err_method_not_allowed(exchange); return; } - JSONObject request = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject request = getBody(exchange); String accessToken = request.getString("accessToken"); String clientToken = request.getString("clientToken"); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Refresh.java b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Refresh.java index 3afe21a..8614cbc 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Refresh.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Refresh.java @@ -17,6 +17,8 @@ import java.sql.SQLException; import java.util.Objects; import java.util.UUID; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; + public class Refresh implements HttpHandler { @Override public void handle(HttpExchange exchange) { @@ -28,7 +30,7 @@ public class Refresh implements HttpHandler { return; } Connection connection = SqlManager.getConnection(); - JSONObject body = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject body = getBody(exchange); String accessToken = body.getString("accessToken"); String clientToken = body.getString("clientToken"); Boolean requestUser = body.getBoolean("requestUser"); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/SignOut.java b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/SignOut.java index f4adbc5..da301b4 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/SignOut.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/SignOut.java @@ -17,6 +17,8 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; + public class SignOut implements HttpHandler { @Override public void handle(HttpExchange exchange) { @@ -26,7 +28,7 @@ public class SignOut implements HttpHandler { Response.err_method_not_allowed(exchange); return; } - JSONObject request = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject request = getBody(exchange); String username = request.getString("username"); String password = request.getString("password"); Connection connection = SqlManager.getConnection(); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Validate.java b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Validate.java index b185c8c..66bb1ed 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Validate.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/authserver/Validate.java @@ -14,6 +14,8 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.Objects; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; + public class Validate implements HttpHandler { @Override public void handle(HttpExchange exchange) throws IOException { @@ -24,7 +26,7 @@ public class Validate implements HttpHandler { return; } Connection connection = SqlManager.getConnection(); - JSONObject request = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject request = getBody(exchange); String accessToken = request.getString("accessToken"); String clientToken = request.getString("clientToken"); Token token = TokenDAO.selectByAccessToken(connection, accessToken); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/GetProfile.java b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/GetProfile.java index dc0459c..e09a0b4 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/GetProfile.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/GetProfile.java @@ -13,7 +13,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.Map; -import static site.deercloud.identityverification.Utils.Utils.ParseQueryString; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getQuery; public class GetProfile implements HttpHandler { @Override @@ -25,7 +25,7 @@ public class GetProfile implements HttpHandler { return; } String uuid = exchange.getRequestURI().getPath().split("/")[4]; - Map request = ParseQueryString(exchange.getRequestURI().getQuery()); + Map request = getQuery(exchange); boolean unsigned = true; if (request.containsKey("unsigned")) { unsigned = Boolean.parseBoolean(request.get("unsigned")); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/HasJoined.java b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/HasJoined.java index d09ec9e..6c10e8f 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/HasJoined.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/HasJoined.java @@ -15,7 +15,7 @@ import java.sql.Connection; import java.util.Map; import java.util.Objects; -import static site.deercloud.identityverification.Utils.Utils.ParseQueryString; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getQuery; public class HasJoined implements HttpHandler { @@ -27,7 +27,7 @@ public class HasJoined implements HttpHandler { Response.err_method_not_allowed(exchange); return; } - Map query = ParseQueryString(exchange.getRequestURI().getQuery()); + Map query = getQuery(exchange); String username = query.get("username"); String serverId = query.get("serverId"); String ip = query.get("ip"); diff --git a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/Join.java b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/Join.java index 14a7718..c0f3c82 100644 --- a/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/Join.java +++ b/src/main/java/site/deercloud/identityverification/HttpServer/Yggdrasil/sessionserver/Join.java @@ -14,6 +14,8 @@ import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; +import static site.deercloud.identityverification.HttpServer.HttpServerManager.getBody; + public class Join implements HttpHandler { @Override public void handle(HttpExchange exchange){ @@ -23,7 +25,7 @@ public class Join implements HttpHandler { Response.err_method_not_allowed(exchange); return; } - JSONObject request = JSONObject.parseObject(exchange.getRequestBody().toString()); + JSONObject request = getBody(exchange); String accessToken = request.getString("accessToken"); String selectedProfile = request.getString("selectedProfile"); String serverId = request.getString("serverId"); diff --git a/src/main/java/site/deercloud/identityverification/IdentityVerification.java b/src/main/java/site/deercloud/identityverification/IdentityVerification.java index 574ee3b..81a6752 100644 --- a/src/main/java/site/deercloud/identityverification/IdentityVerification.java +++ b/src/main/java/site/deercloud/identityverification/IdentityVerification.java @@ -9,9 +9,11 @@ import site.deercloud.identityverification.SQLite.SqlManager; import site.deercloud.identityverification.SQLite.UserDAO; import site.deercloud.identityverification.Controller.AFKTracker; import site.deercloud.identityverification.Controller.ConfigManager; +import site.deercloud.identityverification.Utils.FileToString; import site.deercloud.identityverification.Utils.MyLogger; import site.deercloud.identityverification.Controller.GameSessionCache; +import java.io.FileReader; import java.sql.Connection; import java.sql.SQLException; import java.util.UUID; @@ -41,20 +43,31 @@ public final class IdentityVerification extends JavaPlugin { } connection.close(); } catch (SQLException e) { - throw new RuntimeException(e); + MyLogger.debug(e); } // 初始化RSA - String publicKey = new File(this.getDataFolder(), configManager.getPublicKeyFileName()).toString(); - String privateKey = new File(this.getDataFolder(), configManager.getPrivateKeyFileName()).toString(); - if (publicKey == null || privateKey == null) { + File publicKeyPath = new File(this.getDataFolder(), configManager.getPublicKeyFileName()); + File privateKeyPath = new File(this.getDataFolder(), configManager.getPrivateKeyFileName()); + String pubKeyContent = FileToString.Read(publicKeyPath); + String priKeyContent = FileToString.Read(privateKeyPath); + if (pubKeyContent == null || priKeyContent == null) { MyLogger.error("RSA文件不存在, 插件退出。"); this.getServer().getPluginManager().disablePlugin(this); }else { - privateKey = privateKey.replace("-----BEGIN OPENSSH PRIVATE KEY-----", ""); - privateKey = privateKey.replace("-----END OPENSSH PRIVATE KEY-----", ""); - configManager.setSignaturePublicKey(publicKey); - configManager.setSignaturePrivateKey(privateKey); + pubKeyContent = pubKeyContent.replace("-----BEGIN PUBLIC KEY-----", "") + .replace("-----END PUBLIC KEY-----", "") + .replace("\n", ""); + priKeyContent = priKeyContent.replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replace("\n", ""); + MyLogger.debug("publicKey: " + pubKeyContent); + MyLogger.debug("privateKey: " + priKeyContent); + configManager.setSignaturePublicKey(pubKeyContent); + configManager.setSignaturePrivateKey(priKeyContent); } + // 注册事件 指令 + this.getServer().getPluginManager().registerEvents(new Events(), this); + this.getCommand("identityverification").setExecutor(new Commands()); } diff --git a/src/main/java/site/deercloud/identityverification/SQLite/InviteCodeDAO.java b/src/main/java/site/deercloud/identityverification/SQLite/InviteCodeDAO.java index 265f660..3db90c8 100644 --- a/src/main/java/site/deercloud/identityverification/SQLite/InviteCodeDAO.java +++ b/src/main/java/site/deercloud/identityverification/SQLite/InviteCodeDAO.java @@ -3,6 +3,7 @@ package site.deercloud.identityverification.SQLite; import site.deercloud.identityverification.HttpServer.model.InviteCode; import java.sql.*; +import java.util.HashSet; import java.util.Set; public class InviteCodeDAO { @@ -77,7 +78,7 @@ public class InviteCodeDAO { PreparedStatement prep = con.prepareStatement(sql); prep.setString(1, inviterUUID); ResultSet rs = prep.executeQuery(); - Set inviteCodes = null; + Set inviteCodes = new HashSet<>(); while (rs.next()) { InviteCode inviteCode = new InviteCode(); inviteCode.code = rs.getString("code"); diff --git a/src/main/java/site/deercloud/identityverification/SQLite/ProfileDAO.java b/src/main/java/site/deercloud/identityverification/SQLite/ProfileDAO.java index f8295f3..3e195f9 100644 --- a/src/main/java/site/deercloud/identityverification/SQLite/ProfileDAO.java +++ b/src/main/java/site/deercloud/identityverification/SQLite/ProfileDAO.java @@ -15,8 +15,8 @@ public class ProfileDAO { + " name text NOT NULL,\n" // 玩家名字 + " textures text NOT NULL,\n" // 材质 + " textures_signature text NOT NULL,\n" // 材质签名 - + " uploadableTextures text NOT NULL,\n" // 可上传的材质 - + " uploadableTextures_signature text NOT NULL,\n" // 可上传的材质签名 + + " uploadableTextures text ,\n" // 可上传的材质 + + " uploadableTextures_signature text ,\n" // 可上传的材质签名 + " update_time integer NOT NULL\n" // 数据更新时间 + ");"; PreparedStatement preparedStatement = connection.prepareStatement(sql); diff --git a/src/main/java/site/deercloud/identityverification/SQLite/SqlManager.java b/src/main/java/site/deercloud/identityverification/SQLite/SqlManager.java index 518189b..8c65ab2 100644 --- a/src/main/java/site/deercloud/identityverification/SQLite/SqlManager.java +++ b/src/main/java/site/deercloud/identityverification/SQLite/SqlManager.java @@ -7,17 +7,34 @@ import java.sql.*; public class SqlManager { + public SqlManager() throws SQLException { + SQLiteConfig config = new SQLiteConfig(); + config.setSharedCache(true); + config.enableRecursiveTriggers(true); + config.setBusyTimeout(10000); + SQLiteDataSource ds = new SQLiteDataSource(config); + String url = System.getProperty("user.dir"); // 获取工作目录 + ds.setUrl("jdbc:sqlite:"+url+"/plugins/IdentityVerification/"+"IV-Database.db"); + session = ds.getConnection(); + } + + public static Connection session; + public static Connection getConnection(){ - try { - SQLiteConfig config = new SQLiteConfig(); - config.setSharedCache(true); - config.enableRecursiveTriggers(true); - SQLiteDataSource ds = new SQLiteDataSource(config); - String url = System.getProperty("user.dir"); // 获取工作目录 - ds.setUrl("jdbc:sqlite:"+url+"/plugins/IdentityVerification/"+"IV-Database.db"); - return ds.getConnection(); - } catch (SQLException e) { - throw new RuntimeException(e); + // 加锁 防止多线程同时访问 + synchronized (SqlManager.class) { + try { + SQLiteConfig config = new SQLiteConfig(); + config.setSharedCache(true); + config.enableRecursiveTriggers(true); + config.setBusyTimeout(10000); + SQLiteDataSource ds = new SQLiteDataSource(config); + String url = System.getProperty("user.dir"); // 获取工作目录 + ds.setUrl("jdbc:sqlite:"+url+"/plugins/IdentityVerification/"+"IV-Database.db"); + return ds.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } } } diff --git a/src/main/java/site/deercloud/identityverification/SQLite/UserDAO.java b/src/main/java/site/deercloud/identityverification/SQLite/UserDAO.java index 00db003..b3f939c 100644 --- a/src/main/java/site/deercloud/identityverification/SQLite/UserDAO.java +++ b/src/main/java/site/deercloud/identityverification/SQLite/UserDAO.java @@ -22,7 +22,7 @@ public class UserDAO { } public static void insert(Connection con, User user) throws SQLException { - String sql = "INSERT INTO user(uuid, email, password, create_time, update_time) VALUES(?,?,?,?,?,?)"; + String sql = "INSERT INTO user(uuid, email, password, create_time, update_time) VALUES(?,?,?,?,?)"; PreparedStatement prep = con.prepareStatement(sql); prep.setString(1, user.uuid); prep.setString(2, user.email); @@ -90,9 +90,10 @@ public class UserDAO { } public static Boolean isEmailExist(Connection con, String email) throws SQLException { - String sql = "SELECT * FROM user WHERE email = ?"; + String sql = "SELECT count(*) FROM user WHERE email = ?"; PreparedStatement prep = con.prepareStatement(sql); - return prep.executeQuery().next(); + prep.setString(1, email); + return prep.executeQuery().getInt(1) > 0; } } diff --git a/src/main/java/site/deercloud/identityverification/Utils/EmailSender.java b/src/main/java/site/deercloud/identityverification/Utils/EmailSender.java index ac08688..f742a5e 100644 --- a/src/main/java/site/deercloud/identityverification/Utils/EmailSender.java +++ b/src/main/java/site/deercloud/identityverification/Utils/EmailSender.java @@ -38,13 +38,15 @@ public class EmailSender { try { // 1. 创建参数配置, 用于连接邮件服务器的参数配置 Properties props = new Properties(); // 参数配置 + props.setProperty("mail.debug", "false"); + props.setProperty("mail.transport.protocol", "smtp"); // 使用的协议(JavaMail规范要求) props.setProperty("mail.smtp.host", host); // 发件人的邮箱的 SMTP 服务器地址 props.setProperty("mail.smtp.auth", "true"); // 需要请求认证 props.setProperty("mail.smtp.port", port); + props.setProperty("mail.smtp.ssl.enable", "true"); props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.setProperty("mail.smtp.socketFactory.fallback", "false"); - props.setProperty("mail.smtp.socketFactory.port", port); // 2. 根据配置创建会话对象, 用于和邮件服务器交互 Session session = Session.getInstance(props); @@ -52,7 +54,7 @@ public class EmailSender { // 3. 创建一封邮件 MimeMessage message = new MimeMessage(session); - message.setFrom(new InternetAddress(from, "IdentityVerification", "UTF-8")); // 发件人 + message.setFrom(new InternetAddress(from, account, "UTF-8")); // 发件人 message.setRecipient(Message.RecipientType.TO, new InternetAddress(to, "no-reply", "UTF-8")); // 收件人 message.setSubject(subject, "UTF-8"); // 邮件主题 message.setContent(content, "text/html;charset=UTF-8"); // 邮件正文(可以使用html标签) diff --git a/src/main/java/site/deercloud/identityverification/Utils/FileToString.java b/src/main/java/site/deercloud/identityverification/Utils/FileToString.java new file mode 100644 index 0000000..501bf0e --- /dev/null +++ b/src/main/java/site/deercloud/identityverification/Utils/FileToString.java @@ -0,0 +1,22 @@ +package site.deercloud.identityverification.Utils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; + +public class FileToString { + + public static String Read(File file){ + try (FileReader fileReader = new FileReader(file)) { + char[] chars = new char[(int) file.length()]; + if (fileReader.read(chars) != -1) { + return new String(chars); + } + return new String(chars); + } catch (Exception e) { + MyLogger.debug(e); + return null; + } + } + +} diff --git a/src/main/java/site/deercloud/identityverification/Utils/MyLogger.java b/src/main/java/site/deercloud/identityverification/Utils/MyLogger.java index 1eb2f48..374faae 100644 --- a/src/main/java/site/deercloud/identityverification/Utils/MyLogger.java +++ b/src/main/java/site/deercloud/identityverification/Utils/MyLogger.java @@ -28,6 +28,7 @@ public class MyLogger { public static void debug(Exception e) { if (plugin.getConfigManager().getDebug()) { plugin.getLogger().info(ChatColor.AQUA + "| " + e.getMessage()); + e.printStackTrace(); } } diff --git a/src/main/java/site/deercloud/identityverification/Utils/SignatureUtil.java b/src/main/java/site/deercloud/identityverification/Utils/SignatureUtil.java index 9572581..cb5eb7b 100644 --- a/src/main/java/site/deercloud/identityverification/Utils/SignatureUtil.java +++ b/src/main/java/site/deercloud/identityverification/Utils/SignatureUtil.java @@ -6,7 +6,7 @@ import java.io.StringWriter; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; -import java.util.Base64; +import org.apache.commons.codec.binary.Base64; public class SignatureUtil { private final static String SIGN_TYPE_RSA = "RSA"; @@ -24,10 +24,10 @@ public class SignatureUtil { if (algorithm == null || "".equals(algorithm) || priKey == null || "".equals(priKey)) return null; - KeyFactory keyFactory = KeyFactory.getInstance(algorithm); + KeyFactory keyFactory = KeyFactory.getInstance(algorithm); // 获取密钥工厂 byte[] encodedKey = StreamUtil.readText(new ByteArrayInputStream(priKey.getBytes())).getBytes(); - encodedKey = Base64.getDecoder().decode(priKey.getBytes()); + encodedKey = Base64.decodeBase64(priKey.getBytes()); return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey)); } @@ -49,7 +49,7 @@ public class SignatureUtil { StreamUtil.io(new InputStreamReader(new ByteArrayInputStream(pubKey.getBytes())), writer); byte[] encodeByte = writer.toString().getBytes(); - encodeByte = Base64.getDecoder().decode(pubKey.getBytes()); + encodeByte = Base64.decodeBase64(pubKey.getBytes()); return keyFactory.generatePublic(new X509EncodedKeySpec(encodeByte)); } @@ -71,7 +71,7 @@ public class SignatureUtil { signature.update(plain.getBytes(CHARSETTING)); byte[] signed = signature.sign(); - return new String(Base64.getEncoder().encode(signed)); + return new String(Base64.encodeBase64(signed)); } /** @@ -91,6 +91,6 @@ public class SignatureUtil { signature.initVerify(publicKey); signature.update(plain.getBytes(CHARSETTING)); - return signature.verify(Base64.getDecoder().decode(sign.getBytes())); + return signature.verify(Base64.decodeBase64(sign.getBytes())); } } diff --git a/src/main/java/site/deercloud/identityverification/Utils/StreamUtil.java b/src/main/java/site/deercloud/identityverification/Utils/StreamUtil.java index b2d8c8b..2a74530 100644 --- a/src/main/java/site/deercloud/identityverification/Utils/StreamUtil.java +++ b/src/main/java/site/deercloud/identityverification/Utils/StreamUtil.java @@ -47,8 +47,7 @@ public class StreamUtil { return readText(in, encoding, -1); } - public static String readText(InputStream in, String encoding, int bufferSize) - throws IOException { + public static String readText(InputStream in, String encoding, int bufferSize) throws IOException { Reader reader = (encoding == null) ? new InputStreamReader(in) : new InputStreamReader(in, encoding); diff --git a/src/main/java/site/deercloud/identityverification/Utils/Utils.java b/src/main/java/site/deercloud/identityverification/Utils/Utils.java index e5343de..7030801 100644 --- a/src/main/java/site/deercloud/identityverification/Utils/Utils.java +++ b/src/main/java/site/deercloud/identityverification/Utils/Utils.java @@ -13,24 +13,24 @@ import java.util.*; public class Utils { - public static Map ParseQueryString(String formData ) { - Map result = new HashMap<>(); - if(formData== null || formData.trim().length() == 0) { - return result; - } - final String[] items = formData.split("&"); - Arrays.stream(items).forEach(item ->{ - final String[] keyAndVal = item.split("="); - if( keyAndVal.length == 2) { - try{ - final String key = URLDecoder.decode( keyAndVal[0],"utf8"); - final String val = URLDecoder.decode( keyAndVal[1],"utf8"); - result.put(key,val); - }catch (UnsupportedEncodingException ignored) {} - } - }); - return result; - } +// public static Map ParseQueryString(String formData ) { +// Map result = new HashMap<>(); +// if(formData== null || formData.trim().length() == 0) { +// return result; +// } +// final String[] items = formData.split("&"); +// Arrays.stream(items).forEach(item ->{ +// final String[] keyAndVal = item.split("="); +// if( keyAndVal.length == 2) { +// try{ +// final String key = URLDecoder.decode( keyAndVal[0],"utf8"); +// final String val = URLDecoder.decode( keyAndVal[1],"utf8"); +// result.put(key,val); +// }catch (UnsupportedEncodingException ignored) {} +// } +// }); +// return result; +// } /** * 根据玩家名字从Mojiang服务器获取UUID,如果不存在则返回null diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 40b9a3a..ca1529a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -7,3 +7,9 @@ load: STARTUP authors: [ Luming ] description: 实名认证添加白名单、正版玩家邀请非正版注册管理。 website: https://blog.deercloud.site +commands: + identityverification: + description: 实名认证插件 + usage: /iv + aliases: [iv] + plugin: IdentityVerification diff --git a/src/web/src/components/Registration.vue b/src/web/src/components/Registration.vue index 5da9f83..26f3e59 100644 --- a/src/web/src/components/Registration.vue +++ b/src/web/src/components/Registration.vue @@ -7,21 +7,21 @@ + + + + + + - - + + - {{send_code_text}} - - - - - - + {{profile_name_text}} @@ -36,6 +36,18 @@ {{verify_invite_code_text}} + + + + + + + + + + {{send_code_text}} + + @@ -57,6 +69,7 @@ const invite_code = ref('') const send_code_text = ref('发送验证码') const verify_invite_code_text = ref('验证邀请码') +const profile_name_text = ref('验证可用性') const onSubmit = () => {