Bukkitstr. Thanks ChatGPT...
and nostr:npub1826v365he5ty69lk3xgvzqrwy8587vdfrxnsz0k09khzustf8r7s6j7t95
This commit is contained in:
commit
69f7fb2534
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
target/
|
99
README.md
Normal file
99
README.md
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
# BukkitstrPlugin
|
||||||
|
|
||||||
|
BukkitstrPlugin is a Minecraft plugin that integrates with the Nostr relay to authenticate players. Players must authenticate by signing a valid Nostr event before they can move in the game.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **WebSocket Integration**: Connects to a Nostr relay using WebSockets.
|
||||||
|
- **Player Authentication**: Players must authenticate with their Minecraft username via a Nostr event.
|
||||||
|
- **Movement Lock**: Prevents players from moving until they are authenticated.
|
||||||
|
- **Real-time Messaging**: Sends and receives messages from the Nostr relay in real-time.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Java 8 or higher**
|
||||||
|
- **Maven** (for building the plugin)
|
||||||
|
- **Spigot/Paper** server (Minecraft 1.20 or higher)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. **Clone the repository**:
|
||||||
|
```sh
|
||||||
|
git clone https://git.vanderwarker.family/nostr/bukkitstr.git
|
||||||
|
cd bukkitstr
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Build the plugin**:
|
||||||
|
```sh
|
||||||
|
mvn clean package
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Copy the plugin JAR**:
|
||||||
|
Copy the generated `bukkitstr-plugin-1.0-SNAPSHOT.jar` file from the `target` directory to your Minecraft server's `plugins` directory.
|
||||||
|
|
||||||
|
4. **Configure the plugin**:
|
||||||
|
Make sure to replace `wss://your-nostr-relay-url` in the `BukkitstrPlugin.java` file with your actual Nostr relay WebSocket URL.
|
||||||
|
|
||||||
|
5. **Start your server**:
|
||||||
|
Start your Minecraft server and check the console for any errors. The plugin should initialize and connect to the Nostr relay.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Authentication Command
|
||||||
|
|
||||||
|
Players need to use the `/auth` command to start the authentication process. The plugin will wait for a Nostr event containing the player's Minecraft username in the `d` tag content.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
/auth
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sign Event
|
||||||
|
|
||||||
|
Next, you need to sign a event kind "13378008" and the "d" tag to be your Minecraft username.
|
||||||
|
|
||||||
|
Using [nostril]() is quite easy.
|
||||||
|
```sh
|
||||||
|
nostril --kind 13378008 --tag "d" "MinecraftUsername"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then send to the relay you've specified in src/../BukkitstrPlugin.java
|
||||||
|
|
||||||
|
|
||||||
|
### Player Authentication Process
|
||||||
|
|
||||||
|
1. **Connect to the Nostr relay**: The plugin connects to the specified Nostr relay when the server starts.
|
||||||
|
2. **Send Authentication Request**: The plugin sends an initial request to the Nostr relay to listen for authentication events.
|
||||||
|
3. **Wait for Nostr Event**: When a player uses the `/auth` command, the plugin waits for a Nostr event containing the player's username in the `d` tag.
|
||||||
|
4. **Authenticate Player**: If the received Nostr event's `d` tag content matches the player's username, the player is authenticated and can move freely. Otherwise, they will receive an authentication failure message.
|
||||||
|
|
||||||
|
## Developer Information
|
||||||
|
|
||||||
|
### Source Code
|
||||||
|
|
||||||
|
The main source code is located in the `src/main/java/family/vanderwarker/bukkitstr/BukkitstrPlugin.java` file.
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
Ensure the following dependencies are added to your `pom.xml`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.java-websocket</groupId>
|
||||||
|
<artifactId>Java-WebSocket</artifactId>
|
||||||
|
<version>1.5.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.13.3</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
- Thanks to the SpigotMC community for their documentation and support.
|
||||||
|
- Thanks to the Nostr community for their innovative protocol.
|
||||||
|
- Thanks to [npub1826v365he5ty69lk3xgvzqrwy8587vdfrxnsz0k09khzustf8r7s6j7t95](nostr:npub1826v365he5ty69lk3xgvzqrwy8587vdfrxnsz0k09khzustf8r7s6j7t95)
|
||||||
|
- Thanks to ChatGPT 4.o
|
78
pom.xml
Normal file
78
pom.xml
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<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>family.vanderwarker.bukkitstr</groupId>
|
||||||
|
<artifactId>bukkistr</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spigot-repo</id>
|
||||||
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Bukkit/Spigot API -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spigotmc</groupId>
|
||||||
|
<artifactId>spigot-api</artifactId>
|
||||||
|
<version>1.16.5-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- Java WebSocket -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.java-websocket</groupId>
|
||||||
|
<artifactId>Java-WebSocket</artifactId>
|
||||||
|
<version>1.5.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.12.3</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.4</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<relocations>
|
||||||
|
<relocation>
|
||||||
|
<pattern>org.java_websocket</pattern>
|
||||||
|
<shadedPattern>shaded.org.java_websocket</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
</relocations>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
150
src/main/java/family/vanderwarker/bukkitstr/BukkitstrPlugin.java
Normal file
150
src/main/java/family/vanderwarker/bukkitstr/BukkitstrPlugin.java
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
package family.vanderwarker.bukkitstr;
|
||||||
|
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.java_websocket.client.WebSocketClient;
|
||||||
|
import org.java_websocket.handshake.ServerHandshake;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class BukkitstrPlugin extends JavaPlugin implements Listener {
|
||||||
|
|
||||||
|
private NostrWebSocketClient webSocketClient;
|
||||||
|
private final Set<Player> authenticatedPlayers = new HashSet<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
getLogger().info("BukkitstrPlugin enabled!");
|
||||||
|
try {
|
||||||
|
URI uri = new URI("wss://"); // Replace with your Nostr relay URL
|
||||||
|
webSocketClient = new NostrWebSocketClient(uri, getLogger());
|
||||||
|
webSocketClient.connect();
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
getLogger().severe("Invalid URI for Nostr relay: " + e.getMessage());
|
||||||
|
}
|
||||||
|
getServer().getPluginManager().registerEvents(this, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
getLogger().info("BukkitstrPlugin disabled!");
|
||||||
|
if (webSocketClient != null) {
|
||||||
|
webSocketClient.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if (sender instanceof Player) {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
player.sendMessage("Waiting for Nostr event...");
|
||||||
|
|
||||||
|
webSocketClient.waitForEvent(content -> handleSpecificEvent(content, player));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSpecificEvent(String content, Player player) {
|
||||||
|
if (content.equals(player.getName())) {
|
||||||
|
authenticatedPlayers.add(player);
|
||||||
|
player.sendMessage("You are now authenticated.");
|
||||||
|
} else {
|
||||||
|
player.sendMessage("Authentication failed. Username does not match.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (!authenticatedPlayers.contains(player)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
player.sendMessage("You need to authenticate first!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NostrWebSocketClient extends WebSocketClient {
|
||||||
|
|
||||||
|
private final Logger logger;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
private Consumer<String> eventConsumer;
|
||||||
|
|
||||||
|
public NostrWebSocketClient(URI serverUri, Logger logger) {
|
||||||
|
super(serverUri);
|
||||||
|
this.logger = logger;
|
||||||
|
this.objectMapper = new ObjectMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(ServerHandshake handshakedata) {
|
||||||
|
logger.info("Connected to Nostr relay: " + getURI());
|
||||||
|
sendInitialRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(String message) {
|
||||||
|
logger.info("Received message from Nostr relay: " + message);
|
||||||
|
handleNostrEvent(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose(int code, String reason, boolean remote) {
|
||||||
|
logger.warning("Connection to Nostr relay closed: " + reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception ex) {
|
||||||
|
logger.severe("Error with WebSocket connection: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleNostrEvent(String message) {
|
||||||
|
try {
|
||||||
|
JsonNode jsonNode = objectMapper.readTree(message);
|
||||||
|
if (jsonNode.isArray() && jsonNode.size() > 2) {
|
||||||
|
JsonNode eventNode = jsonNode.get(2);
|
||||||
|
JsonNode tagsNode = eventNode.path("tags");
|
||||||
|
if (tagsNode.isArray()) {
|
||||||
|
for (JsonNode tag : tagsNode) {
|
||||||
|
if (tag.isArray() && tag.size() > 1 && "d".equals(tag.get(0).asText())) {
|
||||||
|
String content = tag.get(1).asText();
|
||||||
|
if (eventConsumer != null) {
|
||||||
|
eventConsumer.accept(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warning("No 'tags' array found in the event message.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warning("Event message is not in the expected format.");
|
||||||
|
}
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
logger.severe("Failed to parse Nostr event: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void waitForEvent(Consumer<String> eventConsumer) {
|
||||||
|
this.eventConsumer = eventConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendInitialRequest() {
|
||||||
|
String initialRequest = "[\"REQ\",\"mc_auth\",{\"kinds\":[13378008],\"limit\":0}]";
|
||||||
|
send(initialRequest);
|
||||||
|
logger.info("Sent initial request to Nostr relay: " + initialRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
src/main/resources/plugin.yml
Normal file
8
src/main/resources/plugin.yml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
name: BukkitstrPlugin
|
||||||
|
version: 0.1
|
||||||
|
main: family.vanderwarker.bukkitstr.BukkitstrPlugin
|
||||||
|
api-version: 1.20
|
||||||
|
commands:
|
||||||
|
auth:
|
||||||
|
description: Authenticate with the server using Nostr
|
||||||
|
usage: /auth
|
Loading…
Reference in New Issue
Block a user