From b29fd8c2d70c1e8348a40e93a0bd0578967da4c6 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Thu, 15 Nov 2018 08:45:17 +0100 Subject: [PATCH] SEBWIN-221: Implemented basic gzip decompression & binary format detection. The browser is now automatically started after client initialization. --- .../BrowserApplicationController.cs | 5 + SafeExamBrowser.Client/ClientController.cs | 7 ++ .../Compression/GZipCompressor.cs | 116 +++++++++++++++++ .../ConfigurationRepository.cs | 40 ++---- .../DataFormats/BinaryFormat.cs | 119 ++++++++++++++++++ .../DataFormats/DefaultFormat.cs | 35 ------ .../ResourceLoaders/FileResourceLoader.cs | 6 +- .../ResourceLoaders/NetworkResourceLoader.cs | 8 +- .../SafeExamBrowser.Configuration.csproj | 3 +- .../Configuration/IDataCompressor.cs | 38 ++++++ .../Configuration/Settings/Settings.cs | 4 + .../Core/IApplicationController.cs | 5 + .../SafeExamBrowser.Contracts.csproj | 1 + .../Operations/ConfigurationOperationTests.cs | 4 +- SafeExamBrowser.Runtime/CompositionRoot.cs | 8 +- .../Operations/ConfigurationOperation.cs | 39 +++--- 16 files changed, 346 insertions(+), 92 deletions(-) create mode 100644 SafeExamBrowser.Configuration/Compression/GZipCompressor.cs create mode 100644 SafeExamBrowser.Configuration/DataFormats/BinaryFormat.cs delete mode 100644 SafeExamBrowser.Configuration/DataFormats/DefaultFormat.cs create mode 100644 SafeExamBrowser.Contracts/Configuration/IDataCompressor.cs diff --git a/SafeExamBrowser.Browser/BrowserApplicationController.cs b/SafeExamBrowser.Browser/BrowserApplicationController.cs index fc6e54c8..063c9f59 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationController.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationController.cs @@ -69,6 +69,11 @@ namespace SafeExamBrowser.Browser this.button.Clicked += Button_OnClick; } + public void Start() + { + CreateNewInstance(); + } + public void Terminate() { foreach (var instance in instances) diff --git a/SafeExamBrowser.Client/ClientController.cs b/SafeExamBrowser.Client/ClientController.cs index 3478a4a8..a1675a2c 100644 --- a/SafeExamBrowser.Client/ClientController.cs +++ b/SafeExamBrowser.Client/ClientController.cs @@ -105,6 +105,7 @@ namespace SafeExamBrowser.Client if (success) { RegisterEvents(); + StartBrowser(); var communication = runtime.InformClientReady(); @@ -182,6 +183,12 @@ namespace SafeExamBrowser.Client windowMonitor.WindowChanged -= WindowMonitor_WindowChanged; } + private void StartBrowser() + { + logger.Info("Starting browser application..."); + Browser.Start(); + } + private void DisplayMonitor_DisplaySettingsChanged() { logger.Info("Reinitializing working area..."); diff --git a/SafeExamBrowser.Configuration/Compression/GZipCompressor.cs b/SafeExamBrowser.Configuration/Compression/GZipCompressor.cs new file mode 100644 index 00000000..43d09b93 --- /dev/null +++ b/SafeExamBrowser.Configuration/Compression/GZipCompressor.cs @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2018 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; +using System.IO; +using System.IO.Compression; +using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.Logging; + +namespace SafeExamBrowser.Configuration.Compression +{ + /// + /// Data compression using the GNU-Zip format (see https://en.wikipedia.org/wiki/Gzip). + /// + public class GZipCompressor : IDataCompressor + { + private const int ID1 = 0x1F; + private const int ID2 = 0x8B; + private const int CM = 8; + private const int FOOTER_LENGTH = 8; + private const int HEADER_LENGTH = 10; + + private ILogger logger; + + public GZipCompressor(ILogger logger) + { + this.logger = logger; + } + + public Stream Compress(Stream data) + { + throw new NotImplementedException(); + } + + public Stream Decompress(Stream data) + { + var decompressed = new MemoryStream(); + + logger.Debug($"Starting decompression of '{data}' with {data.Length / 1000.0} KB data..."); + data.Seek(0, SeekOrigin.Begin); + + using (var stream = new GZipStream(data, CompressionMode.Decompress)) + { + var buffer = new byte[4096]; + var bytesRead = 0; + + do + { + bytesRead = stream.Read(buffer, 0, buffer.Length); + decompressed.Write(buffer, 0, bytesRead); + } while (bytesRead > 0); + } + + logger.Debug($"Successfully decompressed {decompressed.Length / 1000.0} KB data into '{decompressed}'."); + + return decompressed; + } + + /// + /// All gzip-compressed data has a 10-byte header and 8-byte footer. The header starts with two magic numbers (ID1 and ID2) and + /// the used compression method (CM), which normally denotes the DEFLATE algorithm. See https://tools.ietf.org/html/rfc1952 for + /// the original data format specification. + /// + public bool IsCompressed(Stream data) + { + try + { + var longEnough = data.Length > HEADER_LENGTH + FOOTER_LENGTH; + + data.Seek(0, SeekOrigin.Begin); + + if (longEnough) + { + var id1 = data.ReadByte(); + var id2 = data.ReadByte(); + var cm = data.ReadByte(); + var compressed = id1 == ID1 && id2 == ID2 && cm == CM; + + logger.Debug($"'{data}' is {(compressed ? string.Empty : "not ")}a gzip-compressed stream."); + + return compressed; + } + + logger.Debug($"'{data}' is not long enough ({data.Length} bytes) to be a gzip-compressed stream."); + } + catch (Exception e) + { + logger.Error($"Failed to check whether '{data}' with {data.Length / 1000.0} KB data is a gzip-compressed stream!", e); + } + + return false; + } + + public byte[] Peek(Stream data, int count) + { + logger.Debug($"Peeking {count} bytes from '{data}'..."); + data.Seek(0, SeekOrigin.Begin); + + using (var stream = new GZipStream(data, CompressionMode.Decompress)) + using (var decompressed = new MemoryStream()) + { + var buffer = new byte[count]; + var bytesRead = stream.Read(buffer, 0, buffer.Length); + + decompressed.Write(buffer, 0, bytesRead); + + return decompressed.ToArray(); + } + } + } +} diff --git a/SafeExamBrowser.Configuration/ConfigurationRepository.cs b/SafeExamBrowser.Configuration/ConfigurationRepository.cs index 4d615f65..141be2c6 100644 --- a/SafeExamBrowser.Configuration/ConfigurationRepository.cs +++ b/SafeExamBrowser.Configuration/ConfigurationRepository.cs @@ -9,7 +9,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.IO.Compression; using System.Linq; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration.Settings; @@ -133,12 +132,15 @@ namespace SafeExamBrowser.Configuration { var status = TryLoadData(resource, out Stream data); - switch (status) + using (data) { - case LoadStatus.LoadWithBrowser: - return HandleBrowserResource(resource, out settings); - case LoadStatus.Success: - return TryParseData(data, out settings, adminPassword, settingsPassword); + switch (status) + { + case LoadStatus.LoadWithBrowser: + return HandleBrowserResource(resource, out settings); + case LoadStatus.Success: + return TryParseData(data, out settings, adminPassword, settingsPassword); + } } return status; @@ -201,32 +203,6 @@ namespace SafeExamBrowser.Configuration return LoadStatus.Success; } - private byte[] Decompress(byte[] bytes) - { - try - { - var buffer = new byte[4096]; - - using (var stream = new GZipStream(new MemoryStream(bytes), CompressionMode.Decompress)) - using (var decompressed = new MemoryStream()) - { - var bytesRead = 0; - - do - { - bytesRead = stream.Read(buffer, 0, buffer.Length); - decompressed.Write(buffer, 0, bytesRead); - } while (bytesRead > 0); - - return decompressed.ToArray(); - } - } - catch (InvalidDataException) - { - return bytes; - } - } - private void UpdateAppConfig() { appConfig.ClientId = Guid.NewGuid(); diff --git a/SafeExamBrowser.Configuration/DataFormats/BinaryFormat.cs b/SafeExamBrowser.Configuration/DataFormats/BinaryFormat.cs new file mode 100644 index 00000000..ecbb1e3a --- /dev/null +++ b/SafeExamBrowser.Configuration/DataFormats/BinaryFormat.cs @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2018 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; +using System.IO; +using System.Text; +using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.Configuration.Settings; +using SafeExamBrowser.Contracts.Logging; + +namespace SafeExamBrowser.Configuration.DataFormats +{ + public class BinaryFormat : IDataFormat + { + private const int PREFIX_LENGTH = 4; + + private IDataCompressor compressor; + private ILogger logger; + + public BinaryFormat(IDataCompressor compressor, ILogger logger) + { + this.compressor = compressor; + this.logger = logger; + } + + public bool CanParse(Stream data) + { + try + { + var longEnough = data.Length > PREFIX_LENGTH; + + if (longEnough) + { + var prefix = ParsePrefix(data); + var success = TryDetermineFormat(prefix, out DataFormat format); + + logger.Debug($"'{data}' starting with '{prefix}' does {(success ? string.Empty : "not ")}match the binary format."); + + return success; + } + + logger.Debug($"'{data}' is not long enough ({data.Length} bytes) to match the binary format."); + } + catch (Exception e) + { + logger.Error($"Failed to determine whether '{data}' with {data.Length / 1000.0} KB data matches the binary format!", e); + } + + return false; + } + + public LoadStatus TryParse(Stream data, out Settings settings, string adminPassword = null, string settingsPassword = null) + { + settings = new Settings(); + settings.Browser.AllowAddressBar = true; + settings.Browser.StartUrl = "www.duckduckgo.com"; + settings.Browser.AllowConfigurationDownloads = true; + + return LoadStatus.Success; + } + + private string ParsePrefix(Stream data) + { + var prefixData = new byte[PREFIX_LENGTH]; + + if (compressor.IsCompressed(data)) + { + prefixData = compressor.Peek(data, PREFIX_LENGTH); + } + else + { + data.Seek(0, SeekOrigin.Begin); + data.Read(prefixData, 0, PREFIX_LENGTH); + } + + return Encoding.UTF8.GetString(prefixData); + } + + private bool TryDetermineFormat(string prefix, out DataFormat format) + { + format = default(DataFormat); + + switch (prefix) + { + case "pswd": + format = DataFormat.Password; + return true; + case "pwcc": + format = DataFormat.PasswordForConfigureClient; + return true; + case "plnd": + format = DataFormat.PlainData; + return true; + case "pkhs": + format = DataFormat.PublicKeyHash; + return true; + case "phsk": + format = DataFormat.PublicKeyHashWithSymmetricKey; + return true; + } + + return false; + } + + private enum DataFormat + { + Password = 1, + PasswordForConfigureClient, + PlainData, + PublicKeyHash, + PublicKeyHashWithSymmetricKey + } + } +} diff --git a/SafeExamBrowser.Configuration/DataFormats/DefaultFormat.cs b/SafeExamBrowser.Configuration/DataFormats/DefaultFormat.cs deleted file mode 100644 index 44826da7..00000000 --- a/SafeExamBrowser.Configuration/DataFormats/DefaultFormat.cs +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018 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.Contracts.Configuration; -using SafeExamBrowser.Contracts.Configuration.Settings; -using SafeExamBrowser.Contracts.Logging; - -namespace SafeExamBrowser.Configuration.DataFormats -{ - public class DefaultFormat : IDataFormat - { - private ILogger logger; - - public DefaultFormat(ILogger logger) - { - this.logger = logger; - } - - public bool CanParse(Stream data) - { - return false; - } - - public LoadStatus TryParse(Stream data, out Settings settings, string adminPassword = null, string settingsPassword = null) - { - throw new System.NotImplementedException(); - } - } -} diff --git a/SafeExamBrowser.Configuration/ResourceLoaders/FileResourceLoader.cs b/SafeExamBrowser.Configuration/ResourceLoaders/FileResourceLoader.cs index b731a554..177514e5 100644 --- a/SafeExamBrowser.Configuration/ResourceLoaders/FileResourceLoader.cs +++ b/SafeExamBrowser.Configuration/ResourceLoaders/FileResourceLoader.cs @@ -24,7 +24,7 @@ namespace SafeExamBrowser.Configuration.ResourceLoaders public bool CanLoad(Uri resource) { - var exists = resource.IsFile && File.Exists(resource.AbsolutePath); + var exists = resource.IsFile && File.Exists(resource.LocalPath); if (exists) { @@ -41,8 +41,8 @@ namespace SafeExamBrowser.Configuration.ResourceLoaders public LoadStatus TryLoad(Uri resource, out Stream data) { logger.Debug($"Loading data from '{resource}'..."); - data = new FileStream(resource.AbsolutePath, FileMode.Open, FileAccess.Read); - logger.Debug($"Created {data} for {data.Length / 1000.0} KB data in '{resource}'."); + data = new FileStream(resource.LocalPath, FileMode.Open, FileAccess.Read); + logger.Debug($"Created '{data}' for {data.Length / 1000.0} KB data in '{resource}'."); return LoadStatus.Success; } diff --git a/SafeExamBrowser.Configuration/ResourceLoaders/NetworkResourceLoader.cs b/SafeExamBrowser.Configuration/ResourceLoaders/NetworkResourceLoader.cs index e5e3351c..20a544fa 100644 --- a/SafeExamBrowser.Configuration/ResourceLoaders/NetworkResourceLoader.cs +++ b/SafeExamBrowser.Configuration/ResourceLoaders/NetworkResourceLoader.cs @@ -23,6 +23,9 @@ namespace SafeExamBrowser.Configuration.ResourceLoaders private AppConfig appConfig; private ILogger logger; + /// + /// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types. + /// private string[] SupportedContentTypes => new[] { MediaTypeNames.Application.Octet, @@ -77,7 +80,7 @@ namespace SafeExamBrowser.Configuration.ResourceLoaders logger.Debug($"Trying to extract response data..."); data = Extract(response.Content); - logger.Debug($"Created {data} for {data.Length / 1000.0} KB data of response body."); + logger.Debug($"Created '{data}' for {data.Length / 1000.0} KB data of response body."); return LoadStatus.Success; } @@ -137,6 +140,9 @@ namespace SafeExamBrowser.Configuration.ResourceLoaders return LoadStatus.LoadWithBrowser; } + /// + /// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type. + /// private bool HasHtmlContent(HttpResponseMessage response) { return response.Content.Headers.ContentType.MediaType == MediaTypeNames.Text.Html; diff --git a/SafeExamBrowser.Configuration/SafeExamBrowser.Configuration.csproj b/SafeExamBrowser.Configuration/SafeExamBrowser.Configuration.csproj index 17427d29..aa22a3c4 100644 --- a/SafeExamBrowser.Configuration/SafeExamBrowser.Configuration.csproj +++ b/SafeExamBrowser.Configuration/SafeExamBrowser.Configuration.csproj @@ -53,7 +53,8 @@ - + + diff --git a/SafeExamBrowser.Contracts/Configuration/IDataCompressor.cs b/SafeExamBrowser.Contracts/Configuration/IDataCompressor.cs new file mode 100644 index 00000000..b3767c65 --- /dev/null +++ b/SafeExamBrowser.Contracts/Configuration/IDataCompressor.cs @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 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; + +namespace SafeExamBrowser.Contracts.Configuration +{ + /// + /// Defines the functionality for data compression and decompression. + /// + public interface IDataCompressor + { + /// + /// Compresses the data from the given stream. + /// + Stream Compress(Stream data); + + /// + /// Decompresses the data from the given stream. + /// + Stream Decompress(Stream data); + + /// + /// Indicates whether the given stream holds compressed data. + /// + bool IsCompressed(Stream data); + + /// + /// Decompresses the specified number of bytes from the beginning of the given stream. + /// + byte[] Peek(Stream data, int count); + } +} diff --git a/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs b/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs index f6d00873..3d7ab19b 100644 --- a/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs +++ b/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs @@ -57,6 +57,10 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings Keyboard = new KeyboardSettings(); Mouse = new MouseSettings(); Taskbar = new TaskbarSettings(); + + // TODO: For version 3.0 alpha only, remove for final release! + ServicePolicy = ServicePolicy.Optional; + Taskbar.AllowApplicationLog = true; } } } diff --git a/SafeExamBrowser.Contracts/Core/IApplicationController.cs b/SafeExamBrowser.Contracts/Core/IApplicationController.cs index e8e9eff0..12d9fc20 100644 --- a/SafeExamBrowser.Contracts/Core/IApplicationController.cs +++ b/SafeExamBrowser.Contracts/Core/IApplicationController.cs @@ -25,6 +25,11 @@ namespace SafeExamBrowser.Contracts.Core /// void RegisterApplicationButton(IApplicationButton button); + /// + /// Starts the execution of the application. + /// + void Start(); + /// /// Performs any termination work, e.g. releasing of used resources. /// diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index e2819818..ec08d424 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -53,6 +53,7 @@ + diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs index 57281a9a..58d17b7f 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs @@ -381,7 +381,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations var location = Path.GetDirectoryName(GetType().Assembly.Location); var resource = new Uri(Path.Combine(location, nameof(Operations), "SettingsDummy.txt")); - sessionContext.ReconfigurationFilePath = resource.AbsolutePath; + sessionContext.ReconfigurationFilePath = resource.LocalPath; repository.Setup(r => r.TryLoadSettings(It.Is(u => u.Equals(resource)), out settings, null, null)).Returns(LoadStatus.Success); sut = new ConfigurationOperation(null, repository.Object, logger.Object, sessionContext); @@ -408,7 +408,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations repository.Verify(r => r.TryLoadSettings(It.Is(u => u.Equals(resource)), out settings, null, null), Times.Never); Assert.AreEqual(OperationResult.Failed, result); - sessionContext.ReconfigurationFilePath = resource.AbsolutePath; + sessionContext.ReconfigurationFilePath = resource.LocalPath; result = sut.Repeat(); repository.Verify(r => r.TryLoadSettings(It.Is(u => u.Equals(resource)), out settings, null, null), Times.Never); diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index 1f9639be..195d0ede 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -13,6 +13,7 @@ using System.Reflection; using SafeExamBrowser.Communication.Hosts; using SafeExamBrowser.Communication.Proxies; using SafeExamBrowser.Configuration; +using SafeExamBrowser.Configuration.Compression; using SafeExamBrowser.Configuration.DataFormats; using SafeExamBrowser.Configuration.ResourceLoaders; using SafeExamBrowser.Contracts.Configuration; @@ -112,12 +113,13 @@ namespace SafeExamBrowser.Runtime var programCopyright = executable.GetCustomAttribute().Copyright; var programTitle = executable.GetCustomAttribute().Title; var programVersion = executable.GetCustomAttribute().InformationalVersion; - var moduleLogger = new ModuleLogger(logger, nameof(ConfigurationRepository)); + var compressor = new GZipCompressor(new ModuleLogger(logger, nameof(GZipCompressor))); + var repositoryLogger = new ModuleLogger(logger, nameof(ConfigurationRepository)); - configuration = new ConfigurationRepository(moduleLogger, executable.Location, programCopyright, programTitle, programVersion); + configuration = new ConfigurationRepository(repositoryLogger, executable.Location, programCopyright, programTitle, programVersion); appConfig = configuration.InitializeAppConfig(); - configuration.Register(new DefaultFormat(new ModuleLogger(logger, nameof(DefaultFormat)))); + configuration.Register(new BinaryFormat(compressor, new ModuleLogger(logger, nameof(BinaryFormat)))); configuration.Register(new XmlFormat(new ModuleLogger(logger, nameof(XmlFormat)))); configuration.Register(new FileResourceLoader(new ModuleLogger(logger, nameof(FileResourceLoader)))); configuration.Register(new NetworkResourceLoader(appConfig, new ModuleLogger(logger, nameof(NetworkResourceLoader)))); diff --git a/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs b/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs index 208fd308..858f1bf0 100644 --- a/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs @@ -44,22 +44,22 @@ namespace SafeExamBrowser.Runtime.Operations logger.Info("Initializing application configuration..."); StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration); + var result = OperationResult.Failed; var isValidUri = TryInitializeSettingsUri(out Uri uri); if (isValidUri) { - var result = LoadSettings(uri); - + result = LoadSettings(uri); HandleClientConfiguration(ref result, uri); - LogOperationResult(result); - - return result; + } + else + { + result = LoadDefaultSettings(); } - logger.Info("No valid configuration resource specified nor found in PROGRAMDATA or APPDATA - loading default settings..."); - Context.Next.Settings = configuration.LoadDefaultSettings(); + LogOperationResult(result); - return OperationResult.Success; + return result; } public override OperationResult Repeat() @@ -67,20 +67,21 @@ namespace SafeExamBrowser.Runtime.Operations logger.Info("Initializing new application configuration..."); StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration); + var result = OperationResult.Failed; var isValidUri = TryValidateSettingsUri(Context.ReconfigurationFilePath, out Uri uri); if (isValidUri) { - var result = LoadSettings(uri); - - LogOperationResult(result); - - return result; + result = LoadSettings(uri); + } + else + { + logger.Warn($"The resource specified for reconfiguration does not exist or is not valid!"); } - logger.Warn($"The resource specified for reconfiguration does not exist or is not valid!"); + LogOperationResult(result); - return OperationResult.Failed; + return result; } public override OperationResult Revert() @@ -88,6 +89,14 @@ namespace SafeExamBrowser.Runtime.Operations return OperationResult.Success; } + private OperationResult LoadDefaultSettings() + { + logger.Info("No valid configuration resource specified nor found in PROGRAMDATA or APPDATA - loading default settings..."); + Context.Next.Settings = configuration.LoadDefaultSettings(); + + return OperationResult.Success; + } + private OperationResult LoadSettings(Uri uri) { var adminPassword = default(string);