diff --git a/README.md b/README.md
index 363df20..275b186 100644
--- a/README.md
+++ b/README.md
@@ -7,9 +7,32 @@
+> [!NOTE]
+> Support for other mod loaders is not planned. PRs implementing such support will not be accepted, please fork this project instead.
+
+> [!WARNING]
+> This mod does not provide support for standard permission systems, and by default only verifies permissions by operator status (i.e. commands can only be run by operators).
+
+## Supported versions
+
+| Version | Support level |
+| ------- | ------------- |
+| 1.20.1 | ✅ Fully supported |
+| * | ❌ Not supported |
+
## Installing
-Download the latest release from the releases tab or go to the [latest release directly](https://code.lilyvex.dev/lily/oauth-fabric/releases/latest), then put it in your Fabric server's `mods` directory.
+Download the latest release from the releases tab or go to the [latest release directly](https://code.lilyvex.dev/lily/oauth-fabric/releases/latest), you may optionally choose to build from source, then put it in your Fabric server's `mods` directory.
+
+## Usage
+
+On initial load, this mod will create a commented configuration file. Edit the created file to contain the correct credentials for your OAuth provider, then restart the server.
+
+Players who are not registered will be kicked on join and given a link to the OAuth provider, where they can login to register for the server.
+
+Each new login with create a new session which will expire after a set period of time (usually defined by your OAuth provider).
+
+Use the `/oauth` command to see a list of all available commands.
## Building from source
@@ -30,4 +53,4 @@ gradlew.bat build
## Contributing
-Fork this repository and create a branch for your changes, then create a pull request for the `main` branch with a "why", "what", and "how" to explain your changes.
\ No newline at end of file
+Fork this repository and create a branch for your changes, then create a pull request for the `dev` branch with a "why", "what", and "how" to explain your changes.
diff --git a/src/main/java/dev/lilyvex/oauthfabric/OAuthFabric.java b/src/main/java/dev/lilyvex/oauthfabric/OAuthFabric.java
index 8cc3afd..4eb8675 100644
--- a/src/main/java/dev/lilyvex/oauthfabric/OAuthFabric.java
+++ b/src/main/java/dev/lilyvex/oauthfabric/OAuthFabric.java
@@ -5,6 +5,8 @@ import net.fabricmc.api.ModInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import dev.lilyvex.oauthfabric.database.Database;
+
public class OAuthFabric implements ModInitializer {
public static final String MOD_ID = "oauth-fabric";
@@ -21,6 +23,9 @@ public class OAuthFabric implements ModInitializer {
OAuthFabricConfig oAuthFabricConfig = new OAuthFabricConfig();
oAuthFabricConfig.load();
+
+ Database database = new Database();
+ database.setDatabase(oAuthFabricConfig.getDatabase());
LOGGER.info("oauth-fabric: Initialized");
}
diff --git a/src/main/java/dev/lilyvex/oauthfabric/OAuthFabricConfig.java b/src/main/java/dev/lilyvex/oauthfabric/OAuthFabricConfig.java
index c6f4b17..809096a 100644
--- a/src/main/java/dev/lilyvex/oauthfabric/OAuthFabricConfig.java
+++ b/src/main/java/dev/lilyvex/oauthfabric/OAuthFabricConfig.java
@@ -27,7 +27,7 @@ public class OAuthFabricConfig {
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()
+ private static final Path CONFIG_FILE_PATH = FabricLoader.getInstance().getConfigDir()
.resolve("oauth-fabric.toml")
.normalize();
diff --git a/src/main/java/dev/lilyvex/oauthfabric/database/Database.java b/src/main/java/dev/lilyvex/oauthfabric/database/Database.java
new file mode 100644
index 0000000..6b348f8
--- /dev/null
+++ b/src/main/java/dev/lilyvex/oauthfabric/database/Database.java
@@ -0,0 +1,36 @@
+package dev.lilyvex.oauthfabric.database;
+
+public class Database implements IDatabase {
+ private IDatabase databaseClass;
+
+ public void setDatabase(String database) {
+ switch (database) {
+ case "sqlite":
+ databaseClass = new SQLite();
+ }
+ }
+
+ public void addUser(String uuid, String oauthId, String sessionToken) {
+ databaseClass.addUser(uuid, oauthId, sessionToken);
+ }
+
+ public void updateUser(String uuid, String oauthId, String sessionToken) {
+ databaseClass.updateUser(uuid, oauthId, sessionToken);
+ }
+
+ public void removeUser(String uuid) {
+ databaseClass.removeUser(uuid);
+ }
+
+ public boolean isRegisteredUser(String uuid) {
+ return databaseClass.isRegisteredUser(uuid);
+ }
+
+ public String getOauthId(String uuid) {
+ return databaseClass.getOauthId(uuid);
+ }
+
+ public String getSessionToken(String uuid) {
+ return databaseClass.getSessionToken(uuid);
+ }
+}
diff --git a/src/main/java/dev/lilyvex/oauthfabric/database/IDatabase.java b/src/main/java/dev/lilyvex/oauthfabric/database/IDatabase.java
new file mode 100644
index 0000000..f036f51
--- /dev/null
+++ b/src/main/java/dev/lilyvex/oauthfabric/database/IDatabase.java
@@ -0,0 +1,11 @@
+package dev.lilyvex.oauthfabric.database;
+
+public interface IDatabase {
+ public void addUser(String uuid, String oauthId, String sessionToken);
+ public void updateUser(String uuid, String oauthId, String sessionToken);
+ public void removeUser(String uuid);
+ public boolean isRegisteredUser(String uuid);
+
+ public String getOauthId(String uuid);
+ public String getSessionToken(String uuid);
+}
\ No newline at end of file
diff --git a/src/main/java/dev/lilyvex/oauthfabric/database/SQLite.java b/src/main/java/dev/lilyvex/oauthfabric/database/SQLite.java
new file mode 100644
index 0000000..340f1c0
--- /dev/null
+++ b/src/main/java/dev/lilyvex/oauthfabric/database/SQLite.java
@@ -0,0 +1,200 @@
+package dev.lilyvex.oauthfabric.database;
+
+import java.nio.file.Path;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.fabricmc.loader.api.FabricLoader;
+
+public class SQLite implements IDatabase {
+ private static final Logger LOGGER = LoggerFactory.getLogger("oauth-fabric");
+ private static final Path DATABASE_PATH = FabricLoader.getInstance().getConfigDir()
+ .resolve("oauth-fabric.db")
+ .normalize();
+
+ private static final String databaseUrl = "jdbc:sqlite:" + DATABASE_PATH;
+ private Connection connection = null;
+
+ private void createDatabase() throws SQLException {
+ try {
+ connection = DriverManager.getConnection(databaseUrl);
+
+ Statement statement = connection.createStatement();
+ statement.executeUpdate("""
+ CREATE TABLE IF NOT EXISTS users (
+ id INTEGER PRIMARY KEY,
+ uuid TEXT UNIQUE,
+ oauth_id TEXT UNIQUE,
+ session_token TEXT UNIQUE
+ )
+ """);
+ } catch (SQLException e) {
+ LOGGER.error("oauth-fabric: Unable to create SQLite database");
+ } finally {
+ try {
+ if (connection != null) {
+ connection.close();
+ }
+ } catch (SQLException e) {
+ LOGGER.error("oauth-fabric: Could not close SQLite connection");
+ }
+ }
+ }
+
+ public void addUser(String uuid, String oauthId, String sessionToken) {
+ try {
+ createDatabase();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ try {
+ connection = DriverManager.getConnection(databaseUrl);
+
+ PreparedStatement statement = connection.prepareStatement("""
+ INSERT INTO users (
+ uuid,
+ oauth_id,
+ session_token
+ ) VALUES (
+ ?,
+ ?,
+ ?
+ )
+ """);
+
+ statement.setString(1, uuid);
+ statement.setString(2, oauthId);
+ statement.setString(3, sessionToken);
+ statement.executeQuery();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void updateUser(String uuid, String oauthId, String sessionToken) {
+ try {
+ createDatabase();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ try {
+ connection = DriverManager.getConnection(databaseUrl);
+
+ PreparedStatement statement = connection.prepareStatement("UPDATE users SET oauth_id = ?, session_token = ? WHERE uuid = ?");
+ statement.setString(1, oauthId);
+ statement.setString(2, sessionToken);
+ statement.setString(3, uuid);
+ statement.executeUpdate();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void removeUser(String uuid) {
+ try {
+ createDatabase();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ try {
+ connection = DriverManager.getConnection(databaseUrl);
+
+ PreparedStatement statement = connection.prepareStatement("DELETE FROM users WHERE uuid = ?");
+ statement.setString(1, uuid);
+ statement.executeUpdate();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean isRegisteredUser(String uuid) {
+ try {
+ createDatabase();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ try {
+ connection = DriverManager.getConnection(databaseUrl);
+
+ PreparedStatement statement = connection.prepareStatement("SELECT * FROM users WHERE uuid = ?");
+ statement.setString(1, uuid);
+ ResultSet resultSet = statement.executeQuery();
+
+ int results = 0;
+ while (resultSet.next()) {
+ results++;
+ }
+
+ if (results > 0) {
+ return true;
+ }
+
+ return false;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String getOauthId(String uuid) {
+ try {
+ createDatabase();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ try {
+ connection = DriverManager.getConnection(databaseUrl);
+
+ PreparedStatement statement = connection.prepareStatement("SELECT * FROM users WHERE uuid = ?");
+ statement.setString(1, uuid);
+ ResultSet resultSet = statement.executeQuery();
+
+ String userOauthId = "";
+
+ while (resultSet.next()) {
+ userOauthId = resultSet.getString("oauth_id");
+ }
+
+ return userOauthId;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String getSessionToken(String uuid) {
+ try {
+ createDatabase();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ try {
+ connection = DriverManager.getConnection(databaseUrl);
+
+ PreparedStatement statement = connection.prepareStatement("SELECT * FROM users WHERE uuid = ?");
+ statement.setString(1, uuid);
+ ResultSet resultSet = statement.executeQuery();
+
+ String userSessionToken = "";
+
+ while (resultSet.next()) {
+ userSessionToken = resultSet.getString("session_token");
+ }
+
+ return userSessionToken;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}