Public Access
Give each profile its own device key, and make the Linux PIN window able to open at all
- The Windows CNG key and the macOS keychain tag were one name for every profile, so signing out of the nightly deleted the key the release build's device unlock was sealed to. DeviceKeyNames keeps the existing name for the default profile and gives every other profile its own; sign-out deletes only its own key, and a profile sealed before this keeps reading the shared one. - DevicePinWindow named two palette resources that do not exist and loaded itself with AvaloniaXamlLoader.Load, which never assigns the named fields, so it threw on construction and no PIN prompt was ever shown. A layout test now builds it against the real palette.
This commit is contained in:
1 parent
2ff9dff560
commit
0e8fe4fc80
7 files changed
+213
-22
No files matched your search
@@ -0,0 +1,39 @@
|
||||
using DodoSSH.Client.App.Views;
|
||||
|
||||
namespace DodoSSH.Client.App.Layout.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// The Linux device-key PIN window, which no other test constructs.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It named two palette resources that have never existed, <c>Surface</c> and <c>MutedText</c>, and a
|
||||
/// <c>StaticResource</c> that cannot be found throws when the window is built — so on the one platform that
|
||||
/// shows it, registering or unlocking with the TPM failed before any PIN was asked for. Only constructing it
|
||||
/// against the real palette can catch that, which is what the harness's application provides.
|
||||
/// </remarks>
|
||||
public sealed class DevicePinWindowTests
|
||||
{
|
||||
private static CancellationToken Token => TestContext.Current.CancellationToken;
|
||||
|
||||
[Fact]
|
||||
public async Task TheWindowBuildsAgainstThePalette()
|
||||
{
|
||||
await LayoutHarness.OnTheUiThreadAsync(
|
||||
() =>
|
||||
{
|
||||
var window = new DevicePinWindow();
|
||||
|
||||
try
|
||||
{
|
||||
LayoutHarness.Settle(window, window.Width, 240);
|
||||
|
||||
LayoutHarness.Unreachable(window).ShouldBeEmpty();
|
||||
}
|
||||
finally
|
||||
{
|
||||
window.Close();
|
||||
}
|
||||
},
|
||||
Token);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using DodoSSH.Client.App.Platform;
|
||||
using DodoSSH.Client.Session;
|
||||
|
||||
namespace DodoSSH.Client.App.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// <c>DeviceKeyNames</c>: which hardware key a profile's device unlock is sealed to.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The stores themselves cannot be exercised here — every call past the probe raises a Windows Hello or
|
||||
/// Touch ID dialog — so the rule that keeps two installations off one key is tested on its own. It is the
|
||||
/// whole of what stops signing out of the nightly deleting the key the release build unlocks with.
|
||||
/// </remarks>
|
||||
public sealed class DeviceKeyNamesTests
|
||||
{
|
||||
private const string Legacy = "DodoSSH.DeviceKey.v1";
|
||||
|
||||
[Fact]
|
||||
public void TheDefaultProfile_KeepsTheNameEveryExistingInstallIsSealedTo() =>
|
||||
DeviceKeyNames.For(ClientPaths.Default, Legacy).ShouldBe(Legacy);
|
||||
|
||||
[Fact]
|
||||
public void TheNightlyProfile_HasAKeyOfItsOwn()
|
||||
{
|
||||
var nightly = DeviceKeyNames.For(ClientPaths.ForChannel("nightly"), Legacy);
|
||||
|
||||
nightly.ShouldNotBe(Legacy);
|
||||
nightly.ShouldStartWith(Legacy + ".");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TwoProfilesWhoseFoldersShareAName_HaveDifferentKeys()
|
||||
{
|
||||
var first = new ClientPaths(Path.Combine(Path.GetTempPath(), "one", "DodoSSH"));
|
||||
var second = new ClientPaths(Path.Combine(Path.GetTempPath(), "two", "DodoSSH"));
|
||||
|
||||
DeviceKeyNames.For(first, Legacy).ShouldNotBe(DeviceKeyNames.For(second, Legacy));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OneProfile_AlwaysNamesTheSameKey()
|
||||
{
|
||||
var directory = Path.Combine(Path.GetTempPath(), "portable", "DodoSSH");
|
||||
|
||||
DeviceKeyNames.For(new ClientPaths(directory), Legacy)
|
||||
.ShouldBe(DeviceKeyNames.For(new ClientPaths(directory + Path.DirectorySeparatorChar), Legacy));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user