Skip to content

Releases: jamesmblakely/IdentityBridge

IdentityBridge 1.0.0

Choose a tag to compare

@github-actions github-actions released this 06 Jul 17:40

First public release.

Features

  • Login continuity: while the server is in offline mode, known returning Java players are
    restored to their real online UUID at pre-login (via Paper's createProfileExact profile API),
    so they keep inventory, location, stats, advancements, and other UUID-keyed progress. Only
    genuine offline-style logins are rewritten — proxy/forwarded UUIDs are left untouched.
  • Known-player learning: authenticated online-mode logins are recorded (name → online UUID,
    last IP, timestamps), with careful name-capitalisation handling.
  • Temporary offline identities: unknown players seen during an outage are recorded for later
    migration (or can be blocked instead).
  • Safe data migration: /idb migrate and /idb migrate-uuid move UUID-keyed data to the
    correct online UUID — dry-run by default, with backups, missing-source reporting, an extensible
    file-location list, and a hard stop if the source or target player is currently online.
  • Lossless conflict resolution: when both UUIDs already hold data, migration unifies the two
    profiles instead of skipping or clobbering — stats counters are summed, advancements are
    unioned (earliest criterion timestamp wins), and an un-mergeable inventory (.dat) clash is
    decided in favour of the file with more play time — an exact play-time tie is broken by the
    number of completed advancement criteria — so the least progress is lost (--overwrite
    forces the source side). Nothing is ever discarded without a backup, and merged sources are
    folded in so a re-run never double-counts.
  • Auto-migrate on rejoin (migration.auto-migrate-on-rejoin, default on): when a player
    with temporary offline data logs back in, their data is folded into their real online UUID at
    pre-login — the only window where the files are not in use. Stats and advancements are merged
    losslessly; an un-mergeable inventory (.dat) clash is resolved in favour of the file with more
    play time (the displaced file is backed up first — never discarded without a backup), exactly like
    a manual migration without --overwrite. If a conflict can't be resolved safely (e.g. backups
    disabled), it is left untouched and logged for manual handling.
  • Optional auto-migration IP verification (migration.auto-migrate-require-ip-match, default off):
    when enabled, unattended rejoin migration only runs when the temporary outage record's IP matches
    the authenticated online rejoin IP. If the IP is missing or different, IdentityBridge captures the
    target UUID and leaves the record pending for manual /idb migrate review.
  • Startup cache backfill (async): on enable, IdentityBridge scans the UUID-keyed data files
    already on disk (migration.data-locations) and resolves any real online (Java) UUID it does not
    yet know to its current name via the Mojang session server, so players whose progress predates
    the plugin's install are still recognised if the server later goes offline. Runs entirely off the
    main thread (never blocks startup), is read-only, filters out offline-style and Bedrock UUIDs
    before contacting Mojang, throttles requests, backs off on rate limits, and records definitively
    unresolvable UUIDs in the identity store's ignored: list so they are looked up once and skipped
    thereafter. Custom templates whose {uuid} appears in the filename are discoverable too, including
    root-level entries like {uuid}.dat; per-player directory templates still work for explicit
    migrations but cannot be discovered by the startup directory scan.
  • Auth/service monitoring: periodic, detailed health checks of Mojang/Microsoft endpoints
    with an overall verdict, surfaced via /idb check and /idb status. Endpoints can declare
    their own healthy-statuses (defaults to any 2xx).
  • Advisory notifications: admins are advised (console + in-game) when auth looks down while
    online, or healthy while offline; monitoring.advise-on-degraded opts into acting on partial
    outages too. Advisory only — never edits config, switches mode, or restarts.
  • Identity cache management: /idb lookup, and a consistent action-first cache surface —
    /idb cache list [<java|offline|bedrock>], /idb cache add java, and
    /idb cache remove <java|offline|bedrock>. /idb status also shows the size of the startup
    backfill's ignored: skip-list (when non-empty), so it is visible without opening identities.yml.
  • Colour codes in kick messages: the configurable unknown-kick-message and
    ip-mismatch-kick-message honour legacy &-style colour/formatting codes (e.g. &c) and
    &#rrggbb hex colours; plain text passes through unchanged.
  • Optional Bedrock/Floodgate support: detects Bedrock players, records their identity keyed
    by XUID (with Floodgate UUID, linked Java UUID, and link state), and never rewrites Bedrock
    UUIDs. No hard dependency; fully functional on Java-only servers.
  • Full account-linking support (global and local): Floodgate's global (GeyserMC hosted) and
    local (database) linking are both supported transparently. Linked Bedrock players join under
    their linked Java UUID (already stable, never rewritten); links are read live for online players
    and resolved through Floodgate's link manager for offline ones. /idb lookup accepts a name,
    UUID, or XUID and cross-references the linked Java account; /idb status reports whether linking
    is global or local. A linked Java account is also recorded as a known player
    (bedrock.record-linked-java-account) so it gets Java-side continuity during an outage.
  • Consolidated storage: all identities live in one identities.yml with uniform java: /
    offline: / bedrock: sections, written atomically (temp file + atomic move) so a crash
    mid-write can never corrupt the cache.
  • Self-upgrading configuration: on future versions, new config keys merge in automatically
    with a backup of the previous file.
  • Privacy & IP-match hardening controls: privacy.store-player-ip can disable IP persistence
    entirely, and login-continuity.require-ip-match-strict makes the IP-match rule refuse logins it
    cannot verify (the default keeps the documented fail-open behaviour for backfilled/dynamic-IP
    players).

Safety & correctness

  • A manual /idb check run while monitoring.enabled is off shows the advisory that probe implied
    in the command output but never stores it — with no background monitor running, nothing could ever
    refresh or clear a stored advisory, so it would otherwise be repeated to every joining admin
    indefinitely. /idb check also reports the advisory computed by its own probe rather than
    re-reading shared state a concurrent scheduled check could have changed.
  • A scheduled auth check that was already running when /idb reload stopped/restarted monitoring
    can no longer publish a stale last-report or advisory state after reload; scheduled probes are
    generation-gated, and advisory persistence is still checked against the latest config snapshot
    when the probe finishes.
  • The offline-mode unknown-player path refuses to record anything if it is ever handed a
    non-offline-style UUID, instead of recording an unauthenticated connection as an authenticated
    known player (unreachable today thanks to the pre-login offline-UUID gate; defence in depth).
  • With login continuity disabled, a recognised player admitted under a temporary offline UUID is
    logged as a known player whose identity was not restored, instead of being mislabelled
    "Unknown player" — which would contradict /idb lookup for the same account mid-outage.
  • An authenticated online-mode login is only recorded as a known Java player - and only used as an
    auto-migration target - when it carries a real online-style (v4) UUID. Previously, with Floodgate
    installed but bedrock.enabled: false (so Bedrock detection was skipped), a Bedrock player's
    v0 UUID could be cached as a known Java identity, and a same-named temporary offline record could
    even be auto-migrated into that v0 UUID - the same wrong-destination hazard the join-time
    online-UUID capture already guarded against. The pre-login path now enforces the identical
    invariant.
  • The same v4-only and Java-username-shape invariants are enforced at the identity store's single
    entry point for automatically-learned identities (backfillKnown), which also covers the linked
    Java account recorded from a Bedrock join. That UUID/name pair comes from Floodgate's link data
    (a reflective API, and for local linking an admin-run database) rather than an authenticated login,
    so a non-v4 UUID or malformed name there - e.g. from a corrupt linking database or an unexpected
    Floodgate result - is refused instead of being cached as an offline-mode restore target. Only the
    explicit /idb cache add java --force admin override may store a non-v4 UUID.
  • The startup backfill's ignored: (no Java profile) list and the known-player cache are mutually
    exclusive: an authenticated join, backfill/link hit, or manual /idb cache add java for an
    ignored UUID clears the stale ignore marker, a cached known player is never marked ignored (e.g.
    a stale NOT_FOUND lookup racing an authenticated join), and on load the java: section wins over
    a contradictory hand-edited ignored: entry - so /idb status counts and identities.yml can
    never contradict each other.
  • Mojang profile responses are accepted only when their id is an online-style (v4) Java UUID and
    their name is shaped like a valid Java username. For UUID-to-profile startup backfill lookups,
    an unexpected HTTP 400 is treated as a transient error rather than a definitive "no profile"
    result, so the permanent ignored: list cannot be poisoned by a bad response to a syntactically
    valid UUID query.
  • Floodgate reflection now resolves API methods through a public declaring type (with an
    accessibility fallback), so a Floodgate build whose ...
Read more