Skip to content
PDF

How it works

Minecraft Plugin Messages

GeyserLink makes use of the normal PluginMessage channel provided through a special packet in Minecraft. As a result it will not cause any issues if a server does not have GeyserLink. The plugin writer does not have to deal with Plugin Messages as they will make use of events and methods provided by GeyserLink.

GeyserLink takes a message provided by the program and will wrap it inside a signed message (or a signed response). This signed message will contain identifiers for the sequence, the sender, the packet payload and a signature for the packet. Responses are similarly wrapped and are associated to Messages by the sequence number and Sender.

The reason for the signature is that we cannot trust messages that could come from a client. This means that every message sent and received by GeyserLink has a signature affirming that the data is correct and who has sent it. GeyserLink can also be configured as to which keys that sign a signature can be trusted.

The only difference between an untrusted and trusted message is that the key used to sign a trusted message has been placed in the trusted field in dynamic.yml rather than a 'known' field. Untrusted messages can still be useful and unless there are any security implications then plugin writers should consider trying to support messages from untrusted sources or gracefully dealing with them.

Info

Geyserlink will send signed messages using the plugin channel geyserlink:message and responses using the plugin channel geyserlink:response. There is no need to trap these as GeyserLink provides its own events, GeyserLinkMessageEvent and GeyserLinkResponseEvent that will unwrap the message properly.

Creating a Raw Message

Before we create custom messages it is worth knowing how to create a raw message and response as it describes how GeyserLink works.

Here is an example:

Example

GeyserLink.getInstance().sendMessage(player, "myChannel", "mySubChannel", "test".getBytes());

This will send a GeyserLink message with a channel myChannel and a sub channel of mySubChannel. These are similar sounding to the Plugin Message channel but are not related and are used to allow you to trap what GeyserLink messages are interesting.

GeyserLink will trigger the event GeyserLinkMessageEvent when a GeyserLink message is received. The following is an example of how to trap the above message in Spigot:

Example

@EventHandler
public void onGeyserLinkMessage(GeyserLinkMessageEvent event) {
    GeyserLinkMessage message = event.getSignedMessage().getMessage();

    if (message.getChannel().equals("myChannel") && message.getSubChannel().equals("mySubChannel")) {
        getLogger().info("Got a GeyserLink message with payload: " + new String(message.getPayload()));
    }
}

Alert

The channel and subchannel here are not related to the Plugin Message channel. These are wrapped inside the message and are available for your use and it is recommended to namespace the name like the regular PluginChannel channel does to avoid collisions. GeyserLink reserves geyserlink:main as a channel for its own use.

Creating a Raw Response

Lets expand on the previous example and return something back. The Event will now look like this:

Example

@EventHandler
public void onGeyserLinkMessage(GeyserLinkMessageEvent event) {
    GeyserLinkMessage message = event.getSignedMessage().getMessage();

    if (message.getChannel().equals("myChannel") && message.getSubChannel().equals("mySubChannel")) {
        getLogger().info("Got a GeyserLink message with payload: " + new String(message.getPayload()));

        GeyserLink.getInstance().sendResponse(event.getPlayer(), message, "responded".getBytes());
    }
}

Note that to respond we had to pass the message as a parameter. This allows GeyserLink to properly link the response to the message.

Let's update how it is executed now:

Example

GeyserLink.getInstance().sendMessage(player, "myChannel", "mySubChannel", "test".getBytes())
    .onResponse(() -> (result, signed) -> {
        getLogger().info("Got a GeyserLink response: " + new String(signed.getMessage().getPayload());
    });

Now it will output the response it receives. Note that the lambda here is passed the signed message.

Note

GeyserLink will trigger a GeyserLinkResponseEvent for any response but it is less useful as responses can more easily be used through the onResponse method as demonstrated here.

Private and Public Keys

When first run GeyserLink will generate a new public and private key for itself, storing these in the configuration file dynamic.yml. The private key should be considered confidential.

When sending signed messages GeyserLink will use its private key to sign the message. The receiving server will use the public key to verify if a signature is valid and if it is a trusted public key.

If GeyserLink receives a message by a sender it does not have the public key for it will send out a WHOIS packet asking the sender for their public key and will then add it to its known key list and persist this into the dynamic.yml configuration file.

Any key can be made trusted by editing the dynamic.yml file and moving the key into the trusted list.


Last update: