refactor(securestore): remove password-based authentication in favor of key-file only

Simplify SecureStore by removing MasterKeyEnvVar and password-based methods, leaving only key-file authentication for better security practices.
This commit is contained in:
Joseph Doherty
2026-01-23 00:17:19 -05:00
parent 9c4a184233
commit 1b7bb26def
22 changed files with 101 additions and 1421 deletions
@@ -25,17 +25,6 @@ public class UnlockStoreDialogViewModelTests
Should.Throw<ArgumentNullException>(() => new UnlockStoreDialogViewModel(null!));
}
[Fact]
public void Constructor_DefaultsToUseKeyFile()
{
// Arrange & Act
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure");
// Assert
sut.UseKeyFile.ShouldBeTrue();
sut.UsePassword.ShouldBeFalse();
}
[Fact]
public void StorePath_IsReadOnly()
{
@@ -47,12 +36,11 @@ public class UnlockStoreDialogViewModelTests
}
[Fact]
public void KeyFilePath_WhenRequiredAndEmpty_IsValidReturnsFalse()
public void KeyFilePath_WhenEmpty_IsValidReturnsFalse()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UseKeyFile = true,
KeyFilePath = ""
};
@@ -61,12 +49,11 @@ public class UnlockStoreDialogViewModelTests
}
[Fact]
public void KeyFilePath_WhenRequiredAndEmpty_ValidationErrorReturnsKeyFilePathRequired()
public void KeyFilePath_WhenEmpty_ValidationErrorReturnsKeyFilePathRequired()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UseKeyFile = true,
KeyFilePath = ""
};
@@ -75,12 +62,11 @@ public class UnlockStoreDialogViewModelTests
}
[Fact]
public void KeyFilePath_WhenRequiredAndWhitespace_IsValidReturnsFalse()
public void KeyFilePath_WhenWhitespace_IsValidReturnsFalse()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UseKeyFile = true,
KeyFilePath = " "
};
@@ -90,12 +76,11 @@ public class UnlockStoreDialogViewModelTests
}
[Fact]
public void KeyFilePath_WhenRequiredAndFileDoesNotExist_IsValidReturnsFalse()
public void KeyFilePath_WhenFileDoesNotExist_IsValidReturnsFalse()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UseKeyFile = true,
KeyFilePath = "/nonexistent/path/to/key.key"
};
@@ -104,12 +89,11 @@ public class UnlockStoreDialogViewModelTests
}
[Fact]
public void KeyFilePath_WhenRequiredAndFileDoesNotExist_ValidationErrorReturnsKeyFileNotFound()
public void KeyFilePath_WhenFileDoesNotExist_ValidationErrorReturnsKeyFileNotFound()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UseKeyFile = true,
KeyFilePath = "/nonexistent/path/to/key.key"
};
@@ -117,110 +101,6 @@ public class UnlockStoreDialogViewModelTests
sut.ValidationError.ShouldBe(SecureStoreStrings.KeyFileNotFound);
}
[Fact]
public void Password_WhenRequiredAndEmpty_IsValidReturnsFalse()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UsePassword = true,
Password = ""
};
// Act & Assert
sut.IsValid.ShouldBeFalse();
}
[Fact]
public void Password_WhenRequiredAndEmpty_ValidationErrorReturnsPasswordRequired()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UsePassword = true,
Password = ""
};
// Act & Assert
sut.ValidationError.ShouldBe(SecureStoreStrings.PasswordRequired);
}
[Fact]
public void Password_WhenRequiredAndWhitespace_IsValidReturnsFalse()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UsePassword = true,
Password = " "
};
// Act & Assert
sut.IsValid.ShouldBeFalse();
sut.ValidationError.ShouldBe(SecureStoreStrings.PasswordRequired);
}
[Fact]
public void Password_WhenRequiredAndProvided_IsValidReturnsTrue()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UsePassword = true,
Password = "password123"
};
// Act & Assert
sut.IsValid.ShouldBeTrue();
sut.ValidationError.ShouldBeNull();
}
[Fact]
public void UseKeyFile_WhenSetToTrue_SetsUsePasswordToFalse()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UsePassword = true
};
// Act
sut.UseKeyFile = true;
// Assert
sut.UseKeyFile.ShouldBeTrue();
sut.UsePassword.ShouldBeFalse();
}
[Fact]
public void UsePassword_WhenSetToTrue_SetsUseKeyFileToFalse()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure")
{
UseKeyFile = true
};
// Act
sut.UsePassword = true;
// Assert
sut.UsePassword.ShouldBeTrue();
sut.UseKeyFile.ShouldBeFalse();
}
[Fact]
public void IsValid_WhenNeitherKeyFileNorPasswordSelected_ReturnsFalse()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure");
// Manually set both to false (shouldn't happen in UI, but test edge case)
sut.UseKeyFile = false;
// Act & Assert
sut.IsValid.ShouldBeFalse();
}
[Fact]
public void KeyFilePath_WhenChanged_RaisesPropertyChanged()
{
@@ -278,63 +158,6 @@ public class UnlockStoreDialogViewModelTests
validationErrorPropertyChangedRaised.ShouldBeTrue();
}
[Fact]
public void Password_WhenChanged_RaisesPropertyChanged()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure");
var propertyChangedRaised = false;
sut.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(UnlockStoreDialogViewModel.Password))
propertyChangedRaised = true;
};
// Act
sut.Password = "newpassword";
// Assert
propertyChangedRaised.ShouldBeTrue();
}
[Fact]
public void UseKeyFile_WhenChanged_RaisesPropertyChanged()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure") { UseKeyFile = false };
var propertyChangedRaised = false;
sut.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(UnlockStoreDialogViewModel.UseKeyFile))
propertyChangedRaised = true;
};
// Act
sut.UseKeyFile = true;
// Assert
propertyChangedRaised.ShouldBeTrue();
}
[Fact]
public void UsePassword_WhenChanged_RaisesPropertyChanged()
{
// Arrange
var sut = new UnlockStoreDialogViewModel("/path/to/store.secure");
var propertyChangedRaised = false;
sut.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(UnlockStoreDialogViewModel.UsePassword))
propertyChangedRaised = true;
};
// Act
sut.UsePassword = true;
// Assert
propertyChangedRaised.ShouldBeTrue();
}
[Fact]
public void BrowseKeyFilePathCommand_IsInitialized()
{