Lightning-paid wireguard config delivery and payment hash mismatch fixes#3
Open
libertas-primordium wants to merge 2 commits into
Open
Conversation
Store the payment hash returned by the Lightning backend when creating a pending LNURL purchase session instead of always storing the locally generated preimage hash. This fixes phoenixd-backed payment reconciliation because phoenixd creates invoices with its own payment hash while Europa previously stored the generated preimage hash and then polled phoenixd for a hash it did not recognize. Validated with pnpm install --frozen-lockfile, pnpm build, and pnpm test. Also validated on a live phoenixd-backed Europa node: after this change, a 100 sat Lightning purchase increased phoenixd balance, the session changed from pending to active automatically, and the WireGuard peer was added without manual database or wg intervention.
Use phoenixd's backend-created invoice payment hash and preimage for Lightning purchases so settlement polling and LNURL AES successAction encryption both reference the actual payable invoice. Phoenixd creates invoices with its own payment hash and preimage, while Europa previously encrypted the WireGuard config with a locally generated preimage and stored the locally generated payment hash. That caused phoenixd-backed sessions to remain pending before the payment-hash fix, and caused wallets to be unable to decrypt the returned successAction payload. Update the phoenixd backend to fetch the incoming payment record after invoice creation and return the real phoenixd preimage. Update LNURL config delivery to encrypt the successAction with that backend preimage and store the backend invoice payment hash for settlement checks. Also update LNURL AES encryption to use the LUD-10-compatible AES-CBC mode, then wrap the decrypted WireGuard config in a browser-compatible HTTPS config-viewer URL whose fragment carries the config locally without sending it back to the server in the HTTP request. Validated on the live libertas-ams-1 phoenixd-backed Europa node: Phoenix Wallet payment succeeds, the receipt opens, the attached message link opens the config viewer, the WireGuard config is displayed for the purchaser, the session activates automatically, and the WireGuard peer is added without manual database or wg intervention.
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.
Summary
This PR fixes phoenixd-backed Lightning purchases so they can complete the full Europa purchase flow: payment reconciliation, session activation, and purchaser-only WireGuard config delivery.
The previous phoenixd path had two related problems:
Europa generated a local preimage/payment hash and stored that local payment hash in the pending session row, but phoenixd created the actual payable invoice with its own payment hash. Settlement polling then checked phoenixd for a hash phoenixd did not recognize, so paid sessions could remain
pending.Europa encrypted the LNURL
successActionpayload with the locally generated preimage, but wallets receive the actual payment preimage from the invoice they paid. With phoenixd-backed invoices, those preimages did not match, so the wallet could not decrypt the returned WireGuard config.This branch fixes both issues by treating the backend-created phoenixd invoice as the source of truth for both the payment hash and the payment preimage.
The previous smaller PR that only fixed the payment-hash mismatch can be closed in favor of this branch because this branch includes that fix plus the complete WireGuard config delivery fix.
Code changes
Use the backend invoice payment hash for settlement checks
When creating a pending LNURL purchase session, Europa now stores the
paymentHashreturned by the Lightning backend-created invoice instead of always storing the locally generated hash.This preserves the existing fallback behavior while using the actual payable invoice hash when the backend supplies one.
Before, phoenixd-backed payments could reach phoenixd successfully while Europa still left the session pending, because Europa was polling phoenixd for the locally generated hash rather than the hash of the invoice phoenixd actually created.
Fetch and return the real phoenixd invoice preimage
The phoenixd backend now creates the invoice, then immediately queries phoenixd’s incoming-payment record by the returned
paymentHash.Phoenixd exposes the real invoice preimage before payment through its incoming-payment record. Europa can therefore use that real preimage for the LNURL AES
successAction.This keeps the LNURL flow secure and purchaser-gated: the wallet can only decrypt the success payload after paying the invoice and receiving the matching payment preimage.
Encrypt LNURL
successActionwith the backend preimageThe LNURL callback now encrypts the WireGuard config delivery payload using the preimage returned by the Lightning backend.
For phoenixd, this is the actual phoenixd invoice preimage. That makes the encrypted
successActiondecryptable by the paying wallet.Update LNURL AES encryption to LUD-10-compatible AES-CBC
The successAction AES encryption was updated to use the LNURL LUD-10-compatible AES-CBC flow rather than AES-GCM.
This was required for wallet compatibility. In live testing, Phoenix Wallet stopped crashing when viewing the receipt after the AES mode was corrected.
Add a browser-compatible config viewer route
Phoenix Wallet can decrypt the
successAction, but it presents the decrypted payload as an “open link” action. A raw WireGuard config is not a URL, and adata:URL caused Phoenix to crash when tapped.This branch adds a
/config-viewerroute and changes the decrypted success payload to a normal HTTPS URL:https://<public_host>/config-viewer#<base64url-wireguard-config>The WireGuard config is placed in the URL fragment after
#. Browser URL fragments are handled client-side and are not sent to the server in the HTTP request. The/config-viewerpage decodes the fragment locally and displays a copyable WireGuard config.This keeps the config delivery flow wallet-compatible while avoiding sending the decrypted config back to the server through the request path.
Security properties
The WireGuard config delivery remains purchaser-gated:
successActionpayload is encrypted with the actual Lightning payment preimage.successAction.GET /config-viewer; the fragment containing the config is not included in the HTTP request.The operator system necessarily creates the session config, and phoenixd necessarily knows the invoice preimage because it created the invoice. The security goal here is that third parties and unpaid users cannot decrypt or retrieve the config, while the purchaser can access it after payment.
Testing and verification
This branch was validated on a live phoenixd-backed Europa node.
Payment hash mismatch validation
Before the fix:
fee_credit_satstayed at0, confirming the payment was no longer just fee credit.pending.After storing the backend-created invoice payment hash:
pendingtoactiveautomatically.wg setcommand was required.Phoenixd preimage validation
A direct phoenixd API test confirmed that after creating an invoice, phoenixd’s incoming-payment record for the returned
paymentHashexposes a valid 64-character preimage before payment.That made it possible for Europa to fetch the actual phoenixd invoice preimage and use it for LNURL AES encryption without modifying phoenixd.
Wallet receipt/config delivery validation
The config delivery flow was tested with Phoenix Wallet:
successAction.Build and test validation
The code was validated with:
pnpm buildpnpm testDuring development, a test expectation for the canonical SHA-256 hash of
"abc"was corrected after the AES encryption test updates. The final expected value matches the standard SHA-256 hash:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015adNotes
This branch supersedes the earlier PR that only fixed the payment-hash mismatch. That smaller fix restored automatic activation, but it did not solve the wallet receipt/config delivery problem.
This PR includes both pieces needed for the full phoenixd-backed Lightning purchase flow: