add ratelimit

This commit is contained in:
muhammadeko 2022-06-01 10:40:05 +07:00
parent 738a642dba
commit de6438e063
No known key found for this signature in database
GPG Key ID: 51366716C10E98B1
5 changed files with 50 additions and 10 deletions

View File

@ -46,4 +46,16 @@ Grasscutter Authentication System
- `jwt` : JWT token if success with body :
- `token` : Token used for authentication, paste it in username field of client.
- `username` : Username of the user.
- `uid` : UID of the user.
- `uid` : UID of the user.
## Config :
- hash : Hash algorithm used for password hashing. (Only Bcrypt and Scrypt is supported)
- jwtSecret : Secret used for JWT token.
- jwtExpiration : Expiration time of JWT token.
- otpExpiration : Expiration time of OTP.
- defaultPermission : Default permission of user.
- accessKey : Access key used for access control. (Optional)
- rateLimit :
- maxRequests : Maximum requests per timeUnit.
- timeUnit : Time unit of rateLimit. (seconds, minutes, hours, days)
- endPoints[] : Endpoint to rate limit. (login, register, change_password)

View File

@ -10,7 +10,7 @@ sourceCompatibility = 17
targetCompatibility = 17
group 'me.exzork.gcauth'
version '2.3.1'
version '2.4.0'
repositories {
mavenCentral()

View File

@ -3,10 +3,16 @@ package me.exzork.gcauth;
import me.exzork.gcauth.utils.Authentication;
public final class Config {
public String Hash = "BCRYPT";
public String hash = "BCRYPT";
public String jwtSecret = Authentication.generateRandomString(32);
public long jwtExpiration = 86400;
public long otpExpiration = 300;
public String[] defaultPermissions = new String[]{""};
public String accessKey = "";
public RateLimit rateLimit = new RateLimit();
public static class RateLimit {
public int maxRequests = 10;
public String timeUnit = "MINUTES";
public String[] endPoints = new String[]{"login","register","change_password"};
}
}

View File

@ -1,12 +1,15 @@
package me.exzork.gcauth.handler;
import com.google.gson.Gson;
import com.mchange.v1.util.ArrayUtils;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.auth.AuthenticationSystem;
import emu.grasscutter.auth.ExternalAuthenticator;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account;
import express.http.Response;
import io.javalin.http.Context;
import io.javalin.http.util.RateLimit;
import me.exzork.gcauth.GCAuth;
import me.exzork.gcauth.json.AuthResponseJson;
import me.exzork.gcauth.json.ChangePasswordAccount;
@ -14,13 +17,20 @@ import me.exzork.gcauth.json.LoginGenerateToken;
import me.exzork.gcauth.json.RegisterAccount;
import me.exzork.gcauth.utils.Authentication;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
public class GCAuthExternalAuthenticator implements ExternalAuthenticator {
private String[] endPoints = GCAuth.getInstance().getConfig().rateLimit.endPoints;
private int maxRequests = GCAuth.getInstance().getConfig().rateLimit.maxRequests;
private String timeUnit = GCAuth.getInstance().getConfig().rateLimit.timeUnit;
@Override
public void handleLogin(AuthenticationSystem.AuthenticationRequest authenticationRequest) {
AuthResponseJson authResponse = new AuthResponseJson();
Response response = authenticationRequest.getResponse();
assert response != null; // This should never be null.
if (Arrays.asList(endPoints).contains("login"))
new RateLimit(response.ctx()).requestPerTimeUnit(maxRequests, Authentication.getTimeUnit(timeUnit));
try {
String requestBody = response.ctx().body();
if (requestBody.isEmpty()) {
@ -67,7 +77,8 @@ public class GCAuthExternalAuthenticator implements ExternalAuthenticator {
AuthResponseJson authResponse = new AuthResponseJson();
Response response = authenticationRequest.getResponse();
assert response != null; // This should never be null.
if (Arrays.asList(endPoints).contains("register"))
new RateLimit(response.ctx()).requestPerTimeUnit(maxRequests, Authentication.getTimeUnit(timeUnit));
Account account = null;
try {
String requestBody = response.ctx().body();
@ -145,7 +156,8 @@ public class GCAuthExternalAuthenticator implements ExternalAuthenticator {
AuthResponseJson authResponse = new AuthResponseJson();
Response response = authenticationRequest.getResponse();
assert response != null; // This should never be null.
if (Arrays.asList(endPoints).contains("change_password"))
new RateLimit(response.ctx()).requestPerTimeUnit(maxRequests, Authentication.getTimeUnit(timeUnit));
try {
String requestBody = response.ctx().body();
if (requestBody.isEmpty()) {
@ -172,12 +184,11 @@ public class GCAuthExternalAuthenticator implements ExternalAuthenticator {
account.save();
authResponse.success = true;
authResponse.message = "";
authResponse.jwt = "";
} else {
authResponse.success = false;
authResponse.message = "PASSWORD_INVALID"; // ENG = "Password must be at least 8 characters long"
authResponse.jwt = "";
}
authResponse.jwt = "";
}
} else {
authResponse.success = false;

View File

@ -13,6 +13,7 @@ import java.time.Instant;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
public final class Authentication {
public static final HashMap<String, String> otps = new HashMap<>();
@ -77,7 +78,7 @@ public final class Authentication {
}
public static String generateHash(String password) {
return switch (GCAuth.getInstance().getConfig().Hash.toLowerCase()) {
return switch (GCAuth.getInstance().getConfig().hash.toLowerCase()) {
case "bcrypt" -> new BCryptPasswordEncoder().encode(password);
case "scrypt" -> new SCryptPasswordEncoder().encode(password);
default -> password;
@ -85,7 +86,7 @@ public final class Authentication {
}
private static boolean verifyPassword(String password, String hash) {
return switch (GCAuth.getInstance().getConfig().Hash.toLowerCase()) {
return switch (GCAuth.getInstance().getConfig().hash.toLowerCase()) {
case "bcrypt" -> new BCryptPasswordEncoder().matches(password, hash);
case "scrypt" -> new SCryptPasswordEncoder().matches(password, hash);
default -> password.equals(hash);
@ -114,4 +115,14 @@ public final class Authentication {
}
},GCAuth.getInstance().getConfig().otpExpiration * 1000);
}
public static TimeUnit getTimeUnit(String timeUnit) {
return switch (timeUnit.toLowerCase()) {
case "seconds" -> TimeUnit.SECONDS;
case "minutes" -> TimeUnit.MINUTES;
case "hours" -> TimeUnit.HOURS;
case "days" -> TimeUnit.DAYS;
default -> TimeUnit.MINUTES;
};
}
}