feat(bedrock): consume signed principal v2 - #129
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Implement the connect-java v2 consumer for the frozen Bedrock Option A signed-principal protocol. Consume the exact Connect/Moxy v2 wire fields, schema, error categories, and literal core vectors; expose only a sealed verifier-constructed principal; preserve all v1 behavior and legacy config-version 1 warn files; add generation-2 require configuration without making it the default for existing files; apply the verified effective profile before platform mutation; advertise operational readiness only with usable trust/replay/profile support over authenticated Watch and explicitly negotiated libp2p framing; and prevent raw XUID, link, envelope, nonce, or replay material from reaching logs, errors, or serialized surfaces. Source-only: no credential, OAuth, release, deployment, production activation, Moxy PR GeyserMC#511, or kunchenguid repository action.
What Changed
Risk Assessment
Testing
Inspected the base-to-target diff, exercised targeted v2, legacy, transport, and platform tests, manually verified linked-profile selection and replay rejection, captured sanitized reviewer-visible evidence, and removed generated build outputs. No UI surface applies to this protocol-only change.
Evidence: Bedrock v2 sanitized end-to-end transcript
v2 admission: subject=bedrock_linked_java, effectiveProfile=verified-linked-java-selected, envelope=consumed, rawIdentity=redacted replay retry: rejected category=REPLAY, rawIdentity=redacted WATCH admission: session=session-1, token=opaque, proposalPrivateEnvelope=false, stagedPlayerPrivateEnvelope=falsePipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 6 issues found → auto-fixed (2) ✅
core/src/main/java/com/minekube/connect/bedrock/BedrockPrincipalConsumer.java:78- The 16 KiB envelope limit is enforced only after copying and UTF-8 decoding the entire protobuf field. A peer can therefore force substantially larger allocations before rejection; check the ByteString size before toByteArray()/decoding.core/src/main/java/com/minekube/connect/bedrock/BedrockPrincipalConfiguration.java:39- Malformed generation-2 configuration does not fail closed: URI.create(null) throws NPE because only IllegalArgumentException is caught, and null public-key values similarly escape the consumer's IllegalArgumentException handler. Readiness/admission should return bounded not-ready or trust errors instead of unchecked exceptions.api/src/main/java/com/minekube/connect/api/player/principal/DefaultBedrockPrincipalVerifier.java:148- The frozen schema accepts canonical_xuid values up to 19 digits, but Long.parseLong rejects valid values above Long.MAX_VALUE (for example 9223372036854775808), so this consumer rejects schema-valid principals and cannot derive their low-64-bit UUID. This conflicts with the intent to consume the exact v2 schema; please confirm the required unsigned-XUID behavior.core/src/main/java/com/minekube/connect/bedrock/BedrockPrincipalReadiness.java:123- The readiness predicate validates only canonical base64 shape and length, not whether the bytes form a usable Ed25519 public key. An invalid 32-byte key can pass isReady()/capability advertisement, while BedrockPrincipalVerifierFactory.create later rejects it. This conflicts with the requirement to “advertise operational readiness only with usable trust/replay/profile support”; please confirm that readiness must instantiate or otherwise validate the verifier.core/src/main/java/com/minekube/connect/bedrock/BedrockPrincipalConsumer.java:55- The intent requires “add generation-2 require configuration without making it the default for existing files.” However, the new require-mode path returns Optional.empty() when field 12 is absent, and BedrockAdmissionCoordinator then falls through to the legacy enforcer; with the preserved v1 warn behavior, a session with no v2 principal can still be admitted. Please confirm whether require is intended to reject missing v2 data or only gate readiness.core/src/main/java/com/minekube/connect/tunnel/p2p/Libp2pEndpointRuntime.java:321- The intent requires “advertise operational readiness only with usable trust/replay/profile support over authenticated Watch and explicitly negotiated libp2p framing.” principalCapabilities() adds the v2 capability to the initial registration record before the kind-prefixed framing offer is sent on a later renewal; if that offer is rejected, framed remains false while subsequent legacy renewals retain the v2 capability. Please confirm whether the capability must be withheld until negotiation succeeds or withdrawn after rejection.🔧 Fix: Harden Bedrock v2 admission and negotiated readiness
1 error still open:
core/src/main/java/com/minekube/connect/watch/WatchClient.java:66- The new @Inject WatchClient constructor requires BedrockPrincipalReadiness, but no provider binds that type and its constructors are not injectable. Guice therefore cannot provision WatchClient during plugin startup; add a shared CommonModule provider using ConfigHolder.get() lazily.🔧 Fix: Bind shared Bedrock readiness across startup and libp2p
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
Focused v2 core tests for vectors, consumer admission, config generation, readiness, privacy, sealed construction, Watch, and libp2p framing.Legacy Bedrock identity, admission lifecycle, registry, API, and local-session tests.Spigot, Velocity, and Bungee tests covering changed adapters.Manual JShell verification of linked-profile selection and one-use replay rejection.Sanitized Watch admission transcript capture and generated-build cleanup.✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.