diff --git a/pom.xml b/pom.xml index 3a09830..757a91e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,13 +6,13 @@ org.hff grasscutter-plugin - 1.2.2 + 1.4.0 17 17 UTF-8 - 1.2.3 + 1.3.2 0.11.5 0.5.10 1.18.24 @@ -25,7 +25,7 @@ grasscutter ${grasscutter.version} system - ${project.basedir}/lib/grasscutter-1.2.3-dev.jar + ${project.basedir}/lib/grasscutter-1.3.2-dev.jar @@ -49,7 +49,7 @@ net.jodah expiringmap - ${expiringmap.version} + ${expiringMap.version} diff --git a/src/main/java/org/hff/PluginHandler.java b/src/main/java/org/hff/PluginHandler.java index 35fbe60..b212b01 100644 --- a/src/main/java/org/hff/PluginHandler.java +++ b/src/main/java/org/hff/PluginHandler.java @@ -13,8 +13,7 @@ import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; import emu.grasscutter.utils.Position; -import express.http.Request; -import express.http.Response; +import io.javalin.http.Context; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import org.hff.api.ApiCode; @@ -39,29 +38,27 @@ public final class PluginHandler { - private final Request request; - private final Response response; + private final Context ctx; private final Locale locale; private final String token; private final String adminToken; - public PluginHandler(@NotNull Request request, @NotNull Response response) { - this.request = request; - this.response = response; - this.locale = LanguageManager.getLocale(request.get("locale")); - this.token = request.get("token"); - this.adminToken = request.get("admin_token"); + public PluginHandler(@NotNull Context ctx) { + this.ctx = ctx; + this.locale = LanguageManager.getLocale(ctx.req.getHeader("locale")); + this.token = ctx.req.getHeader("token"); + this.adminToken = ctx.req.getHeader("admin_token"); } public void adminAuth() { - String adminVoucher = request.body().get("adminVoucher").toString(); + String adminVoucher = ctx.queryParam("adminVoucher"); if (adminVoucher == null) { - response.json(ApiResult.result(ApiCode.PARAM_EMPTY_EXCEPTION, locale)); + ctx.json(ApiResult.result(ApiCode.PARAM_EMPTY_EXCEPTION, locale)); return; } if (!AuthUtil.checkAdminVoucher(adminVoucher)) { - response.json(ApiResult.result(ApiCode.AUTH_FAIL, locale)); + ctx.json(ApiResult.result(ApiCode.AUTH_FAIL, locale)); return; } @@ -74,19 +71,19 @@ public void adminCreateAccount() { return; } - AccountParam param = request.body(AccountParam.class); + AccountParam param = ctx.bodyAsClass(AccountParam.class); if (checkParamFail(param)) { return; } Account account = DatabaseHelper.getAccountByName(param.getUsername()); if (account != null) { - response.json(ApiResult.result(ApiCode.ACCOUNT_IS_EXIST, locale)); + ctx.json(ApiResult.result(ApiCode.ACCOUNT_IS_EXIST, locale)); return; } getAuthenticationSystem().createAccount(param.getUsername(), param.getPassword()); - response.json(ApiResult.success(locale)); + ctx.json(ApiResult.success(locale)); } public void adminCommand() { @@ -95,9 +92,9 @@ public void adminCommand() { return; } - String command = request.body().get("command").toString(); + String command = ctx.queryParam("command"); if (command == null) { - response.json(ApiResult.result(ApiCode.PARAM_EMPTY_EXCEPTION, locale)); + ctx.json(ApiResult.result(ApiCode.PARAM_EMPTY_EXCEPTION, locale)); return; } @@ -105,9 +102,9 @@ public void adminCommand() { } public void mailVerifyCode() { - String username = request.body().get("username").toString(); + String username = ctx.queryParam("username"); if (username == null) { - response.json(ApiResult.result(ApiCode.PARAM_EMPTY_EXCEPTION, locale)); + ctx.json(ApiResult.result(ApiCode.PARAM_EMPTY_EXCEPTION, locale)); return; } @@ -118,15 +115,15 @@ public void mailVerifyCode() { boolean flag = MailUtil.sendVerifyCodeMail(player, locale); if (!flag) { - response.json(ApiResult.result(ApiCode.MAIL_TIME_LIMIT, locale)); + ctx.json(ApiResult.result(ApiCode.MAIL_TIME_LIMIT, locale)); return; } - response.json(ApiResult.success(locale)); + ctx.json(ApiResult.success(locale)); } public void playerAuthByVerifyCode() { - AuthByVerifyCodeParam param = request.body(AuthByVerifyCodeParam.class); + AuthByVerifyCodeParam param = ctx.bodyAsClass(AuthByVerifyCodeParam.class); if (checkParamFail(param)) { return; } @@ -136,7 +133,7 @@ public void playerAuthByVerifyCode() { return; } - boolean flag = MailUtil.checkVerifyCode(account.getId(), param.getVerifyCode(), locale, response); + boolean flag = MailUtil.checkVerifyCode(account.getId(), param.getVerifyCode(), locale, ctx); if (!flag) { return; } @@ -145,7 +142,7 @@ public void playerAuthByVerifyCode() { } public void playerAuthByPassword() { - AccountParam param = request.body(AccountParam.class); + AccountParam param = ctx.bodyAsClass(AccountParam.class); if (checkParamFail(param)) { return; } @@ -156,7 +153,7 @@ public void playerAuthByPassword() { } if (!param.getPassword().equals(account.getPassword())) { - response.json(ApiResult.result(ApiCode.AUTH_FAIL, locale)); + ctx.json(ApiResult.result(ApiCode.AUTH_FAIL, locale)); return; } @@ -169,9 +166,9 @@ public void playerCommand() { return; } - String command = request.body().get("command").toString(); + String command = ctx.queryParam("command"); if (command == null) { - response.json(ApiResult.result(ApiCode.PARAM_EMPTY_EXCEPTION, locale)); + ctx.json(ApiResult.result(ApiCode.PARAM_EMPTY_EXCEPTION, locale)); return; } @@ -242,7 +239,7 @@ public void levelUpAllSkill() { } } - response.json(ApiResult.success(locale)); + ctx.json(ApiResult.success(locale)); } public void getProps() { @@ -279,7 +276,7 @@ public void getProps() { .setConstellation(avatar.getCoreProudSkillLevel()) .setFetterLevel(avatar.getFetterLevel()); - response.json(ApiResult.success(locale, propsVo)); + ctx.json(ApiResult.success(locale, propsVo)); } public void cdr() { @@ -306,13 +303,13 @@ public void cdr() { avatar.save(); } - response.json(ApiResult.success(locale)); + ctx.json(ApiResult.success(locale)); } private Claims parseAdminToken() { if (adminToken == null) { - response.json(ApiResult.result(ApiCode.TOKEN_NOT_FOUND, locale)); + ctx.json(ApiResult.result(ApiCode.TOKEN_NOT_FOUND, locale)); return null; } Claims claims = parseToken(adminToken); @@ -320,7 +317,7 @@ private Claims parseAdminToken() { return null; } if (!RoleEnum.ADMIN.getDesc().equals(claims.get("role").toString())) { - response.json(ApiResult.result(ApiCode.ROLE_ERROR, locale)); + ctx.json(ApiResult.result(ApiCode.ROLE_ERROR, locale)); return null; } return claims; @@ -328,7 +325,7 @@ private Claims parseAdminToken() { private Claims parsePlayerToken() { if (token == null) { - response.json(ApiResult.result(ApiCode.TOKEN_NOT_FOUND, locale)); + ctx.json(ApiResult.result(ApiCode.TOKEN_NOT_FOUND, locale)); return null; } return parseToken(token); @@ -338,9 +335,9 @@ private Claims parseToken(String token) { try { return JwtUtil.parseToken(token); } catch (ExpiredJwtException e) { - response.json(ApiResult.result(ApiCode.TOKEN_EXPIRED, locale)); + ctx.json(ApiResult.result(ApiCode.TOKEN_EXPIRED, locale)); } catch (Exception e) { - response.json(ApiResult.result(ApiCode.TOKEN_PARSE_EXCEPTION, locale)); + ctx.json(ApiResult.result(ApiCode.TOKEN_PARSE_EXCEPTION, locale)); } return null; } @@ -348,9 +345,9 @@ private Claims parseToken(String token) { private void generateToken(RoleEnum role, String accountId) { try { String token = JwtUtil.generateToken(role, accountId); - response.json(ApiResult.success(locale, token)); + ctx.json(ApiResult.success(locale, token)); } catch (Exception e) { - response.json(ApiResult.result(ApiCode.TOKEN_GENERATE_FAIL, locale, token)); + ctx.json(ApiResult.result(ApiCode.TOKEN_GENERATE_FAIL, locale, token)); } } @@ -361,11 +358,11 @@ private boolean checkParamFail(Object param) { try { Object object = field.get(param); if (object == null || object.toString().isEmpty()) { - response.json(ApiResult.result(ApiCode.PARAM_EMPTY_EXCEPTION, locale)); + ctx.json(ApiResult.result(ApiCode.PARAM_EMPTY_EXCEPTION, locale)); return true; } } catch (IllegalAccessException e) { - response.json(ApiResult.result(ApiCode.PARAM_ILLEGAL_EXCEPTION, locale)); + ctx.json(ApiResult.result(ApiCode.PARAM_ILLEGAL_EXCEPTION, locale)); return true; } } @@ -375,7 +372,7 @@ private boolean checkParamFail(Object param) { private Account getAccountByUsername(String username) { Account account = DatabaseHelper.getAccountByName(username); if (account == null) { - response.json(ApiResult.result(ApiCode.ACCOUNT_NOT_EXIST, locale)); + ctx.json(ApiResult.result(ApiCode.ACCOUNT_NOT_EXIST, locale)); } return account; } @@ -383,7 +380,7 @@ private Account getAccountByUsername(String username) { private Player getPlayerByAccountId(String accountId) { Player player = getGameServer().getPlayerByAccountId(accountId); if (player == null) { - response.json(ApiResult.result(ApiCode.PLAYER_NOT_ONLINE, locale)); + ctx.json(ApiResult.result(ApiCode.PLAYER_NOT_ONLINE, locale)); } return player; } @@ -395,7 +392,7 @@ private Player getPlayerByUsername(String username) { } Player player = getGameServer().getPlayerByAccountId(account.getId()); if (player == null) { - response.json(ApiResult.result(ApiCode.PLAYER_NOT_ONLINE, locale)); + ctx.json(ApiResult.result(ApiCode.PLAYER_NOT_ONLINE, locale)); } return player; } @@ -405,9 +402,9 @@ private void invokeCommand(Player player, String command, String accountId) { CommandMap.getInstance().invoke(player, player, command); String message = EventListeners.getMessage(accountId); if (message != null) { - response.json(ApiResult.success(message)); + ctx.json(ApiResult.success(message)); } else { - response.json(ApiResult.fail(locale)); + ctx.json(ApiResult.fail(locale)); } } } diff --git a/src/main/java/org/hff/PluginRouter.java b/src/main/java/org/hff/PluginRouter.java index 92d160f..c426a51 100644 --- a/src/main/java/org/hff/PluginRouter.java +++ b/src/main/java/org/hff/PluginRouter.java @@ -1,41 +1,40 @@ package org.hff; import emu.grasscutter.server.http.Router; -import express.Express; import io.javalin.Javalin; public final class PluginRouter implements Router { @Override - public void applyRoutes(Express express, Javalin javalin) { - express.get("/plugin/admin/auth", - (request, response) -> new PluginHandler(request, response).adminAuth()); + public void applyRoutes(Javalin javalin) { + javalin.get("/plugin/admin/auth", + ctx -> new PluginHandler(ctx).adminAuth()); - express.get("/plugin/admin/createAccount", - (request, response) -> new PluginHandler(request, response).adminCreateAccount()); + javalin.get("/plugin/admin/createAccount", + ctx -> new PluginHandler(ctx).adminCreateAccount()); - express.get("/plugin/admin/command", - (request, response) -> new PluginHandler(request, response).adminCommand()); + javalin.get("/plugin/admin/command", + ctx -> new PluginHandler(ctx).adminCommand()); - express.get("/plugin/mail/verifyCode", - (request, response) -> new PluginHandler(request, response).mailVerifyCode()); + javalin.get("/plugin/mail/verifyCode", + ctx -> new PluginHandler(ctx).mailVerifyCode()); - express.get("/plugin/player/authByVerifyCode", - (request, response) -> new PluginHandler(request, response).playerAuthByVerifyCode()); + javalin.get("/plugin/player/authByVerifyCode", + ctx -> new PluginHandler(ctx).playerAuthByVerifyCode()); - express.get("/plugin/player/authByPassword", - (request, response) -> new PluginHandler(request, response).playerAuthByPassword()); + javalin.get("/plugin/player/authByPassword", + ctx -> new PluginHandler(ctx).playerAuthByPassword()); - express.get("/plugin/player/command", - (request, response) -> new PluginHandler(request, response).playerCommand()); + javalin.get("/plugin/player/command", + ctx -> new PluginHandler(ctx).playerCommand()); - express.get("/plugin/player/levelUpAllSkill", - (request, response) -> new PluginHandler(request, response).levelUpAllSkill()); + javalin.get("/plugin/player/levelUpAllSkill", + ctx -> new PluginHandler(ctx).levelUpAllSkill()); - express.get("/plugin/player/getProps", - (request, response) -> new PluginHandler(request, response).getProps()); + javalin.get("/plugin/player/getProps", + ctx -> new PluginHandler(ctx).getProps()); - express.get("/plugin/player/cdr", - (request, response) -> new PluginHandler(request, response).cdr()); + javalin.get("/plugin/player/cdr", + ctx -> new PluginHandler(ctx).cdr()); } } diff --git a/src/main/java/org/hff/permission/Authentication.java b/src/main/java/org/hff/permission/Authentication.java index db61604..9b17694 100644 --- a/src/main/java/org/hff/permission/Authentication.java +++ b/src/main/java/org/hff/permission/Authentication.java @@ -15,6 +15,7 @@ public class Authentication implements AuthenticationSystem { private final Authenticator tokenAuthenticator = new DefaultAuthenticators.TokenAuthenticator(); private final Authenticator sessionKeyAuthenticator = new DefaultAuthenticators.SessionKeyAuthenticator(); private final ExternalAuthenticator externalAuthenticator = new DefaultAuthenticators.ExternalAuthentication(); + private final OAuthAuthenticator oAuthAuthenticator = new DefaultAuthenticators.OAuthAuthentication(); @Override public void createAccount(String username, String password) { @@ -58,6 +59,6 @@ public emu.grasscutter.auth.ExternalAuthenticator getExternalAuthenticator() { @Override public OAuthAuthenticator getOAuthAuthenticator() { - return null; + return this.oAuthAuthenticator; } } diff --git a/src/main/java/org/hff/permission/PasswordAuthenticator.java b/src/main/java/org/hff/permission/PasswordAuthenticator.java index 453b394..29fae0f 100644 --- a/src/main/java/org/hff/permission/PasswordAuthenticator.java +++ b/src/main/java/org/hff/permission/PasswordAuthenticator.java @@ -1,5 +1,6 @@ package org.hff.permission; +import at.favre.lib.crypto.bcrypt.BCrypt; import emu.grasscutter.auth.AuthenticationSystem; import emu.grasscutter.auth.Authenticator; import emu.grasscutter.database.DatabaseHelper; @@ -21,7 +22,7 @@ public LoginResultJson authenticate(AuthenticationSystem.AuthenticationRequest r assert requestData != null; var response = new LoginResultJson(); - String address = request.getRequest().ip(); + String address = request.getContext().ip(); response.retcode = -201; if (getGameServer().getPlayers().size() >= ACCOUNT.maxPlayer && ACCOUNT.maxPlayer > -1) { @@ -30,33 +31,44 @@ public LoginResultJson authenticate(AuthenticationSystem.AuthenticationRequest r return response; } - Account account = DatabaseHelper.getAccountByName(requestData.account); - if (account == null && !ACCOUNT.autoCreate) { - getLogger().info(translate("messages.dispatch.account.account_login_exist_error", address)); - response.message = translate("messages.dispatch.account.username_error"); + String password = requestData.password; + if (password == null) { + getLogger().info(translate("messages.dispatch.account.login_password_error", address)); + response.message = translate("messages.dispatch.account.password_error"); return response; } + try { + password = AuthUtil.decryptPassword(password); + } catch (Exception ignored) { + } + + Account account = DatabaseHelper.getAccountByName(requestData.account); if (account == null) { + if (!ACCOUNT.autoCreate) { + getLogger().info(translate("messages.dispatch.account.account_login_exist_error", address)); + response.message = translate("messages.dispatch.account.username_error"); + return response; + } + account = DatabaseHelper.createAccountWithUid(requestData.account, 0); if (account == null) { getLogger().info(translate("messages.dispatch.account.account_login_create_error", address)); response.message = translate("messages.dispatch.account.username_create_error"); return response; - } else { - getLogger().info(translate("messages.dispatch.account.account_login_create_success", address, response.data.account.uid)); } - } - if (account.getPassword() != null) { - try { - String password = AuthUtil.decryptPassword(requestData.password); - if (!password.equals(account.getPassword())) { + account.setPassword(BCrypt.withDefaults().hashToString(12, password.toCharArray())); + account.save(); + getLogger().info(translate("messages.dispatch.account.account_login_create_success", address, response.data.account.uid)); + } else { + String accountPassword = account.getPassword(); + if (accountPassword != null && !accountPassword.isEmpty()) { + if (!BCrypt.verifyer().verify(password.toCharArray(), accountPassword).verified && !accountPassword.equals(password)) { + getLogger().info(translate("messages.dispatch.account.login_password_error", address)); response.message = translate("messages.dispatch.account.password_error"); return response; } - } catch (Exception e) { - getLogger().error("Error with decrypt password: " + e.getMessage()); } } diff --git a/src/main/java/org/hff/utils/MailUtil.java b/src/main/java/org/hff/utils/MailUtil.java index f8c8b80..c2275ac 100644 --- a/src/main/java/org/hff/utils/MailUtil.java +++ b/src/main/java/org/hff/utils/MailUtil.java @@ -2,20 +2,21 @@ import emu.grasscutter.game.mail.Mail; import emu.grasscutter.game.player.Player; -import express.http.Response; +import io.javalin.http.Context; import lombok.Getter; import lombok.Setter; +import net.jodah.expiringmap.ExpiringMap; import org.hff.api.ApiCode; import org.hff.api.ApiResult; import org.hff.i18n.LanguageManager; import org.hff.i18n.Locale; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; public class MailUtil { - private static final Map verifyCodeMailMap = new ConcurrentHashMap<>(); + private static final Map verifyCodeMailMap = ExpiringMap.builder().expiration(2, TimeUnit.MINUTES).build(); public static boolean sendVerifyCodeMail(Player player, Locale locale) { String accountId = player.getAccount().getId(); @@ -36,17 +37,17 @@ public static boolean sendVerifyCodeMail(Player player, Locale locale) { return true; } - public static boolean checkVerifyCode(String accountId, String verifyCode, Locale locale, Response response) { + public static boolean checkVerifyCode(String accountId, String verifyCode, Locale locale, Context ctx) { VerifyCodeMail verifyCodeMail = verifyCodeMailMap.get(accountId); if (verifyCodeMail == null) { - response.json(ApiResult.result(ApiCode.MAIL_VERIFY_NOT_FOUND, locale)); + ctx.json(ApiResult.result(ApiCode.MAIL_VERIFY_NOT_FOUND, locale)); return false; } if (verifyCodeMail.getExpireTime() < System.currentTimeMillis()) { verifyCodeMailMap.remove(accountId); - response.json(ApiResult.result(ApiCode.MAIL_VERIFY_EXPIRED, locale)); + ctx.json(ApiResult.result(ApiCode.MAIL_VERIFY_EXPIRED, locale)); return false; } @@ -55,7 +56,7 @@ public static boolean checkVerifyCode(String accountId, String verifyCode, Local if (verifyCodeMail.getRetries() <= 0) { verifyCodeMailMap.remove(accountId); } - response.json(ApiResult.result(ApiCode.MAIL_VERIFY_FAIL, locale).setArgs(verifyCodeMail.getRetries())); + ctx.json(ApiResult.result(ApiCode.MAIL_VERIFY_FAIL, locale).setArgs(verifyCodeMail.getRetries())); return false; }