Add Origin message framing, formats wrappers, and origin target registration - #19
Draft
mullinmax wants to merge 1 commit into
Draft
Add Origin message framing, formats wrappers, and origin target registration#19mullinmax wants to merge 1 commit into
mullinmax wants to merge 1 commit into
Conversation
…tration Boards have historically pushed live game events to the broadcast address as plain JSON: every board shouting at every listener, noisy enough to jam the board's WiFi chip and trivially spoofable by anything else on the LAN. This adds the client half of a targeted, authenticated replacement: - `warpedpinball.origin` defines the datagram frame -- a truncated HMAC-SHA256 tag over a JSON body carrying a per-send counter -- with `new_secret()`, `pack()`, and `unpack()`. - `Machine.set_origin_target()` / `clear_origin_target()` register a listener over authenticated HTTP. Omitting `ip` lets the board use the address the request arrived from, which is what a listener behind NAT needs. - `Machine.formats()`, `active_format()`, and `set_format()` wrap the formats routes, so callers no longer need the escape hatch for them. `set_format()` sends the options block capitalized, which is the casing the firmware actually reads. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VmtVSp58rDkDBRPzL9hJkt
Coverage report✅ Total coverage: 100.00% (0.00% vs base Files with changed coverage
|
7 tasks
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.
What
The client half of a targeted, authenticated replacement for the broadcast game-state stream. This is the contract PR — the firmware and Origin changes land against it.
Today a board pushes live game events to
255.255.255.255:6809as plain JSON. Every board shouts at every listener, which is noisy enough to jam the board's WiFi chip, and anything on the LAN can forge a score packet.warpedpinball.origin(new module)Defines the datagram frame so firmware, library, and Origin all agree in one place:
The MAC is the first 8 bytes of
HMAC-SHA256(secret, body). The body carriesmachine_id,type,data, andn— a counter that increments per send and resets when a listener re-registers, so a captured packet can't be replayed.new_secret()— 32 hex charspack(secret, body)— mirrors what the firmware sends (tests, simulators)unpack(secret, packet)— verify + decode, raisingOriginAuthErrorTruncating the tag to 64 bits is deliberate: the sender is a 150 MHz microcontroller emitting several of these a second, and 64 bits is far past what a LAN attacker brute-forces within the life of a session secret.
Machine.set_origin_target()/clear_origin_target()Registers a listener over authenticated HTTP. Omitting
iplets the board use the address the request arrived from — the same pattern/api/memory/toggle-broadcastalready uses, and what a listener behind NAT needs, since it cannot name its own translated address.Machine.formats()/active_format()/set_format()Wraps the formats routes so callers don't need the escape hatch. Worth flagging:
set_format()sends the options block asOptions, capitalized. The firmware readsdata.get("Options", {}), so anything sending lowercaseoptionshas been having its options silently dropped.Testing
python -m pytest— 292 passedruff check .— cleantests/test_origin.pycovers round trip, wrong secret, tampered body, malformed frames, and non-object bodies;tests/test_machine.pygains route/auth and body-shape coverage for all five new wrappers.Notes
Version bumped 0.2.2 → 0.3.0 (additive).
docs/machine.mdgains a "Live game events over UDP" section.Generated by Claude Code