chore: unify checkstyle, fix violations, cleanup bin/
This commit is contained in:
parent
9c5e5bccae
commit
da9271b283
17 changed files with 363 additions and 67 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
id("com.gradleup.shadow") version "9.3.1" apply false
|
id("com.gradleup.shadow") version "9.3.1" apply false
|
||||||
|
checkstyle
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
|
|
@ -18,8 +19,24 @@ allprojects {
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
apply(plugin = "java")
|
apply(plugin = "java")
|
||||||
|
apply(plugin = "checkstyle")
|
||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkstyle {
|
||||||
|
toolVersion = "10.21.4"
|
||||||
|
configFile = rootProject.file("config/checkstyle/checkstyle.xml")
|
||||||
|
isIgnoreFailures = false
|
||||||
|
maxErrors = 0
|
||||||
|
maxWarnings = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<Checkstyle>().configureEach {
|
||||||
|
reports {
|
||||||
|
xml.required.set(true)
|
||||||
|
html.required.set(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,9 @@ public final class YamlConfig {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T get(final String key, final T defaultValue) {
|
public <T> T get(final String key, final T defaultValue) {
|
||||||
Object val = data.get(key);
|
Object val = data.get(key);
|
||||||
if (val == null) return defaultValue;
|
if (val == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return (T) val;
|
return (T) val;
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,11 @@ import dev.loki.loAuth.common.util.CodeGenerator;
|
||||||
import com.zaxxer.hikari.HikariConfig;
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -159,7 +163,9 @@ public final class DatabaseManager implements AutoCloseable {
|
||||||
throw new SQLException("INSERT returned no rows");
|
throw new SQLException("INSERT returned no rows");
|
||||||
} else {
|
} else {
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
if (rs.next()) return mapUser(rs);
|
if (rs.next()) {
|
||||||
|
return mapUser(rs);
|
||||||
|
}
|
||||||
throw new SQLException("INSERT returned no rows");
|
throw new SQLException("INSERT returned no rows");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -240,7 +246,9 @@ public final class DatabaseManager implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<String> consumeVerificationCode(final String code) {
|
public Optional<String> consumeVerificationCode(final String code) {
|
||||||
if (sqlite) return consumeDeleteSelect("pending_verifications", "code", code);
|
if (sqlite) {
|
||||||
|
return consumeDeleteSelect("pending_verifications", "code", code);
|
||||||
|
}
|
||||||
try (Connection conn = ds.getConnection();
|
try (Connection conn = ds.getConnection();
|
||||||
PreparedStatement ps = conn.prepareStatement("""
|
PreparedStatement ps = conn.prepareStatement("""
|
||||||
DELETE FROM pending_verifications
|
DELETE FROM pending_verifications
|
||||||
|
|
@ -309,7 +317,9 @@ public final class DatabaseManager implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<String> consumeLoginToken(final String token) {
|
public Optional<String> consumeLoginToken(final String token) {
|
||||||
if (sqlite) return consumeDeleteSelect("pending_logins", "token", token);
|
if (sqlite) {
|
||||||
|
return consumeDeleteSelect("pending_logins", "token", token);
|
||||||
|
}
|
||||||
try (Connection conn = ds.getConnection();
|
try (Connection conn = ds.getConnection();
|
||||||
PreparedStatement ps = conn.prepareStatement("""
|
PreparedStatement ps = conn.prepareStatement("""
|
||||||
DELETE FROM pending_logins
|
DELETE FROM pending_logins
|
||||||
|
|
@ -327,7 +337,9 @@ public final class DatabaseManager implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<String> consumeLoginTokenByMessageId(final String messageId) {
|
public Optional<String> consumeLoginTokenByMessageId(final String messageId) {
|
||||||
if (sqlite) return consumeDeleteSelect("pending_logins", "message_id", messageId);
|
if (sqlite) {
|
||||||
|
return consumeDeleteSelect("pending_logins", "message_id", messageId);
|
||||||
|
}
|
||||||
try (Connection conn = ds.getConnection();
|
try (Connection conn = ds.getConnection();
|
||||||
PreparedStatement ps = conn.prepareStatement("""
|
PreparedStatement ps = conn.prepareStatement("""
|
||||||
DELETE FROM pending_logins
|
DELETE FROM pending_logins
|
||||||
|
|
@ -378,7 +390,9 @@ public final class DatabaseManager implements AutoCloseable {
|
||||||
"SELECT minecraft_nick FROM pending_logins WHERE expires_at <= ?")) {
|
"SELECT minecraft_nick FROM pending_logins WHERE expires_at <= ?")) {
|
||||||
ps.setLong(1, now);
|
ps.setLong(1, now);
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
while (rs.next()) nicks.add(rs.getString("minecraft_nick"));
|
while (rs.next()) {
|
||||||
|
nicks.add(rs.getString("minecraft_nick"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!nicks.isEmpty()) {
|
if (!nicks.isEmpty()) {
|
||||||
|
|
@ -399,7 +413,9 @@ public final class DatabaseManager implements AutoCloseable {
|
||||||
"DELETE FROM pending_logins WHERE expires_at <= ? RETURNING minecraft_nick")) {
|
"DELETE FROM pending_logins WHERE expires_at <= ? RETURNING minecraft_nick")) {
|
||||||
ps.setLong(1, now);
|
ps.setLong(1, now);
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
while (rs.next()) nicks.add(rs.getString("minecraft_nick"));
|
while (rs.next()) {
|
||||||
|
nicks.add(rs.getString("minecraft_nick"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DatabaseException("Failed to pop expired logins", e);
|
throw new DatabaseException("Failed to pop expired logins", e);
|
||||||
|
|
@ -456,23 +472,27 @@ public final class DatabaseManager implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateNick(final String nick) {
|
private static void validateNick(final String nick) {
|
||||||
if (nick == null || !nick.matches("^[a-zA-Z0-9_]{3,16}$"))
|
if (nick == null || !nick.matches("^[a-zA-Z0-9_]{3,16}$")) {
|
||||||
throw new IllegalArgumentException("Invalid Minecraft nick: " + nick);
|
throw new IllegalArgumentException("Invalid Minecraft nick: " + nick);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateDiscordId(final String id) {
|
private static void validateDiscordId(final String id) {
|
||||||
if (id == null || !id.matches("^[0-9]{17,20}$"))
|
if (id == null || !id.matches("^[0-9]{17,20}$")) {
|
||||||
throw new IllegalArgumentException("Invalid Discord ID: " + id);
|
throw new IllegalArgumentException("Invalid Discord ID: " + id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RuntimeException translateSqlException(final SQLException e) {
|
private static RuntimeException translateSqlException(final SQLException e) {
|
||||||
String state = e.getSQLState();
|
String state = e.getSQLState();
|
||||||
if ("23505".equals(state) || "23000".equals(state)) {
|
if ("23505".equals(state) || "23000".equals(state)) {
|
||||||
String msg = e.getMessage();
|
String msg = e.getMessage();
|
||||||
if (msg != null && (msg.contains("minecraft_nick") || msg.contains("UNIQUE constraint failed: users.minecraft_nick")))
|
if (msg != null && (msg.contains("minecraft_nick") || msg.contains("UNIQUE constraint failed: users.minecraft_nick"))) {
|
||||||
return new DuplicateUserException("Minecraft nick already registered");
|
return new DuplicateUserException("Minecraft nick already registered");
|
||||||
if (msg != null && (msg.contains("discord_id") || msg.contains("UNIQUE constraint failed: users.discord_id")))
|
}
|
||||||
|
if (msg != null && (msg.contains("discord_id") || msg.contains("UNIQUE constraint failed: users.discord_id"))) {
|
||||||
return new DuplicateUserException("Discord ID already registered");
|
return new DuplicateUserException("Discord ID already registered");
|
||||||
|
}
|
||||||
return new DuplicateUserException("Duplicate entry");
|
return new DuplicateUserException("Duplicate entry");
|
||||||
}
|
}
|
||||||
return new DatabaseException("Database error", e);
|
return new DatabaseException("Database error", e);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.loki.loAuth.common.exception;
|
package dev.loki.loAuth.common.exception;
|
||||||
|
|
||||||
public final class DatabaseException extends RuntimeException {
|
public final class DatabaseException extends RuntimeException {
|
||||||
public DatabaseException(String msg, Throwable cause) { super(msg, cause); }
|
public DatabaseException(String msg, Throwable cause) {
|
||||||
|
super(msg, cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.loki.loAuth.common.exception;
|
package dev.loki.loAuth.common.exception;
|
||||||
|
|
||||||
public final class DuplicateUserException extends RuntimeException {
|
public final class DuplicateUserException extends RuntimeException {
|
||||||
public DuplicateUserException(String msg) { super(msg); }
|
public DuplicateUserException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -10,12 +10,14 @@ public final class CodeGenerator {
|
||||||
private CodeGenerator() {}
|
private CodeGenerator() {}
|
||||||
|
|
||||||
public static String generate(final int length) {
|
public static String generate(final int length) {
|
||||||
if (length < 4 || length > 16)
|
if (length < 4 || length > 16) {
|
||||||
throw new IllegalArgumentException("Code length must be between 4 and 16");
|
throw new IllegalArgumentException("Code length must be between 4 and 16");
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder(length);
|
StringBuilder sb = new StringBuilder(length);
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++) {
|
||||||
sb.append(ALPHABET.charAt(RNG.nextInt(ALPHABET.length())));
|
sb.append(ALPHABET.charAt(RNG.nextInt(ALPHABET.length())));
|
||||||
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
89
config/checkstyle/checkstyle.xml
Normal file
89
config/checkstyle/checkstyle.xml
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE module PUBLIC
|
||||||
|
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||||
|
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||||
|
|
||||||
|
<module name="Checker">
|
||||||
|
<property name="charset" value="UTF-8"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
<property name="fileExtensions" value="java"/>
|
||||||
|
|
||||||
|
<module name="BeforeExecutionExclusionFileFilter">
|
||||||
|
<property name="fileNamePattern" value=".*[\\/]src[\\/]test[\\/].*"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="SuppressWarningsFilter"/>
|
||||||
|
|
||||||
|
<module name="LineLength">
|
||||||
|
<property name="max" value="150"/>
|
||||||
|
<property name="ignorePattern"
|
||||||
|
value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="TreeWalker">
|
||||||
|
<module name="SuppressWarningsHolder"/>
|
||||||
|
|
||||||
|
<module name="MethodLength">
|
||||||
|
<property name="max" value="80"/>
|
||||||
|
<property name="countEmpty" value="false"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="CyclomaticComplexity">
|
||||||
|
<property name="max" value="20"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="ParameterNumber">
|
||||||
|
<property name="max" value="7"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="AvoidStarImport"/>
|
||||||
|
<module name="UnusedImports"/>
|
||||||
|
<module name="RedundantImport"/>
|
||||||
|
|
||||||
|
<module name="PackageName">
|
||||||
|
<property name="format" value="^[a-z]+(\.[a-zA-Z][a-zA-Z0-9]*)*$"/>
|
||||||
|
</module>
|
||||||
|
<module name="TypeName"/>
|
||||||
|
<module name="MethodName"/>
|
||||||
|
<module name="MemberName"/>
|
||||||
|
<module name="ParameterName"/>
|
||||||
|
<module name="LocalVariableName"/>
|
||||||
|
<module name="ConstantName">
|
||||||
|
<property name="format" value="^log$|^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="NeedBraces"/>
|
||||||
|
<module name="LeftCurly"/>
|
||||||
|
<module name="RightCurly"/>
|
||||||
|
|
||||||
|
<module name="ModifierOrder"/>
|
||||||
|
<module name="RedundantModifier"/>
|
||||||
|
<module name="EmptyStatement"/>
|
||||||
|
<module name="EqualsHashCode"/>
|
||||||
|
<module name="SimplifyBooleanExpression"/>
|
||||||
|
<module name="SimplifyBooleanReturn"/>
|
||||||
|
<module name="StringLiteralEquality"/>
|
||||||
|
<module name="DefaultComesLast"/>
|
||||||
|
<module name="MultipleVariableDeclarations"/>
|
||||||
|
<module name="OneStatementPerLine"/>
|
||||||
|
<module name="FallThrough"/>
|
||||||
|
<module name="HideUtilityClassConstructor"/>
|
||||||
|
<module name="OneTopLevelClass"/>
|
||||||
|
<module name="UpperEll"/>
|
||||||
|
<module name="ArrayTypeStyle"/>
|
||||||
|
<module name="MissingSwitchDefault"/>
|
||||||
|
<module name="OuterTypeFilename"/>
|
||||||
|
|
||||||
|
<module name="EmptyBlock">
|
||||||
|
<property name="option" value="text"/>
|
||||||
|
</module>
|
||||||
|
<module name="EmptyCatchBlock">
|
||||||
|
<property name="exceptionVariableName" value="expected|ignore"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="EqualsAvoidNull"/>
|
||||||
|
<module name="NoFinalizer"/>
|
||||||
|
<module name="NoClone"/>
|
||||||
|
<module name="PackageDeclaration"/>
|
||||||
|
</module>
|
||||||
|
</module>
|
||||||
|
|
@ -11,6 +11,8 @@ import java.nio.file.Path;
|
||||||
|
|
||||||
public final class BotLauncher {
|
public final class BotLauncher {
|
||||||
|
|
||||||
|
private BotLauncher() {}
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(BotLauncher.class);
|
private static final Logger log = LoggerFactory.getLogger(BotLauncher.class);
|
||||||
|
|
||||||
public static void main(final String[] args) {
|
public static void main(final String[] args) {
|
||||||
|
|
@ -33,7 +35,9 @@ public final class BotLauncher {
|
||||||
Path path = Path.of(System.getProperty("user.dir")).resolve(fileName);
|
Path path = Path.of(System.getProperty("user.dir")).resolve(fileName);
|
||||||
if (Files.notExists(path)) {
|
if (Files.notExists(path)) {
|
||||||
try (InputStream in = BotLauncher.class.getResourceAsStream("/" + fileName)) {
|
try (InputStream in = BotLauncher.class.getResourceAsStream("/" + fileName)) {
|
||||||
if (in == null) throw new IOException("Resource not found: " + fileName);
|
if (in == null) {
|
||||||
|
throw new IOException("Resource not found: " + fileName);
|
||||||
|
}
|
||||||
Files.copy(in, path);
|
Files.copy(in, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class AuthService implements AutoCloseable {
|
public final class AuthService implements AutoCloseable {
|
||||||
|
|
||||||
|
|
@ -36,7 +38,9 @@ public final class AuthService implements AutoCloseable {
|
||||||
|
|
||||||
public void verifyNewUser(final String code, final String discordId) {
|
public void verifyNewUser(final String code, final String discordId) {
|
||||||
Optional<String> nick = db.consumeVerificationCode(code.toUpperCase());
|
Optional<String> nick = db.consumeVerificationCode(code.toUpperCase());
|
||||||
if (nick.isEmpty()) throw new IllegalArgumentException("Invalid or expired code: " + code);
|
if (nick.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Invalid or expired code: " + code);
|
||||||
|
}
|
||||||
db.addUser(nick.get(), discordId);
|
db.addUser(nick.get(), discordId);
|
||||||
log.info("New user registered: {} -> {}", nick.get(), discordId);
|
log.info("New user registered: {} -> {}", nick.get(), discordId);
|
||||||
}
|
}
|
||||||
|
|
@ -75,8 +79,9 @@ public final class AuthService implements AutoCloseable {
|
||||||
private void kickExpiredLogins() {
|
private void kickExpiredLogins() {
|
||||||
try {
|
try {
|
||||||
List<String> expired = db.popExpiredLogins();
|
List<String> expired = db.popExpiredLogins();
|
||||||
if (!expired.isEmpty())
|
if (!expired.isEmpty()) {
|
||||||
log.info("Expired logins cleaned up: {}", expired);
|
log.info("Expired logins cleaned up: {}", expired);
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error during expired login cleanup", e);
|
log.error("Error during expired login cleanup", e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,48 @@ public final class BotCfg implements BotConfig {
|
||||||
cfg = new YamlConfig(configPath);
|
cfg = new YamlConfig(configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String getToken() { return cfg.getRequired("token", String.class); }
|
@Override
|
||||||
@Override public String getDbType() { return cfg.getRequired("db_type", String.class); }
|
public String getToken() {
|
||||||
@Override public String getDbHost() { return cfg.getRequired("db_host", String.class); }
|
return cfg.getRequired("token", String.class);
|
||||||
@Override public int getDbPort() { return cfg.getRequired("db_port", Integer.class); }
|
}
|
||||||
@Override public String getDbName() { return cfg.getRequired("db_name", String.class); }
|
|
||||||
@Override public String getDbUser() { return cfg.getRequired("db_user", String.class); }
|
@Override
|
||||||
@Override public String getDbPassword() { return cfg.getRequired("db_password", String.class); }
|
public String getDbType() {
|
||||||
@Override public int getAuthTimeoutSeconds() { return cfg.getRequired("auth_timeout_seconds", Integer.class); }
|
return cfg.getRequired("db_type", String.class);
|
||||||
@Override public int getVerificationCodeLength() { return cfg.getRequired("verification_code_length",Integer.class); }
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbHost() {
|
||||||
|
return cfg.getRequired("db_host", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDbPort() {
|
||||||
|
return cfg.getRequired("db_port", Integer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbName() {
|
||||||
|
return cfg.getRequired("db_name", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbUser() {
|
||||||
|
return cfg.getRequired("db_user", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbPassword() {
|
||||||
|
return cfg.getRequired("db_password", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAuthTimeoutSeconds() {
|
||||||
|
return cfg.getRequired("auth_timeout_seconds", Integer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVerificationCodeLength() {
|
||||||
|
return cfg.getRequired("verification_code_length", Integer.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,12 @@ public final class LoginReactionListener extends ListenerAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessageReactionAdd(final MessageReactionAddEvent event) {
|
public void onMessageReactionAdd(final MessageReactionAddEvent event) {
|
||||||
if (event.getUser() == null || event.getUser().isBot()) return;
|
if (event.getUser() == null || event.getUser().isBot()) {
|
||||||
if (!CHECKMARK.equals(event.getReaction().getEmoji().getName())) return;
|
return;
|
||||||
|
}
|
||||||
|
if (!CHECKMARK.equals(event.getReaction().getEmoji().getName())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Ищем токен по message_id — бот сохранил его при отправке
|
// Ищем токен по message_id — бот сохранил его при отправке
|
||||||
db.consumeLoginTokenByMessageId(event.getMessageId()).ifPresent(nick ->
|
db.consumeLoginTokenByMessageId(event.getMessageId()).ifPresent(nick ->
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,17 @@ public final class VerifyListener extends ListenerAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessageReceived(final MessageReceivedEvent event) {
|
public void onMessageReceived(final MessageReceivedEvent event) {
|
||||||
if (event.getAuthor().isBot()) return;
|
if (event.getAuthor().isBot()) {
|
||||||
if (!event.isFromType(ChannelType.PRIVATE)) return;
|
return;
|
||||||
|
}
|
||||||
|
if (!event.isFromType(ChannelType.PRIVATE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String content = event.getMessage().getContentRaw().trim();
|
String content = event.getMessage().getContentRaw().trim();
|
||||||
if (!content.toUpperCase().startsWith(COMMAND)) return;
|
if (!content.toUpperCase().startsWith(COMMAND)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String[] parts = content.split("\\s+", 2);
|
String[] parts = content.split("\\s+", 2);
|
||||||
if (parts.length < 2) {
|
if (parts.length < 2) {
|
||||||
|
|
|
||||||
0
gradlew
vendored
Normal file → Executable file
0
gradlew
vendored
Normal file → Executable file
|
|
@ -68,15 +68,50 @@ public final class FoxAuth {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
discordBot = new Bot(new BotConfig() {
|
discordBot = new Bot(new BotConfig() {
|
||||||
@Override public String getDbType() { return cfg.getDbType(); }
|
@Override
|
||||||
@Override public String getToken() { return token; }
|
public String getDbType() {
|
||||||
@Override public String getDbHost() { return cfg.getDbHost(); }
|
return cfg.getDbType();
|
||||||
@Override public int getDbPort() { return cfg.getDbPort(); }
|
}
|
||||||
@Override public String getDbName() { return cfg.getDbName(); }
|
|
||||||
@Override public String getDbUser() { return cfg.getDbUser(); }
|
@Override
|
||||||
@Override public String getDbPassword() { return cfg.getDbPassword(); }
|
public String getToken() {
|
||||||
@Override public int getAuthTimeoutSeconds() { return cfg.getAuthTimeoutSeconds(); }
|
return token;
|
||||||
@Override public int getVerificationCodeLength() { return cfg.getVerificationCodeLength(); }
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbHost() {
|
||||||
|
return cfg.getDbHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDbPort() {
|
||||||
|
return cfg.getDbPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbName() {
|
||||||
|
return cfg.getDbName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbUser() {
|
||||||
|
return cfg.getDbUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbPassword() {
|
||||||
|
return cfg.getDbPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAuthTimeoutSeconds() {
|
||||||
|
return cfg.getAuthTimeoutSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVerificationCodeLength() {
|
||||||
|
return cfg.getVerificationCodeLength();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
log.info("Discord bot started in embedded mode.");
|
log.info("Discord bot started in embedded mode.");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
@ -86,8 +121,12 @@ public final class FoxAuth {
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onShutdown(final ProxyShutdownEvent event) {
|
public void onShutdown(final ProxyShutdownEvent event) {
|
||||||
if (discordBot != null) discordBot.shutdown();
|
if (discordBot != null) {
|
||||||
if (db != null) db.close();
|
discordBot.shutdown();
|
||||||
|
}
|
||||||
|
if (db != null) {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path getOrCreateConfig(final String fileName) throws IOException {
|
private Path getOrCreateConfig(final String fileName) throws IOException {
|
||||||
|
|
@ -95,7 +134,9 @@ public final class FoxAuth {
|
||||||
Path target = dataDir.resolve(fileName);
|
Path target = dataDir.resolve(fileName);
|
||||||
if (Files.notExists(target)) {
|
if (Files.notExists(target)) {
|
||||||
try (InputStream in = getClass().getResourceAsStream("/" + fileName)) {
|
try (InputStream in = getClass().getResourceAsStream("/" + fileName)) {
|
||||||
if (in == null) throw new IOException("Resource not found: " + fileName);
|
if (in == null) {
|
||||||
|
throw new IOException("Resource not found: " + fileName);
|
||||||
|
}
|
||||||
Files.copy(in, target);
|
Files.copy(in, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,33 @@ public final class MessageConfig {
|
||||||
this.raw = raw;
|
this.raw = raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Component header() { return text("first_login.header"); }
|
public Component header() {
|
||||||
public Component returningHeader() { return text("returning_login.header"); }
|
return text("first_login.header");
|
||||||
public Component returningBody() { return text("returning_login.body"); }
|
}
|
||||||
public Component returningTimeout() { return text("returning_login.timeout"); }
|
|
||||||
public Component expiredHeader() { return text("expired.header"); }
|
public Component returningHeader() {
|
||||||
public Component expiredBody() { return text("expired.body"); }
|
return text("returning_login.header");
|
||||||
public Component success() { return text("success"); }
|
}
|
||||||
|
|
||||||
|
public Component returningBody() {
|
||||||
|
return text("returning_login.body");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component returningTimeout() {
|
||||||
|
return text("returning_login.timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component expiredHeader() {
|
||||||
|
return text("expired.header");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component expiredBody() {
|
||||||
|
return text("expired.body");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component success() {
|
||||||
|
return text("success");
|
||||||
|
}
|
||||||
|
|
||||||
public Component code(final String code) {
|
public Component code(final String code) {
|
||||||
return parse("first_login.code", Map.of("code", code))
|
return parse("first_login.code", Map.of("code", code))
|
||||||
|
|
@ -60,7 +80,9 @@ public final class MessageConfig {
|
||||||
|
|
||||||
private Component text(final String path, final Map<String, String> placeholders) {
|
private Component text(final String path, final Map<String, String> placeholders) {
|
||||||
String rawStr = resolveRaw(path);
|
String rawStr = resolveRaw(path);
|
||||||
if (rawStr == null) return Component.text('[' + path + ']');
|
if (rawStr == null) {
|
||||||
|
return Component.text('[' + path + ']');
|
||||||
|
}
|
||||||
return parse(rawStr, placeholders);
|
return parse(rawStr, placeholders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,57 @@ public final class PluginCfg implements DbConfig {
|
||||||
cfg = new YamlConfig(configPath);
|
cfg = new YamlConfig(configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMode() { return cfg.getRequired("mode", String.class); }
|
public String getMode() {
|
||||||
public String getToken() { return cfg.get("token", ""); }
|
return cfg.getRequired("mode", String.class);
|
||||||
public String getDiscordLink() { return cfg.get("discord_link", "discord.gg/ЗАМЕНИ_НА_СВОЙ"); }
|
}
|
||||||
|
|
||||||
@Override public String getDbType() { return cfg.getRequired("db_type", String.class); }
|
public String getToken() {
|
||||||
@Override public String getDbHost() { return cfg.getRequired("db_host", String.class); }
|
return cfg.get("token", "");
|
||||||
@Override public int getDbPort() { return cfg.getRequired("db_port", Integer.class); }
|
}
|
||||||
@Override public String getDbName() { return cfg.getRequired("db_name", String.class); }
|
|
||||||
@Override public String getDbUser() { return cfg.getRequired("db_user", String.class); }
|
public String getDiscordLink() {
|
||||||
@Override public String getDbPassword() { return cfg.getRequired("db_password", String.class); }
|
return cfg.get("discord_link", "discord.gg/ЗАМЕНИ_НА_СВОЙ");
|
||||||
@Override public int getAuthTimeoutSeconds() { return cfg.getRequired("auth_timeout_seconds", Integer.class); }
|
}
|
||||||
@Override public int getVerificationCodeLength(){ return cfg.getRequired("verification_code_length",Integer.class); }
|
|
||||||
|
@Override
|
||||||
|
public String getDbType() {
|
||||||
|
return cfg.getRequired("db_type", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbHost() {
|
||||||
|
return cfg.getRequired("db_host", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDbPort() {
|
||||||
|
return cfg.getRequired("db_port", Integer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbName() {
|
||||||
|
return cfg.getRequired("db_name", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbUser() {
|
||||||
|
return cfg.getRequired("db_user", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDbPassword() {
|
||||||
|
return cfg.getRequired("db_password", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAuthTimeoutSeconds() {
|
||||||
|
return cfg.getRequired("auth_timeout_seconds", Integer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVerificationCodeLength() {
|
||||||
|
return cfg.getRequired("verification_code_length", Integer.class);
|
||||||
|
}
|
||||||
|
|
||||||
public MessageConfig getMessages() {
|
public MessageConfig getMessages() {
|
||||||
Object msgs = cfg.get("messages", null);
|
Object msgs = cfg.get("messages", null);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,11 @@ import org.slf4j.Logger;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class LoginListener {
|
public final class LoginListener {
|
||||||
|
|
||||||
|
|
@ -129,6 +133,8 @@ public final class LoginListener {
|
||||||
|
|
||||||
private void cancelKick(final String nick) {
|
private void cancelKick(final String nick) {
|
||||||
ScheduledFuture<?> f = pendingKicks.remove(nick);
|
ScheduledFuture<?> f = pendingKicks.remove(nick);
|
||||||
if (f != null) f.cancel(false);
|
if (f != null) {
|
||||||
|
f.cancel(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue