Skip to content

feat(flutter): pin the SEP-10 challenge checks to the live server before the wallet prompt (#136) - #176

Merged
moises-cisneros merged 1 commit into
mainfrom
feat/136-pin-sep10-challenge
Oct 14, 2026
Merged

moises-cisneros merged 1 commit into
mainfrom
feat/136-pin-sep10-challenge

Conversation

@XxHugheadxX

Copy link
Copy Markdown
Contributor

Refs #136. Replaces the rebase of #174 from the handoff.

Why not a rebase of #174

main already has the app half of #136 through #149: WalletPort.signChallenge(SignInChallenge) with SEP-10 checks, WalletSession reused per wallet, readAuthConfig, and sign-in before createHire. Rebasing #174's four commits would add a second parallel implementation (Sep10ChallengeCheck, AuthConfig, another wallet session).

Its config.json also pins values the live server does not use. A challenge taken from https://puls3-hub-on-stellar.api.serverpod.space today has these values:

#174 pin live server
server key GDVEU3…ZA57 GBEELNIKCJBWCVR4KYEP4LTLXWGD5MOSLRF32CHFULLMPGNTKBBKHOEG
home domain puls3.app puls3-hub-on-stellar.api.serverpod.space
web_auth_domain auth.puls3.app puls3-hub-on-stellar.api.serverpod.space

With the #174 pins, the live server's challenges would always be refused. This PR ports only what #174 checked that main does not.

What changes

  • assertSep10Challenge (run before Freighter is prompted) now also:

    • requires a web_auth_domain operation from the server;
    • checks its value against webAuthDomain when the app has one;
    • verifies the server's own signature (the transaction source, on Testnet).

    Before this PR, a challenge without the server's signature was signed.

  • Pins for static builds. readAuthConfig accepts PULS3_AUTH_SERVER_SIGNING_KEY, PULS3_AUTH_HOME_DOMAIN and PULS3_AUTH_WEB_AUTH_DOMAIN as dart-defines, and they win over config.json. Pages has no server-published auth block, so the public app currently pins nothing. SignInChallenge, WalletSession and main.dart pass webAuthDomain through.

  • scripts/cloudflare-pages-build.sh:

    • passes the three pins as dart-defines;
    • with PULS3_HIRE=server, fails before cloning Flutter if any pin is missing;
    • refuses a server key that is not a public G… address, without echoing it.
  • Docs. The puls3_server/README.md Deploy section and .env.example list the three Pages variables and the values of the deployed server.

Needed in the Pages project (Cloudflare access, #31 step 1)

PULS3_HIRE=server
PULS3_AUTH_SERVER_SIGNING_KEY=GBEELNIKCJBWCVR4KYEP4LTLXWGD5MOSLRF32CHFULLMPGNTKBBKHOEG
PULS3_AUTH_HOME_DOMAIN=puls3-hub-on-stellar.api.serverpod.space
PULS3_AUTH_WEB_AUTH_DOMAIN=puls3-hub-on-stellar.api.serverpod.space

Verification

cd puls3_flutter
flutter analyze --fatal-infos   # No issues found!
flutter test                    # 383 passed
bash scripts/tests/cloudflare-pages-build.test.sh   # passed 12, failed 0
bash scripts/tests/env-inventory.test.sh            # passed 84, failed 0
bash scripts/tests/blueprints.test.sh               # passed 328, failed 0

New tests:

  • a challenge with the pinned web_auth_domain is signed;
  • refused: no web_auth_domain, another web_auth_domain, unsigned, signed by another key;
  • pins win over config.json, and blank pins do not;
  • the Pages build passes the pins and fails closed when any one is missing.

Against the live server: a temporary, uncommitted probe ran the app's own WalletSession and assertSep10Challenge against https://puls3-hub-on-stellar.api.serverpod.space. It signed with a throwaway testnet key instead of Freighter.

Not done yet: the run with a real Freighter wallet on the public app. It needs the Pages rebuild with the variables above.

…ore the wallet prompt (#136)

Ports what the #174 draft added over main's sign-in (#149), onto main's
WalletPort.signChallenge(SignInChallenge):

- assertSep10Challenge now also requires a web_auth_domain operation from
  the server, checks its value when the app knows it, and verifies the
  server's own signature (the transaction source, on Testnet) before
  Freighter is prompted. Before, a challenge with no server signature was
  signed.
- SignInChallenge, WalletSession and readAuthConfig carry webAuthDomain.
  readAuthConfig takes build-time pins (PULS3_AUTH_SERVER_SIGNING_KEY,
  PULS3_AUTH_HOME_DOMAIN, PULS3_AUTH_WEB_AUTH_DOMAIN) that win over
  config.json, because the static Pages build has no server-published
  auth block, so today it pins nothing.
- cloudflare-pages-build.sh passes the pins as dart-defines, fails when
  PULS3_HIRE=server is missing any of them, and refuses a server key that
  is not a public G... address without echoing it.
- README (Deploy) and .env.example list the three Pages variables and the
  values of the deployed server.

The #174 config.json pinned GDVEU3..., puls3.app and auth.puls3.app; the
live server signs with GBEEL... and uses
puls3-hub-on-stellar.api.serverpod.space for both domains, so those pins
would refuse every real challenge. They are not carried over.

Tests: signed challenge with the pinned web_auth_domain; refused without
web_auth_domain, with another web_auth_domain, unsigned, and signed by
another key; pins over config.json; Pages build pins and fail-closed cases.

Refs #136
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying puls3 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 8737e30
Status: ✅  Deploy successful!
Preview URL: https://7460860f.puls3-4lw.pages.dev
Branch Preview URL: https://feat-136-pin-sep10-challenge.puls3-4lw.pages.dev

View logs

@TOMOKI977

Copy link
Copy Markdown
Contributor

Closed #174 in favor of this. The draft was a second SEP-10 path on top of #149, and its config pins do not match the live server. This branch is the one to review.

@moises-cisneros moises-cisneros left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Porting only what #174 checked and main did not, instead of rebasing a second parallel implementation, was the right call, and the live-server probe with the old pins being refused is good evidence.

I read the diff: the web_auth_domain presence and value checks and the server-signature check run before the wallet prompt, pins win over config.json only when non-blank, and the Pages script fails closed without echoing a bad key.

One nit, not blocking: in app_config.dart the new authConfigOverrides block was inserted between the resolveApiUrl doc comment ("Returns the Serverpod API URL...") and resolveApiUrl itself. That comment now sits on top of the pins and resolveApiUrl has none. Moving the pins above that doc fixes it.

Reminder for whoever merges: until the four Pages variables are set (#31 step 1), the public app still runs the demo hire.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants