Skip to content

Harden native login Cloudflare cookie handoff#87

Merged
fannnzhang merged 39 commits into
mainfrom
feature/v0218-login-cf-cookie-migration
Jun 18, 2026
Merged

Harden native login Cloudflare cookie handoff#87
fannnzhang merged 39 commits into
mainfrom
feature/v0218-login-cf-cookie-migration

Conversation

@fannnzhang

Copy link
Copy Markdown
Contributor

Summary

  • Require platform Cloudflare verification to return the accepted fresh cf_clearance before Rust trusts WebView cookie snapshots, filtering stale variants during challenge completion.
  • Replace the iOS monolithic login WebView with a native login form, hCaptcha dialog WebView, and full WebView fallback for OAuth/passkey/password reset.
  • Align Android login/CF cookie extraction with richer WebView cookie metadata and update docs/reference knowledge for the v0.2.18 login cookie contract.

Verification

  • cargo test -p fire-models -p fire-core -p fire-uniffi-session
  • cargo fmt --check
  • ./gradlew testDebugUnitTest
  • xcodebuild test -scheme Fire -destination 'id=D733CCB1-7B2A-49B5-B3F8-36CB6D0CB2BF' -only-testing:FireTests/FireLoginScriptsTests CODE_SIGNING_ALLOWED=NO

Redesign login flow to align with fluxdo:
- Native UIKit login page (FireLoginViewController) with logo,
  credential inputs, remember-password checkbox, social login icons
- hCaptcha + login request moved to separate dialog VC
  (FireCaptchaLoginDialogController), presented on-demand after
  user taps login
- CF verification triggered on-demand instead of on page open
- Social login icons route to full WebView fallback
- Error handling uses inline banner instead of UIAlertController
Address 7 review items:
- Merge Phase 1+2: UI and login flow wired together as one deliverable
- Add live WebView handoff constraint for cookie extraction
- Thread rememberCredential param through to finalization
- VC owns dialog presentation, ViewModel exposes async capabilities
- Replace 3 social icons with single 'other login methods' button + forgot password link
- Rewrite error table per WebViewLoginDecisionState (2FA repeat, CF retry precision)
- Remove duplicate Phase 2 section
8 tasks across 3 phases:
- Phase 1: FireCaptchaLoginDialogController + FireLoginViewController +
  ViewModel async capabilities + coordinator switch + CF retry (Tasks 1-5)
- Phase 2: FireWebViewBrowserViewController for OAuth/forgot-password (Task 6)
- Phase 3: Error banner polish + 2FA messaging (Task 7)
- Verification: Manual flow testing (Task 8)
- Fix FireWebViewBrowserProfile usage: static API, not instance
- Fix FireCaptchaScriptMessageProxy delegate type
- Fix hcaptcha_pass parsing: token is String not dictionary
- Move classifyResult to class stored property (not extension)
- CF retry uses recoverLoginCloudflareChallenge(in:) not ensureCloudflareClearance
- Full WebView fallback uses completeLogin(from:) not completeMinimalLogin
- Uncheck remember-password clears saved credentials (product decision)
- Build commands use xcodegen + Fire.xcodeproj (not .xcworkspace)
- Credential auto-fill uses Combine subscription (not viewDidLoad read)
- Add xcodegen generate + project.pbxproj to commit steps
Require platform challenge flows to report the accepted fresh cf_clearance value before Rust trusts WebView cookies. Replace the iOS monolithic login WebView with a native form plus captcha/fallback WebView controllers, and align Android login extraction with WebView cookie metadata.
Document fresh cf_clearance handoff, rich WebView cookie extraction, the native login split, and move the fluxdo reference pointer to the v0.2.18-derived source used for this behavior.
Do not require the platform-reported clearance to differ from Rust's previous snapshot. The WebView baseline can be missing while Rust still has the same accepted value, and forcing a rotation leaves follow-up requests stuck behind the local Cloudflare cooldown.
P1: restore completeStartupAfterPreheat driving path via performStartupValidation
P1: replace isBootstrappingSession phase derivation with isStartupValidationComplete
P1: add explicit captcha dialog/logginIn phase dismissal on login success
P1: extract prepareLoginForm for saved credential loading
P2: add scroll/keyboard constraints to form view spec
P2: expand doc sync scope to README + architecture
Step 1 of unified onboarding launch design (docs/architecture/2026-06-17-unified-onboarding-launch-design.md §2).

Three new additive UIView subclasses, not yet wired into the onboarding VC:
- FireOnboardingValidatingView: loading indicator + label for .validating phase
- FireOnboardingCredentialFormView: scroll-backed credential form migrated from FireLoginViewController (identifier/password/remember/login/forgot/other-methods fields, keyboard inset handling, closure-based callbacks, applySavedCredential/setLoggingIn API)
- FireOnboardingLoggingInView: semi-transparent overlay for .loggingIn phase

Build verified: xcodebuild BUILD SUCCEEDED.
phaseContainerView is an arranged subview of bottomStack (a UIStackView
with alignment=.fill); manual leading/trailing/bottom constraints
duplicated and conflicted with the stack's auto-generated ones. Keep
only the heightAnchor minimum so the stack manages position, matching
errorBanner's treatment.

Found in WS1 code quality review.
applyPhase(.loggingIn) now calls setLoginLoading(true) to disable
view.isUserInteractionEnabled (restoring the original LoginVC screen-freeze
invariant that was lost in the migration), and setLoginLoading(false) when
leaving .loggingIn. The loggingInView overlay + form disabling alone left
the brand area and dev-tools button tappable during login.

Found in WS2 code quality review.
Step 6 of unified onboarding launch design:
- fire-native-architecture.md: RootCoordinator comment (launch↔main),
  Auth/ file tree (FireLoginViewController → onboarding subviews + Startup/),
  changelog (login/preheat consolidated into onboarding page)
- README.md: FireLoginViewController entry → FireOnboardingCredentialFormView,
  RootCoordinator role (two-state, no preheat/auth-modal),
  FireAppViewModel startup-validation bullet (phase state machine),
  UX note (single unified launch page, three phases, no preheat gate)
Replace stale assertions for the deleted auth-presentation modal path
(syncAuthPresentation, FireLoginWebViewController/FireLoginWebView) with
assertions that pin the new unified onboarding contract: launch/main
two-state root in FireRootCoordinator and login orchestration
(performLogin + FireCaptchaLoginDialogController) in FireOnboardingView.

Also drops the four pre-existing FireLoginWebView assertions that
referenced a file already absent before this branch.

Found in final whole-implementation review.
Push topic details through the selected tab navigation stack and remove the presented route host.

Treat Cloudflare refresh as a clearance merge instead of an authoritative login cookie replace, with regressions and docs.
@fannnzhang
fannnzhang merged commit d0a1dfd into main Jun 18, 2026
11 checks passed
@fannnzhang
fannnzhang deleted the feature/v0218-login-cf-cookie-migration branch June 18, 2026 10:10
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.

1 participant