feat(ui): refuse alias collision on Create/Restore (#117)#125
Merged
iduartgomez merged 2 commits intomainfrom May 6, 2026
Merged
feat(ui): refuse alias collision on Create/Restore (#117)#125iduartgomez merged 2 commits intomainfrom
iduartgomez merged 2 commits intomainfrom
Conversation
…on (#81) #114 + #115 + #120 fixes plus a spec correction (use page.reload() instead of page.goBack(), since the SPA doesn't push history entries on click — goBack landed on about:blank rather than the inbox) make tests 2 + 3 deterministically green on the iso harness. Drop the FREENET_LIVE_E2E_SEND gate so they run by default. Two assertions stay gated as separate concerns: - Test 3 round 3 (alice → bob retry) gated on FREENET_LIVE_E2E_AFT_CAP_RAISED — AFT day-1 cap is 1 slot, alice burned hers in round 1; needs #85 to make tier configurable. - Test 3 round 2 (bob → alice reply) gated on FREENET_LIVE_E2E_REPLY — flaky ~33%, separate flake tracked in #122. Click-to-read + reload assertion (the original #113 target) still runs and passes deterministically. Verified locally via 3 consecutive `cargo make test-e2e-real-node` runs, all passing in ~12s each.
Before submitting a NodeAction::CreateIdentity for a new alias name,
check Identity::get_alias(name). If it returns Some, refuse with an
inline error banner instead of advancing through keygen → reveal →
delegate write.
Two paths are guarded:
- CreateAliasForm::submit — Create new identity. Rejects before
keygen (no burned keys for a refused name).
- ImportForm::onclick (Restore) — refuses to overwrite an existing
identity record from a backup file, since the backup's keys would
silently replace the on-device delegate entry and orphan the
previous inbox.
Mirrors the existing rename collision guard at
\`Identity::rename_in_place\`. The two flows are now consistent:
explicit two-step (delete then create/restore) is required to swap an
alias, and there is no UI path that silently destroys access to a
prior inbox.
Adds an offline-mode Playwright test that submits "address1" — already
seeded — and asserts the banner appears and the fingerprint reveal
does not.
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
Identity::get_alias(name)before submittingCreateIdentityfrom both Create new identity (CreateAliasForm) and Restore from backup (ImportForm). If the name is already in use, refuse with an inline error banner — no keygen, no delegate write, no inbox orphaning.Identity::rename_in_place) for behavioural consistency: every alias-mutating UI path now refuses silent overwrite.email-app.spec.tsthat submits the seededaddress1alias and asserts the error banner shows + the six-word fingerprint reveal does not.Closes #117.
Why refuse, not confirm
Identity replacement is destructive — the prior inbox stays on the network but the keys to decrypt it are gone. A confirm dialog risks accidental clicks; the rename flow already uses refuse, so this matches.
Test plan
cargo check -p freenet-email-ui(default +example-data,no-sync)cargo clippy -p freenet-email-ui -- -D warnings(default +example-data,no-sync)cargo fmt --all -- --checkemail-app.spec.ts, chromium): 39 passed including new collision test