Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: v0.1.0 #2

Merged
merged 8 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,24 @@

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
## Configuration

The plugin can be configured by editing the `config.yml` file in the `plugins/WorldId` directory of your Minecraft server. The following settings are available:

- worldcoin-app-id: ""
- REQUIRED
- The App ID you've gotten from Worldcoin's [Developer Portal](https://developer.worldcoin.org).
- world-id-orb-group-name: "humans"
- REQUIRED
- The name of the LuckPerms group that will be granted to users who verify with World ID's Orb Credential. The Orb credential provides a very high level of assurance that the user is a human with only one account.
- world-id-lite-group-name: ""
- OPTIONAL
- The name of the LuckPerms group that will be granted to users who verify with World ID Lite. World ID Lite verifies that a user has a unique mobile device, providing medium-strength bot protection that is still easy to use.
- web-url: "https://minecraft.worldcoin.org"
- REQUIRED
- The URL to use for the web interface where users will verify with World ID. You shouldn't change this unless you're running the web interface locally for development purposes.

## Dev 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:

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

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

<properties>
<maven.compiler.release>17</maven.compiler.release>
Expand Down
26 changes: 22 additions & 4 deletions src/main/java/org/worldcoin/bukkit/plugin/worldid/WorldId.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,44 @@
package org.worldcoin.bukkit.plugin.worldid;

import java.util.UUID;

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");
public String orbGroupName = this.getConfig().getString("orb-group-name");
public String deviceGroupName = this.getConfig().getString("device-group-name");
public String uuid = this.getConfig().getString("server-uuid");
public String webUrl = this.getConfig().getString("web-url");

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!");
if (uuid == null) {
getLogger().warning("You must configure a server UUID in config.yml file before using this plugin!");
return false;
}
if (orbGroupName == null && deviceGroupName == null) {
getLogger().warning("You have not configured an Orb Group Name or Device Group Name in config.yml. At least one group must be configured.");
return false;
}
if (orbGroupName == null) {
getLogger().warning("You have not configured an Orb Group Name in config.yml. All World ID-verified users will be issued the same role regardless of their verification level.");
}
if (deviceGroupName == null) {
getLogger().warning("You have not configured a Device Group Name in config.yml. Only Orb-verified World ID users will be able to verify.");
}
return true;
}

@Override
public void onEnable() {
this.saveDefaultConfig();
if (this.getConfig().getString("server-uuid") == "") {
this.getConfig().set("server-uuid", UUID.randomUUID().toString());
this.saveConfig();
}
getLogger().info("Initialized the config.");
// configureWorldGuard();
if (!isConfigured()) {
this.getServer().getPluginManager().disablePlugin(this);
getLogger().warning("Plugin disabled.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,25 @@ public boolean onCommand(CommandSender sender, Command command, String s, String
if (sender instanceof Player) {
Player player = (Player) sender;

if (player.hasPermission("group." + plugin.groupName)) {
if (player.hasPermission("group." + plugin.orbGroupName) | player.hasPermission("group." + plugin.deviceGroupName)) {
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");
UUID req_uuid = UUID.randomUUID();
String url = plugin.webUrl + "/verify?reqUUID=" + req_uuid + "&serverUUID=" + plugin.uuid;

player.sendMessage("Click here to verify with World ID:");
player.sendMessage("");

TextComponent button = new TextComponent("Verify !");
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);
new CheckVerified(player, req_uuid, 20).runTaskTimerAsynchronously(plugin, 100, 200);
return true;
} else {
sender.sendMessage("You must be a player!");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ public JoinListener(WorldId plugin) {
public void join(PlayerJoinEvent event) {
Player player = event.getPlayer();
player.sendMessage("Welcome to the server!");
if (player.hasPermission("group."+plugin.groupName)) {
if (player.hasPermission("group."+plugin.orbGroupName) || player.hasPermission("group."+plugin.deviceGroupName)) {
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.");
player.sendMessage("You can get permissions by typing the `/verify` command to verify with World ID.");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,69 +1,99 @@
package org.worldcoin.bukkit.plugin.worldid.tasks;

import java.io.IOException;
import java.util.UUID;

import org.apache.hc.client5.http.fluent.Request;

import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.scheduler.BukkitRunnable;
import org.worldcoin.bukkit.plugin.worldid.WorldId;

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 WorldId plugin = WorldId.getPlugin(WorldId.class);

private final Player player;
private final String groupName;
private final UUID uuid;
private final String url;
private final String webUrl;
private int counter;

public CheckVerified(Player player, String groupName, UUID uuid, String url, int counter) {
public CheckVerified(Player player, UUID uuid, 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;
}
this.webUrl = plugin.webUrl+"/api/isVerified?id="+uuid;
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);
}
Request.get(webUrl).execute().handleResponse(new HttpClientResponseHandler<Boolean>() {

@Override
public Boolean handleResponse(final ClassicHttpResponse response) throws IOException {
final int status = response.getCode();

if (status == 200) {
String verification_level = new String(response.getEntity().getContent().readAllBytes());
String groupName;

plugin.getLogger().log(java.util.logging.Level.INFO, "Verification Level: " + verification_level);

switch (verification_level) {
case "orb":
groupName = plugin.orbGroupName.isBlank() ? plugin.deviceGroupName : plugin.orbGroupName;
break;
case "device":
groupName = plugin.deviceGroupName;
if (groupName == null) {
player.sendMessage("This Verification Level is not accepted.");
CheckVerified.this.cancel();
return false;
}
break;
default:
groupName = null;
player.sendMessage("Invalid Verification Level.");
CheckVerified.this.cancel();
return false;
}

if (player.hasPermission("group." + groupName)) {
throw new IllegalStateException("player is already verified");
}

final RegisteredServiceProvider<LuckPerms> provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class);
final LuckPerms api = provider.getProvider();
final User user = api.getPlayerAdapter(Player.class).getUser(player);
final 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!");
CheckVerified.this.cancel();
return true;
} else {
return false;
}
}
});
} 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();
Expand Down
5 changes: 3 additions & 2 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
worldcoin-app-id: ""
verified-group-name: "humans"
server-uuid: "" # Leave this blank to generate a new one. Once it's been set, do not change it, or users will be able to verify a second time.
orb-group-name: "orb-humans"
device-group-name: "device-humans" # If you want to require Orb verification, leave this blank.
web-url: "https://minecraft.worldcoin.org"
4 changes: 2 additions & 2 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: WorldId
authors: [0xPenryn]
authors: [Penryn]
website: worldcoin.org
version: 0.0.1
version: 0.1.0
api-version: 1.20
main: org.worldcoin.bukkit.plugin.worldid.WorldId
prefix: "World ID"
Expand Down