Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maintenance release #74

Merged
merged 6 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
{
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)
{
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)
{
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)
{
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