Skip to content

Commit

Permalink
#11: Increase choice finding retry period from 5 to 60 seconds, embed…
Browse files Browse the repository at this point in the history
… line numbers in binary (negligible filesize change)
  • Loading branch information
Aldaviva committed Dec 6, 2024
1 parent d292102 commit c9f67c0
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 80 deletions.
104 changes: 48 additions & 56 deletions AuthenticatorChooser/AuthenticatorChooser.csproj
Original file line number Diff line number Diff line change
@@ -1,57 +1,49 @@
<!--EXTERNAL_PROPERTIES: GITHUB_ACTIONS-->
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.2.1</Version>
<Authors>Ben Hutchison</Authors>
<Copyright>© 2024 $(Authors)</Copyright>
<Company>$(Authors)</Company>
<RollForward>latestMajor</RollForward>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>YubiKey.ico</ApplicationIcon>
<NeutralLanguage>en</NeutralLanguage>
</PropertyGroup>

<ItemGroup>
<Content Include="YubiKey.ico" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
<PackageReference Include="mwinapi" Version="0.3.0.5" />
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="System.Management" Version="8.0.0" />
<PackageReference Include="ThrottleDebounce" Version="2.0.0" />
<PackageReference Include="Workshell.PE.Resources" Version="4.0.0.147" />
</ItemGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.WindowsDesktop.App" /> <!-- UseWindowsForms is insufficient to refer to UIAutomationClient -->
</ItemGroup>

<ItemGroup>
<Compile Update="Resources\Strings.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Strings.resx</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="Resources\Strings.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>

<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true' or '$(Configuration)' == 'Release'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<!--EXTERNAL_PROPERTIES: GITHUB_ACTIONS-->
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>0.2.1</Version>
<Authors>Ben Hutchison</Authors>
<Copyright>© 2024 $(Authors)</Copyright>
<Company>$(Authors)</Company>
<RollForward>latestMajor</RollForward>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>YubiKey.ico</ApplicationIcon>
<NeutralLanguage>en</NeutralLanguage>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>embedded</DebugType>
</PropertyGroup>

<ItemGroup>
<Content Include="YubiKey.ico" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
<PackageReference Include="mwinapi" Version="0.3.0.5" />
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="System.Management" Version="9.0.0" />
<PackageReference Include="ThrottleDebounce" Version="2.0.0" />
<PackageReference Include="Workshell.PE.Resources" Version="4.0.0.147" />
</ItemGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.WindowsDesktop.App" /> <!-- UseWindowsForms is insufficient to refer to UIAutomationClient -->
</ItemGroup>

<ItemGroup>
<Compile Update="Resources\Strings.Designer.cs" DesignTime="True" AutoGen="True" DependentUpon="Strings.resx" />
<EmbeddedResource Update="Resources\Strings.resx" Generator="ResXFileCodeGenerator" LastGenOutput="Strings.Designer.cs" />
</ItemGroup>

<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true' or '$(Configuration)' == 'Release'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>

</Project>
22 changes: 16 additions & 6 deletions AuthenticatorChooser/SecurityKeyChooser.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using ManagedWinapi.Windows;
using NLog;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Automation;
using System.Windows.Input;
Expand Down Expand Up @@ -38,10 +39,21 @@ public static void chooseUsbSecurityKey(SystemWindow fidoPrompt) {

Condition credentialsListIdCondition = new PropertyCondition(AutomationElement.AutomationIdProperty, "CredentialsList");
IEnumerable<string> securityKeyLabelPossibilities = I18N.getStrings(I18N.Key.SECURITY_KEY);
ICollection<AutomationElement> authenticatorChoices = Retrier.Attempt(_ =>
outerScrollViewer.FindFirst(TreeScope.Children, credentialsListIdCondition).children().ToList(),
maxAttempts: 18, // #5: ~5 sec
delay: attempt => TimeSpan.FromMilliseconds(Math.Min(500, 1 << attempt)));

Stopwatch authenticatorChoicesStopwatch = Stopwatch.StartNew();
ICollection<AutomationElement> authenticatorChoices;
try {
authenticatorChoices = Retrier.Attempt(_ =>
outerScrollViewer.FindFirst(TreeScope.Children, credentialsListIdCondition).children().ToList(),
maxAttempts: 124, // #5, #11: ~60 sec
delay: attempt => TimeSpan.FromMilliseconds(1 << Math.Min(attempt, 9))); // #11: power series backoff, max=512 ms
LOGGER.Trace("Found authenticator choices after {0:N3} sec", authenticatorChoicesStopwatch.Elapsed.TotalSeconds);
} catch (Exception e) when (e is not OutOfMemoryException) {
LOGGER.Error(e, "Could not find authenticator choices after retrying for {0:N3} sec due to the following exception. Giving up and not automatically selecting Security Key.",
authenticatorChoicesStopwatch.Elapsed.TotalSeconds);
return;
}

AutomationElement? securityKeyChoice = authenticatorChoices.FirstOrDefault(choice => nameContainsAny(choice, securityKeyLabelPossibilities));
if (securityKeyChoice == null) {
LOGGER.Debug("USB security key is not a choice, skipping");
Expand Down Expand Up @@ -73,8 +85,6 @@ public static void chooseUsbSecurityKey(SystemWindow fidoPrompt) {
// Window name and title are localized, so don't match against those
public static bool isFidoPromptWindow(SystemWindow window) => window.ClassName == WINDOW_CLASS_NAME;

// private static bool isAltTabWindow(SystemWindow window) => window.ClassName == ALT_TAB_CLASS_NAME;

private static bool nameContainsAny(AutomationElement element, IEnumerable<string?> possibleSubstrings) {
string name = element.Current.Name;
// #2: in addition to a prefix, there is sometimes also a suffix after the substring
Expand Down
9 changes: 5 additions & 4 deletions AuthenticatorChooser/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class Startup {
[STAThread]
public static int Main(string[] args) => CommandLineApplication.Execute<Startup>(args);

// ReSharper disable once UnusedMember.Global - it's actually invoked by McMaster.Extensions.CommandLineUtils
public int OnExecute() {
Application.SetCompatibleTextRenderingDefault(false);
Application.EnableVisualStyles();
Expand Down Expand Up @@ -92,19 +93,19 @@ private static void showUsage() {
MessageBox.Show(
$"""
{processFilename}
Runs this program in the background, waiting for FIDO credentials dialog boxes to open and choosing the Security Key option each time.
Runs this program in the background, waiting for FIDO credential dialog boxes to open and choosing the Security Key option each time.
{processFilename} --autostart-on-logon
Registers this program to start automatically every time the current user logs on to Windows.
{processFilename} --log[=filename]
Runs this program in the background like the first example, and logs debug messages to a text file. If you don't specify a filename, it goes to %TEMP%\{PROGRAM_NAME}.log.
Runs this program in the background like the first example, and logs debug messages to a text file. If you don't specify a filename, it goes to {Path.Combine(Environment.GetEnvironmentVariable("TEMP") ?? "%TEMP%", PROGRAM_NAME + ".log")}.
{processFilename} --help
Shows usage.
For more information, see https://github.com/Aldaviva/{PROGRAM_NAME}
Press Ctrl+C to copy this message
For more information, see https://github.com/Aldaviva/{PROGRAM_NAME}.
Press Ctrl+C to copy this message.
""", $"{PROGRAM_NAME} {PROGRAM_VERSION} usage", MessageBoxButtons.OK, MessageBoxIcon.Information);
}

Expand Down
28 changes: 14 additions & 14 deletions AuthenticatorChooser/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
},
"System.Management": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==",
"requested": "[9.0.0, )",
"resolved": "9.0.0",
"contentHash": "bVh4xAMI5grY5GZoklKcMBLirhC8Lqzp63Ft3zXJacwGAlLyFdF4k0qz4pnKIlO6HyL2Z4zqmHm9UkzEo6FFsA==",
"dependencies": {
"System.CodeDom": "8.0.0"
"System.CodeDom": "9.0.0"
}
},
"ThrottleDebounce": {
Expand All @@ -58,8 +58,8 @@
},
"System.CodeDom": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "WTlRjL6KWIMr/pAaq3rYqh0TJlzpouaQ/W1eelssHgtlwHAH25jXTkUphTYx9HaIIf7XA6qs/0+YhtLEQRkJ+Q=="
"resolved": "9.0.0",
"contentHash": "oTE5IfuMoET8yaZP/vdvy9xO47guAv/rOhe4DODuFBN3ySprcQOlXqO3j+e/H/YpKKR5sglrxRaZ2HYOhNJrqA=="
},
"System.ComponentModel.Annotations": {
"type": "Transitive",
Expand All @@ -83,11 +83,11 @@
"net8.0-windows7.0/win-arm64": {
"System.Management": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==",
"requested": "[9.0.0, )",
"resolved": "9.0.0",
"contentHash": "bVh4xAMI5grY5GZoklKcMBLirhC8Lqzp63Ft3zXJacwGAlLyFdF4k0qz4pnKIlO6HyL2Z4zqmHm9UkzEo6FFsA==",
"dependencies": {
"System.CodeDom": "8.0.0"
"System.CodeDom": "9.0.0"
}
},
"Microsoft.Win32.SystemEvents": {
Expand All @@ -107,11 +107,11 @@
"net8.0-windows7.0/win-x64": {
"System.Management": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==",
"requested": "[9.0.0, )",
"resolved": "9.0.0",
"contentHash": "bVh4xAMI5grY5GZoklKcMBLirhC8Lqzp63Ft3zXJacwGAlLyFdF4k0qz4pnKIlO6HyL2Z4zqmHm9UkzEo6FFsA==",
"dependencies": {
"System.CodeDom": "8.0.0"
"System.CodeDom": "9.0.0"
}
},
"Microsoft.Win32.SystemEvents": {
Expand Down

0 comments on commit c9f67c0

Please sign in to comment.