From cac64864c6135b415c76c6fe9a91dc2592f5a2fa Mon Sep 17 00:00:00 2001 From: lily Date: Wed, 23 Apr 2025 22:47:02 -0400 Subject: [PATCH] feat: add basic configuration management --- build.gradle | 12 +++ .../dev/lilyvex/oauthfabric/OAuthFabric.java | 5 +- .../oauthfabric/OAuthFabricConfig.java | 102 ++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/main/java/dev/lilyvex/oauthfabric/OAuthFabricConfig.java diff --git a/build.gradle b/build.gradle index 6724450..b626148 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,13 @@ loom { } +configurations { + include { + canBeResolved = true + canBeConsumed = true + } +} + dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" @@ -43,6 +50,7 @@ dependencies { implementation 'com.google.oauth-client:google-oauth-client:1.39.0' // Configuration library + include 'com.electronwill.night-config:toml:3.6.0' implementation 'com.electronwill.night-config:toml:3.6.0' } @@ -74,6 +82,10 @@ jar { from("LICENSE") { rename { "${it}_${inputs.properties.archivesName}"} } + + from { + configurations.include.collect { it.isDirectory() ? it : zipTree(it) } + } } // configure the maven publication diff --git a/src/main/java/dev/lilyvex/oauthfabric/OAuthFabric.java b/src/main/java/dev/lilyvex/oauthfabric/OAuthFabric.java index 06c0680..8cc3afd 100644 --- a/src/main/java/dev/lilyvex/oauthfabric/OAuthFabric.java +++ b/src/main/java/dev/lilyvex/oauthfabric/OAuthFabric.java @@ -19,6 +19,9 @@ public class OAuthFabric implements ModInitializer { // However, some things (like resources) may still be uninitialized. // Proceed with mild caution. - LOGGER.info("Hello Fabric world!"); + OAuthFabricConfig oAuthFabricConfig = new OAuthFabricConfig(); + oAuthFabricConfig.load(); + + LOGGER.info("oauth-fabric: Initialized"); } } \ No newline at end of file diff --git a/src/main/java/dev/lilyvex/oauthfabric/OAuthFabricConfig.java b/src/main/java/dev/lilyvex/oauthfabric/OAuthFabricConfig.java new file mode 100644 index 0000000..580e90f --- /dev/null +++ b/src/main/java/dev/lilyvex/oauthfabric/OAuthFabricConfig.java @@ -0,0 +1,102 @@ +package dev.lilyvex.oauthfabric; + +import com.electronwill.nightconfig.core.CommentedConfig; +import com.electronwill.nightconfig.core.io.ParsingException; +import com.electronwill.nightconfig.core.io.ParsingMode; +import com.electronwill.nightconfig.toml.TomlParser; +import com.electronwill.nightconfig.toml.TomlWriter; + +import net.fabricmc.loader.api.FabricLoader; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OAuthFabricConfig { + private static final Logger LOGGER = LoggerFactory.getLogger("oauth-fabric"); + private static final String DEFAULT_PROVIDER = "auth.lilyvex.dev"; + private static final String DEFAULT_CLIENT_ID = "minecraft"; + private static final String DEFAULT_CLIENT_SECRET = ""; + private static final String DEFAULT_REDIRECT_URI = "mc.lilyvex.dev/oauth2"; + private static final String DEFAULT_DATABASE = "sqlite"; + + public static final Path CONFIG_FILE_PATH = FabricLoader.getInstance().getConfigDir() + .resolve("oauth-fabric.toml") + .normalize(); + + private final CommentedConfig config = CommentedConfig.inMemory(); + + // URL to the OAuth provider (e.g. accounts.google.com, discord.com/oauth2) + private String provider; + + // ID of the OAuth client. This is usually defined when creating the OAuth application. + private String client_id; + + // Client secret + private String client_secret; + + // URI to redirect to. Ensure that this URI is listed in the allowed redirect URIs section + // of your OAuth provider. + private String redirect_uri; + + // Which database to use (SQLite is currently the only supported database). + private String database; + + public void load() { + this.config.getOrElse("provider", DEFAULT_PROVIDER); + this.config.getOrElse("client_id", DEFAULT_CLIENT_ID); + this.config.getOrElse("client_secret", DEFAULT_CLIENT_SECRET); + this.config.getOrElse("redirect_uri", DEFAULT_REDIRECT_URI); + this.config.getOrElse("database", DEFAULT_DATABASE); + + try { + this.loadFromFile(true); + } catch (IOException e) { + throw new RuntimeException(e); + } + + LOGGER.info("oauth-fabric: Configuration loaded."); + } + + private void loadFromFile(boolean firstAttempt) throws IOException { + try (var reader = Files.newBufferedReader(CONFIG_FILE_PATH)) { + new TomlParser().parse(reader, this.config, ParsingMode.REPLACE); + } catch (NoSuchFileException | FileNotFoundException e) { + if (!firstAttempt) { + throw e; + } + + this.copyDefaultFile(); + this.loadFromFile(true); + } catch (ParsingException e) { + if (!firstAttempt) { + throw e; + } + + var backupPath = CONFIG_FILE_PATH.resolveSibling("oauth-fabric.toml.old").toAbsolutePath().normalize(); + + LOGGER.error("oauth-fabric: Failed to parse configuration file, THIS IS BAD.", e); + LOGGER.error("oauth-fabric: Copying the corrupt file to \"{}\".", backupPath); + Files.copy(CONFIG_FILE_PATH, backupPath, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING); + this.copyDefaultFile(); + this.loadFromFile(false); + } + } + + private void copyDefaultFile() throws IOException { + Files.createDirectories(CONFIG_FILE_PATH.getParent()); + + try (var writer = Files.newBufferedWriter(CONFIG_FILE_PATH, StandardCharsets.UTF_8)) { + new TomlWriter().write(this.config.unmodifiable(), writer); + } catch (NoSuchFileException | FileNotFoundException e) { + LOGGER.error("oauth-fabric: Failed to write default configuration file."); + } + } +}