mirror of
https://github.com/JonasunderscoreJones/McWebserver.git
synced 2025-10-23 11:29:19 +02:00
added token system implementation
This commit is contained in:
parent
cee5af6617
commit
6cdf285613
7 changed files with 435 additions and 3 deletions
|
@ -1,16 +1,21 @@
|
||||||
package me.jonasjones.mcwebserver;
|
package me.jonasjones.mcwebserver;
|
||||||
|
|
||||||
import me.jonasjones.mcwebserver.config.ModConfigs;
|
import me.jonasjones.mcwebserver.config.ModConfigs;
|
||||||
import me.jonasjones.mcwebserver.web.HttpServer;
|
|
||||||
import me.jonasjones.mcwebserver.web.api.v1.ApiHandler;
|
import me.jonasjones.mcwebserver.web.api.v1.ApiHandler;
|
||||||
import me.jonasjones.mcwebserver.web.ServerHandler;
|
import me.jonasjones.mcwebserver.web.ServerHandler;
|
||||||
|
import me.jonasjones.mcwebserver.web.api.v2.tokenmgr.Token;
|
||||||
|
import me.jonasjones.mcwebserver.web.api.v2.tokenmgr.TokenManager;
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.command.CommandManager;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static me.jonasjones.mcwebserver.commands.McWebCommand.registerCommands;
|
||||||
import static me.jonasjones.mcwebserver.config.ModConfigs.*;
|
import static me.jonasjones.mcwebserver.config.ModConfigs.*;
|
||||||
|
import static me.jonasjones.mcwebserver.web.api.v2.tokenmgr.TokenSaveManager.readOrCreateTokenFile;
|
||||||
|
|
||||||
public class McWebserver implements ModInitializer {
|
public class McWebserver implements ModInitializer {
|
||||||
// This logger is used to write text to the console and the log file.
|
// This logger is used to write text to the console and the log file.
|
||||||
|
@ -20,6 +25,7 @@ public class McWebserver implements ModInitializer {
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||||
public static final Logger VERBOSELOGGER = LoggerFactory.getLogger(MOD_ID + " - VERBOSE LOGGER");
|
public static final Logger VERBOSELOGGER = LoggerFactory.getLogger(MOD_ID + " - VERBOSE LOGGER");
|
||||||
public static Boolean ISFIRSTSTART = false;
|
public static Boolean ISFIRSTSTART = false;
|
||||||
|
public static MinecraftServer MC_SERVER;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
|
@ -35,6 +41,14 @@ public class McWebserver implements ModInitializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SERVER_API_ENABLED) {
|
if (SERVER_API_ENABLED) {
|
||||||
|
if (API_INGAME_COMMAND_ENABLED) {
|
||||||
|
ArrayList< Token > tokens = readOrCreateTokenFile();
|
||||||
|
LOGGER.info("Loaded " + tokens.size() + " tokens from file.");
|
||||||
|
// register commands
|
||||||
|
registerCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//start collecting api info
|
//start collecting api info
|
||||||
ApiHandler.startHandler();
|
ApiHandler.startHandler();
|
||||||
LOGGER.info("Server API enabled!");
|
LOGGER.info("Server API enabled!");
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
package me.jonasjones.mcwebserver.commands;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||||
|
import me.jonasjones.mcwebserver.McWebserver;
|
||||||
|
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||||
|
import net.minecraft.command.argument.MessageArgumentType;
|
||||||
|
import net.minecraft.server.command.CommandManager;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import static me.jonasjones.mcwebserver.McWebserver.MC_SERVER;
|
||||||
|
import static me.jonasjones.mcwebserver.web.api.v2.tokenmgr.TokenManager.*;
|
||||||
|
import static net.minecraft.server.command.CommandManager.*;
|
||||||
|
|
||||||
|
public class McWebCommand {
|
||||||
|
public static void registerCommands() {
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("mcweb")
|
||||||
|
.then(literal("token")
|
||||||
|
.then(literal("new")
|
||||||
|
.then(CommandManager.argument("Name", StringArgumentType.word())
|
||||||
|
.then(CommandManager.argument("Expiration Time (example: 1y3d4h -> 1 Year, 3 Days, 4 Hours)", StringArgumentType.word())
|
||||||
|
.suggests(ExpirationTimeArgumentType::suggestExpirationTimes)
|
||||||
|
.executes(context -> {
|
||||||
|
String name = StringArgumentType.getString(context, "Name");
|
||||||
|
String expires = StringArgumentType.getString(context, "Expiration Time (example: 1y3d4h -> 1 Year, 3 Days, 4 Hours)");
|
||||||
|
String result = registerToken(name, expires);
|
||||||
|
if (result.equals("exists")) {
|
||||||
|
context.getSource().sendFeedback(() -> Text.of("A token with that name already exists"), false);
|
||||||
|
return 0;
|
||||||
|
} else if (result.equals("failed")) {
|
||||||
|
context.getSource().sendFeedback(() -> Text.of("Failed to create token (Unknown Error)"), false);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
context.getSource().sendFeedback(() -> Text.of("Token Created!\nExpires " + convertToHumanReadable(convertExpirationDate(expires))), true);
|
||||||
|
if (MC_SERVER != null) {
|
||||||
|
// get the player name
|
||||||
|
String playerName = Objects.requireNonNull(context.getSource().getPlayer()).getName().getString();
|
||||||
|
MC_SERVER.getCommandManager().executeWithPrefix(MC_SERVER.getCommandSource(), "tellraw " + playerName + " [\"\",\"Token (will only show once): \",\"\\n\",\"[\",{\"text\":\"" + result + "\",\"color\":\"green\",\"clickEvent\":{\"action\":\"copy_to_clipboard\",\"value\":\"\"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[\"Click to Copy to Clipboard\"]}},\"]\"]");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
context.getSource().sendFeedback(() -> Text.of("Failed to create token (Unknown Error)"), false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}))))
|
||||||
|
.then(literal("list")
|
||||||
|
.executes(context -> {
|
||||||
|
context.getSource().sendFeedback(() -> Text.of(listTokens()), false);
|
||||||
|
return 1;
|
||||||
|
}))
|
||||||
|
.then(literal("delete")
|
||||||
|
.then(argument("Token Name", StringArgumentType.word())
|
||||||
|
.suggests(DeleteTokenNameArgumentType::suggestTokenNames)
|
||||||
|
.executes(context -> {
|
||||||
|
String name = StringArgumentType.getString(context, "Token Name");
|
||||||
|
if (deleteToken(name)) {
|
||||||
|
context.getSource().sendFeedback(() -> Text.of("Token '" + name + "' deleted!"), true);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
context.getSource().sendFeedback(() -> Text.of("Token not found!"), false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExpirationTimeArgumentType {
|
||||||
|
|
||||||
|
public static ExpirationTimeArgumentType word() {
|
||||||
|
return new ExpirationTimeArgumentType();
|
||||||
|
}
|
||||||
|
private boolean isValid(String input) {
|
||||||
|
// The regex pattern for your requirements.
|
||||||
|
String pattern = "^(\\d+h)?(\\d+d)?(\\d+y)?$";
|
||||||
|
|
||||||
|
// Check if the input matches the pattern.
|
||||||
|
//return input.matches(pattern);
|
||||||
|
return input.equals("1h");
|
||||||
|
}
|
||||||
|
|
||||||
|
static CompletableFuture<Suggestions> suggestExpirationTimes(CommandContext<ServerCommandSource> serverCommandSourceCommandContext, SuggestionsBuilder builder) {
|
||||||
|
try {
|
||||||
|
// get the current input
|
||||||
|
String input = StringArgumentType.getString(serverCommandSourceCommandContext, "Expiration Time (example: 1y3d4h -> 1 Year, 3 Days, 4 Hours)");
|
||||||
|
|
||||||
|
|
||||||
|
// check if the input matches the pattern
|
||||||
|
if (!input.equals("0")) {
|
||||||
|
if (input.matches("\\d+")) {
|
||||||
|
builder.suggest(input + "y");
|
||||||
|
builder.suggest(input + "d");
|
||||||
|
builder.suggest(input + "h");
|
||||||
|
suggestIntRange(builder, input, 0);
|
||||||
|
} else if (input.matches("\\d+y\\d+")) {
|
||||||
|
builder.suggest(input + "y");
|
||||||
|
builder.suggest(input + "d");
|
||||||
|
suggestIntRange(builder, input, 0);
|
||||||
|
} else if (input.matches("\\d+d\\d+")) {
|
||||||
|
builder.suggest(input + "d");
|
||||||
|
builder.suggest(input + "h");
|
||||||
|
suggestIntRange(builder, input, 0);
|
||||||
|
} else if (input.matches("\\d+y\\d+d\\d+")) {
|
||||||
|
builder.suggest(input + "h");
|
||||||
|
suggestIntRange(builder, input, 0);
|
||||||
|
} else if (input.matches("\\d+y")) {
|
||||||
|
suggestIntRange(builder, input, 1);
|
||||||
|
} else if (input.matches("\\d+d")) {
|
||||||
|
suggestIntRange(builder, input, 1);
|
||||||
|
} else if (input.matches("\\d+y\\d+d")) {
|
||||||
|
suggestIntRange(builder, input, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
suggestIntRange(builder, "", 0);
|
||||||
|
}
|
||||||
|
return builder.buildFuture();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void suggestIntRange(SuggestionsBuilder builder, String input, int min) {
|
||||||
|
for (int i = min; i <= 9; i++) {
|
||||||
|
builder.suggest(input + String.valueOf(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DeleteTokenNameArgumentType {
|
||||||
|
static CompletableFuture<Suggestions> suggestTokenNames(CommandContext<ServerCommandSource> serverCommandSourceCommandContext, SuggestionsBuilder builder) {
|
||||||
|
String[] tokenNames = getTokenNames();
|
||||||
|
|
||||||
|
for (String tokenName : tokenNames) {
|
||||||
|
builder.suggest(tokenName);
|
||||||
|
}
|
||||||
|
return builder.buildFuture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ public class ModConfigs {
|
||||||
public static String WEB_FILE_404;
|
public static String WEB_FILE_404;
|
||||||
public static Boolean SERVER_API_ENABLED;
|
public static Boolean SERVER_API_ENABLED;
|
||||||
public static Boolean ADV_API_ENABLED;
|
public static Boolean ADV_API_ENABLED;
|
||||||
|
public static Boolean API_INGAME_COMMAND_ENABLED;
|
||||||
public static String WEB_FILE_NOSUPPORT;
|
public static String WEB_FILE_NOSUPPORT;
|
||||||
public static Boolean VERBOSE = false; //needs to be set to false since the verbose logger is called before config file is fully loaded
|
public static Boolean VERBOSE = false; //needs to be set to false since the verbose logger is called before config file is fully loaded
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ public class ModConfigs {
|
||||||
config.addKeyValuePair(new Pair<>("web.file.404", "404.html"), "the name of the html file for 404 page");
|
config.addKeyValuePair(new Pair<>("web.file.404", "404.html"), "the name of the html file for 404 page");
|
||||||
config.addKeyValuePair(new Pair<>("web.api", true), "whether or not the webserver api should be enabled or not");
|
config.addKeyValuePair(new Pair<>("web.api", true), "whether or not the webserver api should be enabled or not");
|
||||||
config.addKeyValuePair(new Pair<>("web.api.adv", true), "whether or not the api should expose information such as player coordinates and inventory");
|
config.addKeyValuePair(new Pair<>("web.api.adv", true), "whether or not the api should expose information such as player coordinates and inventory");
|
||||||
|
config.addKeyValuePair(new Pair<>("web.api.cmd", true), "whether or not the ingame command to manage tokens should be enabled or not");
|
||||||
config.addKeyValuePair(new Pair<>("web.file.notSupported", "not_supported.html"), "the name of the html file for 'not supported' page");
|
config.addKeyValuePair(new Pair<>("web.file.notSupported", "not_supported.html"), "the name of the html file for 'not supported' page");
|
||||||
config.addKeyValuePair(new Pair<>("logger.verbose", false), "whether or not to log verbose output");
|
config.addKeyValuePair(new Pair<>("logger.verbose", false), "whether or not to log verbose output");
|
||||||
}
|
}
|
||||||
|
@ -55,7 +57,8 @@ public class ModConfigs {
|
||||||
WEB_FILE_ROOT = CONFIG.getOrDefault("web.file.root", "index.html");
|
WEB_FILE_ROOT = CONFIG.getOrDefault("web.file.root", "index.html");
|
||||||
WEB_FILE_404 = CONFIG.getOrDefault("web.file.404", "404.html");
|
WEB_FILE_404 = CONFIG.getOrDefault("web.file.404", "404.html");
|
||||||
SERVER_API_ENABLED = CONFIG.getOrDefault("web.api", true);
|
SERVER_API_ENABLED = CONFIG.getOrDefault("web.api", true);
|
||||||
ADV_API_ENABLED = CONFIG.getOrDefault("web.api.adv", false);
|
ADV_API_ENABLED = CONFIG.getOrDefault("web.api.adv", true);
|
||||||
|
API_INGAME_COMMAND_ENABLED = CONFIG.getOrDefault("web.api.cmd", true);
|
||||||
WEB_FILE_NOSUPPORT = CONFIG.getOrDefault("web.file.notSupported", "not_supported.html");
|
WEB_FILE_NOSUPPORT = CONFIG.getOrDefault("web.file.notSupported", "not_supported.html");
|
||||||
VERBOSE = CONFIG.getOrDefault("logger.verbose", true);
|
VERBOSE = CONFIG.getOrDefault("logger.verbose", true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package me.jonasjones.mcwebserver.web.api.v1;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
|
|
||||||
|
import static me.jonasjones.mcwebserver.McWebserver.MC_SERVER;
|
||||||
|
|
||||||
public class ApiHandler {
|
public class ApiHandler {
|
||||||
|
|
||||||
public static Boolean isApiRequest(String request) {
|
public static Boolean isApiRequest(String request) {
|
||||||
|
@ -64,6 +66,7 @@ public class ApiHandler {
|
||||||
public static void startHandler() {
|
public static void startHandler() {
|
||||||
ServerTickEvents.END_SERVER_TICK.register(server -> {
|
ServerTickEvents.END_SERVER_TICK.register(server -> {
|
||||||
if (server.isRunning()) {
|
if (server.isRunning()) {
|
||||||
|
MC_SERVER = server;
|
||||||
ApiRequestsUtil.setMOTD(server.getServerMotd());
|
ApiRequestsUtil.setMOTD(server.getServerMotd());
|
||||||
ApiRequestsUtil.setSERVER_IP(server.getServerIp());
|
ApiRequestsUtil.setSERVER_IP(server.getServerIp());
|
||||||
ApiRequestsUtil.setSERVER_PORT(server.getServerPort());
|
ApiRequestsUtil.setSERVER_PORT(server.getServerPort());
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v2.tokenmgr;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter @Setter
|
||||||
|
public class Token {
|
||||||
|
private String name;
|
||||||
|
private String tokenHash;
|
||||||
|
private String tokenStart;
|
||||||
|
private long expires;
|
||||||
|
|
||||||
|
public Token(String name, String tokenHash, String tokenStart, long expires) {
|
||||||
|
this.name = name;
|
||||||
|
this.tokenHash = tokenHash;
|
||||||
|
this.tokenStart = tokenStart;
|
||||||
|
this.expires = expires;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v2.tokenmgr;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import me.jonasjones.mcwebserver.McWebserver;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static me.jonasjones.mcwebserver.web.api.v2.tokenmgr.TokenSaveManager.*;
|
||||||
|
|
||||||
|
public class TokenManager {
|
||||||
|
@Getter
|
||||||
|
private static ArrayList<Token> tokens = new ArrayList<>();
|
||||||
|
|
||||||
|
private static String hashString(String input) throws NoSuchAlgorithmException {
|
||||||
|
try {
|
||||||
|
// Create a MessageDigest instance for SHA-256
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||||
|
|
||||||
|
// Update the digest with the input string
|
||||||
|
byte[] hashedBytes = digest.digest(input.getBytes());
|
||||||
|
|
||||||
|
// Convert the byte array to a hexadecimal string
|
||||||
|
StringBuilder hexString = new StringBuilder();
|
||||||
|
for (byte b : hashedBytes) {
|
||||||
|
String hex = Integer.toHexString(0xff & b);
|
||||||
|
if (hex.length() == 1) {
|
||||||
|
hexString.append('0');
|
||||||
|
}
|
||||||
|
hexString.append(hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hexString.toString();
|
||||||
|
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static String generateToken() {
|
||||||
|
try {
|
||||||
|
// Generate random bytes using SecureRandom
|
||||||
|
SecureRandom secureRandom = new SecureRandom();
|
||||||
|
byte[] randomBytes = new byte[16]; // 16 bytes for a 128-bit hash
|
||||||
|
secureRandom.nextBytes(randomBytes);
|
||||||
|
|
||||||
|
return hashString(new String(randomBytes));
|
||||||
|
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long convertExpirationDate(String expiresIn) {
|
||||||
|
if (expiresIn == null || expiresIn.equals("0")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
long timestamp = Long.parseLong(expiresIn);
|
||||||
|
if (timestamp > Instant.now().getEpochSecond()) {
|
||||||
|
// The input is already a future timestamp
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
// Input is not a valid timestamp, continue to parse the duration format
|
||||||
|
}
|
||||||
|
// Pattern to match the duration format (XyXdXh)
|
||||||
|
Pattern pattern = Pattern.compile("(\\d+)?[yY]?(\\d+)?[dD]?(\\d+)?[hH]?");
|
||||||
|
Matcher matcher = pattern.matcher(expiresIn);
|
||||||
|
|
||||||
|
int years = 0, days = 0, hours = 0;
|
||||||
|
|
||||||
|
// Check if the input matches the pattern
|
||||||
|
if (matcher.matches()) {
|
||||||
|
String yearsStr = matcher.group(1);
|
||||||
|
String daysStr = matcher.group(2);
|
||||||
|
String hoursStr = matcher.group(3);
|
||||||
|
|
||||||
|
// Parse and add the corresponding values
|
||||||
|
years = yearsStr != null ? Integer.parseInt(yearsStr) : 0;
|
||||||
|
days = daysStr != null ? Integer.parseInt(daysStr) : 0;
|
||||||
|
hours = hoursStr != null ? Integer.parseInt(hoursStr) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the future timestamp based on the current timestamp and the parsed values
|
||||||
|
long currentTimestamp = Instant.now().getEpochSecond();
|
||||||
|
long futureTimestamp = currentTimestamp + (years * 365 * 24 * 60 * 60) + (days * 24 * 60 * 60) + (hours * 60 * 60);
|
||||||
|
|
||||||
|
return futureTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convertToHumanReadable(long unixTimestamp) {
|
||||||
|
if (unixTimestamp == 0) {
|
||||||
|
return "Never";
|
||||||
|
}
|
||||||
|
// Convert Unix timestamp to LocalDateTime
|
||||||
|
Instant instant = Instant.ofEpochSecond(unixTimestamp);
|
||||||
|
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||||
|
|
||||||
|
// Define a format for the human-readable date-time
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
// Format the LocalDateTime to a string
|
||||||
|
return localDateTime.format(formatter) + " (UTC)";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String registerToken(String name, String expires) {
|
||||||
|
tokens = readTokensFromFile();
|
||||||
|
// check if token already exists
|
||||||
|
for (Token tokenObj : tokens) {
|
||||||
|
if (tokenObj.getName().equals(name)) {
|
||||||
|
|
||||||
|
return "exists";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String token = generateToken();
|
||||||
|
String tokenStart = token.substring(0, 5);
|
||||||
|
Token tokenObj = new Token(name, hashString(token), tokenStart, convertExpirationDate(expires));
|
||||||
|
tokens.add(tokenObj);
|
||||||
|
writeTokensToFile(tokens);
|
||||||
|
return token;
|
||||||
|
} catch (Exception e) {
|
||||||
|
McWebserver.LOGGER.error("Error generating token: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return "failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String listTokens() {
|
||||||
|
tokens = readTokensFromFile();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (tokens.size() == 0) {
|
||||||
|
return "No active tokens.";
|
||||||
|
}
|
||||||
|
sb.append("Active Tokens:\n");
|
||||||
|
sb.append("Name | Expiration Date | Beginning of Token value\n");
|
||||||
|
for (Token token : tokens) {
|
||||||
|
sb.append(token.getName()).append(" | ").append(convertToHumanReadable(token.getExpires())).append(" | ").append(token.getTokenStart()).append("...").append("\n");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean deleteToken(String name) {
|
||||||
|
tokens = readTokensFromFile();
|
||||||
|
for (Token token : tokens) {
|
||||||
|
if (token.getName().equals(name)) {
|
||||||
|
tokens.remove(token);
|
||||||
|
writeTokensToFile(tokens);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getToken(String name) {
|
||||||
|
tokens = readTokensFromFile();
|
||||||
|
for (Token token : tokens) {
|
||||||
|
if (token.getName().equals(name)) {
|
||||||
|
return token.getTokenHash();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getTokenNames() {
|
||||||
|
tokens = readTokensFromFile();
|
||||||
|
String[] tokenNames = new String[tokens.size()];
|
||||||
|
for (int i = 0; i < tokens.size(); i++) {
|
||||||
|
tokenNames[i] = tokens.get(i).getName();
|
||||||
|
}
|
||||||
|
return tokenNames;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v2.tokenmgr;
|
||||||
|
|
||||||
|
import me.jonasjones.mcwebserver.McWebserver;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class TokenSaveManager {
|
||||||
|
private static final String TOKEN_FILE_PATH = String.valueOf(FabricLoader.getInstance().getConfigDir()) + "/mcwebserver_tokens.txt";
|
||||||
|
|
||||||
|
public static Boolean isExpired(Token token) {
|
||||||
|
if (token.getExpires() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return token.getExpires() < Instant.now().getEpochSecond();
|
||||||
|
}
|
||||||
|
public static ArrayList<Token> readTokensFromFile() {
|
||||||
|
ArrayList<Token> tokenList = new ArrayList<>();
|
||||||
|
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(TOKEN_FILE_PATH))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
String[] parts = line.split("\\|");
|
||||||
|
if (parts.length == 4 && !parts[0].equals("null")) {
|
||||||
|
String name = parts[0];
|
||||||
|
String token = parts[1];
|
||||||
|
String tokenStart = parts[2];
|
||||||
|
long expires = Long.parseLong(parts[3]);
|
||||||
|
|
||||||
|
Token tokenObj = new Token(name, token, tokenStart, expires);
|
||||||
|
|
||||||
|
if (!isExpired(tokenObj)) {
|
||||||
|
tokenList.add(tokenObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException | NumberFormatException e) {
|
||||||
|
McWebserver.LOGGER.error("Error reading tokens from file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeTokensToFile(ArrayList<Token> tokenList) {
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter(TOKEN_FILE_PATH))) {
|
||||||
|
for (Token token : tokenList) {
|
||||||
|
String line = token.getName() + "|" + token.getTokenHash() + "|" + token.getTokenStart() + "|" + token.getExpires();
|
||||||
|
writer.write(line);
|
||||||
|
writer.newLine();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
McWebserver.LOGGER.error("Error writing tokens to file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayList<Token> readOrCreateTokenFile() {
|
||||||
|
File file = new File(TOKEN_FILE_PATH);
|
||||||
|
if (!file.exists()) {
|
||||||
|
try {
|
||||||
|
file.createNewFile();
|
||||||
|
McWebserver.LOGGER.info("Created api token file.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
McWebserver.LOGGER.error("Error creating api token file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
|
} else {
|
||||||
|
return readTokensFromFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue