feat(register): align with element-desktop — Phase 1+2 (MAS browser signup)#114
Open
TigerInYourDream wants to merge 12 commits intomainfrom
Open
feat(register): align with element-desktop — Phase 1+2 (MAS browser signup)#114TigerInYourDream wants to merge 12 commits intomainfrom
TigerInYourDream wants to merge 12 commits intomainfrom
Conversation
Add empty register module with mod.rs, register_screen.rs, register_status_modal.rs, validation.rs. Register the module in src/lib.rs and wire the script_mod aggregator per the login/mod.rs pattern. Part of specs/task-register-flow.spec.md Phase 1.
Accept bare hostname (prepend https://), strip trailing slash, reject non-http(s) schemes and empty input. 8 unit tests cover the edge cases.
Introduce the data model used across Phase 1-5: - HsCapabilities with is_mas_native_oidc / registration_enabled / uiaa_probe / sso_providers fields matching the spec - RegisterMode enum (MasWebOnly / Uiaa / Disabled) derived via HsCapabilities::mode() — MAS wins over UIAA per element-web rule - RegisterAction with NavigateToLogin / CapabilitiesDiscovered / DiscoveryFailed variants for Phase 1 + None default
Add LoginAction::NavigateToRegister variant. Replace set_signup_mode(true) call with Cx::post_action dispatch so the main App can route to the new RegisterScreen. The signup-mode rendering code is removed in a later task.
Implement MatrixRequest::DiscoverHomeserverCapabilities handler that probes .well-known, /versions, /v3/login, and empty POST /register to build HsCapabilities. Results post back as RegisterAction::CapabilitiesDiscovered / DiscoveryFailed. RegisterScreen widget renders the homeserver input, Next button, and three-state status area (MAS / UIAA / Disabled / errors). The full wizard body is added in Phase 2+.
Delete confirm_password input, mode-toggle state (signup_mode field, set_signup_mode, sync_mode_texts), and the signup submit branch in handle_actions. The "Sign up here" button (DSL id mode_toggle_button) keeps its text, position and style; its click now posts LoginAction::NavigateToRegister (wired in f40871d) — the navigation handler lands in a follow-up commit (Task 8). Registration logic moves wholesale to src/register/; see specs/task-register-flow.spec.md.
Handle LoginAction::NavigateToRegister and RegisterAction::NavigateToLogin to toggle visibility between login_screen_view and the new register_screen_view. Both screens live as siblings under the overlay_container; default visibility stays on LoginScreen. auth_ui_state and update_login_visibility are intentionally left untouched — Phase 2+ will layer auth-state machinery on top of this minimal inline toggle.
Task 9 testing found two bugs: 1. register_screen.rs hard-coded dark-theme colors (#x1F2124 bg, #xF1F2F3 text) conflicted with the project's light palette; combined with `draw_bg:` (replace) instead of `draw_bg +:` (merge, Pitfall #44) the shader silently fell back to transparent and text appeared washed out. Replace all hex colors with the shared COLOR_SECONDARY / COLOR_TEXT tokens and use TITLE_TEXT / REGULAR_TEXT styles, matching login_screen conventions. 2. MAS detection only looked at the stable .well-known key `m.authentication.issuer`. matrix.org still serves the unstable key `org.matrix.msc2965.authentication.issuer`, so it was mis-classified as non-MAS and fell through to the "registration disabled" branch. Accept both keys (element-web does the same).
Runtime DSL errors surfaced at `cargo run`:
1. register_status_modal.rs used Makepad 1.x live_design! form
`pub RegisterStatusModal := {{RegisterStatusModal}} View {...}`.
In script_mod! the 2.0 form is
`mod.widgets.RegisterStatusModal = #(RegisterStatusModal::register_widget(vm)) {...}`
(Pitfall #43). The 1.x form emitted
"variable pub not found in scope" +
"variable RegisterStatusModal not found in scope".
2. register_screen.rs set `empty_message:` on a RobrixTextInput.
The correct property is `empty_text:` (the error helper
suggested it exactly). Symptom: the homeserver input was
never created because its property bag failed to bind.
Both failures pass `cargo build` because script_mod! bodies
are parsed at widget init by the Makepad script VM, not by
rustc. Caught when running the app.
Phase 2 groundwork. HsCapabilities grows a new Option<String> field populated from the same .well-known probe Phase 1 already runs, preferring the explicit `account` field and falling back to `<issuer>/account/` when absent (alvin.meldry.com currently omits the field; matrix.org provides it). No extra HTTP round trips. The URL is consumed in the next commit by RegisterScreen to launch the system browser.
When CapabilitiesDiscovered reports MasWebOnly, call
robius_open::Uri::new(&url).open() on the mas_account_url
captured in the previous commit, then replace the status text
with a user-facing instruction: complete signup in the browser,
return, hit Back to Login, sign in with the new credentials.
Handles three paths:
- browser opens cleanly -> instruction text
- robius_open errors -> fallback text with the URL for copy
- mas_account_url None -> defensive message ("advertises but
no signup URL was found")
Simple-version scope: no OAuth callback, no token exchange, no
Dynamic Client Registration. Element Desktop's full callback
flow is Phase 2.5 if we decide to ship it. With this commit the
alvin.meldry.com / matrix.org paths are end-to-end usable: user
completes signup in the browser and returns to log in via the
existing password flow.
The previous commit opened <issuer>/account/, which is MSC2965's account-management URI and requires an authenticated session — hitting it without a cookie loops between /account/ and /login (verified in incognito against alvin.meldry.com). MAS exposes the direct self-registration form at <issuer>/register; confirmed to render a proper "Create account" page with username/email/phone/ password fields on alvin.meldry.com. Rename the field from mas_account_url to mas_signup_url to match the real semantics, and drop the `account` field lookup from discovery — we do not use it and keeping it as a fallback only invited this bug. Future account-management features in later phases can add it back when there is a real consumer.
This was referenced Apr 22, 2026
6 tasks
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
src/register/module with dual-mode capability discovery (MAS / UIAA / Disabled), homeserver URL input + validation, error states, back-to-login nav. Signup mode residue removed from LoginScreen.<issuer>/registerviarobius_open; no OAuth callback / token exchange (simple version — Element Desktop's full callback is future Phase 2.5).Usable after merge
Key design choices
<issuer>/register— NOT MSC2965'saccountfield, which is for post-login account management and redirect-loops when opened unauthenticated (verified on alvin.meldry.com).m.authenticationand unstableorg.matrix.msc2965.authentication— alvin uses stable, matrix.org still uses unstable; missing either key would mis-classify the server as Disabled.robius_open::Uri::new(url).open()(no callback / custom URI scheme) — user completes signup on web, returns to robrix2, logs in manually.Test plan
"Please enter a homeserver URL..."ftp://…→"Unsupported scheme: ftp. Only http(s) is allowed.""Could not reach that server: …"COLOR_TEXT,TITLE_TEXT/REGULAR_TEXT)References
specs/task-register-flow.spec.mddocs/superpowers/plans/2026-04-21-register-phase-1-skeleton.md,docs/superpowers/plans/2026-04-21-register-phase-2-mas-browser.md