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); + } + } +}