Skip to content

Commit 14e9ac0

Browse files
committed
Improved IVaultCredentialsService.FromUnlockProcedureAsync
1 parent 82ede12 commit 14e9ac0

19 files changed

Lines changed: 202 additions & 176 deletions

File tree

src/Core/SecureFolderFS.Core.Cryptography/SecureFolderFS.Core.Cryptography.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<PackageReference Include="Base4K" Version="1.0.4" />
1212
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.1" />
1313
<PackageReference Include="Miscreant" Version="0.3.3" />
14-
<PackageReference Include="NSec.Cryptography" Version="26.1.0-preview.1" />
14+
<PackageReference Include="NSec.Cryptography" Version="26.4.0" />
1515
<PackageReference Include="RFC3394.net" Version="1.0.0" />
1616
</ItemGroup>
1717

src/Core/SecureFolderFS.Core.WinFsp/SecureFolderFS.Core.WinFsp.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="winfsp.net" Version="2.1.25156" />
10+
<PackageReference Include="winfsp.net" Version="2.2.26112" />
1111
</ItemGroup>
1212

1313
<ItemGroup>

src/Platforms/Directory.Packages.props

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PackageVersion Include="AathifMahir.Maui.MauiIcons.Cupertino" Version="6.0.0" />
44
<PackageVersion Include="AathifMahir.Maui.MauiIcons.Material" Version="6.0.0" />
55
<PackageVersion Include="AcrylicView.Maui" Version="3.0.1" />
6-
<PackageVersion Include="CliFx" Version="2.3.0" />
6+
<PackageVersion Include="CliFx" Version="3.0.0" />
77
<PackageVersion Include="CommunityToolkit.Maui" Version="14.0.0" />
88
<PackageVersion Include="CommunityToolkit.WinUI.Animations" Version="8.2.251219" />
99
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.2.251219" />
@@ -12,7 +12,7 @@
1212
<PackageVersion Include="H.NotifyIcon.Uno.WinUI" Version="2.3.0" />
1313
<PackageVersion Include="IconPacks.Material" Version="1.0.8940.2-build" />
1414
<PackageVersion Include="LibVLCSharp.MAUI" Version="3.9.7.1" />
15-
<PackageVersion Include="LiveChartsCore.SkiaSharpView.Uno.WinUI" Version="2.0.0-rc6.1" />
15+
<PackageVersion Include="LiveChartsCore.SkiaSharpView.Uno.WinUI" Version="2.0.2" />
1616
<PackageVersion Include="Microsoft.Maui.Controls" Version="10.0.31" />
1717
<PackageVersion Include="Microsoft.Maui.Controls.Compatibility" Version="10.0.31" />
1818
<PackageVersion Include="Microsoft.Maui.Core" Version="10.0.31" />
@@ -24,7 +24,7 @@
2424
<PackageVersion Include="Octokit" Version="14.0.0" />
2525
<PackageVersion Include="Plugin.Maui.BottomSheet" Version="9.1.4" />
2626
<PackageVersion Include="Plugin.SegmentedControl.Maui" Version="1.4.36" />
27-
<PackageVersion Include="Sentry" Version="6.1.0" />
27+
<PackageVersion Include="Sentry" Version="6.4.1" />
2828
<PackageVersion Include="SkiaSharp" Version="3.119.2" />
2929
<PackageVersion Include="SkiaSharp.Skottie" Version="3.119.2" />
3030
<PackageVersion Include="SkiaSharp.Views.Maui.Controls" Version="3.119.2" />
@@ -43,7 +43,7 @@
4343
<PackageVersion Include="Uno.WinUI.Lottie" Version="5.3.90" />
4444
<PackageVersion Include="VideoLAN.LibVLC.Android" Version="3.7.0-beta" />
4545
<PackageVersion Include="VideoLAN.LibVLC.iOS" Version="3.6.1" />
46-
<PackageVersion Include="WinUI.TableView" Version="1.4.0" />
46+
<PackageVersion Include="WinUI.TableView" Version="1.4.1" />
4747
<PackageVersion Include="Xamarin.AndroidX.DocumentFile" Version="1.1.0.3" />
4848
<PackageVersion Include="Yubico.YubiKey" Version="1.16.0" />
4949
</ItemGroup>
Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,37 @@
1-
using System.Collections.Generic;
2-
using System.Threading;
1+
using System.Runtime.CompilerServices;
32
using OwlCore.Storage;
3+
using SecureFolderFS.Sdk.Services;
44
using SecureFolderFS.Sdk.ViewModels.Controls.Authentication;
5+
using SecureFolderFS.Shared.Models;
56
using SecureFolderFS.UI.ServiceImplementation;
67

7-
namespace SecureFolderFS.Cli;
8-
9-
internal sealed class CliVaultCredentialsService : BaseVaultCredentialsService
8+
namespace SecureFolderFS.Cli
109
{
11-
public override async IAsyncEnumerable<AuthenticationViewModel> GetLoginAsync(IFolder vaultFolder, CancellationToken cancellationToken = default)
10+
/// <inheritdoc cref="IVaultCredentialsService"/>
11+
internal sealed class CliVaultCredentialsService : BaseVaultCredentialsService
1212
{
13-
_ = vaultFolder;
14-
await Task.CompletedTask;
15-
yield break;
16-
}
13+
/// <inheritdoc/>
14+
public override async IAsyncEnumerable<AuthenticationViewModel> GetCreationAsync(IFolder vaultFolder, string vaultId, [EnumeratorCancellation] CancellationToken cancellationToken = default)
15+
{
16+
_ = vaultFolder;
17+
_ = vaultId;
18+
await Task.CompletedTask;
19+
yield break;
20+
}
1721

18-
public override async IAsyncEnumerable<AuthenticationViewModel> GetCreationAsync(IFolder vaultFolder, string vaultId,
19-
CancellationToken cancellationToken = default)
20-
{
21-
_ = vaultFolder;
22-
_ = vaultId;
23-
await Task.CompletedTask;
24-
yield break;
22+
/// <inheritdoc/>
23+
protected override async IAsyncEnumerable<AuthenticationViewModel> GetLoginAsync(
24+
IFolder vaultFolder,
25+
AuthenticationMethod unlockProcedure,
26+
string vaultId,
27+
[EnumeratorCancellation] CancellationToken cancellationToken = default)
28+
{
29+
_ = vaultFolder;
30+
_ = unlockProcedure;
31+
_ = vaultId;
32+
await Task.CompletedTask;
33+
yield break;
34+
}
2535
}
2636
}
2737

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Runtime.CompilerServices;
22
using OwlCore.Storage;
3-
using SecureFolderFS.Core.Cryptography;
4-
using SecureFolderFS.Core.VaultAccess;
3+
using SecureFolderFS.Core;
54
using SecureFolderFS.Maui.Platforms.Android.ViewModels;
65
using SecureFolderFS.Sdk.Services;
76
using SecureFolderFS.Sdk.ViewModels.Controls.Authentication;
@@ -11,40 +10,9 @@
1110

1211
namespace SecureFolderFS.Maui.Platforms.Android.ServiceImplementation
1312
{
14-
/// <inheritdoc cref="IVaultService"/>
13+
/// <inheritdoc cref="IVaultCredentialsService"/>
1514
internal sealed class AndroidVaultCredentialsService : BaseVaultCredentialsService
1615
{
17-
/// <inheritdoc/>
18-
public override IEnumerable<string> GetContentCiphers()
19-
{
20-
// XChaCha20-Poly1305 is not supported in NSec implementation for Android
21-
// Trackers:
22-
// - https://github.com/ektrah/nsec/issues/81
23-
// - https://nsec.rocks/docs/install#supported-platforms
24-
25-
yield return Constants.CipherId.AES_GCM;
26-
yield return Constants.CipherId.NONE;
27-
}
28-
29-
/// <inheritdoc/>
30-
public override async IAsyncEnumerable<AuthenticationViewModel> GetLoginAsync(IFolder vaultFolder, [EnumeratorCancellation] CancellationToken cancellationToken = default)
31-
{
32-
var vaultReader = new VaultReader(vaultFolder, StreamSerializer.Instance);
33-
var config = await vaultReader.ReadConfigurationAsync(cancellationToken);
34-
var authenticationMethod = AuthenticationMethod.FromString(config.AuthenticationMethod);
35-
36-
foreach (var item in authenticationMethod.Methods)
37-
{
38-
yield return item switch
39-
{
40-
Core.Constants.Vault.Authentication.AUTH_PASSWORD => new PasswordLoginViewModel(),
41-
Core.Constants.Vault.Authentication.AUTH_KEYFILE => new KeyFileLoginViewModel(vaultFolder),
42-
Core.Constants.Vault.Authentication.AUTH_ANDROID_BIOMETRIC => new AndroidBiometricLoginViewModel(vaultFolder, config.Uid),
43-
_ => throw new NotSupportedException($"The authentication method '{item}' is not supported by the platform.")
44-
};
45-
}
46-
}
47-
4816
/// <inheritdoc/>
4917
public override async IAsyncEnumerable<AuthenticationViewModel> GetCreationAsync(IFolder vaultFolder, string vaultId,
5018
[EnumeratorCancellation] CancellationToken cancellationToken = default)
@@ -60,5 +28,24 @@ public override async IAsyncEnumerable<AuthenticationViewModel> GetCreationAsync
6028

6129
await Task.CompletedTask;
6230
}
31+
32+
/// <inheritdoc/>
33+
protected override async IAsyncEnumerable<AuthenticationViewModel> GetLoginAsync(
34+
IFolder vaultFolder,
35+
AuthenticationMethod unlockProcedure,
36+
string vaultId,
37+
[EnumeratorCancellation] CancellationToken cancellationToken = default)
38+
{
39+
foreach (var item in unlockProcedure.Methods)
40+
{
41+
yield return item switch
42+
{
43+
Constants.Vault.Authentication.AUTH_PASSWORD => new PasswordLoginViewModel(),
44+
Constants.Vault.Authentication.AUTH_KEYFILE => new KeyFileLoginViewModel(vaultFolder),
45+
Constants.Vault.Authentication.AUTH_ANDROID_BIOMETRIC => new AndroidBiometricLoginViewModel(vaultFolder, vaultId),
46+
_ => throw new NotSupportedException($"The authentication method '{item}' is not supported by the platform.")
47+
};
48+
}
49+
}
6350
}
6451
}

src/Platforms/SecureFolderFS.Maui/Platforms/iOS/ServiceImplementation/IOSVaultCredentialsService.cs

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,21 @@
11
using System.Runtime.CompilerServices;
2-
using Foundation;
32
using LocalAuthentication;
43
using OwlCore.Storage;
54
using SecureFolderFS.Core;
6-
using SecureFolderFS.Core.VaultAccess;
75
using SecureFolderFS.Maui.Platforms.iOS.ViewModels;
86
using SecureFolderFS.Sdk.Services;
97
using SecureFolderFS.Sdk.ViewModels.Controls.Authentication;
108
using SecureFolderFS.Shared.Models;
119
using SecureFolderFS.UI.ServiceImplementation;
1210
using SecureFolderFS.UI.ViewModels.Authentication;
13-
using UIKit;
1411

1512
namespace SecureFolderFS.Maui.Platforms.iOS.ServiceImplementation
1613
{
1714
/// <inheritdoc cref="IVaultCredentialsService"/>
1815
internal sealed class IOSVaultCredentialsService : BaseVaultCredentialsService
1916
{
2017
/// <inheritdoc/>
21-
public override async IAsyncEnumerable<AuthenticationViewModel> GetLoginAsync(IFolder vaultFolder, [EnumeratorCancellation] CancellationToken cancellationToken = default)
22-
{
23-
var vaultReader = new VaultReader(vaultFolder, StreamSerializer.Instance);
24-
var config = await vaultReader.ReadConfigurationAsync(cancellationToken);
25-
var authenticationMethod = AuthenticationMethod.FromString(config.AuthenticationMethod);
26-
27-
foreach (var item in authenticationMethod.Methods)
28-
{
29-
yield return item switch
30-
{
31-
Constants.Vault.Authentication.AUTH_PASSWORD => new PasswordLoginViewModel(),
32-
Constants.Vault.Authentication.AUTH_KEYFILE => new KeyFileLoginViewModel(vaultFolder),
33-
Constants.Vault.Authentication.AUTH_APPLE_BIOMETRIC when AreBiometricsAvailable(out var biometryType) =>
34-
new IOSBiometricLoginViewModel(vaultFolder, config.Uid, biometryType switch
35-
{
36-
LABiometryType.FaceId => "Face ID",
37-
LABiometryType.TouchId => "Touch ID",
38-
_ => string.Empty
39-
}),
40-
_ => throw new NotSupportedException($"The authentication method '{item}' is not supported by the platform.")
41-
};
42-
}
43-
}
44-
45-
/// <inheritdoc/>
46-
public override async IAsyncEnumerable<AuthenticationViewModel> GetCreationAsync(IFolder vaultFolder, string vaultId,
47-
[EnumeratorCancellation] CancellationToken cancellationToken = default)
18+
public override async IAsyncEnumerable<AuthenticationViewModel> GetCreationAsync(IFolder vaultFolder, string vaultId, [EnumeratorCancellation] CancellationToken cancellationToken = default)
4819
{
4920
// Password
5021
yield return new PasswordCreationViewModel();
@@ -63,6 +34,32 @@ public override async IAsyncEnumerable<AuthenticationViewModel> GetCreationAsync
6334

6435
await Task.CompletedTask;
6536
}
37+
38+
/// <inheritdoc/>
39+
protected override async IAsyncEnumerable<AuthenticationViewModel> GetLoginAsync(
40+
IFolder vaultFolder,
41+
AuthenticationMethod unlockProcedure,
42+
string vaultId,
43+
[EnumeratorCancellation] CancellationToken cancellationToken = default)
44+
{
45+
await Task.CompletedTask;
46+
foreach (var item in unlockProcedure.Methods)
47+
{
48+
yield return item switch
49+
{
50+
Constants.Vault.Authentication.AUTH_PASSWORD => new PasswordLoginViewModel(),
51+
Constants.Vault.Authentication.AUTH_KEYFILE => new KeyFileLoginViewModel(vaultFolder),
52+
Constants.Vault.Authentication.AUTH_APPLE_BIOMETRIC when AreBiometricsAvailable(out var biometryType) =>
53+
new IOSBiometricLoginViewModel(vaultFolder, vaultId, biometryType switch
54+
{
55+
LABiometryType.FaceId => "Face ID",
56+
LABiometryType.TouchId => "Touch ID",
57+
_ => string.Empty
58+
}),
59+
_ => throw new NotSupportedException($"The authentication method '{item}' is not supported by the platform.")
60+
};
61+
}
62+
}
6663

6764
private static bool AreBiometricsAvailable(out LABiometryType biometryType)
6865
{

src/Platforms/SecureFolderFS.UI/ServiceImplementation/BaseVaultCredentialsService.cs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Runtime.CompilerServices;
45
using System.Threading;
56
using System.Threading.Tasks;
67
using OwlCore.Storage;
8+
using SecureFolderFS.Core.VaultAccess;
79
using SecureFolderFS.Sdk.Extensions;
810
using SecureFolderFS.Sdk.Services;
911
using SecureFolderFS.Sdk.ViewModels.Controls.Authentication;
1012
using SecureFolderFS.Shared.Extensions;
1113
using SecureFolderFS.Shared.Models;
12-
using SecureFolderFS.Storage.MemoryStorageEx;
1314

1415
namespace SecureFolderFS.UI.ServiceImplementation
1516
{
@@ -41,18 +42,15 @@ public virtual IEnumerable<string> GetFileNameCiphers()
4142
}
4243

4344
/// <inheritdoc/>
44-
public virtual async Task<string> FromUnlockProcedureAsync(AuthenticationMethod unlockProcedure, CancellationToken cancellationToken = default)
45+
public virtual async Task<string> FromUnlockProcedureAsync(IFolder vaultFolder, AuthenticationMethod unlockProcedure, CancellationToken cancellationToken = default)
4546
{
4647
try
4748
{
48-
var emptyFolder = new MemoryFolderEx(string.Empty, string.Empty, null);
49-
var procedures = await GetCreationAsync(emptyFolder, string.Empty, cancellationToken).ToArrayAsyncImpl(cancellationToken);
50-
var result = unlockProcedure.Methods
51-
.Select(method => procedures.FirstOrDefault(p => p.Id == method)?.Title)
52-
.Where(title => title is not null);
49+
var procedures = await GetLoginAsync(vaultFolder, unlockProcedure, string.Empty, cancellationToken).ToArrayAsyncImpl(cancellationToken);
50+
var result = string.Join(" + ", procedures.Select(x => x.Title));
5351

5452
procedures.DisposeAll();
55-
return string.Join(" + ", result);
53+
return result;
5654
}
5755
catch (Exception)
5856
{
@@ -61,8 +59,31 @@ public virtual async Task<string> FromUnlockProcedureAsync(AuthenticationMethod
6159
}
6260

6361
/// <inheritdoc/>
64-
public abstract IAsyncEnumerable<AuthenticationViewModel> GetLoginAsync(IFolder vaultFolder, CancellationToken cancellationToken = default);
62+
public virtual async IAsyncEnumerable<AuthenticationViewModel> GetLoginAsync(IFolder vaultFolder, [EnumeratorCancellation] CancellationToken cancellationToken = default)
63+
{
64+
var vaultReader = new VaultReader(vaultFolder, StreamSerializer.Instance);
65+
var config = await vaultReader.ReadConfigurationAsync(cancellationToken);
66+
var authenticationMethod = AuthenticationMethod.FromString(config.AuthenticationMethod);
6567

68+
cancellationToken.ThrowIfCancellationRequested();
69+
await foreach (var item in GetLoginAsync(vaultFolder, authenticationMethod, config.Uid, cancellationToken))
70+
{
71+
cancellationToken.ThrowIfCancellationRequested();
72+
yield return item;
73+
}
74+
}
75+
76+
/// <summary>
77+
/// Retrieves the authentication methods for login routine.
78+
/// </summary>
79+
/// <param name="vaultFolder">The folder representing the vault for which authentication methods should be retrieved.</param>
80+
/// <param name="unlockProcedure">The authentication method used to unlock the vault.</param>
81+
/// <param name="vaultId">The unique identifier of the vault.</param>
82+
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that cancels this action.</param>
83+
/// <returns>Returns an async operation represented by <see cref="IAsyncEnumerable{T}"/> of type <see cref="AuthenticationViewModel"/> representing available authentication options.</returns>
84+
protected abstract IAsyncEnumerable<AuthenticationViewModel> GetLoginAsync(IFolder vaultFolder, AuthenticationMethod unlockProcedure, string vaultId, CancellationToken cancellationToken = default);
85+
86+
/// <inheritdoc/>
6687
public abstract IAsyncEnumerable<AuthenticationViewModel> GetCreationAsync(IFolder vaultFolder, string vaultId, CancellationToken cancellationToken = default);
6788
}
6889
}

src/Platforms/SecureFolderFS.UI/ServiceImplementation/VaultService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public virtual async Task<VaultOptions> GetVaultOptionsAsync(IFolder vaultFolder
4242
{
4343
var vaultReader = new VaultReader(vaultFolder, StreamSerializer.Instance);
4444
var config = await vaultReader.ReadConfigurationAsync(cancellationToken);
45-
Shared.Models.AppPlatformVaultOptions? appPlatform = null;
45+
AppPlatformVaultOptions? appPlatform = null;
4646

4747
if (config.AuthenticationMethod.Contains(Core.Constants.Vault.Authentication.AUTH_APP_PLATFORM, StringComparison.Ordinal))
4848
{

0 commit comments

Comments
 (0)