SEBWIN-308: Ensured temporary configuration file is deleted after reconfiguration.

This commit is contained in:
dbuechel 2020-01-29 10:07:28 +01:00
parent c3a2fb38ce
commit cf2a74f6ce
12 changed files with 163 additions and 61 deletions

View file

@ -535,7 +535,7 @@ namespace SafeExamBrowser.Client.UnitTests
var filename = "filepath.seb";
var args = new DownloadEventArgs();
appConfig.DownloadDirectory = @"C:\Folder\Does\Not\Exist";
appConfig.TemporaryDirectory = @"C:\Folder\Does\Not\Exist";
settings.ConfigurationMode = ConfigurationMode.ConfigureClient;
messageBox.Setup(m => m.Show(
It.IsAny<TextKey>(),
@ -562,7 +562,7 @@ namespace SafeExamBrowser.Client.UnitTests
var filename = "filepath.seb";
var args = new DownloadEventArgs();
appConfig.DownloadDirectory = @"C:\Folder\Does\Not\Exist";
appConfig.TemporaryDirectory = @"C:\Folder\Does\Not\Exist";
settings.ConfigurationMode = ConfigurationMode.ConfigureClient;
messageBox.Setup(m => m.Show(
It.IsAny<TextKey>(),
@ -586,7 +586,7 @@ namespace SafeExamBrowser.Client.UnitTests
var filename = "filepath.seb";
var args = new DownloadEventArgs();
appConfig.DownloadDirectory = @"C:\Folder\Does\Not\Exist";
appConfig.TemporaryDirectory = @"C:\Folder\Does\Not\Exist";
settings.ConfigurationMode = ConfigurationMode.ConfigureClient;
messageBox.Setup(m => m.Show(
It.IsAny<TextKey>(),

View file

@ -337,7 +337,7 @@ namespace SafeExamBrowser.Client
{
args.AllowDownload = true;
args.Callback = Browser_ConfigurationDownloadFinished;
args.DownloadPath = Path.Combine(context.AppConfig.DownloadDirectory, fileName);
args.DownloadPath = Path.Combine(context.AppConfig.TemporaryDirectory, fileName);
logger.Info($"Allowed download request for configuration file '{fileName}'.");
}
else

View file

@ -91,11 +91,6 @@ namespace SafeExamBrowser.Configuration.Contracts
/// </summary>
public string ConfigurationFileExtension { get; set; }
/// <summary>
/// The default directory for file downloads.
/// </summary>
public string DownloadDirectory { get; set; }
/// <summary>
/// The build version of the application.
/// </summary>
@ -161,6 +156,11 @@ namespace SafeExamBrowser.Configuration.Contracts
/// </summary>
public string ServiceLogFilePath { get; set; }
/// <summary>
/// The directory to be used for temporary application data.
/// </summary>
public string TemporaryDirectory { get; set; }
/// <summary>
/// Creates a shallow clone.
/// </summary>

View file

@ -68,7 +68,6 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
appConfig.ClientExecutablePath = Path.Combine(Path.GetDirectoryName(executablePath), $"{nameof(SafeExamBrowser)}.Client.exe");
appConfig.ClientLogFilePath = Path.Combine(logFolder, $"{logFilePrefix}_Client.log");
appConfig.ConfigurationFileExtension = ".seb";
appConfig.DownloadDirectory = Path.Combine(appDataLocalFolder, "Downloads");
appConfig.ProgramBuildVersion = programBuild;
appConfig.ProgramCopyright = programCopyright;
appConfig.ProgramDataFilePath = Path.Combine(programDataFolder, DEFAULT_CONFIGURATION_NAME);
@ -82,6 +81,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
appConfig.ServiceAddress = $"{AppConfig.BASE_ADDRESS}/service";
appConfig.ServiceEventName = $@"Global\{nameof(SafeExamBrowser)}-{Guid.NewGuid()}";
appConfig.ServiceLogFilePath = Path.Combine(logFolder, $"{logFilePrefix}_Service.log");
appConfig.TemporaryDirectory = Path.Combine(appDataLocalFolder, "Temp");
return appConfig;
}
@ -123,8 +123,10 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
settings.Browser.AdditionalWindow.RelativeWidth = 50;
settings.Browser.AdditionalWindow.ShowReloadWarning = false;
settings.Browser.AllowConfigurationDownloads = true;
settings.Browser.AllowCustomDownloadLocation = false;
settings.Browser.AllowDownloads = true;
settings.Browser.AllowPageZoom = true;
settings.Browser.AllowUploads = true;
settings.Browser.MainWindow.AllowAddressBar = false;
settings.Browser.MainWindow.AllowBackwardNavigation = false;
settings.Browser.MainWindow.AllowDeveloperConsole = false;

View file

@ -18,6 +18,7 @@ using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Runtime.Operations;
using SafeExamBrowser.Runtime.Operations.Events;
using SafeExamBrowser.Settings;
using SafeExamBrowser.SystemComponents.Contracts;
namespace SafeExamBrowser.Runtime.UnitTests.Operations
{
@ -27,6 +28,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
private const string FILE_NAME = "SebClientSettings.seb";
private AppConfig appConfig;
private Mock<IFileSystem> fileSystem;
private Mock<IHashAlgorithm> hashAlgorithm;
private Mock<ILogger> logger;
private Mock<IConfigurationRepository> repository;
@ -38,6 +40,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Initialize()
{
appConfig = new AppConfig();
fileSystem = new Mock<IFileSystem>();
hashAlgorithm = new Mock<IHashAlgorithm>();
logger = new Mock<ILogger>();
repository = new Mock<IConfigurationRepository>();
@ -65,7 +68,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Perform();
var resource = new Uri(url);
@ -83,7 +86,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
var sut = new ConfigurationOperation(null, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Perform();
repository.Verify(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(location)), out settings, It.IsAny<PasswordParameters>()), Times.Once);
@ -99,7 +102,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
appConfig.AppDataFilePath = location;
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
var sut = new ConfigurationOperation(null, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Perform();
repository.Verify(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(location)), out settings, It.IsAny<PasswordParameters>()), Times.Once);
@ -115,7 +118,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
nextSession.Settings = settings;
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.LoadWithBrowser);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Perform();
Assert.AreEqual(url, settings.Browser.StartUrl);
@ -129,7 +132,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.LoadDefaultSettings()).Returns(defaultSettings);
var sut = new ConfigurationOperation(null, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Perform();
repository.Verify(r => r.LoadDefaultSettings(), Times.Once);
@ -149,7 +152,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
repository.Setup(r => r.ConfigureClientWith(It.IsAny<Uri>(), It.IsAny<PasswordParameters>())).Returns(SaveStatus.Success);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is ConfigurationCompletedEventArgs c)
@ -173,7 +176,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
repository.Setup(r => r.ConfigureClientWith(It.IsAny<Uri>(), It.IsAny<PasswordParameters>())).Returns(SaveStatus.Success);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is ConfigurationCompletedEventArgs c)
@ -198,7 +201,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
repository.Setup(r => r.ConfigureClientWith(It.IsAny<Uri>(), It.IsAny<PasswordParameters>())).Returns(SaveStatus.UnexpectedError);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is ClientConfigurationErrorMessageArgs)
@ -221,7 +224,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
settings.ConfigurationMode = ConfigurationMode.Exam;
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
var sut = new ConfigurationOperation(null, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is ConfigurationCompletedEventArgs c)
@ -243,14 +246,14 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.LoadDefaultSettings()).Returns(defaultSettings);
var sut = new ConfigurationOperation(null, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
result = sut.Perform();
repository.Verify(r => r.LoadDefaultSettings(), Times.Once);
Assert.AreEqual(OperationResult.Success, result);
Assert.AreSame(defaultSettings, nextSession.Settings);
sut = new ConfigurationOperation(new string[] { }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut = new ConfigurationOperation(new string[] { }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
result = sut.Perform();
repository.Verify(r => r.LoadDefaultSettings(), Times.Exactly(2));
@ -262,7 +265,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Perform_MustNotFailWithInvalidUri()
{
var uri = @"an/invalid\uri.'*%yolo/()你好";
var sut = new ConfigurationOperation(new[] { "blubb.exe", uri }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", uri }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Perform();
Assert.AreEqual(OperationResult.Success, result);
@ -284,7 +287,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.Is<Uri>(u => u.LocalPath.Contains(FILE_NAME)), out localSettings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
nextSession.Settings = settings;
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is PasswordRequiredEventArgs p && p.Purpose == PasswordRequestPurpose.LocalAdministrator)
@ -309,7 +312,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.PasswordNeeded);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is PasswordRequiredEventArgs p && p.Purpose == PasswordRequestPurpose.Settings)
@ -343,7 +346,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.Is<Uri>(u => u.AbsoluteUri == url), out nextSettings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
repository.Setup(r => r.ConfigureClientWith(It.IsAny<Uri>(), It.IsAny<PasswordParameters>())).Returns(SaveStatus.Success);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is PasswordRequiredEventArgs p && p.Purpose == PasswordRequestPurpose.LocalAdministrator)
@ -374,7 +377,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.Is<Uri>(u => u.AbsoluteUri == url), out nextSettings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
repository.Setup(r => r.ConfigureClientWith(It.IsAny<Uri>(), It.IsAny<PasswordParameters>())).Returns(SaveStatus.Success);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is PasswordRequiredEventArgs)
@ -400,7 +403,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.PasswordNeeded);
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.Is<PasswordParameters>(p => p.Password == password))).Returns(LoadStatus.Success);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is PasswordRequiredEventArgs p)
@ -437,7 +440,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.Is<PasswordParameters>(p => p.IsHash == true && p.Password == settings.Security.AdminPasswordHash)))
.Returns(LoadStatus.Success);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Perform();
repository.Verify(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.Is<PasswordParameters>(p => p.Password == settings.Security.AdminPasswordHash)), Times.AtLeastOnce);
@ -462,7 +465,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out currentSettings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
repository.Setup(r => r.TryLoadSettings(It.Is<Uri>(u => u.AbsoluteUri == url), out nextSettings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is PasswordRequiredEventArgs p && p.Purpose == PasswordRequestPurpose.LocalAdministrator)
@ -486,7 +489,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.PasswordNeeded);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(new[] { "blubb.exe", url }, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is PasswordRequiredEventArgs p)
@ -512,9 +515,10 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
sessionContext.ReconfigurationFilePath = resource.LocalPath;
repository.Setup(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(resource)), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
var sut = new ConfigurationOperation(null, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Repeat();
fileSystem.Verify(f => f.Delete(It.Is<string>(s => s == resource.LocalPath)), Times.Once);
repository.Verify(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(resource)), out settings, It.IsAny<PasswordParameters>()), Times.AtLeastOnce);
repository.Verify(r => r.ConfigureClientWith(It.Is<Uri>(u => u.Equals(resource)), It.IsAny<PasswordParameters>()), Times.Never);
@ -534,15 +538,45 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
repository.Setup(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(resource)), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
repository.Setup(r => r.ConfigureClientWith(It.Is<Uri>(u => u.Equals(resource)), It.IsAny<PasswordParameters>())).Returns(SaveStatus.Success);
var sut = new ConfigurationOperation(null, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Repeat();
fileSystem.Verify(f => f.Delete(It.Is<string>(s => s == resource.LocalPath)), Times.Once);
repository.Verify(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(resource)), out settings, It.IsAny<PasswordParameters>()), Times.AtLeastOnce);
repository.Verify(r => r.ConfigureClientWith(It.Is<Uri>(u => u.Equals(resource)), It.IsAny<PasswordParameters>()), Times.Once);
Assert.AreEqual(OperationResult.Success, result);
}
[TestMethod]
public void Repeat_MustDeleteTemporaryFileAfterClientConfiguration()
{
var currentSettings = new AppSettings();
var location = Path.GetDirectoryName(GetType().Assembly.Location);
var resource = new Uri(Path.Combine(location, nameof(Operations), "Testdata", FILE_NAME));
var settings = new AppSettings { ConfigurationMode = ConfigurationMode.ConfigureClient };
var delete = 0;
var configure = 0;
var order = 0;
currentSession.Settings = currentSettings;
sessionContext.ReconfigurationFilePath = resource.LocalPath;
fileSystem.Setup(f => f.Delete(It.IsAny<string>())).Callback(() => delete = ++order);
repository.Setup(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(resource)), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
repository.Setup(r => r.ConfigureClientWith(It.Is<Uri>(u => u.Equals(resource)), It.IsAny<PasswordParameters>())).Returns(SaveStatus.Success).Callback(() => configure = ++order);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Repeat();
fileSystem.Verify(f => f.Delete(It.Is<string>(s => s == resource.LocalPath)), Times.Once);
repository.Verify(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(resource)), out settings, It.IsAny<PasswordParameters>()), Times.AtLeastOnce);
repository.Verify(r => r.ConfigureClientWith(It.Is<Uri>(u => u.Equals(resource)), It.IsAny<PasswordParameters>()), Times.Once);
Assert.AreEqual(OperationResult.Success, result);
Assert.AreEqual(1, configure);
Assert.AreEqual(2, delete);
}
[TestMethod]
public void Repeat_MustFailWithInvalidUri()
{
@ -552,15 +586,17 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
sessionContext.ReconfigurationFilePath = null;
repository.Setup(r => r.TryLoadSettings(It.IsAny<Uri>(), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.Success);
var sut = new ConfigurationOperation(null, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Repeat();
fileSystem.Verify(f => f.Delete(It.Is<string>(s => s == resource.LocalPath)), Times.Never);
repository.Verify(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(resource)), out settings, It.IsAny<PasswordParameters>()), Times.Never);
Assert.AreEqual(OperationResult.Failed, result);
sessionContext.ReconfigurationFilePath = resource.LocalPath;
result = sut.Repeat();
fileSystem.Verify(f => f.Delete(It.Is<string>(s => s == resource.LocalPath)), Times.Never);
repository.Verify(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(resource)), out settings, It.IsAny<PasswordParameters>()), Times.Never);
Assert.AreEqual(OperationResult.Failed, result);
}
@ -577,7 +613,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
sessionContext.ReconfigurationFilePath = resource.LocalPath;
repository.Setup(r => r.TryLoadSettings(It.Is<Uri>(u => u.Equals(resource)), out settings, It.IsAny<PasswordParameters>())).Returns(LoadStatus.PasswordNeeded);
var sut = new ConfigurationOperation(null, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
sut.ActionRequired += args =>
{
if (args is PasswordRequiredEventArgs p)
@ -588,15 +624,17 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
var result = sut.Repeat();
fileSystem.Verify(f => f.Delete(It.Is<string>(s => s == resource.LocalPath)), Times.Once);
Assert.AreEqual(OperationResult.Aborted, result);
}
[TestMethod]
public void Revert_MustDoNothing()
{
var sut = new ConfigurationOperation(null, repository.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var sut = new ConfigurationOperation(null, repository.Object, fileSystem.Object, hashAlgorithm.Object, logger.Object, sessionContext);
var result = sut.Revert();
fileSystem.VerifyNoOtherCalls();
hashAlgorithm.VerifyNoOtherCalls();
repository.VerifyNoOtherCalls();

View file

@ -83,7 +83,7 @@ namespace SafeExamBrowser.Runtime
bootstrapOperations.Enqueue(new CommunicationHostOperation(runtimeHost, logger));
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost, sessionContext));
sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new HashAlgorithm(), logger, sessionContext));
sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new FileSystem(), new HashAlgorithm(), logger, sessionContext));
sessionOperations.Enqueue(new VirtualMachineOperation(vmDetector, logger, sessionContext));
sessionOperations.Enqueue(new ServiceOperation(logger, runtimeHost, serviceProxy, sessionContext, THIRTY_SECONDS, userInfo));
sessionOperations.Enqueue(new ClientTerminationOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, THIRTY_SECONDS));

View file

@ -17,6 +17,7 @@ using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Runtime.Operations.Events;
using SafeExamBrowser.Settings;
using SafeExamBrowser.SystemComponents.Contracts;
namespace SafeExamBrowser.Runtime.Operations
{
@ -24,6 +25,7 @@ namespace SafeExamBrowser.Runtime.Operations
{
private string[] commandLineArgs;
private IConfigurationRepository configuration;
private IFileSystem fileSystem;
private IHashAlgorithm hashAlgorithm;
private ILogger logger;
@ -36,12 +38,14 @@ namespace SafeExamBrowser.Runtime.Operations
public ConfigurationOperation(
string[] commandLineArgs,
IConfigurationRepository configuration,
IFileSystem fileSystem,
IHashAlgorithm hashAlgorithm,
ILogger logger,
SessionContext sessionContext) : base(sessionContext)
{
this.commandLineArgs = commandLineArgs;
this.configuration = configuration;
this.fileSystem = fileSystem;
this.hashAlgorithm = hashAlgorithm;
this.logger = logger;
}
@ -150,19 +154,27 @@ namespace SafeExamBrowser.Runtime.Operations
var currentPassword = Context.Current.Settings.Security.AdminPasswordHash;
var source = UriSource.Reconfiguration;
var status = TryLoadSettings(uri, source, out var passwordParams, out var settings, currentPassword);
var result = OperationResult.Failed;
if (status.HasValue)
{
return DetermineLoadResult(uri, source, settings, status.Value, passwordParams, currentPassword);
result = DetermineLoadResult(uri, source, settings, status.Value, passwordParams, currentPassword);
}
else
{
return OperationResult.Aborted;
result = OperationResult.Aborted;
}
fileSystem.Delete(uri.LocalPath);
logger.Info($"Deleted temporary configuration file '{uri}'.");
return result;
}
private OperationResult DetermineLoadResult(Uri uri, UriSource source, AppSettings settings, LoadStatus status, PasswordParameters passwordParams, string currentPassword = default(string))
{
var result = OperationResult.Failed;
if (status == LoadStatus.LoadWithBrowser || status == LoadStatus.Success)
{
var isNewConfiguration = source == UriSource.CommandLine || source == UriSource.Reconfiguration;
@ -171,20 +183,23 @@ namespace SafeExamBrowser.Runtime.Operations
if (status == LoadStatus.LoadWithBrowser)
{
return HandleBrowserResource(uri);
result = HandleBrowserResource(uri);
}
if (isNewConfiguration && settings.ConfigurationMode == ConfigurationMode.ConfigureClient)
else if (isNewConfiguration && settings.ConfigurationMode == ConfigurationMode.ConfigureClient)
{
return HandleClientConfiguration(uri, passwordParams, currentPassword);
result = HandleClientConfiguration(uri, passwordParams, currentPassword);
}
return OperationResult.Success;
else
{
result = OperationResult.Success;
}
}
else
{
ShowFailureMessage(status, uri);
}
ShowFailureMessage(status, uri);
return OperationResult.Failed;
return result;
}
private OperationResult HandleBrowserResource(Uri uri)
@ -199,23 +214,18 @@ namespace SafeExamBrowser.Runtime.Operations
{
var isFirstSession = Context.Current == null;
var success = TryConfigureClient(uri, passwordParams, currentPassword);
var result = OperationResult.Failed;
if (success == true)
if (!success.HasValue || (success == true && isFirstSession && AbortAfterClientConfiguration()))
{
if (isFirstSession && AbortAfterClientConfiguration())
{
return OperationResult.Aborted;
}
return OperationResult.Success;
result = OperationResult.Aborted;
}
else if (success == true)
{
result = OperationResult.Success;
}
if (!success.HasValue)
{
return OperationResult.Aborted;
}
return OperationResult.Failed;
return result;
}
private LoadStatus? TryLoadSettings(Uri uri, UriSource source, out PasswordParameters passwordParams, out AppSettings settings, string currentPassword = default(string))

View file

@ -11,7 +11,7 @@ using System;
namespace SafeExamBrowser.Settings.Browser
{
/// <summary>
/// Defines all settings for the browser engine.
/// Defines all settings for the integrated browser application.
/// </summary>
[Serializable]
public class BrowserSettings

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
namespace SafeExamBrowser.SystemComponents.Contracts
{
/// <summary>
/// Provides access to file system operations.
/// </summary>
public interface IFileSystem
{
/// <summary>
/// Deletes the item at the given path, if it exists. Directories will be completely deleted, including all subdirectories and files.
/// </summary>
void Delete(string path);
}
}

View file

@ -56,6 +56,7 @@
<ItemGroup>
<Compile Include="Audio\Events\VolumeChangedEventHandler.cs" />
<Compile Include="Audio\IAudio.cs" />
<Compile Include="IFileSystem.cs" />
<Compile Include="IVirtualMachineDetector.cs" />
<Compile Include="PowerSupply\Events\StatusChangedEventHandler.cs" />
<Compile Include="PowerSupply\IPowerSupply.cs" />

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.IO;
using SafeExamBrowser.SystemComponents.Contracts;
namespace SafeExamBrowser.SystemComponents
{
public class FileSystem : IFileSystem
{
public void Delete(string path)
{
if (File.Exists(path))
{
File.Delete(path);
}
if (Directory.Exists(path))
{
Directory.Delete(path, true);
}
}
}
}

View file

@ -64,6 +64,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Audio\Audio.cs" />
<Compile Include="FileSystem.cs" />
<Compile Include="Keyboard\KeyboardLayout.cs" />
<Compile Include="Keyboard\Keyboard.cs" />
<Compile Include="PowerSupply\PowerSupply.cs" />