Nostr-transport create/update bypass the HTTP validation; fiat links created over the transport are served at 1/100 of the configured price #3

Open
opened 2026-10-09 17:12:18 +00:00 by padreug · 0 comments
Owner

handle_lnurlp_create (transport_rpcs.py:44-51) does CreatePayLinkData(**body) → create_pay_link(data) and skips the whole validation block of api_link_create_or_update (views_api.py:120-170). The concrete money bug: the HTTP path stores fiat amounts in minor units (data.min *= data.fiat_base_multiplier, views_api.py:151-153) and the serving path divides back (views_lnurl.py:54-56, :165-167). A link created over the transport with currency: "EUR", min: 5, max: 10 is stored as 5/10 and served as 0.05–0.10 EUR. Also skipped: min > max, the full-satoshi rule, webhook_headers/webhook_body JSON validity (which send_webhook later json.loads), the success_url scheme, and the username regex. handle_lnurlp_update (:103-105) does raw setattr on a pydantic v1 model, so even the CreatePayLinkData field constraints (min >= 0.01, comment_chars <= 799, fiat_base_multiplier >= 1) don't apply on update. The transport is the path lamassu-next uses to manage links.

Fix direction: extract the validation (including fiat scaling) into one helper called from both the HTTP handler and the transport handlers; in update, rebuild through CreatePayLinkData rather than setattr. Tests: fiat create over the transport → stored min/max in cents and LNURL response matches the configured price; min > max rejected; malformed webhook_headers rejected.

Found during reforge run #1 (sandbox lnurlp#9).

`handle_lnurlp_create` (`transport_rpcs.py:44-51`) does `CreatePayLinkData(**body)` → `create_pay_link(data)` and skips the whole validation block of `api_link_create_or_update` (`views_api.py:120-170`). The concrete money bug: the HTTP path stores fiat amounts in minor units (`data.min *= data.fiat_base_multiplier`, `views_api.py:151-153`) and the serving path divides back (`views_lnurl.py:54-56`, `:165-167`). A link created over the transport with `currency: "EUR", min: 5, max: 10` is stored as 5/10 and served as 0.05–0.10 EUR. Also skipped: `min > max`, the full-satoshi rule, `webhook_headers`/`webhook_body` JSON validity (which `send_webhook` later `json.loads`), the `success_url` scheme, and the username regex. `handle_lnurlp_update` (`:103-105`) does raw `setattr` on a pydantic v1 model, so even the `CreatePayLinkData` field constraints (`min >= 0.01`, `comment_chars <= 799`, `fiat_base_multiplier >= 1`) don't apply on update. The transport is the path lamassu-next uses to manage links. Fix direction: extract the validation (including fiat scaling) into one helper called from both the HTTP handler and the transport handlers; in update, rebuild through `CreatePayLinkData` rather than `setattr`. Tests: fiat create over the transport → stored min/max in cents and LNURL response matches the configured price; `min > max` rejected; malformed `webhook_headers` rejected. Found during reforge run #1 (sandbox lnurlp#9).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/lnurlp#3
No description provided.