SEBWIN-221: Changed configuration file handling to support special case with resource URL as startup URL and switched to data stream instead of byte array.
This commit is contained in:
parent
902b0c2b3b
commit
1d58a84db8
13 changed files with 200 additions and 148 deletions
|
@ -11,7 +11,6 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using SafeExamBrowser.Configuration.DataFormats;
|
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
@ -132,29 +131,17 @@ namespace SafeExamBrowser.Configuration
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var resourceLoader = resourceLoaders.FirstOrDefault(l => l.CanLoad(resource));
|
var status = TryLoadData(resource, out Stream data);
|
||||||
|
|
||||||
if (resourceLoader != null)
|
switch (status)
|
||||||
{
|
{
|
||||||
var data = resourceLoader.Load(resource);
|
case LoadStatus.LoadWithBrowser:
|
||||||
var dataFormat = dataFormats.FirstOrDefault(f => f.CanParse(data));
|
return HandleBrowserResource(resource, out settings);
|
||||||
|
case LoadStatus.Success:
|
||||||
logger.Info($"Successfully loaded {data.Length / 1000.0} KB data from '{resource}' using {resourceLoader.GetType().Name}.");
|
return TryParseData(data, out settings, adminPassword, settingsPassword);
|
||||||
|
|
||||||
if (dataFormat is HtmlFormat)
|
|
||||||
{
|
|
||||||
return HandleHtml(resource, out settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dataFormat != null)
|
|
||||||
{
|
|
||||||
return dataFormat.TryParse(data, out settings, adminPassword, settingsPassword);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Warn($"No {(resourceLoader == null ? "resource loader" : "data format")} found for '{resource}'!");
|
return status;
|
||||||
|
|
||||||
return LoadStatus.NotSupported;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -164,13 +151,53 @@ namespace SafeExamBrowser.Configuration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoadStatus HandleHtml(Uri resource, out Settings settings)
|
private LoadStatus TryLoadData(Uri resource, out Stream data)
|
||||||
{
|
{
|
||||||
logger.Info($"Loaded data appears to be HTML, loading default settings and using '{resource}' as startup URL.");
|
var status = LoadStatus.NotSupported;
|
||||||
|
var resourceLoader = resourceLoaders.FirstOrDefault(l => l.CanLoad(resource));
|
||||||
|
|
||||||
|
data = default(Stream);
|
||||||
|
|
||||||
|
if (resourceLoader != null)
|
||||||
|
{
|
||||||
|
status = resourceLoader.TryLoad(resource, out data);
|
||||||
|
logger.Info($"Tried to load data from '{resource}' using {resourceLoader.GetType().Name} -> Result: {status}.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Warn($"No resource loader found for '{resource}'!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoadStatus TryParseData(Stream data, out Settings settings, string adminPassword, string settingsPassword)
|
||||||
|
{
|
||||||
|
var status = LoadStatus.NotSupported;
|
||||||
|
var dataFormat = dataFormats.FirstOrDefault(f => f.CanParse(data));
|
||||||
|
|
||||||
|
settings = default(Settings);
|
||||||
|
|
||||||
|
if (dataFormat != null)
|
||||||
|
{
|
||||||
|
status = dataFormat.TryParse(data, out settings, adminPassword, settingsPassword);
|
||||||
|
logger.Info($"Tried to parse data from '{data}' using {dataFormat.GetType().Name} -> Result: {status}.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Warn($"No data format found for '{data}'!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoadStatus HandleBrowserResource(Uri resource, out Settings settings)
|
||||||
|
{
|
||||||
settings = LoadDefaultSettings();
|
settings = LoadDefaultSettings();
|
||||||
settings.Browser.StartUrl = resource.AbsoluteUri;
|
settings.Browser.StartUrl = resource.AbsoluteUri;
|
||||||
|
|
||||||
|
logger.Info($"The resource needs authentication or is HTML data, loaded default settings with '{resource}' as startup URL.");
|
||||||
|
|
||||||
return LoadStatus.Success;
|
return LoadStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
@ -21,17 +22,14 @@ namespace SafeExamBrowser.Configuration.DataFormats
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanParse(byte[] data)
|
public bool CanParse(Stream data)
|
||||||
{
|
{
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoadStatus TryParse(byte[] data, out Settings settings, string adminPassword = null, string settingsPassword = null)
|
public LoadStatus TryParse(Stream data, out Settings settings, string adminPassword = null, string settingsPassword = null)
|
||||||
{
|
{
|
||||||
settings = new Settings();
|
throw new System.NotImplementedException();
|
||||||
settings.ServicePolicy = ServicePolicy.Optional;
|
|
||||||
|
|
||||||
return LoadStatus.Success;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +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 SafeExamBrowser.Contracts.Configuration;
|
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Configuration.DataFormats
|
|
||||||
{
|
|
||||||
public class HtmlFormat : IDataFormat
|
|
||||||
{
|
|
||||||
private ILogger logger;
|
|
||||||
|
|
||||||
public HtmlFormat(ILogger logger)
|
|
||||||
{
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanParse(byte[] data)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoadStatus TryParse(byte[] data, out Settings settings, string adminPassword = null, string settingsPassword = null)
|
|
||||||
{
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
@ -21,12 +22,12 @@ namespace SafeExamBrowser.Configuration.DataFormats
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanParse(byte[] data)
|
public bool CanParse(Stream data)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoadStatus TryParse(byte[] data, out Settings settings, string adminPassword = null, string settingsPassword = null)
|
public LoadStatus TryParse(Stream data, out Settings settings, string adminPassword = null, string settingsPassword = null)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,23 +24,27 @@ namespace SafeExamBrowser.Configuration.ResourceLoaders
|
||||||
|
|
||||||
public bool CanLoad(Uri resource)
|
public bool CanLoad(Uri resource)
|
||||||
{
|
{
|
||||||
if (resource.IsFile && File.Exists(resource.AbsolutePath))
|
var exists = resource.IsFile && File.Exists(resource.AbsolutePath);
|
||||||
|
|
||||||
|
if (exists)
|
||||||
{
|
{
|
||||||
logger.Debug($"Can load '{resource}' as it references an existing file.");
|
logger.Debug($"Can load '{resource}' as it references an existing file.");
|
||||||
|
}
|
||||||
return true;
|
else
|
||||||
|
{
|
||||||
|
logger.Debug($"Can't load '{resource}' since it isn't a file URI or no file exists at the specified path.");
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug($"Can't load '{resource}' since it isn't a file URI or no file exists at the specified path.");
|
return exists;
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Load(Uri resource)
|
public LoadStatus TryLoad(Uri resource, out Stream data)
|
||||||
{
|
{
|
||||||
logger.Debug($"Loading data from '{resource}'...");
|
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}'.");
|
||||||
|
|
||||||
return File.ReadAllBytes(resource.AbsolutePath);
|
return LoadStatus.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Net.Mime;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
@ -20,6 +23,12 @@ namespace SafeExamBrowser.Configuration.ResourceLoaders
|
||||||
private AppConfig appConfig;
|
private AppConfig appConfig;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
|
|
||||||
|
private string[] SupportedContentTypes => new[]
|
||||||
|
{
|
||||||
|
MediaTypeNames.Application.Octet,
|
||||||
|
MediaTypeNames.Text.Xml
|
||||||
|
};
|
||||||
|
|
||||||
private string[] SupportedSchemes => new[]
|
private string[] SupportedSchemes => new[]
|
||||||
{
|
{
|
||||||
appConfig.SebUriScheme,
|
appConfig.SebUriScheme,
|
||||||
|
@ -36,54 +45,41 @@ namespace SafeExamBrowser.Configuration.ResourceLoaders
|
||||||
|
|
||||||
public bool CanLoad(Uri resource)
|
public bool CanLoad(Uri resource)
|
||||||
{
|
{
|
||||||
if (SupportedSchemes.Contains(resource.Scheme) && IsAvailable(resource))
|
var available = SupportedSchemes.Contains(resource.Scheme) && IsAvailable(resource);
|
||||||
|
|
||||||
|
if (available)
|
||||||
{
|
{
|
||||||
logger.Debug($"Can load '{resource}' as it references an existing network resource.");
|
logger.Debug($"Can load '{resource}' as it references an existing network resource.");
|
||||||
|
}
|
||||||
return true;
|
else
|
||||||
|
{
|
||||||
|
logger.Debug($"Can't load '{resource}' since its URI scheme is not supported or the resource is unavailable.");
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug($"Can't load '{resource}' since its URI scheme is not supported or the resource is unavailable.");
|
return available;
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Load(Uri resource)
|
public LoadStatus TryLoad(Uri resource, out Stream data)
|
||||||
{
|
{
|
||||||
var uri = BuildUriFor(resource);
|
var uri = BuildUriFor(resource);
|
||||||
|
|
||||||
logger.Debug($"Downloading data from '{uri}'...");
|
logger.Debug($"Sending GET request for '{uri}'...");
|
||||||
|
|
||||||
var request = new HttpRequestMessage(HttpMethod.Get, uri);
|
var request = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||||
var response = Execute(request);
|
var response = Execute(request);
|
||||||
|
|
||||||
logger.Debug($"Sent GET request for '{uri}', received response '{(int) response.StatusCode} - {response.ReasonPhrase}'.");
|
logger.Debug($"Received response '{ToString(response)}'.");
|
||||||
|
|
||||||
var data = Extract(response.Content);
|
if (IsUnauthorized(response) || HasHtmlContent(response))
|
||||||
|
|
||||||
logger.Debug($"Extracted {data.Length / 1000.0} KB data from response.");
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsAvailable(Uri resource)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var uri = BuildUriFor(resource);
|
return HandleBrowserResource(response, out data);
|
||||||
var request = new HttpRequestMessage(HttpMethod.Head, uri);
|
|
||||||
var response = Execute(request);
|
|
||||||
|
|
||||||
logger.Debug($"Sent HEAD request for '{uri}', received response '{(int) response.StatusCode} - {response.ReasonPhrase}'.");
|
|
||||||
|
|
||||||
return response.IsSuccessStatusCode;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
logger.Error($"Failed to check availability of '{resource}'!", e);
|
|
||||||
|
|
||||||
return false;
|
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.");
|
||||||
|
|
||||||
|
return LoadStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Uri BuildUriFor(Uri resource)
|
private Uri BuildUriFor(Uri resource)
|
||||||
|
@ -94,6 +90,29 @@ namespace SafeExamBrowser.Configuration.ResourceLoaders
|
||||||
return builder.Uri;
|
return builder.Uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HttpResponseMessage Execute(HttpRequestMessage request)
|
||||||
|
{
|
||||||
|
var task = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
{
|
||||||
|
return await client.SendAsync(request);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return task.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream Extract(HttpContent content)
|
||||||
|
{
|
||||||
|
var task = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
return await content.ReadAsStreamAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
return task.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
private string GetSchemeFor(Uri resource)
|
private string GetSchemeFor(Uri resource)
|
||||||
{
|
{
|
||||||
if (resource.Scheme == appConfig.SebUriScheme)
|
if (resource.Scheme == appConfig.SebUriScheme)
|
||||||
|
@ -109,27 +128,52 @@ namespace SafeExamBrowser.Configuration.ResourceLoaders
|
||||||
return resource.Scheme;
|
return resource.Scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpResponseMessage Execute(HttpRequestMessage request)
|
private LoadStatus HandleBrowserResource(HttpResponseMessage response, out Stream data)
|
||||||
{
|
{
|
||||||
var task = Task.Run(async () =>
|
data = default(Stream);
|
||||||
{
|
|
||||||
using (var client = new HttpClient())
|
|
||||||
{
|
|
||||||
return await client.SendAsync(request);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return task.GetAwaiter().GetResult();
|
logger.Debug($"The {(IsUnauthorized(response) ? "resource needs authentication" : " response data is HTML")}.");
|
||||||
|
|
||||||
|
return LoadStatus.LoadWithBrowser;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] Extract(HttpContent content)
|
private bool HasHtmlContent(HttpResponseMessage response)
|
||||||
{
|
{
|
||||||
var task = Task.Run(async () =>
|
return response.Content.Headers.ContentType.MediaType == MediaTypeNames.Text.Html;
|
||||||
{
|
}
|
||||||
return await content.ReadAsByteArrayAsync();
|
|
||||||
});
|
|
||||||
|
|
||||||
return task.GetAwaiter().GetResult();
|
private bool IsAvailable(Uri resource)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var uri = BuildUriFor(resource);
|
||||||
|
|
||||||
|
logger.Debug($"Sending HEAD request for '{uri}'...");
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Head, uri);
|
||||||
|
var response = Execute(request);
|
||||||
|
var isAvailable = response.IsSuccessStatusCode || IsUnauthorized(response);
|
||||||
|
|
||||||
|
logger.Debug($"Received response '{ToString(response)}'.");
|
||||||
|
|
||||||
|
return isAvailable;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to check availability of '{resource}'!", e);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsUnauthorized(HttpResponseMessage response)
|
||||||
|
{
|
||||||
|
return response.StatusCode == HttpStatusCode.Unauthorized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ToString(HttpResponseMessage response)
|
||||||
|
{
|
||||||
|
return $"{(int)response.StatusCode} - {response.ReasonPhrase}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,6 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="DataFormats\DefaultFormat.cs" />
|
<Compile Include="DataFormats\DefaultFormat.cs" />
|
||||||
<Compile Include="DataFormats\HtmlFormat.cs" />
|
|
||||||
<Compile Include="DataFormats\XmlFormat.cs" />
|
<Compile Include="DataFormats\XmlFormat.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="ConfigurationRepository.cs" />
|
<Compile Include="ConfigurationRepository.cs" />
|
||||||
|
|
|
@ -31,12 +31,12 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
Settings.Settings LoadDefaultSettings();
|
Settings.Settings LoadDefaultSettings();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers the specified <see cref="IDataFormat"/> as option to parse configuration data.
|
/// Registers the specified <see cref="IDataFormat"/> as option to parse data from a configuration resource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Register(IDataFormat dataFormat);
|
void Register(IDataFormat dataFormat);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers the specified <see cref="IResourceLoader"/> as option to load configuration data.
|
/// Registers the specified <see cref="IResourceLoader"/> as option to load data from a configuration resource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Register(IResourceLoader resourceLoader);
|
void Register(IResourceLoader resourceLoader);
|
||||||
|
|
||||||
|
|
|
@ -6,21 +6,24 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Configuration
|
namespace SafeExamBrowser.Contracts.Configuration
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the data format for a configuration file.
|
/// Provides functionality to parse configuration data with a particular format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDataFormat
|
public interface IDataFormat
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates whether the given data complies with the required format.
|
/// Indicates whether the given data complies with the required format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool CanParse(byte[] data);
|
bool CanParse(Stream data);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to parse the given binary data.
|
/// Tries to parse the given data, using the optional passwords. As long as the result is not <see cref="LoadStatus.Success"/>,
|
||||||
|
/// the referenced settings may be <c>null</c> or in an undefinable state!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
LoadStatus TryParse(byte[] data, out Settings.Settings settings, string adminPassword = null, string settingsPassword = null);
|
LoadStatus TryParse(Stream data, out Settings.Settings settings, string adminPassword = null, string settingsPassword = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Configuration
|
namespace SafeExamBrowser.Contracts.Configuration
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads binary data from a particular resource.
|
/// Provides functionality to load configuration data from a particular resource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IResourceLoader
|
public interface IResourceLoader
|
||||||
{
|
{
|
||||||
|
@ -21,8 +22,8 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
bool CanLoad(Uri resource);
|
bool CanLoad(Uri resource);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads the binary data from the specified resource.
|
/// Tries to load the configuration data from the specified resource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
byte[] Load(Uri resource);
|
LoadStatus TryLoad(Uri resource, out Stream data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
namespace SafeExamBrowser.Contracts.Configuration
|
namespace SafeExamBrowser.Contracts.Configuration
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines all possible results of an attempt to load a configuration file.
|
/// Defines all possible results of an attempt to load a configuration resource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum LoadStatus
|
public enum LoadStatus
|
||||||
{
|
{
|
||||||
|
@ -19,10 +19,15 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
AdminPasswordNeeded = 1,
|
AdminPasswordNeeded = 1,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that a resource does not comply with the required data format.
|
/// Indicates that a resource does not comply with the declared data format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
InvalidData,
|
InvalidData,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that a resource needs to be loaded with the browser.
|
||||||
|
/// </summary>
|
||||||
|
LoadWithBrowser,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that a resource is not supported.
|
/// Indicates that a resource is not supported.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -118,7 +118,6 @@ namespace SafeExamBrowser.Runtime
|
||||||
appConfig = configuration.InitializeAppConfig();
|
appConfig = configuration.InitializeAppConfig();
|
||||||
|
|
||||||
configuration.Register(new DefaultFormat(new ModuleLogger(logger, nameof(DefaultFormat))));
|
configuration.Register(new DefaultFormat(new ModuleLogger(logger, nameof(DefaultFormat))));
|
||||||
configuration.Register(new HtmlFormat(new ModuleLogger(logger, nameof(HtmlFormat))));
|
|
||||||
configuration.Register(new XmlFormat(new ModuleLogger(logger, nameof(XmlFormat))));
|
configuration.Register(new XmlFormat(new ModuleLogger(logger, nameof(XmlFormat))));
|
||||||
configuration.Register(new FileResourceLoader(new ModuleLogger(logger, nameof(FileResourceLoader))));
|
configuration.Register(new FileResourceLoader(new ModuleLogger(logger, nameof(FileResourceLoader))));
|
||||||
configuration.Register(new NetworkResourceLoader(appConfig, new ModuleLogger(logger, nameof(NetworkResourceLoader))));
|
configuration.Register(new NetworkResourceLoader(appConfig, new ModuleLogger(logger, nameof(NetworkResourceLoader))));
|
||||||
|
|
|
@ -48,17 +48,15 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
if (isValidUri)
|
if (isValidUri)
|
||||||
{
|
{
|
||||||
logger.Info($"Attempting to load settings from '{uri}'...");
|
|
||||||
|
|
||||||
var result = LoadSettings(uri);
|
var result = LoadSettings(uri);
|
||||||
|
|
||||||
HandleClientConfiguration(ref result);
|
HandleClientConfiguration(ref result, uri);
|
||||||
LogOperationResult(result);
|
LogOperationResult(result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("No valid settings resource specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
|
logger.Info("No valid configuration resource specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
|
||||||
Context.Next.Settings = configuration.LoadDefaultSettings();
|
Context.Next.Settings = configuration.LoadDefaultSettings();
|
||||||
|
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
|
@ -73,8 +71,6 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
if (isValidUri)
|
if (isValidUri)
|
||||||
{
|
{
|
||||||
logger.Info($"Attempting to load settings from '{uri}'...");
|
|
||||||
|
|
||||||
var result = LoadSettings(uri);
|
var result = LoadSettings(uri);
|
||||||
|
|
||||||
LogOperationResult(result);
|
LogOperationResult(result);
|
||||||
|
@ -82,7 +78,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Warn($"The resource specified for reconfiguration does not exist or is not a file!");
|
logger.Warn($"The resource specified for reconfiguration does not exist or is not valid!");
|
||||||
|
|
||||||
return OperationResult.Failed;
|
return OperationResult.Failed;
|
||||||
}
|
}
|
||||||
|
@ -126,10 +122,17 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
if (status == LoadStatus.Success)
|
if (status == LoadStatus.Success)
|
||||||
{
|
{
|
||||||
Context.Next.Settings = settings;
|
Context.Next.Settings = settings;
|
||||||
|
}
|
||||||
return OperationResult.Success;
|
else
|
||||||
|
{
|
||||||
|
ShowFailureMessage(status, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return status == LoadStatus.Success ? OperationResult.Success : OperationResult.Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowFailureMessage(LoadStatus status, Uri uri)
|
||||||
|
{
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case LoadStatus.InvalidData:
|
case LoadStatus.InvalidData:
|
||||||
|
@ -142,8 +145,6 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
ActionRequired?.Invoke(new UnexpectedErrorMessageArgs(uri.ToString()));
|
ActionRequired?.Invoke(new UnexpectedErrorMessageArgs(uri.ToString()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OperationResult.Failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PasswordRequiredEventArgs TryGetPassword(LoadStatus status)
|
private PasswordRequiredEventArgs TryGetPassword(LoadStatus status)
|
||||||
|
@ -169,21 +170,21 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
{
|
{
|
||||||
path = commandLineArgs[1];
|
path = commandLineArgs[1];
|
||||||
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
||||||
logger.Info($"Found command-line argument for settings file: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}.");
|
logger.Info($"Found command-line argument for configuration resource: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isValidUri && File.Exists(programDataSettings))
|
if (!isValidUri && File.Exists(programDataSettings))
|
||||||
{
|
{
|
||||||
path = programDataSettings;
|
path = programDataSettings;
|
||||||
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
||||||
logger.Info($"Found settings file in PROGRAMDATA: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}.");
|
logger.Info($"Found configuration file in PROGRAMDATA: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isValidUri && File.Exists(appDataSettings))
|
if (!isValidUri && File.Exists(appDataSettings))
|
||||||
{
|
{
|
||||||
path = appDataSettings;
|
path = appDataSettings;
|
||||||
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
||||||
logger.Info($"Found settings file in APPDATA: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}.");
|
logger.Info($"Found configuration file in APPDATA: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return isValidUri;
|
return isValidUri;
|
||||||
|
@ -199,9 +200,13 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return isValidUri;
|
return isValidUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleClientConfiguration(ref OperationResult result)
|
private void HandleClientConfiguration(ref OperationResult result, Uri uri)
|
||||||
{
|
{
|
||||||
if (result == OperationResult.Success && Context.Next.Settings.ConfigurationMode == ConfigurationMode.ConfigureClient)
|
var configureMode = Context.Next.Settings?.ConfigurationMode == ConfigurationMode.ConfigureClient;
|
||||||
|
var loadWithBrowser = Context.Next.Settings?.Browser.StartUrl == uri.AbsoluteUri;
|
||||||
|
var successful = result == OperationResult.Success;
|
||||||
|
|
||||||
|
if (successful && configureMode && !loadWithBrowser)
|
||||||
{
|
{
|
||||||
var args = new ConfigurationCompletedEventArgs();
|
var args = new ConfigurationCompletedEventArgs();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue