mirror of
https://github.com/SimplexDevelopment/FreedomNetworkSuite.git
synced 2024-11-14 21:23:33 +00:00
Tyr Backbone Creation
# Changes: ## Patchwork - Renamed FreedomExecutor to ExecutorProvider and moved the class to the provider package. - Created an SQL Registry to prevent dependencies on Datura for SQL data. SQL is returned through an Optional, in the event that there is no SQL service registered. - Created SQLResult, a generic ORM for ResultSets to avoid working directly with SQL data. ## Tyr - Created Identity, which houses a username and related secret key. - Created SQLEntry which stores the information from the Identity class into an SQL table called sessionData. - Created TOTP, a simple static class that allows easy access to TimeBasedOneTimePasswordUtils class. - Created OAuth2 which houses identities and performs the appropriate credential validations (incomplete)
This commit is contained in:
parent
85cc1f7ae0
commit
33731b611f
@ -32,7 +32,7 @@ import fns.datura.punishment.Locker;
|
|||||||
import fns.datura.sql.MySQL;
|
import fns.datura.sql.MySQL;
|
||||||
import fns.patchwork.base.Registration;
|
import fns.patchwork.base.Registration;
|
||||||
import fns.patchwork.command.CommandHandler;
|
import fns.patchwork.command.CommandHandler;
|
||||||
import fns.patchwork.service.SubscriptionProvider;
|
import fns.patchwork.provider.SubscriptionProvider;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
@ -26,11 +26,11 @@ package fns.datura.sql;
|
|||||||
import fns.patchwork.base.Patchwork;
|
import fns.patchwork.base.Patchwork;
|
||||||
import fns.patchwork.base.Shortcuts;
|
import fns.patchwork.base.Shortcuts;
|
||||||
import fns.patchwork.sql.SQL;
|
import fns.patchwork.sql.SQL;
|
||||||
|
import fns.patchwork.sql.SQLResult;
|
||||||
import fns.patchwork.utils.container.Identity;
|
import fns.patchwork.utils.container.Identity;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CompletionException;
|
import java.util.concurrent.CompletionException;
|
||||||
@ -74,7 +74,7 @@ public class MySQL implements SQL
|
|||||||
.append(password);
|
.append(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<ResultSet> getRow(final String table, final String column, final Identity identity)
|
public CompletableFuture<SQLResult> getRow(final String table, final String column, final Identity identity)
|
||||||
{
|
{
|
||||||
return executeQuery("SELECT * FROM ? WHERE ? = ?", table, column, identity.getId());
|
return executeQuery("SELECT * FROM ? WHERE ? = ?", table, column, identity.getId());
|
||||||
}
|
}
|
||||||
@ -83,99 +83,104 @@ public class MySQL implements SQL
|
|||||||
public CompletableFuture<PreparedStatement> prepareStatement(final String query, final Object... args)
|
public CompletableFuture<PreparedStatement> prepareStatement(final String query, final Object... args)
|
||||||
{
|
{
|
||||||
return getConnection()
|
return getConnection()
|
||||||
.thenApplyAsync(connection ->
|
.thenApplyAsync(connection ->
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
final PreparedStatement statement = connection.prepareStatement(query);
|
final PreparedStatement statement = connection.prepareStatement(query);
|
||||||
for (int i = 0; i < args.length; i++)
|
for (int i = 0; i < args.length; i++)
|
||||||
{
|
{
|
||||||
statement.setObject(i + 1, args[i]);
|
statement.setObject(i + 1, args[i]);
|
||||||
}
|
}
|
||||||
return statement;
|
return statement;
|
||||||
} catch (SQLException ex)
|
}
|
||||||
{
|
catch (SQLException ex)
|
||||||
throw new CompletionException("Failed to prepare statement: "
|
{
|
||||||
+ query + "\n", ex);
|
throw new CompletionException("Failed to prepare statement: "
|
||||||
}
|
+ query + "\n", ex);
|
||||||
}, Shortcuts.provideModule(Patchwork.class)
|
}
|
||||||
.getExecutor()
|
}, Shortcuts.provideModule(Patchwork.class)
|
||||||
.getAsync());
|
.getExecutor()
|
||||||
|
.getAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Connection> getConnection()
|
private CompletableFuture<Connection> getConnection()
|
||||||
{
|
{
|
||||||
return CompletableFuture.supplyAsync(() ->
|
return CompletableFuture.supplyAsync(() ->
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return DriverManager.getConnection(url.toString());
|
return DriverManager.getConnection(url.toString());
|
||||||
} catch (SQLException ex)
|
}
|
||||||
{
|
catch (SQLException ex)
|
||||||
throw new CompletionException("Failed to connect to the database: "
|
{
|
||||||
+ url.toString() + "\n", ex);
|
throw new CompletionException("Failed to connect to the database: "
|
||||||
}
|
+ url.toString() + "\n", ex);
|
||||||
}, Shortcuts.provideModule(Patchwork.class)
|
}
|
||||||
.getExecutor()
|
}, Shortcuts.provideModule(Patchwork.class)
|
||||||
.getAsync());
|
.getExecutor()
|
||||||
|
.getAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<ResultSet> executeQuery(final String query, final Object... args)
|
public CompletableFuture<SQLResult> executeQuery(final String query, final Object... args)
|
||||||
{
|
{
|
||||||
return prepareStatement(query, args)
|
return prepareStatement(query, args)
|
||||||
.thenApplyAsync(statement ->
|
.thenApplyAsync(statement ->
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return statement.executeQuery();
|
return new SQLResult(statement.executeQuery());
|
||||||
} catch (SQLException ex)
|
}
|
||||||
{
|
catch (SQLException ex)
|
||||||
throw new CompletionException(
|
{
|
||||||
"Failed to retrieve a result set from query: "
|
throw new CompletionException(
|
||||||
|
"Failed to retrieve a result set from query: "
|
||||||
+ query + "\n", ex);
|
+ query + "\n", ex);
|
||||||
}
|
}
|
||||||
}, Shortcuts.provideModule(Patchwork.class)
|
}, Shortcuts.provideModule(Patchwork.class)
|
||||||
.getExecutor()
|
.getExecutor()
|
||||||
.getAsync());
|
.getAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Integer> executeUpdate(final String query, final Object... args)
|
public CompletableFuture<Integer> executeUpdate(final String query, final Object... args)
|
||||||
{
|
{
|
||||||
return prepareStatement(query, args)
|
return prepareStatement(query, args)
|
||||||
.thenApplyAsync(statement ->
|
.thenApplyAsync(statement ->
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return statement.executeUpdate();
|
return statement.executeUpdate();
|
||||||
} catch (SQLException ex)
|
}
|
||||||
{
|
catch (SQLException ex)
|
||||||
throw new CompletionException("Failed to execute update: "
|
{
|
||||||
+ query + "\n", ex);
|
throw new CompletionException("Failed to execute update: "
|
||||||
}
|
+ query + "\n", ex);
|
||||||
}, Shortcuts.provideModule(Patchwork.class)
|
}
|
||||||
.getExecutor()
|
}, Shortcuts.provideModule(Patchwork.class)
|
||||||
.getAsync());
|
.getExecutor()
|
||||||
|
.getAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> execute(final String query, final Object... args)
|
public CompletableFuture<Boolean> execute(final String query, final Object... args)
|
||||||
{
|
{
|
||||||
return prepareStatement(query, args)
|
return prepareStatement(query, args)
|
||||||
.thenApplyAsync(statement ->
|
.thenApplyAsync(statement ->
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return statement.execute();
|
return statement.execute();
|
||||||
} catch (SQLException ex)
|
}
|
||||||
{
|
catch (SQLException ex)
|
||||||
throw new CompletionException("Failed to execute statement: "
|
{
|
||||||
+ query + "\n", ex);
|
throw new CompletionException("Failed to execute statement: "
|
||||||
}
|
+ query + "\n", ex);
|
||||||
}, Shortcuts.provideModule(Patchwork.class)
|
}
|
||||||
.getExecutor()
|
}, Shortcuts.provideModule(Patchwork.class)
|
||||||
.getAsync());
|
.getExecutor()
|
||||||
|
.getAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -201,42 +206,27 @@ public class MySQL implements SQL
|
|||||||
final Identity identity, final Class<T> type)
|
final Identity identity, final Class<T> type)
|
||||||
{
|
{
|
||||||
return executeQuery("SELECT ? FROM ? WHERE ? = ?", column, table, key, identity.getId())
|
return executeQuery("SELECT ? FROM ? WHERE ? = ?", column, table, key, identity.getId())
|
||||||
.thenApplyAsync(resultSet ->
|
.thenApplyAsync(resultSet -> (resultSet.hasNext()) ? resultSet.autoCast(1, column, type) : null,
|
||||||
{
|
Shortcuts.provideModule(Patchwork.class)
|
||||||
try
|
.getExecutor()
|
||||||
{
|
.getAsync());
|
||||||
if (resultSet.next())
|
|
||||||
{
|
|
||||||
return resultSet.getObject(column, type);
|
|
||||||
}
|
|
||||||
} catch (SQLException ex)
|
|
||||||
{
|
|
||||||
throw new CompletionException(
|
|
||||||
"Failed to retrieve column: " + column + " from table: " + table + " " +
|
|
||||||
"where primary key: " + key + " is equal to: " + identity.getId() + "\n",
|
|
||||||
ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}, Shortcuts.provideModule(Patchwork.class)
|
|
||||||
.getExecutor()
|
|
||||||
.getAsync());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<Boolean> updateColumn(final String table, final String column, final Object value,
|
public CompletableFuture<Boolean> updateColumn(final String table, final String column, final Object value,
|
||||||
final String key, final Identity identity)
|
final String key, final Identity identity)
|
||||||
{
|
{
|
||||||
return executeUpdate("UPDATE ? SET ? = ? WHERE ? = ?", table, column, value, key, identity.getId())
|
return executeUpdate("UPDATE ? SET ? = ? WHERE ? = ?", table, column, value, key, identity.getId())
|
||||||
.thenApplyAsync(result -> result > 0, Shortcuts.provideModule(Patchwork.class)
|
.thenApplyAsync(result -> result > 0, Shortcuts.provideModule(Patchwork.class)
|
||||||
.getExecutor()
|
.getExecutor()
|
||||||
.getAsync());
|
.getAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<Boolean> deleteRow(final String table, final String key, final Identity identity)
|
public CompletableFuture<Boolean> deleteRow(final String table, final String key, final Identity identity)
|
||||||
{
|
{
|
||||||
return executeUpdate("DELETE FROM ? WHERE ? = ?", table, key, identity.getId())
|
return executeUpdate("DELETE FROM ? WHERE ? = ?", table, key, identity.getId())
|
||||||
.thenApplyAsync(result -> result > 0, Shortcuts.provideModule(Patchwork.class)
|
.thenApplyAsync(result -> result > 0, Shortcuts.provideModule(Patchwork.class)
|
||||||
.getExecutor()
|
.getExecutor()
|
||||||
.getAsync());
|
.getAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<Boolean> insertRow(final String table, final Object... values)
|
public CompletableFuture<Boolean> insertRow(final String table, final Object... values)
|
||||||
|
@ -34,10 +34,8 @@ import fns.patchwork.sql.SQL;
|
|||||||
import fns.patchwork.user.User;
|
import fns.patchwork.user.User;
|
||||||
import fns.patchwork.user.UserData;
|
import fns.patchwork.user.UserData;
|
||||||
import fns.patchwork.utils.logging.FNS4J;
|
import fns.patchwork.utils.logging.FNS4J;
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -69,14 +67,14 @@ public class SimpleUserData implements UserData
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SimpleUserData(
|
private SimpleUserData(
|
||||||
final UUID uuid,
|
final UUID uuid,
|
||||||
final String username,
|
final String username,
|
||||||
final User user,
|
final User user,
|
||||||
final Group group,
|
final Group group,
|
||||||
final long playtime,
|
final long playtime,
|
||||||
final boolean canInteract,
|
final boolean canInteract,
|
||||||
final long balance,
|
final long balance,
|
||||||
final boolean transactionsFrozen)
|
final boolean transactionsFrozen)
|
||||||
{
|
{
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
@ -93,56 +91,53 @@ public class SimpleUserData implements UserData
|
|||||||
{
|
{
|
||||||
return sql.executeQuery("SELECT * FROM users WHERE UUID = ?", uuid)
|
return sql.executeQuery("SELECT * FROM users WHERE UUID = ?", uuid)
|
||||||
.thenApplyAsync(result ->
|
.thenApplyAsync(result ->
|
||||||
{
|
{
|
||||||
try
|
|
||||||
{
|
|
||||||
if (result.next())
|
|
||||||
{
|
|
||||||
final String g = result.getString("group");
|
|
||||||
|
|
||||||
final UUID u = UUID.fromString(uuid);
|
if (result.hasNext())
|
||||||
final String username = result.getString("username");
|
{
|
||||||
|
final String g = result.getString("group");
|
||||||
|
|
||||||
final Player player = Bukkit.getPlayer(u);
|
final UUID u = UUID.fromString(uuid);
|
||||||
|
final String username = result.getString("username");
|
||||||
|
|
||||||
if (player == null)
|
final Player player = Bukkit.getPlayer(u);
|
||||||
throw new IllegalStateException("Player should be online but they are not!");
|
|
||||||
|
|
||||||
final User user = new FreedomUser(player);
|
if (player == null)
|
||||||
final Group group = Registration
|
throw new IllegalStateException(
|
||||||
.getGroupRegistry()
|
"Player should be online but they are not!");
|
||||||
.getGroup(g);
|
|
||||||
|
|
||||||
final long playtime = result.getLong("playtime");
|
final User user = new FreedomUser(player);
|
||||||
final boolean canInteract = result.getBoolean("canInteract");
|
final Group group = Registration
|
||||||
final long balance = result.getLong("balance");
|
.getGroupRegistry()
|
||||||
final boolean transactionsFrozen = result.getBoolean("transactionsFrozen");
|
.getGroup(g);
|
||||||
|
|
||||||
return new SimpleUserData(u, username, user, group, playtime,
|
final long playtime = result.getLong("playtime");
|
||||||
canInteract, balance, transactionsFrozen);
|
final boolean canInteract = result.getBoolean("canInteract");
|
||||||
}
|
final long balance = result.getLong("balance");
|
||||||
} catch (SQLException ex)
|
final boolean transactionsFrozen = result.getBoolean("transactionsFrozen");
|
||||||
{
|
|
||||||
final String sb = "An error occurred while trying to retrieve user data for" +
|
|
||||||
" UUID " +
|
|
||||||
uuid +
|
|
||||||
" from the database." +
|
|
||||||
"\nCaused by: " +
|
|
||||||
ExceptionUtils.getRootCauseMessage(ex) +
|
|
||||||
"\nStack trace: " +
|
|
||||||
ExceptionUtils.getStackTrace(ex);
|
|
||||||
|
|
||||||
FNS4J.getLogger("Datura")
|
return new SimpleUserData(u, username, user, group, playtime,
|
||||||
.error(sb);
|
canInteract, balance, transactionsFrozen);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
final String sb = "An error occurred while trying to retrieve user data for" +
|
||||||
|
" UUID " +
|
||||||
|
uuid +
|
||||||
|
" from the database.";
|
||||||
|
|
||||||
final Player player = Bukkit.getPlayer(UUID.fromString(uuid));
|
FNS4J.getLogger("Datura")
|
||||||
if (player == null) throw new IllegalStateException("Player should be online but they are not!");
|
.error(sb);
|
||||||
|
}
|
||||||
|
|
||||||
return new SimpleUserData(player);
|
final Player player = Bukkit.getPlayer(UUID.fromString(uuid));
|
||||||
}, Shortcuts.provideModule(Patchwork.class)
|
if (player == null)
|
||||||
.getExecutor()
|
throw new IllegalStateException("Player should be online but they are not!");
|
||||||
.getAsync())
|
|
||||||
|
return new SimpleUserData(player);
|
||||||
|
}, Shortcuts.provideModule(Patchwork.class)
|
||||||
|
.getExecutor()
|
||||||
|
.getAsync())
|
||||||
.join();
|
.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ import fns.fossil.cmd.CakeCommand;
|
|||||||
import fns.fossil.trail.Trailer;
|
import fns.fossil.trail.Trailer;
|
||||||
import fns.patchwork.base.Registration;
|
import fns.patchwork.base.Registration;
|
||||||
import fns.patchwork.command.CommandHandler;
|
import fns.patchwork.command.CommandHandler;
|
||||||
import fns.patchwork.service.SubscriptionProvider;
|
import fns.patchwork.provider.SubscriptionProvider;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
public class Fossil extends JavaPlugin
|
public class Fossil extends JavaPlugin
|
||||||
|
@ -25,8 +25,8 @@ package fns.patchwork.base;
|
|||||||
|
|
||||||
import fns.patchwork.display.adminchat.AdminChatDisplay;
|
import fns.patchwork.display.adminchat.AdminChatDisplay;
|
||||||
import fns.patchwork.event.EventBus;
|
import fns.patchwork.event.EventBus;
|
||||||
import fns.patchwork.service.FreedomExecutor;
|
import fns.patchwork.provider.ExecutorProvider;
|
||||||
import fns.patchwork.service.SubscriptionProvider;
|
import fns.patchwork.provider.SubscriptionProvider;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
@ -40,9 +40,9 @@ public class Patchwork extends JavaPlugin
|
|||||||
*/
|
*/
|
||||||
private EventBus eventBus;
|
private EventBus eventBus;
|
||||||
/**
|
/**
|
||||||
* The {@link FreedomExecutor} for this plugin.
|
* The {@link ExecutorProvider} for this plugin.
|
||||||
*/
|
*/
|
||||||
private FreedomExecutor executor;
|
private ExecutorProvider executor;
|
||||||
/**
|
/**
|
||||||
* The {@link AdminChatDisplay} for this plugin.
|
* The {@link AdminChatDisplay} for this plugin.
|
||||||
*/
|
*/
|
||||||
@ -64,7 +64,7 @@ public class Patchwork extends JavaPlugin
|
|||||||
public void onEnable()
|
public void onEnable()
|
||||||
{
|
{
|
||||||
eventBus = new EventBus(this);
|
eventBus = new EventBus(this);
|
||||||
executor = new FreedomExecutor(this);
|
executor = new ExecutorProvider(this);
|
||||||
acdisplay = new AdminChatDisplay(this);
|
acdisplay = new AdminChatDisplay(this);
|
||||||
|
|
||||||
|
|
||||||
@ -80,11 +80,11 @@ public class Patchwork extends JavaPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link FreedomExecutor} for this plugin.
|
* Gets the {@link ExecutorProvider} for this plugin.
|
||||||
*
|
*
|
||||||
* @return the {@link FreedomExecutor}
|
* @return the {@link ExecutorProvider}
|
||||||
*/
|
*/
|
||||||
public FreedomExecutor getExecutor()
|
public ExecutorProvider getExecutor()
|
||||||
{
|
{
|
||||||
return executor;
|
return executor;
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import fns.patchwork.registry.ConfigRegistry;
|
|||||||
import fns.patchwork.registry.EventRegistry;
|
import fns.patchwork.registry.EventRegistry;
|
||||||
import fns.patchwork.registry.GroupRegistry;
|
import fns.patchwork.registry.GroupRegistry;
|
||||||
import fns.patchwork.registry.ModuleRegistry;
|
import fns.patchwork.registry.ModuleRegistry;
|
||||||
|
import fns.patchwork.registry.SQLRegistry;
|
||||||
import fns.patchwork.registry.ServiceTaskRegistry;
|
import fns.patchwork.registry.ServiceTaskRegistry;
|
||||||
import fns.patchwork.registry.UserRegistry;
|
import fns.patchwork.registry.UserRegistry;
|
||||||
|
|
||||||
@ -62,6 +63,10 @@ public class Registration
|
|||||||
* The {@link ConfigRegistry}
|
* The {@link ConfigRegistry}
|
||||||
*/
|
*/
|
||||||
private static final ConfigRegistry configRegistry = new ConfigRegistry();
|
private static final ConfigRegistry configRegistry = new ConfigRegistry();
|
||||||
|
/**
|
||||||
|
* The SQL Registry
|
||||||
|
*/
|
||||||
|
private static final SQLRegistry sqlRegistry = new SQLRegistry();
|
||||||
|
|
||||||
private Registration()
|
private Registration()
|
||||||
{
|
{
|
||||||
@ -115,4 +120,12 @@ public class Registration
|
|||||||
{
|
{
|
||||||
return configRegistry;
|
return configRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The {@link SQLRegistry}
|
||||||
|
*/
|
||||||
|
public static SQLRegistry getSQLRegistry()
|
||||||
|
{
|
||||||
|
return sqlRegistry;
|
||||||
|
}
|
||||||
}
|
}
|
@ -23,7 +23,10 @@
|
|||||||
|
|
||||||
package fns.patchwork.base;
|
package fns.patchwork.base;
|
||||||
|
|
||||||
|
import fns.patchwork.provider.ExecutorProvider;
|
||||||
|
import fns.patchwork.sql.SQL;
|
||||||
import fns.patchwork.user.User;
|
import fns.patchwork.user.User;
|
||||||
|
import java.util.Optional;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
@ -37,13 +40,23 @@ public final class Shortcuts
|
|||||||
public static <T extends JavaPlugin> T provideModule(final Class<T> pluginClass)
|
public static <T extends JavaPlugin> T provideModule(final Class<T> pluginClass)
|
||||||
{
|
{
|
||||||
return Registration.getModuleRegistry()
|
return Registration.getModuleRegistry()
|
||||||
.getProvider(pluginClass)
|
.getProvider(pluginClass)
|
||||||
.getModule();
|
.getModule();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static User getUser(final Player player)
|
public static User getUser(final Player player)
|
||||||
{
|
{
|
||||||
return Registration.getUserRegistry()
|
return Registration.getUserRegistry()
|
||||||
.getUser(player);
|
.getUser(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ExecutorProvider getExecutors()
|
||||||
|
{
|
||||||
|
return provideModule(Patchwork.class).getExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<SQL> getSQL()
|
||||||
|
{
|
||||||
|
return Registration.getSQLRegistry().getSQL();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package fns.patchwork.service;
|
package fns.patchwork.provider;
|
||||||
|
|
||||||
import fns.patchwork.base.Patchwork;
|
import fns.patchwork.base.Patchwork;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@ -34,7 +34,7 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||||||
* This class is here for both convenience purposes, and also for the sake of providing easy access to executors for
|
* This class is here for both convenience purposes, and also for the sake of providing easy access to executors for
|
||||||
* {@link CompletableFuture} invocations.
|
* {@link CompletableFuture} invocations.
|
||||||
*/
|
*/
|
||||||
public class FreedomExecutor
|
public class ExecutorProvider
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* An executor which runs tasks synchronously.
|
* An executor which runs tasks synchronously.
|
||||||
@ -46,9 +46,9 @@ public class FreedomExecutor
|
|||||||
private final Executor asyncExecutor;
|
private final Executor asyncExecutor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link FreedomExecutor} instance.
|
* Creates a new {@link ExecutorProvider} instance.
|
||||||
*/
|
*/
|
||||||
public FreedomExecutor(final Patchwork patchwork)
|
public ExecutorProvider(final Patchwork patchwork)
|
||||||
{
|
{
|
||||||
syncExecutor = r -> Bukkit.getScheduler()
|
syncExecutor = r -> Bukkit.getScheduler()
|
||||||
.runTask(patchwork, r);
|
.runTask(patchwork, r);
|
@ -21,8 +21,12 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package fns.patchwork.service;
|
package fns.patchwork.provider;
|
||||||
|
|
||||||
|
import fns.patchwork.service.Service;
|
||||||
|
import fns.patchwork.service.ServiceSubscription;
|
||||||
|
import fns.patchwork.service.Task;
|
||||||
|
import fns.patchwork.service.TaskSubscription;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of FreedomNetworkSuite - https://github.com/SimplexDevelopment/FreedomNetworkSuite
|
||||||
|
* Copyright (C) 2023 Simplex Development and contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fns.patchwork.registry;
|
||||||
|
|
||||||
|
import fns.patchwork.sql.SQL;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class SQLRegistry
|
||||||
|
{
|
||||||
|
private SQL sql;
|
||||||
|
|
||||||
|
public SQLRegistry() {
|
||||||
|
this.sql = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<SQL> getSQL() {
|
||||||
|
return (sql == null) ? Optional.empty() : Optional.of(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSQL(final SQL sql) {
|
||||||
|
this.sql = sql;
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@ package fns.patchwork.registry;
|
|||||||
|
|
||||||
import fns.patchwork.service.Service;
|
import fns.patchwork.service.Service;
|
||||||
import fns.patchwork.service.ServiceSubscription;
|
import fns.patchwork.service.ServiceSubscription;
|
||||||
import fns.patchwork.service.SubscriptionProvider;
|
import fns.patchwork.provider.SubscriptionProvider;
|
||||||
import fns.patchwork.service.Task;
|
import fns.patchwork.service.Task;
|
||||||
import fns.patchwork.service.TaskSubscription;
|
import fns.patchwork.service.TaskSubscription;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
package fns.patchwork.service;
|
package fns.patchwork.service;
|
||||||
|
|
||||||
|
import fns.patchwork.provider.SubscriptionProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a ticking service. Services may be asynchronous or synchronous, however there are some restrictions:
|
* Represents a ticking service. Services may be asynchronous or synchronous, however there are some restrictions:
|
||||||
* <ul>
|
* <ul>
|
||||||
|
@ -31,7 +31,7 @@ public interface SQL
|
|||||||
{
|
{
|
||||||
CompletableFuture<PreparedStatement> prepareStatement(final String query, final Object... args);
|
CompletableFuture<PreparedStatement> prepareStatement(final String query, final Object... args);
|
||||||
|
|
||||||
CompletableFuture<ResultSet> executeQuery(final String query, final Object... args);
|
CompletableFuture<SQLResult> executeQuery(final String query, final Object... args);
|
||||||
|
|
||||||
CompletableFuture<Integer> executeUpdate(final String query, final Object... args);
|
CompletableFuture<Integer> executeUpdate(final String query, final Object... args);
|
||||||
|
|
||||||
|
348
Patchwork/src/main/java/fns/patchwork/sql/SQLResult.java
Normal file
348
Patchwork/src/main/java/fns/patchwork/sql/SQLResult.java
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of FreedomNetworkSuite - https://github.com/SimplexDevelopment/FreedomNetworkSuite
|
||||||
|
* Copyright (C) 2023 Simplex Development and contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fns.patchwork.sql;
|
||||||
|
|
||||||
|
import fns.patchwork.utils.container.Pair;
|
||||||
|
import fns.patchwork.utils.logging.FNS4J;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.ResultSetMetaData;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class SQLResult
|
||||||
|
{
|
||||||
|
private final Map<Integer, Map<String, Object>> resultMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor will create a new SQLResult object from the specified ResultSet.
|
||||||
|
* This will iterate through all rows and columns of the ResultSet and store them in a Map.
|
||||||
|
* The Map will contain keys of integers representing the row number, and values of Maps
|
||||||
|
* containing the column names and their values.
|
||||||
|
*
|
||||||
|
* @param resultSet The ResultSet to create the SQLResult object from.
|
||||||
|
*/
|
||||||
|
public SQLResult(final ResultSet resultSet)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final ResultSetMetaData metaData = resultSet.getMetaData();
|
||||||
|
final int columnCount = metaData.getColumnCount();
|
||||||
|
|
||||||
|
int rowIndex = 0;
|
||||||
|
|
||||||
|
while (resultSet.next())
|
||||||
|
{
|
||||||
|
rowIndex++;
|
||||||
|
final Map<String, Object> rowMap = new HashMap<>();
|
||||||
|
|
||||||
|
for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++)
|
||||||
|
{
|
||||||
|
String columnName = metaData.getColumnName(columnIndex);
|
||||||
|
Object columnValue = resultSet.getObject(columnIndex);
|
||||||
|
rowMap.put(columnName, columnValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
resultMap.put(rowIndex, rowMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
FNS4J.getLogger("Tyr").error(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will return a map of all rows and their columns and values.
|
||||||
|
*
|
||||||
|
* @return A Map containing all rows and their columns and values.
|
||||||
|
*/
|
||||||
|
public Map<Integer, Map<String, Object>> getResultMap()
|
||||||
|
{
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will return a map of all columns and their values from the specified row.
|
||||||
|
*
|
||||||
|
* @param rowIndex The row index to get the column names from.
|
||||||
|
* @return A Map containing all column names and their values from the specified row.
|
||||||
|
*/
|
||||||
|
public Map<String, Object> getRow(final int rowIndex)
|
||||||
|
{
|
||||||
|
return resultMap.get(rowIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will return the value from the specified row and column.
|
||||||
|
*
|
||||||
|
* @param rowIndex The row index to get the column name from.
|
||||||
|
* @param columnName The column name to get the value from.
|
||||||
|
* @return The value from the specified row and column.
|
||||||
|
*/
|
||||||
|
public Object getValue(final int rowIndex, final String columnName)
|
||||||
|
{
|
||||||
|
return resultMap.get(rowIndex).get(columnName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will return the first value from the first row of the result set.
|
||||||
|
*
|
||||||
|
* @return A Pair containing the column name and the stored value.
|
||||||
|
*/
|
||||||
|
public Pair<String, Object> getFirst()
|
||||||
|
{
|
||||||
|
return new Pair<>(resultMap.get(1).entrySet().iterator().next().getKey(),
|
||||||
|
resultMap.get(1).entrySet().iterator().next().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will return the first value from the specified row of the result set.
|
||||||
|
*
|
||||||
|
* @param rowIndex The row index to get the column name from.
|
||||||
|
* @return A Pair containing the column name and the stored value.
|
||||||
|
*/
|
||||||
|
public Pair<String, Object> getFirst(final int rowIndex)
|
||||||
|
{
|
||||||
|
return new Pair<>(resultMap.get(rowIndex).entrySet().iterator().next().getKey(),
|
||||||
|
resultMap.get(rowIndex).entrySet().iterator().next().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will return the last value from the first row of the result set.
|
||||||
|
*
|
||||||
|
* @return A Pair containing the column name and the stored value.
|
||||||
|
*/
|
||||||
|
public Pair<String, Object> getLast()
|
||||||
|
{
|
||||||
|
return new Pair<>(resultMap.get(1).entrySet().iterator().next().getKey(),
|
||||||
|
resultMap.get(1).entrySet().iterator().next().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will return the last value from the specified row of the result set.
|
||||||
|
*
|
||||||
|
* @param rowIndex The row index to get the column name from.
|
||||||
|
* @return A Pair containing the column name and the stored value.
|
||||||
|
*/
|
||||||
|
public Pair<String, Object> getLast(final int rowIndex)
|
||||||
|
{
|
||||||
|
return new Pair<>(resultMap.get(rowIndex).entrySet().iterator().next().getKey(),
|
||||||
|
resultMap.get(rowIndex).entrySet().iterator().next().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will attempt to retrieve the value from the specified row and column,
|
||||||
|
* and cast it to the specified class. This will throw a {@link ClassCastException} if the
|
||||||
|
* returned value is not an instance of the provided class.
|
||||||
|
*
|
||||||
|
* @param rowIndex The row index to get the column name from.
|
||||||
|
* @param columnName The column name to get the value from.
|
||||||
|
* @param clazz The class to cast the value to.
|
||||||
|
* @param <T> The expected type.
|
||||||
|
* @return The value from the specified row and column, cast to the specified class.
|
||||||
|
*/
|
||||||
|
public <T> T autoCast(final int rowIndex, final String columnName, final Class<T> clazz)
|
||||||
|
{
|
||||||
|
final Object value = resultMap.get(rowIndex).get(columnName);
|
||||||
|
|
||||||
|
if (!clazz.isInstance(value))
|
||||||
|
throw new ClassCastException("Cannot cast " + value.getClass().getName() + " to " + clazz.getName());
|
||||||
|
|
||||||
|
return clazz.cast(resultMap.get(rowIndex).get(columnName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rowIndex The row index to get the column names from.
|
||||||
|
* @return A Set containing all column names from the specified row of the result set.
|
||||||
|
*/
|
||||||
|
public Set<String> getColumnNames(final int rowIndex)
|
||||||
|
{
|
||||||
|
return resultMap.get(rowIndex).keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A Set containing all column names from the first row of the result set.
|
||||||
|
*/
|
||||||
|
public Set<String> getColumnNames()
|
||||||
|
{
|
||||||
|
return resultMap.get(1).keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will apply the specified consumer to all rows of the result set.
|
||||||
|
*
|
||||||
|
* @param columnConsumer The consumer to apply to all rows of the result set.
|
||||||
|
*/
|
||||||
|
public void accept(final Consumer<Map<String, Object>> columnConsumer)
|
||||||
|
{
|
||||||
|
this.resultMap.forEach((integer, map) -> columnConsumer.accept(map));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the result set contains the specified row number.
|
||||||
|
* Best used in a for loop, using {@link #rowCount()} as the upper bound.
|
||||||
|
*
|
||||||
|
* @param rowIndex The row index to check.
|
||||||
|
* @return True if the result set contains the specified row number, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean hasNext(final int rowIndex)
|
||||||
|
{
|
||||||
|
return this.resultMap.containsKey(rowIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the result set has the first row.
|
||||||
|
* If row 1 doesn't exist, it's safe to say the result set is empty.
|
||||||
|
*
|
||||||
|
* @return True if the result set has row 1, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean hasNext()
|
||||||
|
{
|
||||||
|
return this.resultMap.containsKey(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The number of rows in the result set.
|
||||||
|
*/
|
||||||
|
public int rowCount()
|
||||||
|
{
|
||||||
|
return this.resultMap.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rowIndex The row index from which to count columns.
|
||||||
|
* @return The number of columns in the specified row.
|
||||||
|
*/
|
||||||
|
public int columnCount(final int rowIndex)
|
||||||
|
{
|
||||||
|
return this.resultMap.get(rowIndex).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a String value from the specified row and column.
|
||||||
|
*
|
||||||
|
* @param rowIndex The row index to get the column name from.
|
||||||
|
* @param columnName The column name to get the value from.
|
||||||
|
* @return The String value from the specified row and column.
|
||||||
|
* @see #autoCast(int, String, Class)
|
||||||
|
*/
|
||||||
|
public String getString(final int rowIndex, final String columnName)
|
||||||
|
{
|
||||||
|
return autoCast(rowIndex, columnName, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will attempt to retrieve a String value from the specified column within the first row of the
|
||||||
|
* result set.
|
||||||
|
*
|
||||||
|
* @param columnName The column name to get the value from.
|
||||||
|
* @return The String value from the specified column within the first row of the result set.
|
||||||
|
* @see #getString(int, String)
|
||||||
|
*/
|
||||||
|
public String getString(final String columnName)
|
||||||
|
{
|
||||||
|
return getString(1, columnName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an Integer value from the specified row and column.
|
||||||
|
*
|
||||||
|
* @param rowIndex The row index to get the column name from.
|
||||||
|
* @param columnName The column name to get the value from.
|
||||||
|
* @return The Integer value from the specified row and column.
|
||||||
|
* @see #autoCast(int, String, Class)
|
||||||
|
*/
|
||||||
|
public int getInteger(final int rowIndex, final String columnName)
|
||||||
|
{
|
||||||
|
return autoCast(rowIndex, columnName, Integer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will attempt to retrieve an Integer value from the specified column within the first row of the
|
||||||
|
* result set.
|
||||||
|
*
|
||||||
|
* @param columnName The column name to get the value from.
|
||||||
|
* @return The Integer value from the specified column within the first row of the result set.
|
||||||
|
* @see #getInteger(int, String)
|
||||||
|
*/
|
||||||
|
public int getInteger(final String columnName)
|
||||||
|
{
|
||||||
|
return getInteger(1, columnName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a Long value from the specified row and column.
|
||||||
|
*
|
||||||
|
* @param rowIndex The row index to get the column name from.
|
||||||
|
* @param columnName The column name to get the value from.
|
||||||
|
* @return The Long value from the specified row and column.
|
||||||
|
* @see #autoCast(int, String, Class)
|
||||||
|
*/
|
||||||
|
public long getLong(final int rowIndex, final String columnName)
|
||||||
|
{
|
||||||
|
return autoCast(rowIndex, columnName, Long.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will attempt to retrieve a Long value from the specified column within the first row of the
|
||||||
|
* result set.
|
||||||
|
*
|
||||||
|
* @param columnName The column name to get the value from.
|
||||||
|
* @return The Long value from the specified column within the first row of the result set.
|
||||||
|
* @see #getLong(int, String)
|
||||||
|
*/
|
||||||
|
public long getLong(final String columnName)
|
||||||
|
{
|
||||||
|
return getLong(1, columnName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a Double value from the specified row and column.
|
||||||
|
*
|
||||||
|
* @param rowIndex The row index to get the column name from.
|
||||||
|
* @param columnName The column name to get the value from.
|
||||||
|
* @return The Double value from the specified row and column.
|
||||||
|
* @see #autoCast(int, String, Class)
|
||||||
|
*/
|
||||||
|
public boolean getBoolean(final int rowIndex, final String columnName)
|
||||||
|
{
|
||||||
|
return autoCast(rowIndex, columnName, Boolean.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will attempt to retrieve a Boolean value from the specified column within the first row of the
|
||||||
|
* result set.
|
||||||
|
*
|
||||||
|
* @param columnName The column name to get the value from.
|
||||||
|
* @return The Boolean value from the specified column within the first row of the result set.
|
||||||
|
* @see #getBoolean(int, String)
|
||||||
|
*/
|
||||||
|
public boolean getBoolean(final String columnName)
|
||||||
|
{
|
||||||
|
return getBoolean(1, columnName);
|
||||||
|
}
|
||||||
|
}
|
@ -16,11 +16,10 @@ bukkit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly project(":Patchwork")
|
compileOnly project(path: ":Patchwork")
|
||||||
compileOnly project(":Datura")
|
compileOnly project(path: ":Datura")
|
||||||
|
|
||||||
library 'com.hierynomus:sshj:0.28.0'
|
library 'com.j256.two-factor-auth:two-factor-auth:1.3'
|
||||||
library 'org.bouncycastle:bcprov-jdk18on:1.76'
|
|
||||||
|
|
||||||
testImplementation platform('org.junit:junit-bom:5.9.1')
|
testImplementation platform('org.junit:junit-bom:5.9.1')
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||||
|
48
Tyr/src/main/java/fns/tyr/Tyr.java
Normal file
48
Tyr/src/main/java/fns/tyr/Tyr.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of FreedomNetworkSuite - https://github.com/SimplexDevelopment/FreedomNetworkSuite
|
||||||
|
* Copyright (C) 2023 Simplex Development and contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fns.tyr;
|
||||||
|
|
||||||
|
import fns.datura.Datura;
|
||||||
|
import fns.patchwork.base.Shortcuts;
|
||||||
|
import fns.patchwork.sql.SQL;
|
||||||
|
import fns.patchwork.utils.logging.FNS4J;
|
||||||
|
|
||||||
|
public class Tyr
|
||||||
|
{
|
||||||
|
public void onEnable()
|
||||||
|
{
|
||||||
|
final SQL sql = Shortcuts.provideModule(Datura.class).getSQL();
|
||||||
|
sql.createTable("sessionData",
|
||||||
|
"user VARCHAR(16) NOT NULL PRIMARY KEY, secretKey VARCHAR(64) NOT NULL;")
|
||||||
|
.whenCompleteAsync((result, throwable) ->
|
||||||
|
{
|
||||||
|
if (throwable != null)
|
||||||
|
FNS4J.getLogger("Tyr")
|
||||||
|
.error(throwable.getMessage());
|
||||||
|
}, Shortcuts.getExecutors()
|
||||||
|
.getAsync());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
93
Tyr/src/main/java/fns/tyr/data/SQLEntry.java
Normal file
93
Tyr/src/main/java/fns/tyr/data/SQLEntry.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of FreedomNetworkSuite - https://github.com/SimplexDevelopment/FreedomNetworkSuite
|
||||||
|
* Copyright (C) 2023 Simplex Development and contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fns.tyr.data;
|
||||||
|
|
||||||
|
import fns.patchwork.base.Shortcuts;
|
||||||
|
import fns.patchwork.utils.logging.FNS4J;
|
||||||
|
import fns.tyr.oauth.Identity;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
public class SQLEntry
|
||||||
|
{
|
||||||
|
private final Identity identity;
|
||||||
|
|
||||||
|
public SQLEntry(final Identity identity)
|
||||||
|
{
|
||||||
|
this.identity = identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SQLEntry load(final String username)
|
||||||
|
{
|
||||||
|
return Shortcuts.getSQL()
|
||||||
|
.map(c ->
|
||||||
|
c.executeQuery("SELECT * FROM sessionData WHERE user = ?;", username)
|
||||||
|
.thenApplyAsync(result ->
|
||||||
|
{
|
||||||
|
SQLEntry entry = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (result.next())
|
||||||
|
{
|
||||||
|
final String user = result.getString("user");
|
||||||
|
final String secretKey = result.getString("secretKey");
|
||||||
|
|
||||||
|
final Identity i = new Identity(user, secretKey);
|
||||||
|
|
||||||
|
entry = new SQLEntry(i);
|
||||||
|
FNS4J.getLogger("Tyr")
|
||||||
|
.info("Loaded entry for " + username);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry = new SQLEntry(Identity.of(username));
|
||||||
|
FNS4J.getLogger("Tyr")
|
||||||
|
.info("Created a new entry for " + username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
FNS4J.getLogger("Tyr").error(ex.getMessage());
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}, Shortcuts.getExecutors()
|
||||||
|
.getAsync())
|
||||||
|
.join())
|
||||||
|
.orElseThrow(() -> new IllegalStateException("SQL is not initialized!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save()
|
||||||
|
{
|
||||||
|
Shortcuts.getSQL()
|
||||||
|
.orElseThrow(() -> new IllegalStateException("SQL is not available!"))
|
||||||
|
.executeUpdate("INSERT INTO sessionData (user, secretKey) VALUES (?, ?);",
|
||||||
|
this.identity.username(),
|
||||||
|
this.identity.secretKey())
|
||||||
|
.whenCompleteAsync((result, throwable) ->
|
||||||
|
{
|
||||||
|
if (throwable != null)
|
||||||
|
FNS4J.getLogger("Tyr").error(throwable.getMessage());
|
||||||
|
}, Shortcuts.getExecutors()
|
||||||
|
.getAsync());
|
||||||
|
}
|
||||||
|
}
|
31
Tyr/src/main/java/fns/tyr/oauth/Identity.java
Normal file
31
Tyr/src/main/java/fns/tyr/oauth/Identity.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of FreedomNetworkSuite - https://github.com/SimplexDevelopment/FreedomNetworkSuite
|
||||||
|
* Copyright (C) 2023 Simplex Development and contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fns.tyr.oauth;
|
||||||
|
|
||||||
|
public record Identity(String username, String secretKey)
|
||||||
|
{
|
||||||
|
public static Identity of(final String username) {
|
||||||
|
return new Identity(username, TOTP.createSecretKey());
|
||||||
|
}
|
||||||
|
}
|
74
Tyr/src/main/java/fns/tyr/oauth/OAuth2.java
Normal file
74
Tyr/src/main/java/fns/tyr/oauth/OAuth2.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of FreedomNetworkSuite - https://github.com/SimplexDevelopment/FreedomNetworkSuite
|
||||||
|
* Copyright (C) 2023 Simplex Development and contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fns.tyr.oauth;
|
||||||
|
|
||||||
|
import fns.patchwork.base.Shortcuts;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class OAuth2
|
||||||
|
{
|
||||||
|
private final Set<Identity> identitySet;
|
||||||
|
|
||||||
|
public OAuth2()
|
||||||
|
{
|
||||||
|
this.identitySet = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addIdentity(Identity identity)
|
||||||
|
{
|
||||||
|
this.identitySet.add(identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeIdentity(Identity identity)
|
||||||
|
{
|
||||||
|
this.identitySet.remove(identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Identity> getIdentity(final String username)
|
||||||
|
{
|
||||||
|
return this.identitySet.stream()
|
||||||
|
.filter(identity -> identity.username().equals(username))
|
||||||
|
.findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadAll()
|
||||||
|
{
|
||||||
|
Shortcuts.getSQL()
|
||||||
|
.ifPresent(sql -> sql.executeQuery("SELECT * FROM sessionData;")
|
||||||
|
.thenAcceptAsync(result ->
|
||||||
|
{
|
||||||
|
for (int i = 1; i < result.rowCount(); i++)
|
||||||
|
{
|
||||||
|
final String username = result.getString(i,
|
||||||
|
"user");
|
||||||
|
final String secretKey = result.getString(i,
|
||||||
|
"secretKey");
|
||||||
|
this.addIdentity(
|
||||||
|
new Identity(username, secretKey));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
63
Tyr/src/main/java/fns/tyr/oauth/TOTP.java
Normal file
63
Tyr/src/main/java/fns/tyr/oauth/TOTP.java
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of FreedomNetworkSuite - https://github.com/SimplexDevelopment/FreedomNetworkSuite
|
||||||
|
* Copyright (C) 2023 Simplex Development and contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fns.tyr.oauth;
|
||||||
|
|
||||||
|
import com.j256.twofactorauth.TimeBasedOneTimePasswordUtil;
|
||||||
|
import fns.patchwork.utils.logging.FNS4J;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User-friendly version of TimeBasedOneTimePasswordUtil.
|
||||||
|
*/
|
||||||
|
public final class TOTP
|
||||||
|
{
|
||||||
|
private TOTP()
|
||||||
|
{
|
||||||
|
throw new AssertionError("This class cannot be instantiated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createSecretKey()
|
||||||
|
{
|
||||||
|
return TimeBasedOneTimePasswordUtil.generateBase32Secret(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createQRCode(final String username, final String secretKey)
|
||||||
|
{
|
||||||
|
return TimeBasedOneTimePasswordUtil.qrImageUrl(username, secretKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean verify(final String secretKey, final int userCode)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int vCode = TimeBasedOneTimePasswordUtil.generateCurrentNumber(secretKey);
|
||||||
|
return vCode == userCode;
|
||||||
|
}
|
||||||
|
catch (GeneralSecurityException ex)
|
||||||
|
{
|
||||||
|
FNS4J.getLogger("Tyr").error("Failed to verify TOTP code: " + ex.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user