Datura - Data Manager

This commit is contained in:
Paul Reilly
2023-05-12 23:30:08 -05:00
parent 98d7ffafe3
commit 90c5f2a6f8
15 changed files with 961 additions and 12 deletions

42
Datura/.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

21
Datura/build.gradle Normal file
View File

@ -0,0 +1,21 @@
plugins {
id 'java'
}
group = 'me.totalfreedom'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
compileOnly project(":Commons")
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
test {
useJUnitPlatform()
}

View File

@ -0,0 +1,16 @@
package me.totalfreedom.datura;
import me.totalfreedom.base.CommonsBase;
import org.bukkit.plugin.java.JavaPlugin;
public class Datura extends JavaPlugin
{
@Override
public void onEnable()
{
CommonsBase.getInstance()
.getRegistrations()
.getModuleRegistry()
.addModule(this);
}
}

View File

@ -0,0 +1,43 @@
package me.totalfreedom.datura.perms;
import me.totalfreedom.security.Node;
import me.totalfreedom.security.NodeType;
public class DefaultNodes
{
private DefaultNodes() {
throw new AssertionError();
}
public static final Node OP = new PermissionNodeBuilder()
.key("freedom.master_key")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(true)
.build();
public static final Node NON_OP = new PermissionNodeBuilder()
.key("freedom.default")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(false)
.build();
public static final Node ALL = new PermissionNodeBuilder()
.key("*")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(true)
.build();
public static final Node NONE = new PermissionNodeBuilder()
.key("freedom.none")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(false)
.build();
}

View File

@ -0,0 +1,240 @@
package me.totalfreedom.datura.perms;
import me.totalfreedom.base.CommonsBase;
import me.totalfreedom.security.Group;
import me.totalfreedom.security.Node;
import net.kyori.adventure.text.Component;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
public class FreedomGroup implements Group
{
private final Component name;
private final Component prefix;
private final Component abbreviation;
private final int weight;
private final boolean isDefault;
private final boolean isHidden;
private final Set<Node> permissions;
private final PermissionAttachment attachment;
public FreedomGroup(Component name,
Component prefix,
Component abbreviation,
int weight,
boolean isDefault,
boolean isHidden)
{
this.name = name;
this.prefix = prefix;
this.abbreviation = abbreviation;
this.weight = weight;
this.isDefault = isDefault;
this.isHidden = isHidden;
this.permissions = new HashSet<>();
this.attachment = new PermissionAttachment(CommonsBase.getInstance(), this);
}
@Override
public Component getName()
{
return name;
}
@Override
public Component getPrefix()
{
return prefix;
}
@Override
public Component getAbbreviation()
{
return abbreviation;
}
@Override
public int getWeight()
{
return weight;
}
@Override
public boolean isDefault()
{
return isDefault;
}
@Override
public boolean isHidden()
{
return isHidden;
}
@Override
public UUID getUniqueId()
{
return UUID.nameUUIDFromBytes(getName().toString().getBytes());
}
@Override
public Set<Node> permissions()
{
return permissions;
}
@Override
public boolean addPermission(Node node)
{
return permissions().add(node);
}
@Override
public boolean removePermission(Node node)
{
return permissions().remove(node);
}
@Override
public boolean isPermissionSet(@NotNull String name)
{
Node node = permissions().stream()
.filter(n -> n.key().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
return node != null && node.value();
}
@Override
public boolean isPermissionSet(@NotNull Permission perm)
{
Node node = permissions()
.stream()
.filter(n -> n.bukkit().equals(perm))
.findFirst()
.orElse(null);
return node != null && node.value();
}
@Override
public boolean hasPermission(@NotNull String name)
{
Node node = permissions().stream()
.filter(n -> n.key().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
return node != null && node.value();
}
@Override
public boolean hasPermission(@NotNull Permission perm)
{
Node node = permissions()
.stream()
.filter(n -> n.bukkit().equals(perm))
.findFirst()
.orElse(null);
return node != null && node.value();
}
/**
* Adds a permission to the relative PermissionAttachment for this group.
* This method is not thread-safe and should not be called asynchronously.
* <p>
* This method is only here for compatibility with the Bukkit API.
*
* @param plugin The plugin responsible for this attachment. May not be null
* or disabled.
* @param name Name of the permission to attach
* @param value Value of the permission
* @return This group's PermissionAttachment.
*/
@Override
public @NotNull PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value)
{
attachment.setPermission(name, value);
return attachment;
}
@Override
public @NotNull PermissionAttachment addAttachment(@NotNull Plugin plugin)
{
return new PermissionAttachment(plugin, this);
}
@Override
public @Nullable PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value, int ticks)
{
attachment.setPermission(name, value);
return attachment;
}
@Override
public @Nullable PermissionAttachment addAttachment(@NotNull Plugin plugin, int ticks)
{
return new PermissionAttachment(plugin, this);
}
@Override
public void removeAttachment(@NotNull PermissionAttachment attachment)
{
// This method shouldn't do anything, because we don't want to remove our attachment.
}
@Override
public void recalculatePermissions()
{
// Not sure what this method should do, so I'm leaving it empty.
}
@Override
public @NotNull Set<PermissionAttachmentInfo> getEffectivePermissions()
{
return permissions()
.stream()
.map(n -> new PermissionAttachmentInfo(
this,
n.key(),
attachment,
n.value()))
.collect(Collectors.toSet());
}
@Override
public boolean isOp()
{
Node node = permissions()
.stream()
.filter(n -> n.equals(DefaultNodes.OP))
.findFirst()
.orElse(null);
return node != null && node.value();
}
@Override
public void setOp(boolean value)
{
if (value)
{
permissions().add(DefaultNodes.OP);
} else
{
permissions().remove(DefaultNodes.OP);
}
}
}

View File

@ -0,0 +1,206 @@
package me.totalfreedom.datura.perms;
import me.totalfreedom.base.CommonsBase;
import me.totalfreedom.security.Node;
import me.totalfreedom.user.User;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* The superinterface User extends PermissionHolder,
* which is an extension of {@link org.bukkit.permissions.Permissible}.
* This means that our permission data can be interchanged with other permission plugins.
*/
public class FreedomUser implements User
{
private final UUID uuid;
private final Set<Node> permissions;
private final Map<Node, PermissionAttachment> bukkitAttachments = new HashMap<>();
private final Component displayName;
private final String NOT_ONLINE = "Player is not online";
public FreedomUser(Player player)
{
this.uuid = player.getUniqueId();
this.permissions = new HashSet<>();
this.displayName = player.displayName();
}
@Override
public UUID getUniqueId()
{
return uuid;
}
@Override
public Set<Node> permissions()
{
return permissions;
}
@Override
public boolean addPermission(Node node)
{
PermissionAttachment attachment = addAttachment(CommonsBase.getInstance(), node.key(), node.value());
bukkitAttachments.put(node, attachment);
return permissions().add(node);
}
@Override
public boolean removePermission(Node node)
{
removeAttachment(bukkitAttachments.get(node));
bukkitAttachments.remove(node);
return permissions.remove(node);
}
@Override
public Component getDisplayName()
{
return displayName;
}
@Override
public boolean isOnline()
{
return Bukkit.getPlayer(uuid) != null;
}
@Override
public boolean isPermissionSet(@NotNull String name)
{
Player player = Bukkit.getPlayer(uuid);
return player != null && player.isPermissionSet(name);
}
@Override
public boolean isPermissionSet(@NotNull Permission perm)
{
Player player = Bukkit.getPlayer(uuid);
return player != null && player.isPermissionSet(perm);
}
@Override
public boolean hasPermission(@NotNull String name)
{
Player player = Bukkit.getPlayer(uuid);
return player != null && player.hasPermission(name);
}
@Override
public boolean hasPermission(@NotNull Permission perm)
{
Player player = Bukkit.getPlayer(uuid);
return player != null && player.hasPermission(perm);
}
@Override
public @NotNull PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value)
{
Player player = Bukkit.getPlayer(uuid);
if (player != null)
{
return player.addAttachment(plugin, name, value);
}
throw new IllegalStateException(NOT_ONLINE);
}
@Override
public @NotNull PermissionAttachment addAttachment(@NotNull Plugin plugin)
{
Player player = Bukkit.getPlayer(uuid);
if (player != null)
{
return player.addAttachment(plugin);
}
throw new IllegalStateException(NOT_ONLINE);
}
@Override
public @Nullable PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value, int ticks)
{
Player player = Bukkit.getPlayer(uuid);
if (player != null)
{
return player.addAttachment(plugin, name, value, ticks);
}
throw new IllegalStateException(NOT_ONLINE);
}
@Override
public @Nullable PermissionAttachment addAttachment(@NotNull Plugin plugin, int ticks)
{
Player player = Bukkit.getPlayer(uuid);
if (player != null)
{
return player.addAttachment(plugin, ticks);
}
throw new IllegalStateException(NOT_ONLINE);
}
@Override
public void removeAttachment(@NotNull PermissionAttachment attachment)
{
Player player = Bukkit.getPlayer(uuid);
if (player != null)
{
player.removeAttachment(attachment);
}
throw new IllegalStateException(NOT_ONLINE);
}
@Override
public void recalculatePermissions()
{
Player player = Bukkit.getPlayer(uuid);
if (player != null)
{
player.recalculatePermissions();
}
throw new IllegalStateException(NOT_ONLINE);
}
@Override
public @NotNull Set<PermissionAttachmentInfo> getEffectivePermissions()
{
Player player = Bukkit.getPlayer(uuid);
if (player != null)
{
return player.getEffectivePermissions();
}
throw new IllegalStateException(NOT_ONLINE);
}
@Override
public boolean isOp()
{
return permissions().contains(DefaultNodes.OP);
}
@Override
public void setOp(boolean value)
{
if (value) {
permissions().add(DefaultNodes.OP);
} else {
permissions().remove(DefaultNodes.OP);
}
}
}

View File

@ -0,0 +1,53 @@
package me.totalfreedom.datura.perms;
import me.totalfreedom.security.Node;
import me.totalfreedom.security.NodeType;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
record PermissionNode(String key,
boolean value,
long expiry,
NodeType type,
boolean wildcard,
boolean negated) implements Node
{
@Override
public Permission bukkit()
{
return new Permission(key(),
value() ? PermissionDefault.TRUE : PermissionDefault.FALSE);
}
@Override
public boolean compare(Node node)
{
return node.key().equalsIgnoreCase(key())
&& node.value() == value()
&& node.type() == type();
}
@Override
public boolean isExpired()
{
if (isPermanent())
{
return false;
}
return System.currentTimeMillis() > expiry();
}
@Override
public boolean isPermanent()
{
return expiry() == -1;
}
@Override
public boolean isTemporary()
{
return !isPermanent();
}
}

View File

@ -0,0 +1,63 @@
package me.totalfreedom.datura.perms;
import me.totalfreedom.security.Node;
import me.totalfreedom.security.NodeBuilder;
import me.totalfreedom.security.NodeType;
public class PermissionNodeBuilder implements NodeBuilder
{
private String key = "freedom.default";
private boolean value = true;
private long expiry = -1;
private NodeType type = NodeType.PERMISSION;
private boolean wildcard = false;
private boolean negated = false;
@Override
public NodeBuilder key(String key)
{
this.key = key;
return this;
}
@Override
public NodeBuilder value(boolean value)
{
this.value = value;
return this;
}
@Override
public NodeBuilder expiry(long expiry)
{
this.expiry = expiry;
return this;
}
@Override
public NodeBuilder type(NodeType type)
{
this.type = type;
return this;
}
@Override
public NodeBuilder wildcard(boolean wildcard)
{
this.wildcard = wildcard;
return this;
}
@Override
public NodeBuilder negated(boolean negated)
{
this.negated = negated;
return this;
}
@Override
public Node build()
{
return new PermissionNode(key, value, expiry, type, wildcard, negated);
}
}

View File

@ -0,0 +1,121 @@
package me.totalfreedom.datura.sql;
import me.totalfreedom.sql.SQL;
import java.sql.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
public class MySQL implements SQL
{
private String url = "jdbc:mysql://";
public MySQL(String host, int port, String database) {
url += host + ":" + port + "/" + database;
}
/**
* Adds credentials to the MySQL URL.
* If the URL already contains credentials, they will be overwritten.
*
* @param username The username to add
* @param password The password to add
*/
public void addCredentials(String username, String password) {
if (url.contains("?user=")) {
url = url.split("\\x3f")[0];
}
url += "?user=" + username + "&password=" + password;
}
@Override
public CompletableFuture<Connection> getConnection(String url)
{
return CompletableFuture.supplyAsync(() -> {
try {
return DriverManager.getConnection(url);
} catch (SQLException ex) {
throw new CompletionException("Failed to connect to the database: "
+ url + "\n", ex);
}
});
}
@Override
public CompletableFuture<PreparedStatement> prepareStatement(String query, Object... args)
{
return getConnection(url)
.thenApplyAsync(connection -> {
try {
PreparedStatement statement = connection.prepareStatement(query);
for (int i = 0; i < args.length; i++) {
statement.setObject(i + 1, args[i]);
}
return statement;
} catch (SQLException ex) {
throw new CompletionException("Failed to prepare statement: "
+ query + "\n", ex);
}
});
}
@Override
public CompletableFuture<ResultSet> executeQuery(String query, Object... args)
{
return prepareStatement(query, args)
.thenApplyAsync(statement -> {
try {
return statement.executeQuery();
} catch (SQLException ex) {
throw new CompletionException("Failed to retrieve a result set from query: "
+ query + "\n", ex);
}
});
}
@Override
public CompletableFuture<Integer> executeUpdate(String query, Object... args)
{
return prepareStatement(query, args)
.thenApplyAsync(statement -> {
try {
return statement.executeUpdate();
} catch (SQLException ex) {
throw new CompletionException("Failed to execute update: "
+ query + "\n", ex);
}
});
}
@Override
public CompletableFuture<Boolean> execute(String query, Object... args)
{
return prepareStatement(query, args)
.thenApplyAsync(statement -> {
try {
return statement.execute();
} catch (SQLException ex) {
throw new CompletionException("Failed to execute statement: "
+ query + "\n", ex);
}
});
}
@Override
public CompletableFuture<Boolean> createTable(String table, String... columns)
{
StringBuilder query = new StringBuilder();
query.append("CREATE TABLE IF NOT EXISTS ? (");
for (int i = 0; i < columns.length; i++) {
query.append("?");
if (i != columns.length - 1) {
query.append(", ");
}
}
query.append(")");
return execute(query.toString(), table, columns);
}
}