diff --git a/README.md b/README.md index a4be75d..5477b6d 100644 --- a/README.md +++ b/README.md @@ -424,8 +424,28 @@ The two vaults are encrypted under different keys, so a move is a re-seal into o other; the host gets a new id, and **its group and its tags stay behind**, because both are items of the vault it is leaving. A picker inside the form would do all of that as a side effect of correcting a port. What a move cannot do is reach a machine that has already synced the host, which is the same limit -everything else about revocation has. Keys, passwords and buckets take theirs from a standing "new items go -to" picker on the Keychain screen and cannot be moved yet. +everything else about revocation has. Buckets take theirs from a standing "new items go to" picker on the +Keychain screen and cannot be moved yet. + +**The move asks whether the key comes too**, because that is the half a host's move could not settle on its +own. A binding resolves across every vault you can read, so the moved host goes on working for *you* either +way — but the people you have just shared it with hold one vault's key, and a host whose key stayed in your +personal vault is one they cannot connect with. The tick box beside the picker is unticked, and stays that +way on purpose: moving a key into a team's vault hands it to everybody who holds that key, and a disclosure +is chosen rather than defaulted into. Under it is the count of everything else that authenticates with that +key, which is what makes the answer decidable — a key twenty machines use is a different decision from one +nothing else touches. Left unticked, the sentence afterwards names the key that is now outside the +destination. A key the host only *inherits* from its group counts too, and is written onto the host on the +way across: the group stays behind, so a host that arrived naming nothing would authenticate with nothing. + +**A key or a password can also be moved on its own** — MOVE beside EDIT and DELETE on the Keychain screen, +on both heads, for keys and passwords only. It is the same re-seal and tombstone, and it takes a new id in +the destination, so **everything that named it is re-aimed at where it went**: every host bound to it and +every group lending it as a default, across every vault you can write to. Without that the move would be a +deletion with extra steps, since a host bound to something its vault no longer holds refuses to connect +rather than falling back to a typed password. Anything that cannot be rewritten here — an item from a newer +client, or one in a vault you can only read — is left naming the old item and is counted in the sentence +afterwards. The panel says what points at the key before you press it, not after. **A group can be moved too, and it takes its contents with it** — "Move to another vault…" on the group card's right-click menu, beside Open, Edit and Delete, which is the whole of what can be done to a group on diff --git a/docs/android-port.md b/docs/android-port.md index 4ae7fc9..6a137b4 100644 --- a/docs/android-port.md +++ b/docs/android-port.md @@ -568,9 +568,16 @@ go at 360dp: believing they typed an `l`. **The surface has since taken the whole screen.** `PhoneShell` collapses the header, the session strip - and the bottom bar while a terminal is showing — one binding on `IsShowingPages` each — and the screen - draws a 35-pixel bar in their place: back, the session pills, and a `+` raising a sheet with the three - connections there are. That sheet is the head's first control that could be drawn over the renderer, so + and the bottom bar while a shell is showing, and the screen draws a 35-pixel bar in their place: back, + the session pills, and a `+` raising a sheet with the three connections there are. + + *A shell rather than the surface, and the two parted company once that surface gained a connect page.* + With nothing running, Connections is a box, a CONNECT button and the machines connected to before — a + page in everything but which enum it is in — so `RefreshChrome` keeps the bar (and, wide, the rail) under + it and the Connections entry lights for the first time. It is the one screen reachable by closing your + last tab, and collapsing the nav there left the system back gesture as the only route to Hosts or + Settings. The header is not part of that: the surface draws its own bar, and a vault header above it is + the second row of chrome this head exists to avoid. That sheet is the head's first control that could be drawn over the renderer, so it collapses it rather than covering it, exactly as the desktop's palette does; whether Android's WebView actually composites above Avalonia content is still the unverified question recorded below, and collapsing is correct under either answer. diff --git a/docs/manual-checks.md b/docs/manual-checks.md index cec0a58..06dd701 100644 --- a/docs/manual-checks.md +++ b/docs/manual-checks.md @@ -446,6 +446,31 @@ target lands. Anything still in the source vault is a partial move, which is sur not happen with the network up: the groups are written top-down and the hosts last, so an interruption leaves hosts behind and never a shelf with nothing on it. +### 3.3b Moving a key, and moving a host with its key · **needs a second vault** + +In your personal vault: add an SSH key, then two hosts that both authenticate with it. On the Keychain +screen select the key and press **MOVE**, and read the panel before choosing the shared vault. + +**Pass:** the panel says what uses the key — "Used by 2 hosts…" — before anything happens. Afterwards the key +carries the destination's badge under an id it did not have a moment ago, *and both hosts still say `key` +under their names* and still connect. The sentence names the vault and the two hosts that followed it. + +Then the other direction: with a key back in your personal vault and a host bound to it, choose **Move to +another vault…** on the host and pick the shared vault. The tick box under the picker offers to bring the +key, unticked, with the count of what else uses it underneath. Leave it and press MOVE; then move the host +back, tick it, and press MOVE again. + +**Pass:** unticked, the host lands in the shared vault and the status line says the key it authenticates with +is in another vault and will not resolve for anybody else there. Ticked, the key lands in the shared vault +too and the host still says `key`. Choosing a *different* vault in the picker re-asks the question, and the +box disappears when the destination is the vault the key is already in. + +**Failure means:** a host that says `password` after either move is the re-aim not having happened — the item +takes a new id in the destination, so every host bound to it and every group lending it has to be rewritten +as it lands, and a host bound to something its vault no longer holds refuses to connect rather than falling +back to a typed password. A tick box that is ticked when the panel opens is worse than a bug: it moves a +private key into a shared vault on the strength of a decision nobody made. + ### 3.4 A group deleted on another machine · **needs two machines** Make a group on machine A, file a host into it, sync. On machine B, sync, then delete the group and sync @@ -1114,6 +1139,29 @@ with both hosts and both ticks still there. "delete prod-db?" is not a confirmation anybody reads. A question that cleared the ticks on KEEP is a selection thrown away for declining to destroy it. +### 8.14a The key question is asked for one host and for a move · **needs two writable vaults** + +With a host bound to a key that is in the vault it is leaving, tick that host alone and choose **Move to +vault**. + +**Pass:** under the picker, an unticked box offering to bring the key, with the count of what else uses it +underneath. Choosing a different destination re-asks it, and it disappears when the destination is the vault +the key is already in — the same behaviour as the desktop's, which 3.3 measures. + +Now choose **Copy to vault** on the same host. + +**Pass:** no box at all. A copy that took the key away would leave the original — still sitting in the vault +it started in — unable to connect, which is the one thing "copy" promises not to do. + +Tick a second host and open **Move to vault** again. + +**Pass:** still no box. Which key to carry is a fact about one machine, and a selection of six has six +answers. + +**Failure means:** a box under a copy is `ChosenBindingToBring` no longer reading +`ChosenHostsAreBeingCopied`, and it moves a private key out from under a host that is still using it. A box +that is ticked when the panel opens is worse than a bug for the reason 3.3 gives. + ### 8.15 A tap connects, and a long press chooses · **the one worth the most care** On a host bound to a key or a stored credential — one that needs nothing typed — tap the row once. @@ -1320,12 +1368,13 @@ headless surface has a native view to answer with. `docs/android-port.md` still Open a shell from HOSTS. -**Pass:** the vault header, the session strip and the four-entry bottom bar are all gone. What is left is +**Pass:** the vault header, the session strip and the three-entry bottom bar are all gone. What is left is one bar — a back arrow, the session pills, a `+` — and then the terminal down to the accessory keys. Press back: all three come back, the tab is still in the strip and its dot is still green. -**Failure means:** one of the three rows is not bound on `IsShowingPages`, or the terminal is being reached -by a route that leaves `Surface` on `Page`. +**Failure means:** the strip is not bound on `IsShowingPages`, `RefreshChrome` is not reading `HasTabs`, or +the terminal is being reached by a route that leaves `Surface` on `Page`. A bar still there **with a shell +showing** is the one that matters: that is the third of the screen this arrangement exists to give back. ### 11.2 The connect menu is not drawn over the renderer · **the important one** @@ -1391,6 +1440,14 @@ Close every tab, then press Connections in the bottom bar. keychain has ever connected to anything — a RECENT list underneath. The whole thing scrolls with the keyboard up, and the password box shows dots with **no suggestion strip** above the keyboard. +**And the bottom bar is still there, with Connections lit.** Press Hosts: it goes straight there, without +the back gesture. Then open a shell — the bar goes, which is 11.1. Wide, the same holds for the rail. + +**Failure means:** for the bar, `RefreshChrome` is back to collapsing the nav for the whole terminal +surface rather than for a shell — which strands anybody who reaches this screen by closing their last tab. +For an unlit Connections entry, `IsCurrent` lost its binding: on this screen it is the only true thing the +bar could say about where you are. + Type a machine you can reach and press CONNECT: a tab appears in the bar and the shell opens. Type something malformed — no `user@`, or `:70000` — and the refusal appears under the boxes, in the warning colour, with no tab and nothing dialled. diff --git a/src/DodoSSH.Client.Android/Views/HostsScreen.axaml b/src/DodoSSH.Client.Android/Views/HostsScreen.axaml index 9ae395b..622cc11 100644 --- a/src/DodoSSH.Client.Android/Views/HostsScreen.axaml +++ b/src/DodoSSH.Client.Android/Views/HostsScreen.axaml @@ -158,6 +158,28 @@ + + + + + +