Skip to content

Classic protocol support #247

@catfromplan9

Description

@catfromplan9

I propose adding /heartbeat.jsp endpoint to the sessionserver endpoint, for the purpose of supporting minecraft classic

Here is a barebones implementation of that endpoint in python

from flask import Flask, request
from urllib.parse import unquote_plus
import hashlib
from werkzeug.middleware.proxy_fix import ProxyFix

app = Flask(__name__)

app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_host=1)

@app.route("/authlib-injector/sessionserver/heartbeat.jsp", methods=["GET", "POST"])  # supports both
def heartbeat():
    vals = request.values

    port    = vals.get("port", "25565")
    maxp    = vals.get("max", "1")
    name    = unquote_plus(vals.get("name", "Minecraft Server"))
    public  = vals.get("public", "False")
    version = vals.get("version", "7")
    salt    = vals.get("salt", "")
    users   = vals.get("users", "0")

    ip = request.remote_addr

    print(f"{name} ({ip}:{port}) - {salt} users: {users}/{maxp}, pub: {public}, v{version}")
    key = hashlib.md5((salt + "Notch").encode("utf-8")).hexdigest()
    print(f"Notch's key: {key}")

    return f"http://minecraft.net/classic/play/foobar", 200, {"Content-Type": "text/plain"}  # mc server accepts anything, this is not important

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

Heartbeat should be sent every 45 seconds by vanilla, we could require getting one every 5 minutes or server will be seen as offline. Drasl must remember IP port and salt.

Authentication works like so: mppass = md5(serverSalt + playerName)

More details here:
https://minecraft.wiki/w/Classic_server_protocol
https://www.grahamedgecombe.com/talks/minecraft.pdf

Historically, the server will at this point be listed on minecraft.net server list with a link (same link as server gets from heartbeat) that takes you to the minecraft applet

minecraft.net will populate the launch parameters for the applet for you, including the mppass for your account which you need correct to join the server. SessionID/accessToken is unused in these versions for authorizing, only mpPass matters.

Launcher will need to support using the custom endpoint to get mppass to launch with, because obviously the old solution is no longer going to work since we don't run game from browser anymore.

I propose an endpoint for this which launchers can implement

GET (sessionServer)/getMpPass?ip=1.2.3.4&port=optional_int_default_25565&player=Dinnerbone

Authorization: Bearer (token)

Returns 200 and body of mppass value e.g.

fd37a1c594b....

If ip/player is not specified, 400. If ip and port combo are not seen as being online (no ping in last 2-5 minutes) then 404. Empty bodies in both error cases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions