feat: add a wake gateway client module - #160
Draft
coreyphillips wants to merge 5 commits into
Draft
coreyphillips wants to merge 5 commits into
coreyphillips wants to merge 5 commits into
Conversation
Adds src/modules/wake, the device side of the wake push gateway, as a port of the gateway's wake-proto crate: - key pair, device secret and install id generation; - wake_prepare_registration builds the 12-line message every identity signs and checks each field the way the gateway does; wake_sign_pubky_proof signs it with the pubky key and refuses any other message; - wake_decrypt_push finds the wake in any delivered APNs or FCM shape and decrypts legacy (v0) and v1 envelopes; a wake_fallback marker is returned without decrypting; - register, ack, presence, topics, unregister, info and topic listing, as pure build and parse functions around a thin reqwest executor that does not follow redirects. The AES key is SHA256(SHA256(S33 || label)) over the compressed ECDH point, computed as two plain sha256 passes rather than the sha256d type, whose display is byte-reversed. IVs must be 12 or 16 bytes. The tests assert the wake-proto golden vectors byte for byte (copied from wake commit 6037343), including rebuilding the v0 and v1 envelopes and the ln proof, and run every pushes.json case through the parser. Adds aes-gcm 0.10.3, already in the lockfile, and the serde_json raw_value feature so payloads come back as the producer sent them. register_device and test_notification are unchanged.
Generated the way build_ios.sh does: cargo build --release, then uniffi-bindgen generate --library target/release/libbitkitcore.dylib --language swift. Before the wake change the same steps reproduced the committed files exactly, so the diff is only the wake functions and types (additions only). module.modulemap is unchanged. Package.swift and the version are untouched.
Kotlin exceptions already have a message property, so a field of that name in an error variant breaks the Android bindings build.
Resolves the Cargo.toml and module list conflicts with the USDT work and regenerates the Swift interface from the merged library.
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.
feat: add a wake gateway client module
Summary
Adds
src/modules/wake, the device side of the wake push gateway, the service that replaces bitkit-notification-server. It covers what an app needs to receive wakes through the gateway:ln:) and pubky (pk:) identities, and register;The module is a port of the gateway's
wake-protocrate, which bitkit-core cannot depend on. It has no database state and no cfg-gated exports.register_deviceandtest_notificationare unchanged, so nothing changes for the apps until they call the new functions.API
The host signs
WakeRegistrationRequest.message:ln:through ldk-nodesignMessage,pk:throughwake_sign_pubky_proof, which refuses anything that is not a wake registration message so the pubky key cannot be used here to sign other data.wake_prepare_registrationchecks every field the way the gateway does, so a request the gateway would reject asinvalid_requestfails before anything is signed, andwake_registerrefuses a request whose fields no longer match its message.The HTTP calls are pure
build_*andparse_*functions around a thin reqwest executor (15 s timeout, no redirects). Every non-2xx response maps toWakeError::GatewayRejected { status, code, detail }(notmessage, which Kotlin exceptions already define) from the gateway's{"error","message"}body, with codeunknownfor any other body. Async exports use the existingensure_runtime().spawn(...)pattern.Crypto and wire compatibility
bitcoin::secp256k1::ecdh::shared_secret_point, compressed to the 33-byte point(0x02 | y & 1) || x.key = SHA256(SHA256(S33 || label)), computed as two plainsha256::Hash::hashcalls, not with thesha256dtype, whose display is byte-reversed.aes-gcm0.10.3, no AAD, 16-byte tag; the IV must be 12 or 16 bytes.bitkit-notifications, 16-byte IV). v1 uses labelwake-v1and a 12-byte IV. A containervother than 1 isUnsupportedEnvelope.wake_decrypt_pushaccepts the four delivered shapes (APNsaps.alert.payload, flat FCM legacy data, APNswakeobject, FCMwakeJSON string) and returnsfallback = truefor awake_fallbackmarker without decrypting.serde_jsongainsraw_value).Dependency changes:
aes-gcm = "0.10.3"(already in the lockfile through trezor-connect-rs) and theraw_valuefeature onserde_json. The onlyCargo.lockchange is the new direct dependency edge.Vectors
src/modules/wake/test_vectors/*.jsonare copied byte for byte from the wake repository (crates/wake-proto/vectors, commit782f66510c505b0331e6299e96c1233d3c263484, recorded in the module README). The tests assert them exactly:S33028ce542...80ee3and key3a9d552c...33b609b;signMessage;pushes.json(all APNs and FCM shapes plus both fallbacks) through the push parser andwake_decrypt_push, including the FCM data-map-only view.Negative cases cover a tampered tag or ciphertext, a wrong key, the wrong label, an 11-byte IV, unknown container and plaintext versions, unpadded base64, an off-curve ephemeral key, misplaced containers and every push shape the parser cannot place.
What is not included
/v1/grants,/v1/peer/wakes) are deferred.Wire format
The v1 wire format is experimental until the apps adopt it. The legacy (v0) envelope is unchanged and stable.
Tests run
cargo fmt --checkcargo clippy --all-targets: no new warnings (the counts match master: 29 lib, 12 example, 81 lib test)cargo test wake: 39 passed, 1 ignored (the live gateway test)cargo test(whole crate): 576 passed, 27 ignored, 11 failed. The 11 failures are the Blocktank tests that callhttps://api.stag.blocktank.to, which timed out from the machine this ran on; no other suite failedbuild_ios.shdoes; the diff is only the wake functions and types.WAKE_GATEWAY_URL=http://127.0.0.1:9010 cargo test wake -- --ignored:live_gateway_round_trippassed against the wake repo's docker dev stack (gateway commit782f665, public listener127.0.0.1:9010). It coverswake_server_info, a registration signed with anln:and apk:proof, presence set and clear,wake_list_topics,wake_set_topics(an unknown topic is dropped), andwake_unregister, after which the device secret is refused with 401. Acks and decryption are not part of the live test; they rely on the vectors and the offline unit tests (build_ack, the push parser andwake_decrypt_push).Draft
Draft because the gateway is not deployed yet, and its repository (a standalone Rust service that replaces bitkit-notification-server) is not published yet. The live round trip has passed against a local gateway stack (see Tests run).