Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ repositories {
maven("https://nexus.neetgames.com/repository/maven-releases/") {
mavenContent { includeGroup("com.gmail.nossr50.mcMMO") }
}

maven("https://repo.warriorrr.dev/releases") {
mavenContent { includeGroupAndSubgroups("dev.warriorrr") }
}
}

dependencies {
Expand All @@ -56,6 +60,7 @@ dependencies {
compileOnly(libs.lynchpin.pursuits)
compileOnly(libs.lynchpin.towny)
compileOnly(libs.lynchpin.advancements)
implementation(libs.inventories)
}

tasks {
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ quickshop = "6.2.0.11"
hikaricp = "7.0.2"
mcmmo = "2.2.040"
lynchpin-api = "1.0-SNAPSHOT"
inventories = "1.1.0"

# plugins
conventions = "1.1.0"
Expand All @@ -30,6 +31,7 @@ mcmmo = { group = "com.gmail.nossr50.mcMMO", name = "mcMMO", version.ref = "mcmm
lynchpin-pursuits = { group = "net.earthmc.lynchpin.api", name = "pursuits", version.ref = "lynchpin-api"}
lynchpin-towny = { group = "net.earthmc.lynchpin.api", name = "towny", version.ref = "lynchpin-api"}
lynchpin-advancements = { group = "net.earthmc.lynchpin.api", name = "advancements", version.ref = "lynchpin-api"}
inventories = { group = "dev.warriorrr.inventories", name = "inventories", version.ref = "inventories" }

[plugins]
conventions-java = { id = "net.earthmc.conventions.java", version.ref = "conventions" }
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/net/earthmc/emcapi/EMCAPI.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package net.earthmc.emcapi;

import com.zaxxer.hikari.HikariConfig;
import dev.warriorrr.inventories.Inventories;
import io.javalin.Javalin;
import io.javalin.http.TooManyRequestsResponse;
import io.javalin.util.JavalinLogger;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import net.earthmc.emcapi.database.APIDatabase;
import net.earthmc.emcapi.database.DatabaseSchema;
import net.earthmc.emcapi.integration.Integrations;
import net.earthmc.emcapi.manager.Authorisation;
import net.earthmc.emcapi.manager.EndpointManager;
import net.earthmc.emcapi.manager.GUIManager;
import net.earthmc.emcapi.manager.KeyManager;
import net.earthmc.emcapi.manager.OptOut;
import net.earthmc.emcapi.sse.SSEManager;
Expand All @@ -35,6 +38,8 @@ public final class EMCAPI extends JavaPlugin {
private final SSEManager sseManager = new SSEManager(this);
private final APIDatabase database = new APIDatabase();
private final OptOut optOut = new OptOut(this);
private final Authorisation auth = new Authorisation(this);
private final GUIManager guiManager = new GUIManager(this);

@Override
public void onLoad() {
Expand All @@ -56,6 +61,7 @@ public void onEnable() {
getSLF4JLogger().warn("exception while loading API keys: ", e);
}
optOut.loadOptOut();
auth.loadAuthSettings();

initialiseJavalin();

Expand All @@ -70,8 +76,10 @@ public void onEnable() {
if (pm.isPluginEnabled("QuickShop-Hikari")) {
pm.registerEvents(new ShopSSEListener(sseManager), this);
}
pm.registerEvents(guiManager, this);

getServer().getAsyncScheduler().runAtFixedRate(this, t -> CooldownUtil.refresh(), 5, 5, TimeUnit.MINUTES);
Inventories.forPlugin(this).build();
}

@Override
Expand Down Expand Up @@ -167,4 +175,12 @@ public APIDatabase getDatabase() {
public OptOut getOptOut() {
return optOut;
}

public Authorisation getAuth() {
return auth;
}

public GUIManager getGUIManager() {
return guiManager;
}
}
51 changes: 25 additions & 26 deletions src/main/java/net/earthmc/emcapi/command/ApiCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,41 +42,33 @@ public static LiteralCommandNode<CommandSourceStack> create(final EMCAPI plugin)
return Commands.literal("api")
.requires(ctx -> ctx.getSender().hasPermission("emcapi.command"))
.executes(ctx -> {
if (ctx.getSource().getSender() instanceof Player player) {
plugin.getGUIManager().createRoot(player).openAsRoot(player);
return Command.SINGLE_SUCCESS;
}
ctx.getSource().getSender().sendMessage(INFO_MESSAGE);
return Command.SINGLE_SUCCESS;
})
.then(Commands.literal("opt-out")
.requires(ctx -> ctx.getSender() instanceof Player)
.requires(ctx -> ctx.getSender() instanceof Player player && player.hasPermission("emcapi.opt-out.editor"))
.executes(ctx -> {
final Player player = (Player) ctx.getSource().getSender();

if (plugin.getOptOut().playerOptedOut(player.getUniqueId())) {
player.sendMessage(Component.text("You have already opted out previously!", NamedTextColor.RED));
} else {
if (isOnCooldown(player, CooldownType.OPT_OUT_CHANGE)) {
return Command.SINGLE_SUCCESS;
}

player.sendMessage(Component.text("You have opted out of having your information being public on the API.", NamedTextColor.GREEN));
plugin.getOptOut().setOptedOut(player.getUniqueId(), true);
if (isOnCooldown(player, CooldownType.OPT_OUT_CHANGE)) {
return Command.SINGLE_SUCCESS;
}
player.sendMessage(Component.text("Opening Opt out Editor", NamedTextColor.GREEN));
plugin.getGUIManager().createOptOutMenu(player).openAsRoot(player);
return Command.SINGLE_SUCCESS;
}))
.then(Commands.literal("opt-in")
.requires(ctx -> ctx.getSender() instanceof Player)
.then(Commands.literal("auth")
.requires(ctx -> ctx.getSender() instanceof Player player && player.hasPermission("emcapi.auth.editor"))
.executes(ctx -> {
final Player player = (Player) ctx.getSource().getSender();

if (plugin.getOptOut().playerOptedOut(player.getUniqueId())) {
if (isOnCooldown(player, CooldownType.OPT_OUT_CHANGE)) {
return Command.SINGLE_SUCCESS;
}

player.sendMessage(Component.text("You have opted back in to your information being public on the API.", NamedTextColor.GREEN));
plugin.getOptOut().setOptedOut(player.getUniqueId(), false);
} else {
player.sendMessage(Component.text("You are currently not opted out!", NamedTextColor.RED));
if (isOnCooldown(player, CooldownType.AUTH_CHANGE)) {
return Command.SINGLE_SUCCESS;
}
player.sendMessage(Component.text("Opening Auth Editor", NamedTextColor.GREEN));
plugin.getGUIManager().createAuthMenu(player).openAsRoot(player);
return Command.SINGLE_SUCCESS;
}))
.then(Commands.literal("key")
Expand Down Expand Up @@ -138,7 +130,7 @@ private static boolean isOnCooldown(final Player player, final CooldownType type
final Instant lastCommandUse = COOLDOWNS.asMap().putIfAbsent(new CommandCooldown(player.getUniqueId(), type), now);

if (lastCommandUse != null) {
final long seconds = Duration.between(now, lastCommandUse.plusSeconds(60)).getSeconds();
final long seconds = Duration.between(now, lastCommandUse.plusSeconds(type.cooldown)).getSeconds();

if (seconds > 0) {
player.sendMessage(Component.text("Please wait " + seconds + " more second" + (seconds == 1 ? "" : "s") + " before trying this command again.", NamedTextColor.RED));
Expand All @@ -150,8 +142,15 @@ private static boolean isOnCooldown(final Player player, final CooldownType type
}

private enum CooldownType {
MODIFY_KEY,
OPT_OUT_CHANGE
MODIFY_KEY(60),
OPT_OUT_CHANGE(15),
AUTH_CHANGE(15);

final int cooldown;

CooldownType(int cooldown) {
this.cooldown = cooldown;
}
}

private record CommandCooldown(UUID uuid, CooldownType type) {}
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/net/earthmc/emcapi/database/DatabaseSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ public static void createTables(Connection connection) throws SQLException {
}

statement.executeUpdate("CREATE TABLE IF NOT EXISTS opt_out(`uuid` CHAR(36) NOT NULL, PRIMARY KEY (`uuid`))");
for (String column : getOptOutColumns()) {
try {
statement.executeUpdate("alter table opt_out add column " + column);
} catch (SQLException ignored) {}
}

statement.executeUpdate("CREATE TABLE IF NOT EXISTS authorised(`uuid` CHAR(36) NOT NULL, PRIMARY KEY (`uuid`))");
Comment thread
Veyronity marked this conversation as resolved.
Outdated
for (String column : getAuthorisedColumns()) {
try {
statement.executeUpdate("alter table authorised add column " + column);
} catch (SQLException ignored) {}
}
}
}

Expand All @@ -34,4 +46,21 @@ private static List<String> getApiKeysColumns() {
"`api_key` VARCHAR(" + KeyManager.MAX_KEY_LENGTH + ") NOT NULL"
);
}

private static List<String> getOptOutColumns() {
return List.of(
"`override_all` BOOLEAN DEFAULT TRUE", // If true, the player is deemed to have opted out of all the options, without checking each one
"`towny_resident` BOOLEAN DEFAULT TRUE",
"`online_status` BOOLEAN DEFAULT TRUE",
"`quickshops` BOOLEAN DEFAULT TRUE",
"`mcmmo_stats` BOOLEAN DEFAULT TRUE"
);
}

private static List<String> getAuthorisedColumns() {
return List.of(
"`shop_sse` TEXT DEFAULT ''",
"`shop_query` TEXT DEFAULT ''"
);
}
}
6 changes: 4 additions & 2 deletions src/main/java/net/earthmc/emcapi/endpoint/McMMOEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import net.earthmc.emcapi.integration.McMMOIntegration;
import net.earthmc.emcapi.manager.KeyManager;
import net.earthmc.emcapi.object.endpoint.PostEndpoint;
import net.earthmc.emcapi.object.optout.OptOutSettings;
import net.earthmc.emcapi.util.CooldownUtil;
import net.earthmc.emcapi.util.HttpExceptions;
import net.earthmc.emcapi.util.JSONUtil;
Expand All @@ -29,7 +30,7 @@ public McMMOEndpoint(EMCAPI plugin) {
@Override
public PlayerProfile getObjectOrNull(JsonElement element, @Nullable String key) {
String string = JSONUtil.getJsonElementAsStringOrNull(element);
if (string == null) throw HttpExceptions.NOT_A_STRING;;
if (string == null) throw HttpExceptions.NOT_A_STRING;

UUID player;
try {
Expand All @@ -42,7 +43,8 @@ public PlayerProfile getObjectOrNull(JsonElement element, @Nullable String key)
if (keyOwner == null) {
throw HttpExceptions.MISSING_API_KEY;
}
if (!player.equals(keyOwner)) {
OptOutSettings settings = plugin.getOptOut().getPlayerSettings(player);
if (!player.equals(keyOwner) && (settings == null || settings.mcmmo())) {
throw HttpExceptions.FORBIDDEN;
}

Expand Down
11 changes: 4 additions & 7 deletions src/main/java/net/earthmc/emcapi/endpoint/ShopEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import net.earthmc.emcapi.integration.QuickShopIntegration;
import net.earthmc.emcapi.manager.KeyManager;
import net.earthmc.emcapi.object.endpoint.PostEndpoint;
import net.earthmc.emcapi.object.optout.AuthSettings;
import net.earthmc.emcapi.object.optout.OptOutSettings;
import net.earthmc.emcapi.util.CooldownUtil;
import net.earthmc.emcapi.util.EndpointUtils;
import net.earthmc.emcapi.util.HttpExceptions;
Expand Down Expand Up @@ -46,7 +48,8 @@ public List<Shop> getObjectOrNull(JsonElement element, @Nullable String key) {
if (keyOwner == null) {
throw HttpExceptions.MISSING_API_KEY;
}
if (!player.equals(KeyManager.getKeyOwner(key))) {
OptOutSettings settings = plugin.getOptOut().getPlayerSettings(player);
if (!player.equals(keyOwner) && (settings == null || settings.quickShops() && !plugin.getAuth().authorize(player, AuthSettings.Type.SHOP_QUERY, keyOwner))) {
throw HttpExceptions.FORBIDDEN;
}
CooldownUtil.checkAndAddCooldownOrThrow("shop", keyOwner.toString(), COOLDOWN_SECONDS);
Expand All @@ -57,19 +60,13 @@ public List<Shop> getObjectOrNull(JsonElement element, @Nullable String key) {
public JsonElement getJsonElement(List<Shop> object, @Nullable String key) {
final Map<String, JsonElement> shops = new ConcurrentHashMap<>();
int counter = 0;
UUID keyOwner = KeyManager.getKeyOwner(key);
if (keyOwner == null) {
throw HttpExceptions.MISSING_API_KEY;
}
if (object.isEmpty()) {
return null;
}

final List<CompletableFuture<Void>> shopFutures = new ArrayList<>();

for (Shop shop : object) {
if (!keyOwner.equals(shop.getOwner().getUniqueId())) continue;

final CompletableFuture<Void> shopFuture = new CompletableFuture<>();
shopFutures.add(shopFuture);

Expand Down
108 changes: 0 additions & 108 deletions src/main/java/net/earthmc/emcapi/endpoint/legacy/DiscordEndpoint.java

This file was deleted.

Loading
Loading