Public Access
Give the phone the rest of its screens, and a way in
All seven screens of the design, plus the two it does not draw because it starts at an enrolled phone: naming a server, and choosing a passphrase. The five states docs/android-port.md worried about losing at 360dp are all here and none of them softened. The changed-key refusal is a full-screen panel rather than a bottom sheet, because a sheet is swipe-to-dismiss by convention and that screen must have no way forward. The recovery code raises FLAG_SECURE for its own state and lowers it afterwards, so the sentence about screenshots is true rather than decorative. The delete confirmations keep their counts and replace the row in place. Signing in works, and the seam it needed is worth more than the implementation: IAuthorizationCallback now sits between OidcClient and the loopback listener, so the two heads differ in where the response arrives and in nothing else. PKCE, the state check, discovery, the token exchange and the key binding stay one implementation — a second OIDC client would be a second place for a security bug to live. The phone registers a private-use scheme with the system rather than binding a loopback port, which on a shared device any other app can do first. The accessory key row needed TerminalWorkspace.SendInputAsync: ordinary typing goes from the renderer straight down the socket, and there was no way in for the keys a software keyboard does not have. Ctrl latches, because one thumb cannot chord, and the latch is drawn — a modifier that is on and does not look on is how somebody sends ^L to a database prompt believing they typed an l. 597 client tests green, including two new ones for the input path and one for the terminal surface command. Nothing has run on a device.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="using:DodoSSH.Client.Shell.ViewModels"
|
||||
x:Class="DodoSSH.Client.Android.Views.RecoveryCodeScreen"
|
||||
x:DataType="vm:MainWindowViewModel"
|
||||
Background="{StaticResource Canvas}">
|
||||
|
||||
<!--
|
||||
Design 07 — RECOVERY CODE, and the ◆ the plan worries about most after the changed-key refusal.
|
||||
|
||||
Three properties make this screen what it is, and all three are structural rather than cosmetic:
|
||||
|
||||
there is no back and no skip — this control draws no navigation at all, and the shell state it belongs
|
||||
to has no other exit; CONTINUE is disabled until the checkbox is ticked, bound to
|
||||
RecoveryCodeWrittenDown rather than to anything this view keeps; and the code is selectable so it can be
|
||||
copied into a password manager, which is what people actually do with it and what refusing would only
|
||||
push into a screenshot.
|
||||
|
||||
The design says screenshots are blocked here. That is FLAG_SECURE on the activity, which is a window
|
||||
flag rather than anything a control can set — see PhoneShell's code-behind, which raises it for exactly
|
||||
this state and lowers it afterwards.
|
||||
-->
|
||||
|
||||
<ScrollViewer>
|
||||
<StackPanel Margin="24,40,24,32" Spacing="0">
|
||||
|
||||
<TextBlock Classes="label" Text="ENROLLMENT · STEP 3 OF 3" Foreground="{StaticResource TextFaint}" />
|
||||
|
||||
<TextBlock Classes="title" Text="YOUR RECOVERY CODE" FontSize="17" Margin="0,10,0,0" />
|
||||
|
||||
<TextBlock Classes="body" Margin="0,10,0,0"
|
||||
Text="This is the only moment this code exists. It is not stored on the server — by design, there is no reset. Losing it together with your passphrase makes the vault unrecoverable." />
|
||||
|
||||
<!--
|
||||
SelectableTextBox rather than a grid of chunks. The design draws eight two-word cells, which is a
|
||||
good way to read a code and a bad way to copy one: a user who cannot select it will photograph the
|
||||
screen, and that is a worse home for it than their clipboard.
|
||||
-->
|
||||
<Border Margin="0,20,0,0" Background="{StaticResource Field}" BorderBrush="{StaticResource BorderMid}"
|
||||
BorderThickness="1" CornerRadius="6" Padding="14,13">
|
||||
<SelectableTextBlock Text="{Binding RecoveryCode}"
|
||||
FontFamily="{StaticResource MonoFont}" FontSize="14"
|
||||
Foreground="{StaticResource Accent}"
|
||||
LetterSpacing="1.5" LineHeight="26" TextWrapping="Wrap" />
|
||||
</Border>
|
||||
|
||||
<CheckBox IsChecked="{Binding RecoveryCodeWrittenDown}" Margin="0,20,0,0" MinHeight="44">
|
||||
<TextBlock Classes="body" Foreground="{StaticResource Text}"
|
||||
Text="I have written this code down. I understand it will never be shown again." />
|
||||
</CheckBox>
|
||||
|
||||
<Button Classes="primary" Content="CONTINUE" Margin="0,16,0,0"
|
||||
Command="{Binding ConfirmRecoveryCodeCommand}"
|
||||
IsEnabled="{Binding RecoveryCodeWrittenDown}" />
|
||||
|
||||
<TextBlock Classes="detail" Margin="0,10,0,0" TextAlignment="Center" TextWrapping="Wrap"
|
||||
Text="no skip · no back · screenshots are blocked on this screen" />
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</UserControl>
|
||||
Reference in New Issue
Block a user