From e1d23c76b59d71523c57505608fdb766ebf9430f Mon Sep 17 00:00:00 2001 From: 0xPenryn Date: Sat, 4 Nov 2023 22:00:06 -0500 Subject: [PATCH] feat: init (#1) * feat: init * chore: readme improvement --- .gitignore | 7 ++ README.md | 40 ++++++++- pom.xml | 84 +++++++++++++++++++ .../bukkit/plugin/worldid/WorldId.java | 36 ++++++++ .../worldid/commands/VerifyCommand.java | 53 ++++++++++++ .../plugin/worldid/event/JoinListener.java | 28 +++++++ .../plugin/worldid/tasks/CheckVerified.java | 72 ++++++++++++++++ src/main/resources/config.yml | 3 + src/main/resources/plugin.yml | 12 +++ 9 files changed, 333 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/org/worldcoin/bukkit/plugin/worldid/WorldId.java create mode 100644 src/main/java/org/worldcoin/bukkit/plugin/worldid/commands/VerifyCommand.java create mode 100644 src/main/java/org/worldcoin/bukkit/plugin/worldid/event/JoinListener.java create mode 100644 src/main/java/org/worldcoin/bukkit/plugin/worldid/tasks/CheckVerified.java create mode 100644 src/main/resources/config.yml create mode 100644 src/main/resources/plugin.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ef1a04 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +out +/.idea/ +/target/ +/mc-plugin-template.iml +.DS_Store +.vscode/settings.json +dependency-reduced-pom.xml diff --git a/README.md b/README.md index f775033..aae4d27 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,38 @@ -# world-id-minecraft -Minecraft server plugin for managing permissions with World ID. Requires SpigotMC (or a fork) and LuckPerms. +# Minecraft World ID Server Plugin + +A plugin for the spigot Minecraft server that can be used to grant users permissions when they verify with World ID. Intended to be used with [LuckPerms](https://luckperms.net/). + +## Quickstart + +This project uses [Maven](https://maven.apache.org/) for building. To build the plugin run the following command in the root directory of the project: + +````bash +mvn package +```` + +To test the plugin we need a Minecraft server! Run a SpigotMC server (or one of its derivatives) locally -- this exercise is left to the reader. We recommend [PaperMC](https://papermc.io/), and you can [find installation instructions here](https://docs.papermc.io/paper/getting-started). Ensure you also install LuckPerms, and create a group for verified users. By default, this group is called `humans`. You can change this setting in the World ID plugin's `config.yml` file. + +Build the plugin and copy the resulting jar file to the `plugins` folder of your server. Restart the server. + +In the log produced by the server on the command line watch out for the following lines indicating that the plugin was deployed properly: + +``` +[22:48:13 INFO]: [World ID] Enabling WorldId v0.0.1 +[22:48:13 INFO]: [World ID] Initialized the config. +[22:48:13 INFO]: [World ID] Plugin configured. +[22:48:13 INFO]: [World ID] Added the 'verify' command. +[22:48:13 INFO]: [World ID] Listening for player joins. +``` + +We also need to run [the Web UI](https://github.com/worldcoin/world-id-minecraft-web) locally. Follow the instructions in the README to get it running. + +Once it's up and running, ensure you set the `web-url` in `{MC_SERVER_DIR}/plugins/WorldId/config.yml` to the URL of the web server, typically `http://localhost:3000`. Also set `worldcoin-app-id` to the App ID you've gotten from Worldcoin's [Developer Portal](https://developer.worldcoin.org). + +Start the Minecraft client on your computer and connect to the local Minecraft server by specifying `localhost` as Server Address. + +Open the command line in Minecraft (by pressing `t`) try the new command and see what happens: +``` +/verify +```` + +Once you're done fiddling with the code don't forget to run `mvn package`, copy the resulting jar file to the `plugins` folder of your server, and restart the server. \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f4e11a8 --- /dev/null +++ b/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + org.worldcoin.bukkit.plugin + worldid + 0.0.2 + + + 17 + UTF-8 + + + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + + com.google.code.gson + gson + 2.10.1 + + + com.google.guava + guava + 32.1.2-jre + + + + + + + org.spigotmc + spigot-api + 1.20.2-R0.1-SNAPSHOT + provided + + + net.luckperms + api + 5.4 + provided + + + org.apache.httpcomponents.client5 + httpclient5-fluent + 5.2.1 + compile + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.1 + + + package + + shade + + + + + org.apache.httpcomponents.*:* + + + true + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/worldcoin/bukkit/plugin/worldid/WorldId.java b/src/main/java/org/worldcoin/bukkit/plugin/worldid/WorldId.java new file mode 100644 index 0000000..b2b5d94 --- /dev/null +++ b/src/main/java/org/worldcoin/bukkit/plugin/worldid/WorldId.java @@ -0,0 +1,36 @@ +package org.worldcoin.bukkit.plugin.worldid; + +import org.bukkit.plugin.java.JavaPlugin; +import org.worldcoin.bukkit.plugin.worldid.commands.VerifyCommand; +import org.worldcoin.bukkit.plugin.worldid.event.JoinListener; + +public class WorldId extends JavaPlugin { + + public String groupName = this.getConfig().getString("verified-group-name"); + + private boolean isConfigured() { + if (this.getConfig().getString("worldcoin-app-id") == null) { + getLogger().warning("You must configure the Worldcoin App ID in config.yml file before using this plugin!"); + return false; + } + return true; + } + + @Override + public void onEnable() { + this.saveDefaultConfig(); + getLogger().info("Initialized the config."); + // configureWorldGuard(); + if (!isConfigured()) { + this.getServer().getPluginManager().disablePlugin(this); + getLogger().warning("Plugin disabled."); + return; + } else { + getLogger().info("Plugin configured."); + this.getCommand("verify").setExecutor(new VerifyCommand()); + getLogger().info("Added the 'verify' command."); + new JoinListener(this); + getLogger().info("Listening for player joins."); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/worldcoin/bukkit/plugin/worldid/commands/VerifyCommand.java b/src/main/java/org/worldcoin/bukkit/plugin/worldid/commands/VerifyCommand.java new file mode 100644 index 0000000..59fe3f2 --- /dev/null +++ b/src/main/java/org/worldcoin/bukkit/plugin/worldid/commands/VerifyCommand.java @@ -0,0 +1,53 @@ +package org.worldcoin.bukkit.plugin.worldid.commands; + +import java.util.UUID; + +import org.worldcoin.bukkit.plugin.worldid.WorldId; +import org.worldcoin.bukkit.plugin.worldid.tasks.CheckVerified; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.TextComponent; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class VerifyCommand implements CommandExecutor { + + private WorldId plugin = WorldId.getPlugin(WorldId.class); + + @Override + public boolean onCommand(CommandSender sender, Command command, String s, String[] strings) { + + if (sender instanceof Player) { + Player player = (Player) sender; + + if (player.hasPermission("group." + plugin.groupName)) { + player.sendMessage("You've already been verified with World ID!"); + return true; + } + String webUrl = plugin.getConfig().getString("web-url"); + UUID uuid = UUID.randomUUID(); + String url = webUrl + "/verify?id=" + uuid + "&app_id=" + plugin.getConfig().getString("worldcoin-app-id"); + + player.sendMessage("Click here to verify with World ID:"); + player.sendMessage(""); + + TextComponent button = new TextComponent("Verify !"); + button.setColor(ChatColor.WHITE); + button.setBold(true); + button.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); + + player.spigot().sendMessage( button ); + player.sendMessage(""); + + new CheckVerified(player, plugin.groupName, uuid, webUrl, 20).runTaskTimer(plugin, 100, 200); + return true; + } else { + sender.sendMessage("You must be a player!"); + return false; + } + } +} diff --git a/src/main/java/org/worldcoin/bukkit/plugin/worldid/event/JoinListener.java b/src/main/java/org/worldcoin/bukkit/plugin/worldid/event/JoinListener.java new file mode 100644 index 0000000..9a6df35 --- /dev/null +++ b/src/main/java/org/worldcoin/bukkit/plugin/worldid/event/JoinListener.java @@ -0,0 +1,28 @@ +package org.worldcoin.bukkit.plugin.worldid.event; + +import org.worldcoin.bukkit.plugin.worldid.WorldId; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class JoinListener implements Listener { + + private WorldId plugin = WorldId.getPlugin(WorldId.class); + + public JoinListener(WorldId plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void join(PlayerJoinEvent event) { + Player player = event.getPlayer(); + player.sendMessage("Welcome to the server!"); + if (player.hasPermission("group."+plugin.groupName)) { + player.sendMessage("You've been verified with World ID!"); + } else { + player.sendMessage("You haven't been verified with World ID!"); + player.sendMessage("You won't be able to interact with the world until you use the `/verify` command."); + } + } +} diff --git a/src/main/java/org/worldcoin/bukkit/plugin/worldid/tasks/CheckVerified.java b/src/main/java/org/worldcoin/bukkit/plugin/worldid/tasks/CheckVerified.java new file mode 100644 index 0000000..afa259f --- /dev/null +++ b/src/main/java/org/worldcoin/bukkit/plugin/worldid/tasks/CheckVerified.java @@ -0,0 +1,72 @@ +package org.worldcoin.bukkit.plugin.worldid.tasks; + +import java.util.UUID; + +import org.apache.hc.client5.http.fluent.Request; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.scheduler.BukkitRunnable; + +import net.luckperms.api.LuckPerms; +import net.luckperms.api.node.types.InheritanceNode; +import net.luckperms.api.model.user.User; + +public class CheckVerified extends BukkitRunnable { + + private final Player player; + private final String groupName; + private final UUID uuid; + private final String url; + private int counter; + + public CheckVerified(Player player, String groupName, UUID uuid, String url, int counter) { + this.player = player; + this.uuid = uuid; + this.url = url; + if (groupName == null) { + throw new IllegalArgumentException("groupName cannot be null"); + } else { + this.groupName = groupName; + } + if (counter <= 0) { + throw new IllegalArgumentException("counter must be greater than 0"); + } else { + this.counter = counter; + } + if (player.hasPermission("group." + groupName)) { + throw new IllegalStateException("player is already verified"); + } + } + + @Override + public void run() { + if (counter > 0) { + try { + int responseCode = Request.get(url + "/api/isVerified?id=" + uuid.toString()).execute().returnResponse().getCode(); + if (responseCode == 200) { + RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class); + LuckPerms api = provider.getProvider(); + User user = api.getPlayerAdapter(Player.class).getUser(player); + InheritanceNode node = InheritanceNode.builder(groupName).value(true).build(); + user.data().add(node); + user.setPrimaryGroup(groupName); + api.getUserManager().saveUser(user); + player.sendMessage("You've successfully verified with World ID!"); + this.cancel(); + } else { + player.sendMessage("Awaiting World ID verification. Retries left: " + counter); + } + } catch (Exception e) { + player.sendMessage("Error while verifying with World ID: ", e.toString()); + this.cancel(); + } finally { + counter--; + } + } else { + player.sendMessage("Timed out waiting for verification. Please try again."); + this.cancel(); + } + } +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..626a3a8 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,3 @@ +worldcoin-app-id: "" +verified-group-name: "humans" +web-url: "https://minecraft.worldcoin.org" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..35d1014 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,12 @@ +name: WorldId +authors: [0xPenryn] +website: worldcoin.org +version: 0.0.1 +api-version: 1.20 +main: org.worldcoin.bukkit.plugin.worldid.WorldId +prefix: "World ID" +depend: [LuckPerms] + +commands: + verify: + description: Verifies you're a unique human and grants you permissions!