feat: store keys per-user using discord instead of having a global key
refactor: use language on DirectMessageEventHandler refactor: some misc refactors (i forgot what i did lol)
This commit is contained in:
@@ -90,7 +90,6 @@ public class Bot extends SessionAdapter {
|
||||
public final TabCompletePlugin tabComplete;
|
||||
public final CommandHandlerPlugin commandHandler;
|
||||
public final ChatCommandHandlerPlugin chatCommandHandler;
|
||||
public final HashingPlugin hashing;
|
||||
public final BossbarManagerPlugin bossbar;
|
||||
public final MusicPlayerPlugin music;
|
||||
public final TPSPlugin tps;
|
||||
@@ -151,7 +150,6 @@ public class Bot extends SessionAdapter {
|
||||
this.tabComplete = new TabCompletePlugin(this);
|
||||
this.commandHandler = new CommandHandlerPlugin(this);
|
||||
this.chatCommandHandler = new ChatCommandHandlerPlugin(this);
|
||||
this.hashing = new HashingPlugin(this);
|
||||
this.bossbar = new BossbarManagerPlugin(this);
|
||||
this.music = new MusicPlayerPlugin(this);
|
||||
this.tps = new TPSPlugin(this);
|
||||
|
||||
@@ -9,7 +9,6 @@ public class Configuration {
|
||||
|
||||
public String consoleCommandPrefix;
|
||||
|
||||
public Keys keys = new Keys();
|
||||
public Backup backup = new Backup();
|
||||
|
||||
public Database database = new Database();
|
||||
@@ -69,22 +68,10 @@ public class Configuration {
|
||||
public List<String> players = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static class Keys {
|
||||
public String trustedKey;
|
||||
public String adminKey;
|
||||
public String ownerKey;
|
||||
}
|
||||
|
||||
public static class Core {
|
||||
public String customName = "{\"text\":\"@\"}";
|
||||
}
|
||||
|
||||
public static class Position {
|
||||
public int x = 0;
|
||||
public int y = 0;
|
||||
public int z = 0;
|
||||
}
|
||||
|
||||
public static class ColorPalette {
|
||||
public String primary = "yellow";
|
||||
public String secondary = "gold";
|
||||
|
||||
@@ -6,10 +6,7 @@ import me.chayapak1.chomens_bot.plugins.ConsolePlugin;
|
||||
import me.chayapak1.chomens_bot.plugins.DatabasePlugin;
|
||||
import me.chayapak1.chomens_bot.plugins.DiscordPlugin;
|
||||
import me.chayapak1.chomens_bot.plugins.IRCPlugin;
|
||||
import me.chayapak1.chomens_bot.util.ArrayUtilities;
|
||||
import me.chayapak1.chomens_bot.util.HttpUtilities;
|
||||
import me.chayapak1.chomens_bot.util.I18nUtilities;
|
||||
import me.chayapak1.chomens_bot.util.LoggerUtilities;
|
||||
import me.chayapak1.chomens_bot.util.*;
|
||||
import net.dv8tion.jda.api.requests.restaction.MessageCreateAction;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
@@ -137,6 +134,7 @@ public class Main {
|
||||
|
||||
try {
|
||||
if (config.database.enabled) database = new DatabasePlugin(config);
|
||||
HashingUtilities.init();
|
||||
|
||||
final Configuration.BotOption[] botsOptions = config.bots;
|
||||
|
||||
|
||||
24
src/main/java/me/chayapak1/chomens_bot/data/keys/Key.java
Normal file
24
src/main/java/me/chayapak1/chomens_bot/data/keys/Key.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package me.chayapak1.chomens_bot.data.keys;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import me.chayapak1.chomens_bot.command.TrustLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
|
||||
@JsonSerialize
|
||||
public record Key(
|
||||
@JsonProperty TrustLevel trustLevel,
|
||||
@JsonProperty String key,
|
||||
@JsonProperty long createdAt
|
||||
) {
|
||||
@Override
|
||||
public @NotNull String toString () {
|
||||
return "Key{" +
|
||||
"trustLevel=" + trustLevel +
|
||||
", key='" + key + '\'' +
|
||||
", createdAt=" + createdAt +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package me.chayapak1.chomens_bot.data.keys;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
|
||||
@JsonSerialize
|
||||
public record KeysData(
|
||||
@JsonProperty ArrayList<Key> keys,
|
||||
@JsonProperty String userId
|
||||
) {
|
||||
@Override
|
||||
public @NotNull String toString () {
|
||||
return "KeysData{" +
|
||||
"keys=" + keys +
|
||||
", userId='" + userId + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package me.chayapak1.chomens_bot.data.mail;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record Mail(String sentBy, String sentTo, long timeSent, String server, String contents) {
|
||||
@Override
|
||||
public String toString () {
|
||||
public @NotNull String toString () {
|
||||
return "Mail{" +
|
||||
"sentBy='" + sentBy + '\'' +
|
||||
", sentTo='" + sentTo + '\'' +
|
||||
|
||||
@@ -3,7 +3,8 @@ package me.chayapak1.chomens_bot.discord;
|
||||
import me.chayapak1.chomens_bot.Configuration;
|
||||
import me.chayapak1.chomens_bot.command.TrustLevel;
|
||||
import me.chayapak1.chomens_bot.data.logging.LogType;
|
||||
import me.chayapak1.chomens_bot.plugins.HashingPlugin;
|
||||
import me.chayapak1.chomens_bot.util.HashingUtilities;
|
||||
import me.chayapak1.chomens_bot.util.I18nUtilities;
|
||||
import me.chayapak1.chomens_bot.util.LoggerUtilities;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
@@ -19,6 +20,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class DirectMessageEventHandler extends ListenerAdapter {
|
||||
private static final String HASH_MESSAGE = "hash";
|
||||
private static final String KEY_MESSAGE = "key";
|
||||
private static final String FORCED_KEY_MESSAGE = "key force";
|
||||
|
||||
private final JDA jda;
|
||||
|
||||
@@ -40,7 +43,11 @@ public class DirectMessageEventHandler extends ListenerAdapter {
|
||||
|
||||
final Message message = event.getMessage();
|
||||
|
||||
if (!message.getContentDisplay().equalsIgnoreCase(HASH_MESSAGE)) return;
|
||||
if (
|
||||
!message.getContentDisplay().equalsIgnoreCase(HASH_MESSAGE)
|
||||
&& !message.getContentDisplay().equalsIgnoreCase(KEY_MESSAGE)
|
||||
&& !message.getContentDisplay().equalsIgnoreCase(FORCED_KEY_MESSAGE)
|
||||
) return;
|
||||
|
||||
final Guild guild;
|
||||
|
||||
@@ -68,16 +75,21 @@ public class DirectMessageEventHandler extends ListenerAdapter {
|
||||
LoggerUtilities.log(
|
||||
LogType.DISCORD,
|
||||
Component.translatable(
|
||||
"User %s tried to get hash in Discord without any trusted roles!",
|
||||
I18nUtilities.get("hashing.discord_direct_message.error.no_roles.log"),
|
||||
Component.text(member.toString())
|
||||
)
|
||||
);
|
||||
message.reply("You do not have any trusted roles!")
|
||||
message
|
||||
.reply(I18nUtilities.get("hashing.discord_direct_message.error.no_roles"))
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
sendHash(trustLevel, message, member);
|
||||
switch (message.getContentDisplay().toLowerCase()) {
|
||||
case HASH_MESSAGE -> sendHash(trustLevel, message, member);
|
||||
case KEY_MESSAGE -> sendKey(trustLevel, message, member, false);
|
||||
case FORCED_KEY_MESSAGE -> sendKey(trustLevel, message, member, true);
|
||||
}
|
||||
},
|
||||
exception -> {
|
||||
if (!(exception instanceof final ErrorResponseException error)) return;
|
||||
@@ -85,13 +97,18 @@ public class DirectMessageEventHandler extends ListenerAdapter {
|
||||
final ErrorResponse errorResponse = error.getErrorResponse();
|
||||
|
||||
if (errorResponse == ErrorResponse.UNKNOWN_MEMBER) {
|
||||
message.reply("You are not in " + guild.getName() + "!")
|
||||
message
|
||||
.reply(
|
||||
String.format(
|
||||
I18nUtilities.get("hashing.discord_direct_message.error.not_in_guild"),
|
||||
guild.getName()
|
||||
)
|
||||
)
|
||||
.queue();
|
||||
} else if (errorResponse == ErrorResponse.UNKNOWN_USER) {
|
||||
LoggerUtilities.error(
|
||||
Component.translatable(
|
||||
"Got ErrorResponse.UNKNOWN_USER while trying to " +
|
||||
"retrieve member! Weird user. User: %s",
|
||||
I18nUtilities.get("hashing.discord_direct_message.error.log_unknown_user"),
|
||||
Component.text(message.getAuthor().toString())
|
||||
)
|
||||
);
|
||||
@@ -102,12 +119,12 @@ public class DirectMessageEventHandler extends ListenerAdapter {
|
||||
}
|
||||
|
||||
private void sendHash (final TrustLevel trustLevel, final Message message, final Member member) {
|
||||
final String result = HashingPlugin.generateDiscordHash(member.getIdLong(), trustLevel);
|
||||
final String result = HashingUtilities.generateDiscordHash(member.getIdLong(), trustLevel);
|
||||
|
||||
message
|
||||
.reply(
|
||||
String.format(
|
||||
"Hash for %s trust level: **%s**",
|
||||
I18nUtilities.get("hashing.discord_direct_message.hash_generated"),
|
||||
trustLevel,
|
||||
result
|
||||
)
|
||||
@@ -117,11 +134,40 @@ public class DirectMessageEventHandler extends ListenerAdapter {
|
||||
LoggerUtilities.log(
|
||||
LogType.DISCORD,
|
||||
Component.translatable(
|
||||
"Generated hash %s (%s) for user %s",
|
||||
I18nUtilities.get("hashing.discord_direct_message.hash_generated.log"),
|
||||
Component.text(result),
|
||||
Component.text(trustLevel.toString()),
|
||||
Component.text(member.getEffectiveName())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private void sendKey (final TrustLevel trustLevel, final Message message, final Member member, final boolean force) {
|
||||
try {
|
||||
final String generatedKey = HashingUtilities.KEY_MANAGER.generate(
|
||||
trustLevel,
|
||||
member.getId(),
|
||||
force,
|
||||
String.format(
|
||||
// long ahh
|
||||
I18nUtilities.get("hashing.discord_direct_message.error.key_for_trust_level_already_exists"),
|
||||
|
||||
trustLevel,
|
||||
FORCED_KEY_MESSAGE
|
||||
)
|
||||
);
|
||||
|
||||
message
|
||||
.reply(
|
||||
String.format(
|
||||
I18nUtilities.get("hashing.discord_direct_message.key_generated"),
|
||||
trustLevel,
|
||||
generatedKey
|
||||
)
|
||||
)
|
||||
.queue();
|
||||
} catch (final IllegalStateException e) {
|
||||
message.reply(e.getMessage()).queue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import me.chayapak1.chomens_bot.commands.*;
|
||||
import me.chayapak1.chomens_bot.data.chat.ChatPacketType;
|
||||
import me.chayapak1.chomens_bot.data.listener.Listener;
|
||||
import me.chayapak1.chomens_bot.util.ExceptionUtilities;
|
||||
import me.chayapak1.chomens_bot.util.HashingUtilities;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@@ -215,7 +216,7 @@ public class CommandHandlerPlugin implements Listener {
|
||||
|
||||
context.trustLevel = authenticatedTrustLevel;
|
||||
} else {
|
||||
final TrustLevel userTrustLevel = bot.hashing.getTrustLevel(userHash, splitInput[0], context.sender);
|
||||
final TrustLevel userTrustLevel = HashingUtilities.getTrustLevel(userHash, splitInput[0], context.sender);
|
||||
|
||||
if (trustLevel.level > userTrustLevel.level) {
|
||||
context.sendOutput(
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
package me.chayapak1.chomens_bot.plugins;
|
||||
|
||||
import com.google.common.hash.Hashing;
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.command.TrustLevel;
|
||||
import me.chayapak1.chomens_bot.data.player.PlayerEntry;
|
||||
import me.chayapak1.chomens_bot.util.RandomStringUtilities;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class HashingPlugin {
|
||||
public static final Map<Long, Pair<TrustLevel, String>> discordHashes = new ConcurrentHashMap<>();
|
||||
|
||||
private final Bot bot;
|
||||
|
||||
public HashingPlugin (final Bot bot) {
|
||||
this.bot = bot;
|
||||
}
|
||||
|
||||
public String getHash (final String prefix, final PlayerEntry sender, final boolean sectionSigns) { return getGenericHash(bot.config.keys.trustedKey, prefix, sender, sectionSigns); }
|
||||
|
||||
public String getAdminHash (final String prefix, final PlayerEntry sender, final boolean sectionSigns) { return getGenericHash(bot.config.keys.adminKey, prefix, sender, sectionSigns); }
|
||||
|
||||
public String getOwnerHash (final String prefix, final PlayerEntry sender, final boolean sectionSigns) { return getGenericHash(bot.config.keys.ownerKey, prefix, sender, sectionSigns); }
|
||||
|
||||
// should this be public?
|
||||
public String getGenericHash (final String key, final String prefix, final PlayerEntry sender, final boolean sectionSigns) {
|
||||
final long time = System.currentTimeMillis() / 5_000;
|
||||
|
||||
final String hashValue = sender.profile.getIdAsString() + prefix + time + key;
|
||||
|
||||
final String hash = Hashing.sha256()
|
||||
.hashString(hashValue, StandardCharsets.UTF_8)
|
||||
.toString()
|
||||
.substring(0, 16);
|
||||
|
||||
return sectionSigns ?
|
||||
String.join("",
|
||||
Arrays.stream(hash.split(""))
|
||||
.map((letter) -> "§" + letter)
|
||||
.toArray(String[]::new)
|
||||
) :
|
||||
hash;
|
||||
}
|
||||
|
||||
private boolean checkHash (final String hash, String input) {
|
||||
// removes reset section sign
|
||||
if (input.length() == (16 * 2 /* <-- don't forget, we have the section signs */) + 2 && input.endsWith("§r"))
|
||||
input = input.substring(0, input.length() - 2);
|
||||
|
||||
return input.equals(hash);
|
||||
}
|
||||
|
||||
public boolean isCorrectHash (final String input, final String prefix, final PlayerEntry sender) {
|
||||
return checkHash(getHash(prefix, sender, true), input) ||
|
||||
checkHash(getHash(prefix, sender, false), input);
|
||||
}
|
||||
|
||||
public boolean isCorrectAdminHash (final String input, final String prefix, final PlayerEntry sender) {
|
||||
return checkHash(getAdminHash(prefix, sender, true), input) ||
|
||||
checkHash(getAdminHash(prefix, sender, false), input);
|
||||
}
|
||||
|
||||
public boolean isCorrectOwnerHash (final String input, final String prefix, final PlayerEntry sender) {
|
||||
return checkHash(getOwnerHash(prefix, sender, true), input) ||
|
||||
checkHash(getOwnerHash(prefix, sender, false), input);
|
||||
}
|
||||
|
||||
public boolean isCorrectDiscordHash (final String input) {
|
||||
for (final Pair<TrustLevel, String> pair : discordHashes.values()) {
|
||||
if (checkHash(pair.getRight(), input)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public TrustLevel getDiscordHashTrustLevel (final String input) {
|
||||
for (final Map.Entry<Long, Pair<TrustLevel, String>> entry : new ArrayList<>(discordHashes.entrySet())) {
|
||||
final Pair<TrustLevel, String> pair = entry.getValue();
|
||||
|
||||
if (!pair.getRight().equals(input)) continue;
|
||||
|
||||
discordHashes.remove(entry.getKey());
|
||||
|
||||
return pair.getLeft();
|
||||
}
|
||||
|
||||
return TrustLevel.PUBLIC;
|
||||
}
|
||||
|
||||
public TrustLevel getTrustLevel (final String input, final String prefix, final PlayerEntry sender) {
|
||||
if (isCorrectOwnerHash(input, prefix, sender)) return TrustLevel.OWNER;
|
||||
else if (isCorrectAdminHash(input, prefix, sender)) return TrustLevel.ADMIN;
|
||||
else if (isCorrectHash(input, prefix, sender)) return TrustLevel.TRUSTED;
|
||||
else if (isCorrectDiscordHash(input)) return getDiscordHashTrustLevel(input);
|
||||
else return TrustLevel.PUBLIC;
|
||||
}
|
||||
|
||||
public static String generateDiscordHash (final long userId, final TrustLevel trustLevel) {
|
||||
// i wouldn't say it's a hash, it's just a random string
|
||||
final String string = RandomStringUtilities.generate(16);
|
||||
|
||||
discordHashes.putIfAbsent(userId, Pair.of(trustLevel, string));
|
||||
|
||||
return discordHashes.get(userId).getRight();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
package me.chayapak1.chomens_bot.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.hash.Hashing;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import me.chayapak1.chomens_bot.Main;
|
||||
import me.chayapak1.chomens_bot.command.TrustLevel;
|
||||
import me.chayapak1.chomens_bot.data.keys.Key;
|
||||
import me.chayapak1.chomens_bot.data.keys.KeysData;
|
||||
import me.chayapak1.chomens_bot.data.player.PlayerEntry;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class HashingUtilities {
|
||||
public static final KeyManager KEY_MANAGER = new KeyManager();
|
||||
public static final Map<Long, Pair<TrustLevel, String>> discordHashes = new ConcurrentHashMap<>();
|
||||
|
||||
public static void init () {
|
||||
}
|
||||
|
||||
public static String getHash (final String key, final String prefix, final PlayerEntry sender) {
|
||||
final long time = System.currentTimeMillis() / 5_000;
|
||||
|
||||
final String hashInput = sender.profile.getIdAsString() + prefix + time + key;
|
||||
|
||||
return Hashing.sha256()
|
||||
.hashString(hashInput, StandardCharsets.UTF_8)
|
||||
.toString()
|
||||
.substring(0, 16);
|
||||
}
|
||||
|
||||
private static String getFixedHashInput (final String input) {
|
||||
String sanitizedInput = input;
|
||||
|
||||
// removes reset section sign
|
||||
if (input.length() == (16 * 2) + 2 && input.endsWith("§r"))
|
||||
sanitizedInput = input.substring(0, input.length() - 2);
|
||||
|
||||
// removes all the section signs
|
||||
sanitizedInput = sanitizedInput.replace("§", "");
|
||||
|
||||
return sanitizedInput;
|
||||
}
|
||||
|
||||
public static TrustLevel getPlayerHashTrustLevel (
|
||||
final String input,
|
||||
final String prefix,
|
||||
final PlayerEntry sender
|
||||
) {
|
||||
final String fixedInput = getFixedHashInput(input);
|
||||
|
||||
final List<KeysData> keys = KEY_MANAGER.keys;
|
||||
|
||||
synchronized (keys) {
|
||||
for (final KeysData keysData : keys) {
|
||||
for (final Key keyObject : keysData.keys()) {
|
||||
final String hashed = getHash(keyObject.key(), prefix, sender);
|
||||
if (fixedInput.equals(hashed)) return keyObject.trustLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not TrustLevel.PUBLIC !
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isCorrectDiscordHash (final String input) {
|
||||
final String fixedInput = getFixedHashInput(input);
|
||||
|
||||
for (final Pair<TrustLevel, String> pair : discordHashes.values()) {
|
||||
if (pair.getValue().equals(fixedInput)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static TrustLevel getDiscordHashTrustLevel (final String input) {
|
||||
for (final Map.Entry<Long, Pair<TrustLevel, String>> entry : new ArrayList<>(discordHashes.entrySet())) {
|
||||
final Pair<TrustLevel, String> pair = entry.getValue();
|
||||
|
||||
if (!pair.getRight().equals(input)) continue;
|
||||
|
||||
discordHashes.remove(entry.getKey());
|
||||
|
||||
return pair.getLeft();
|
||||
}
|
||||
|
||||
return TrustLevel.PUBLIC;
|
||||
}
|
||||
|
||||
public static TrustLevel getTrustLevel (final String input, final String prefix, final PlayerEntry sender) {
|
||||
final TrustLevel playerHashTrustLevel = getPlayerHashTrustLevel(input, prefix, sender);
|
||||
|
||||
if (playerHashTrustLevel != null) return playerHashTrustLevel;
|
||||
else if (isCorrectDiscordHash(input)) return getDiscordHashTrustLevel(input);
|
||||
else return TrustLevel.PUBLIC;
|
||||
}
|
||||
|
||||
public static String generateDiscordHash (final long userId, final TrustLevel trustLevel) {
|
||||
// i wouldn't say it's a hash, it's just a random string
|
||||
final String string = RandomStringUtilities.generate(16);
|
||||
|
||||
discordHashes.putIfAbsent(userId, Pair.of(trustLevel, string));
|
||||
|
||||
return discordHashes.get(userId).getRight();
|
||||
}
|
||||
|
||||
public static class KeyManager {
|
||||
private static final Path KEY_PATH = Path.of("keys.json");
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
public List<KeysData> keys = null;
|
||||
|
||||
public KeyManager () {
|
||||
try {
|
||||
initialLoad();
|
||||
} catch (final IOException e) {
|
||||
LoggerUtilities.error("Failed to load the keys!");
|
||||
LoggerUtilities.error(e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Main.EXECUTOR.scheduleAtFixedRate(this::write, 1, 1, TimeUnit.MINUTES);
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(this::write));
|
||||
}
|
||||
|
||||
public @Nullable String generate (
|
||||
final TrustLevel level,
|
||||
final String userId,
|
||||
final boolean force,
|
||||
final String alreadyExistsMessage // so it's flexible
|
||||
) throws IllegalStateException {
|
||||
if (keys == null) return null;
|
||||
|
||||
// is this useless? although it prevents the synchronization on non-final field warning by IDEA
|
||||
final List<KeysData> keys = this.keys;
|
||||
|
||||
KeysData data = null;
|
||||
|
||||
synchronized (keys) {
|
||||
for (final KeysData keysData : keys) {
|
||||
if (keysData.userId().equals(userId)) {
|
||||
data = keysData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String generatedKey = RandomStringUtilities.generate(48);
|
||||
|
||||
if (data == null) {
|
||||
data = new KeysData(new ArrayList<>(), userId);
|
||||
|
||||
data.keys().add(
|
||||
new Key(
|
||||
level,
|
||||
generatedKey,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
);
|
||||
|
||||
keys.add(data);
|
||||
} else {
|
||||
for (final Key key : new ArrayList<>(data.keys())) {
|
||||
if (!key.trustLevel().equals(level)) continue;
|
||||
|
||||
if (!force) throw new IllegalStateException(alreadyExistsMessage);
|
||||
|
||||
data.keys().remove(key);
|
||||
}
|
||||
|
||||
data.keys().add(
|
||||
new Key(
|
||||
level,
|
||||
generatedKey,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
write();
|
||||
|
||||
return generatedKey;
|
||||
}
|
||||
|
||||
private void initialLoad () throws IOException {
|
||||
if (Files.exists(KEY_PATH)) {
|
||||
try (final BufferedReader reader = Files.newBufferedReader(KEY_PATH)) {
|
||||
keys = Collections.synchronizedList(
|
||||
OBJECT_MAPPER.readValue(
|
||||
reader,
|
||||
OBJECT_MAPPER
|
||||
.getTypeFactory()
|
||||
.constructCollectionType(ObjectArrayList.class, KeysData.class)
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Files.createFile(KEY_PATH);
|
||||
|
||||
keys = Collections.synchronizedList(new ObjectArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
private void write () {
|
||||
try (
|
||||
final BufferedWriter writer = Files.newBufferedWriter(
|
||||
KEY_PATH,
|
||||
StandardOpenOption.CREATE,
|
||||
StandardOpenOption.TRUNCATE_EXISTING
|
||||
)
|
||||
) {
|
||||
writer.write(OBJECT_MAPPER.writeValueAsString(keys));
|
||||
} catch (final IOException e) {
|
||||
LoggerUtilities.error("Failed to write the keys file!");
|
||||
LoggerUtilities.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user