Skip to content

Commit

Permalink
feat: init (#1)
Browse files Browse the repository at this point in the history
* feat: init

* chore: readme improvement
  • Loading branch information
0xPenryn authored Nov 5, 2023
1 parent 62c6497 commit e1d23c7
Show file tree
Hide file tree
Showing 9 changed files with 333 additions and 2 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
out
/.idea/
/target/
/mc-plugin-template.iml
.DS_Store
.vscode/settings.json
dependency-reduced-pom.xml
40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
84 changes: 84 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.worldcoin.bukkit.plugin</groupId>
<artifactId>worldid</artifactId>
<version>0.0.2</version>

<properties>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<repositories>
<repository>
<id>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.20.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.luckperms</groupId>
<artifactId>api</artifactId>
<version>5.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5-fluent</artifactId>
<version>5.2.1</version>
<scope>compile</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>org.apache.httpcomponents.*:*</include>
</includes>
</artifactSet>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
36 changes: 36 additions & 0 deletions src/main/java/org/worldcoin/bukkit/plugin/worldid/WorldId.java
Original file line number Diff line number Diff line change
@@ -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.");
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -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.");
}
}
}
Original file line number Diff line number Diff line change
@@ -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<LuckPerms> 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();
}
}
}
3 changes: 3 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
worldcoin-app-id: ""
verified-group-name: "humans"
web-url: "https://minecraft.worldcoin.org"
12 changes: 12 additions & 0 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
@@ -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!

0 comments on commit e1d23c7

Please sign in to comment.