Skip to content

Commit

Permalink
Maintenance release (#74)
Browse files Browse the repository at this point in the history
* chore: code cleanup

* fix issue where vault may not be sorting after refresh

* chore: performance improvements offloading to background thread

* fix: bitmaps and add lazy loading

fix: tree search
fix: errors when logging in or out of accounts with saved preferences
change window size to be larger

* add ablity to refresh subscriptions

fix issue with subscriptions not saving

* add dynamic splitview based on window PercentageConverter

update avalonia version
fix "unpinned" showing things that were not actually pinned
  • Loading branch information
cricketthomas authored Aug 9, 2024
1 parent 01eb619 commit eabf35e
Show file tree
Hide file tree
Showing 46 changed files with 507 additions and 255 deletions.
2 changes: 1 addition & 1 deletion Desktop/Desktop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@


<ItemGroup>
<PackageReference Include="Avalonia.Desktop" Version="11.1.1" />
<PackageReference Include="Avalonia.Desktop" Version="11.1.2" />
</ItemGroup>


Expand Down
16 changes: 8 additions & 8 deletions Desktop/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"profiles": {
"Desktop": {
"commandName": "Project"
},
"WSL": {
"commandName": "WSL2",
"distributionName": ""
"profiles": {
"Desktop": {
"commandName": "Project"
},
"WSL": {
"commandName": "WSL2",
"distributionName": ""
}
}
}
}
9 changes: 2 additions & 7 deletions KeyVaultExplorer/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input.Platform;
using Avalonia.Markup.Xaml;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using Avalonia.VisualTree;
using KeyVaultExplorer.Database;
Expand All @@ -12,9 +10,7 @@
using KeyVaultExplorer.ViewModels;
using KeyVaultExplorer.Views;
using Microsoft.Extensions.DependencyInjection;
using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;

namespace KeyVaultExplorer;

Expand All @@ -25,7 +21,6 @@ public App()
DataContext = new AppViewModel();
}


public static void CreateDesktopResources()
{
Directory.CreateDirectory(Constants.LocalAppDataFolder);
Expand All @@ -35,8 +30,8 @@ public static void CreateDesktopResources()
if (!dbPassExists)
DatabaseEncryptedPasswordManager.SetSecret($"keyvaultexplorer_{System.Guid.NewGuid().ToString()[..6]}");


Dispatcher.UIThread.Post(async () => {
Dispatcher.UIThread.Post(async () =>
{
await KvExplorerDb.OpenSqlConnection();

if (!dbExists)
Expand Down
56 changes: 21 additions & 35 deletions KeyVaultExplorer/Database/KvExplorerDb.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
using KeyVaultExplorer.Models;
using KeyVaultExplorer.Services;
using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using Avalonia.Animation;
using System.Data.Common;
using KeyVaultExplorer.Services;

namespace KeyVaultExplorer.Database;

Expand All @@ -24,7 +22,7 @@ public KvExplorerDb()
public static async Task OpenSqlConnection()
{
string DataSource = Path.Combine(Constants.DatabaseFilePath);
var pass = await DatabaseEncryptedPasswordManager.GetSecret();
var pass = await DatabaseEncryptedPasswordManager.GetSecret();
var connection = new SqliteConnection($"Filename={DataSource}; Password={pass}");
connection.Open();
_connection = connection;
Expand All @@ -47,8 +45,8 @@ public static async void InitializeDatabase()
BEGIN TRANSACTION;
-- Table: Subscriptions
CREATE TABLE IF NOT EXISTS Subscriptions (
DisplayName TEXT NOT NULL CONSTRAINT UQ_DisplayName UNIQUE ON CONFLICT IGNORE,
SubscriptionId TEXT (200) PRIMARY KEY UNIQUE ON CONFLICT IGNORE,
DisplayName TEXT NOT NULL,
SubscriptionId TEXT (200) PRIMARY KEY UNIQUE ON CONFLICT IGNORE,
TenantId TEXT (200)
);
CREATE UNIQUE INDEX IF NOT EXISTS IX_Subscriptions_DisplayName_SubscriptionsId ON Subscriptions (
Expand Down Expand Up @@ -78,36 +76,18 @@ CREATE INDEX IF NOT EXISTS IX_QuickAccess_KeyVaultId ON QuickAccess (
await createTableCommand.ExecuteNonQueryAsync();
}

public List<QuickAccess> GetQuickAccessItems()
public async IAsyncEnumerable<QuickAccess> GetQuickAccessItemsAsyncEnumerable(string tenantId = null)

Check warning on line 79 in KeyVaultExplorer/Database/KvExplorerDb.cs

View workflow job for this annotation

GitHub Actions / Build macOS Arm64

Cannot convert null literal to non-nullable reference type.

Check warning on line 79 in KeyVaultExplorer/Database/KvExplorerDb.cs

View workflow job for this annotation

GitHub Actions / Build Windows

Cannot convert null literal to non-nullable reference type.

Check warning on line 79 in KeyVaultExplorer/Database/KvExplorerDb.cs

View workflow job for this annotation

GitHub Actions / Build macOS intel

Cannot convert null literal to non-nullable reference type.
{
var command = _connection.CreateCommand();
command.CommandText = "SELECT Id, Name, VaultUri, KeyVaultId, SubscriptionDisplayName, SubscriptionId, TenantId, Location FROM QuickAccess;";

var reader = command.ExecuteReader();
var query = new StringBuilder("SELECT Id, Name, VaultUri, KeyVaultId, SubscriptionDisplayName, SubscriptionId, TenantId, Location FROM QuickAccess");

var items = new List<QuickAccess>();
while (reader.Read())
if (!string.IsNullOrWhiteSpace(tenantId))
{
var item = new QuickAccess
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
VaultUri = reader.GetString(2),
KeyVaultId = reader.GetString(3),
SubscriptionDisplayName = reader.IsDBNull(4) ? null : reader.GetString(4),
SubscriptionId = reader.IsDBNull(5) ? null : reader.GetString(5),
TenantId = reader.GetString(6),
Location = reader.GetString(7),
};
items.Add(item);
query.Append($" WHERE TenantId = '{tenantId}'");
}
return items;
}
query.Append(";");
command.CommandText = query.ToString();

public async IAsyncEnumerable<QuickAccess> GetQuickAccessItemsAsyncEnumerable()
{
var command = _connection.CreateCommand();
command.CommandText = "SELECT Id, Name, VaultUri, KeyVaultId, SubscriptionDisplayName, SubscriptionId, TenantId, Location FROM QuickAccess;";

var reader = await command.ExecuteReaderAsync();

Expand Down Expand Up @@ -193,11 +173,17 @@ public async Task<AppSettings> GetToggleSettings()
return settings;
}

public async Task<List<Subscriptions>> GetStoredSubscriptions()
public async Task<List<Subscriptions>> GetStoredSubscriptions(string tenantId = null)

Check warning on line 176 in KeyVaultExplorer/Database/KvExplorerDb.cs

View workflow job for this annotation

GitHub Actions / Build macOS Arm64

Cannot convert null literal to non-nullable reference type.

Check warning on line 176 in KeyVaultExplorer/Database/KvExplorerDb.cs

View workflow job for this annotation

GitHub Actions / Build Windows

Cannot convert null literal to non-nullable reference type.

Check warning on line 176 in KeyVaultExplorer/Database/KvExplorerDb.cs

View workflow job for this annotation

GitHub Actions / Build macOS intel

Cannot convert null literal to non-nullable reference type.
{
var command = _connection.CreateCommand();
command.CommandText = "SELECT DisplayName, SubscriptionId, TenantId FROM Subscriptions;";

var query = new StringBuilder("SELECT DisplayName, SubscriptionId, TenantId FROM Subscriptions");

if (!string.IsNullOrWhiteSpace(tenantId))
{
query.Append($" WHERE TenantId = '{tenantId.ToUpperInvariant()}'");
}
query.Append(";");
command.CommandText = query.ToString();
var reader = command.ExecuteReader();

var subscriptions = new List<Subscriptions>();
Expand All @@ -214,7 +200,7 @@ public async Task<List<Subscriptions>> GetStoredSubscriptions()
return subscriptions;
}

public async Task InsertSubscriptions(IEnumerable<Subscriptions> subscriptions)
public async Task InsertSubscriptions(IList<Subscriptions> subscriptions)
{
foreach (var subscription in subscriptions)
{
Expand Down
1 change: 0 additions & 1 deletion KeyVaultExplorer/Exceptions/KvExceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public KeyVaultInsufficientPrivilegesException(string message, Exception inner)
}
}


public class SubscriptionInsufficientPrivileges : Exception
{
public SubscriptionInsufficientPrivileges()
Expand Down
8 changes: 4 additions & 4 deletions KeyVaultExplorer/KeyVaultExplorer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,22 @@


<ItemGroup>
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.1.1" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.1.2" />
<PackageReference Include="Avalonia.Svg.Skia" Version="11.1.0" />
<PackageReference Include="DeviceId" Version="6.7.0" />
<PackageReference Include="FluentAvaloniaUI" Version="2.1.0" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.1" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0-preview.6.24327.7" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.0-preview.6.24327.4" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.0-preview.6.24327.7" />
<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.62.0" />
<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.63.0" />
<PackageReference Include="Azure.ResourceManager.KeyVault" Version="1.3.0" />
<PackageReference Include="Azure.Security.KeyVault.Certificates" Version="4.6.0" />
<PackageReference Include="Azure.Security.KeyVault.Keys" Version="4.6.0" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.6.0" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlcipher" Version="2.1.8" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlcipher" Version="2.1.9" />
</ItemGroup>


Expand Down
2 changes: 1 addition & 1 deletion KeyVaultExplorer/Models/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ public class AppSettings

[AllowedValues("Inline", "Overlay")]
public string SplitViewDisplayMode { get; set; } = "Inline";
public string PanePlacement { get; set; } = "Left";

public string PanePlacement { get; set; } = "Left";
}
4 changes: 2 additions & 2 deletions KeyVaultExplorer/Models/Constants.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using Microsoft.Identity.Client.Extensions.Msal;
using System;
using System.Collections.Generic;
using System.IO;

namespace KeyVaultExplorer.Models;

public static class Constants
{
// database password file name
public const string EncryptedSecretFileName = "keyvaultexplorerforazure_database_password.txt";

public const string KeychainSecretName = "keyvaultexplorerforazure_database_password";
public const string KeychainServiceName = "keyvaultexplorerforazure";
public const string ProtectedKeyFileName = "keyvaultexplorerforazure_database_key.bin";
Expand All @@ -31,7 +31,7 @@ public static class Constants

public static readonly string LocalAppDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\KeyVaultExplorerForAzure";

public static readonly string DatabaseFilePath = LocalAppDataFolder+ "\\KeyVaultExplorerForAzure.db";
public static readonly string DatabaseFilePath = LocalAppDataFolder + "\\KeyVaultExplorerForAzure.db";

public const string KeyChainServiceName = "keyvaultexplorerforazure_msal_service";
public const string KeyChainAccountName = "keyvaultexplorerforazure_msal_account";
Expand Down
1 change: 1 addition & 0 deletions KeyVaultExplorer/Models/KeyVaultModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ public partial class KvResourceGroupModel : ObservableObject

public ObservableCollection<KeyVaultResource> KeyVaultResources { get; set; } = [];
public string ResourceGroupDisplayName { get; set; } = null!;

public ResourceGroupResource ResourceGroupResource { get; set; } = null!;
}
2 changes: 0 additions & 2 deletions KeyVaultExplorer/Models/KeyVaultValuesAmalgamation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public class KeyVaultContentsAmalgamation

public string TagValuesString => string.Join(", ", Tags?.Values ?? []);


private string? GetRelativeDateString(DateTimeOffset dateTimeOffset, bool isPast = false)
{
DateTimeOffset now = DateTimeOffset.Now;
Expand Down Expand Up @@ -79,7 +78,6 @@ public class KeyVaultContentsAmalgamation
(_, _) => $"{(isPast ? "" : "in ")}{years} {(years == 1 ? "year" : "years")}{(isPast ? " ago" : "")}"
};
}

}

public enum KeyVaultItemType
Expand Down
1 change: 0 additions & 1 deletion KeyVaultExplorer/Models/SubscriptionDataItems.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ public partial class SubscriptionDataItem : ObservableObject
[ObservableProperty]
private bool? isUpdated;


// this sets the default value to make sure we're not tracking initially loaded items, only changed.
partial void OnIsPinnedChanging(bool oldValue, bool newValue)
{
Expand Down
23 changes: 23 additions & 0 deletions KeyVaultExplorer/Resources/PercentageConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using Avalonia.Data.Converters;
using System.Globalization;

namespace KeyVaultExplorer.Resources;

public class PercentageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

Check warning on line 9 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build macOS Arm64

Nullability of reference types in type of parameter 'value' of 'object PercentageConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.Convert(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).

Check warning on line 9 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build macOS Arm64

Nullability of reference types in type of parameter 'parameter' of 'object PercentageConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.Convert(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).

Check warning on line 9 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build Windows

Nullability of reference types in type of parameter 'value' of 'object PercentageConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.Convert(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).

Check warning on line 9 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build Windows

Nullability of reference types in type of parameter 'parameter' of 'object PercentageConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.Convert(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).

Check warning on line 9 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build macOS intel

Nullability of reference types in type of parameter 'value' of 'object PercentageConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.Convert(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).

Check warning on line 9 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build macOS intel

Nullability of reference types in type of parameter 'parameter' of 'object PercentageConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.Convert(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).
{
if (value is double width)
{
var calculatedWidth = width * 0.25;
return calculatedWidth < 325 ? 325 : calculatedWidth;
}
return value;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

Check warning on line 19 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build macOS Arm64

Nullability of reference types in type of parameter 'value' of 'object PercentageConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).

Check warning on line 19 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build macOS Arm64

Nullability of reference types in type of parameter 'parameter' of 'object PercentageConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).

Check warning on line 19 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build Windows

Nullability of reference types in type of parameter 'value' of 'object PercentageConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).

Check warning on line 19 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build Windows

Nullability of reference types in type of parameter 'parameter' of 'object PercentageConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).

Check warning on line 19 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build macOS intel

Nullability of reference types in type of parameter 'value' of 'object PercentageConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).

Check warning on line 19 in KeyVaultExplorer/Resources/PercentageConverter.cs

View workflow job for this annotation

GitHub Actions / Build macOS intel

Nullability of reference types in type of parameter 'parameter' of 'object PercentageConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)' doesn't match implicitly implemented member 'object? IValueConverter.ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)' (possibly because of nullability attributes).
{
throw new NotImplementedException();
}
}
6 changes: 5 additions & 1 deletion KeyVaultExplorer/Services/AuthService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -22,6 +21,9 @@ public class AuthService

public string TenantName { get; private set; }

public string TenantId { get; private set; }


public IAccount Account { get; private set; }

public AuthService()
Expand Down Expand Up @@ -64,6 +66,7 @@ public async Task<AuthenticationResult> LoginAsync(CancellationToken cancellatio

IsAuthenticated = true;
TenantName = authenticationResult.Account.Username.Split("@").TakeLast(1).Single();
TenantId = authenticationResult.TenantId;
AuthenticatedUserClaims = new AuthenticatedUserClaims()
{
Username = authenticationResult.Account.Username,
Expand Down Expand Up @@ -101,6 +104,7 @@ public async Task<AuthenticationResult> RefreshTokenAsync(CancellationToken canc
authenticationResult = await authenticationClient.AcquireTokenSilent(Constants.Scopes, accounts.FirstOrDefault()).WithForceRefresh(true).ExecuteAsync();
IsAuthenticated = true;
TenantName = Account.Username.Split("@").TakeLast(1).Single();
TenantId = authenticationResult.TenantId;
AuthenticatedUserClaims = new AuthenticatedUserClaims()
{
Username = authenticationResult.Account.Username,
Expand Down
12 changes: 5 additions & 7 deletions KeyVaultExplorer/Services/DatabaseEncryptedPasswordManager.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DeviceId;
using KeyVaultExplorer.Models;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using DeviceId;
using KeyVaultExplorer.Models;

namespace KeyVaultExplorer.Services;

Expand Down Expand Up @@ -106,6 +103,7 @@ private static byte[] GetMachineEntropy()
string deviceId = new DeviceIdBuilder().AddMachineName().AddOsVersion().AddFileToken(Path.Combine(Constants.LocalAppDataFolder, Constants.DeviceFileTokenName)).ToString();
return deviceId.ToByteArray();
}

private static byte[] GetProtectedKey()
{
if (OperatingSystem.IsWindows())
Expand Down
2 changes: 1 addition & 1 deletion KeyVaultExplorer/Services/MacOSKeyChainService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ public static string GetPassword(string serviceName, string accountName)
}
}


public static async Task<string> GetPasswordAsync(string serviceName, string accountName)
{
return await Task.Run(() => GetPassword(serviceName, accountName));
}

public static async void SetPasswordAsync(string serviceName, string accountName, string password)
{
await Task.Run(() => SaveToKeychain(serviceName, accountName, password));
Expand Down
6 changes: 4 additions & 2 deletions KeyVaultExplorer/Services/ServiceCollectionExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

namespace KeyVaultExplorer.Services;

public static class ServiceCollectionExtensions {
public static void AddCommonServices(this IServiceCollection collection) {
public static class ServiceCollectionExtensions
{
public static void AddCommonServices(this IServiceCollection collection)
{
collection.AddMemoryCache();
collection.AddSingleton<AuthService>();
collection.AddSingleton<VaultService>();
Expand Down
Loading

0 comments on commit eabf35e

Please sign in to comment.