SEBWIN-220: Scaffolding for new (re-)configuration procedure.
This commit is contained in:
parent
45dd741e4c
commit
50dcb7502a
54 changed files with 710 additions and 256 deletions
14
.editorconfig
Normal file
14
.editorconfig
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Defines coding style deviations from the Microsoft Minimum Recommended Rules ruleset, which is active per default in Visual Studio 2017
|
||||
# For more info, see https://editorconfig.org/ and https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = crlf
|
||||
|
||||
[*.cs]
|
||||
dotnet_style_object_initializer = false:none
|
||||
indent_style = tab
|
||||
|
||||
[*.xml]
|
||||
indent_style = space
|
|
@ -8,12 +8,10 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using CefSharp;
|
||||
using SafeExamBrowser.Browser.Handlers;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Browser;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
@ -24,30 +22,30 @@ using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.Browser
|
|||
|
||||
namespace SafeExamBrowser.Browser
|
||||
{
|
||||
public class BrowserApplicationController : IApplicationController
|
||||
public class BrowserApplicationController : IBrowserApplicationController
|
||||
{
|
||||
private IApplicationButton button;
|
||||
private IList<IApplicationInstance> instances = new List<IApplicationInstance>();
|
||||
private BrowserSettings settings;
|
||||
private IList<IApplicationInstance> instances;
|
||||
private ILogger logger;
|
||||
private IMessageBox messageBox;
|
||||
private IRuntimeProxy runtime;
|
||||
private RuntimeInfo runtimeInfo;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
private BrowserSettings settings;
|
||||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
|
||||
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||
|
||||
public BrowserApplicationController(
|
||||
BrowserSettings settings,
|
||||
RuntimeInfo runtimeInfo,
|
||||
ILogger logger,
|
||||
IMessageBox messageBox,
|
||||
IRuntimeProxy runtime,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.instances = new List<IApplicationInstance>();
|
||||
this.logger = logger;
|
||||
this.messageBox = messageBox;
|
||||
this.runtime = runtime;
|
||||
this.runtimeInfo = runtimeInfo;
|
||||
this.settings = settings;
|
||||
this.text = text;
|
||||
|
@ -84,15 +82,14 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
private void CreateNewInstance()
|
||||
{
|
||||
var instance = new BrowserApplicationInstance(settings, text, uiFactory, instances.Count == 0);
|
||||
var instance = new BrowserApplicationInstance(settings, runtimeInfo, text, uiFactory, instances.Count == 0);
|
||||
|
||||
instance.Initialize();
|
||||
instance.ConfigurationDetected += Instance_ConfigurationDetected;
|
||||
instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
|
||||
instance.Terminated += Instance_Terminated;
|
||||
|
||||
button.RegisterInstance(instance);
|
||||
instances.Add(instance);
|
||||
|
||||
instance.Window.Show();
|
||||
}
|
||||
|
||||
|
@ -124,36 +121,6 @@ namespace SafeExamBrowser.Browser
|
|||
}
|
||||
}
|
||||
|
||||
private void Instance_ConfigurationDetected(string url, CancelEventArgs args)
|
||||
{
|
||||
var result = messageBox.Show(TextKey.MessageBox_ReconfigurationQuestion, TextKey.MessageBox_ReconfigurationQuestionTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question);
|
||||
var reconfigure = result == MessageBoxResult.Yes;
|
||||
var allowed = false;
|
||||
|
||||
logger.Info($"Detected configuration request for '{url}'. The user chose to {(reconfigure ? "start" : "abort")} the reconfiguration.");
|
||||
|
||||
if (reconfigure)
|
||||
{
|
||||
try
|
||||
{
|
||||
allowed = runtime.RequestReconfiguration(url);
|
||||
logger.Info($"The runtime {(allowed ? "accepted" : "denied")} the reconfiguration request.");
|
||||
|
||||
if (!allowed)
|
||||
{
|
||||
messageBox.Show(TextKey.MessageBox_ReconfigurationDenied, TextKey.MessageBox_ReconfigurationDeniedTitle);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to communicate the reconfiguration request to the runtime!", e);
|
||||
messageBox.Show(TextKey.MessageBox_ReconfigurationError, TextKey.MessageBox_ReconfigurationErrorTitle, icon: MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
args.Cancel = !allowed;
|
||||
}
|
||||
|
||||
private void Instance_Terminated(Guid id)
|
||||
{
|
||||
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
using System;
|
||||
using SafeExamBrowser.Browser.Handlers;
|
||||
using SafeExamBrowser.Contracts.Browser;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
|
@ -22,6 +23,7 @@ namespace SafeExamBrowser.Browser
|
|||
private IBrowserControl control;
|
||||
private IBrowserWindow window;
|
||||
private bool isMainInstance;
|
||||
private RuntimeInfo runtimeInfo;
|
||||
private BrowserSettings settings;
|
||||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
|
@ -30,13 +32,19 @@ namespace SafeExamBrowser.Browser
|
|||
public string Name { get; private set; }
|
||||
public IWindow Window { get { return window; } }
|
||||
|
||||
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
|
||||
public event TerminatedEventHandler Terminated;
|
||||
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||
public event NameChangedEventHandler NameChanged;
|
||||
public event TerminatedEventHandler Terminated;
|
||||
|
||||
public BrowserApplicationInstance(BrowserSettings settings, IText text, IUserInterfaceFactory uiFactory, bool isMainInstance)
|
||||
public BrowserApplicationInstance(
|
||||
BrowserSettings settings,
|
||||
RuntimeInfo runtimeInfo,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory,
|
||||
bool isMainInstance)
|
||||
{
|
||||
this.isMainInstance = isMainInstance;
|
||||
this.runtimeInfo = runtimeInfo;
|
||||
this.settings = settings;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
|
@ -44,13 +52,17 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
internal void Initialize()
|
||||
{
|
||||
var downloadHandler = new DownloadHandler(settings, runtimeInfo);
|
||||
|
||||
Id = Guid.NewGuid();
|
||||
downloadHandler.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
|
||||
|
||||
control = new BrowserControl(settings, text);
|
||||
control.AddressChanged += Control_AddressChanged;
|
||||
(control as BrowserControl).ConfigurationDetected += (url, args) => ConfigurationDetected?.Invoke(url, args);
|
||||
control.LoadingStateChanged += Control_LoadingStateChanged;
|
||||
control.TitleChanged += Control_TitleChanged;
|
||||
(control as BrowserControl).DownloadHandler = downloadHandler;
|
||||
(control as BrowserControl).Initialize();
|
||||
|
||||
window = uiFactory.CreateBrowserWindow(control, settings);
|
||||
window.IsMainWindow = isMainInstance;
|
||||
|
|
|
@ -24,8 +24,6 @@ namespace SafeExamBrowser.Browser
|
|||
private LoadingStateChangedEventHandler loadingStateChanged;
|
||||
private TitleChangedEventHandler titleChanged;
|
||||
|
||||
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
|
||||
|
||||
event AddressChangedEventHandler IBrowserControl.AddressChanged
|
||||
{
|
||||
add { addressChanged += value; }
|
||||
|
@ -48,8 +46,17 @@ namespace SafeExamBrowser.Browser
|
|||
{
|
||||
this.settings = settings;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
Initialize();
|
||||
public void Initialize()
|
||||
{
|
||||
AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
|
||||
LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading);
|
||||
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
|
||||
|
||||
KeyboardHandler = new KeyboardHandler(settings);
|
||||
MenuHandler = new ContextMenuHandler(settings, text);
|
||||
RequestHandler = new RequestHandler();
|
||||
}
|
||||
|
||||
public void NavigateBackwards()
|
||||
|
@ -74,19 +81,5 @@ namespace SafeExamBrowser.Browser
|
|||
{
|
||||
GetBrowser().Reload();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
var requestHandler = new RequestHandler();
|
||||
|
||||
AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
|
||||
LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading);
|
||||
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
|
||||
requestHandler.ConfigurationDetected += (url, args) => ConfigurationDetected?.Invoke(url, args);
|
||||
|
||||
KeyboardHandler = new KeyboardHandler(settings);
|
||||
MenuHandler = new ContextMenuHandler(settings, text);
|
||||
RequestHandler = requestHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
88
SafeExamBrowser.Browser/Handlers/DownloadHandler.cs
Normal file
88
SafeExamBrowser.Browser/Handlers/DownloadHandler.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using CefSharp;
|
||||
using SafeExamBrowser.Contracts.Browser;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Handlers
|
||||
{
|
||||
/// <remarks>
|
||||
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_IDownloadHandler.htm.
|
||||
/// </remarks>
|
||||
internal class DownloadHandler : IDownloadHandler
|
||||
{
|
||||
private BrowserSettings settings;
|
||||
private RuntimeInfo runtimeInfo;
|
||||
private ConcurrentDictionary<int, DownloadFinishedCallback> callbacks;
|
||||
|
||||
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||
|
||||
public DownloadHandler(BrowserSettings settings, RuntimeInfo runtimeInfo)
|
||||
{
|
||||
this.callbacks = new ConcurrentDictionary<int, DownloadFinishedCallback>();
|
||||
this.settings = settings;
|
||||
this.runtimeInfo = runtimeInfo;
|
||||
}
|
||||
|
||||
public void OnBeforeDownload(IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
|
||||
{
|
||||
var uri = new Uri(downloadItem.Url);
|
||||
var extension = Path.GetExtension(uri.AbsolutePath);
|
||||
var isConfigFile = String.Equals(extension, runtimeInfo.ConfigurationFileExtension, StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
if (isConfigFile)
|
||||
{
|
||||
Task.Run(() => RequestConfigurationFileDownload(downloadItem, callback));
|
||||
}
|
||||
else if (!isConfigFile && settings.AllowDownloads)
|
||||
{
|
||||
using (callback)
|
||||
{
|
||||
callback.Continue(null, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDownloadUpdated(IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
|
||||
{
|
||||
if (downloadItem.IsComplete || downloadItem.IsCancelled)
|
||||
{
|
||||
if (callbacks.TryRemove(downloadItem.Id, out DownloadFinishedCallback finished) && finished != null)
|
||||
{
|
||||
Task.Run(() => finished.Invoke(downloadItem.IsComplete, downloadItem.FullPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RequestConfigurationFileDownload(DownloadItem downloadItem, IBeforeDownloadCallback callback)
|
||||
{
|
||||
var args = new DownloadEventArgs();
|
||||
|
||||
ConfigurationDownloadRequested?.Invoke(downloadItem.SuggestedFileName, args);
|
||||
|
||||
if (args.AllowDownload)
|
||||
{
|
||||
if (args.Callback != null)
|
||||
{
|
||||
callbacks[downloadItem.Id] = args.Callback;
|
||||
}
|
||||
|
||||
using (callback)
|
||||
{
|
||||
callback.Continue(args.DownloadPath, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,46 +7,31 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using CefSharp;
|
||||
using CefSharp.Handler;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Handlers
|
||||
{
|
||||
internal delegate void ConfigurationDetectedEventHandler(string url, CancelEventArgs args);
|
||||
|
||||
/// <remarks>
|
||||
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_Handler_DefaultRequestHandler.htm.
|
||||
/// </remarks>
|
||||
internal class RequestHandler : DefaultRequestHandler
|
||||
{
|
||||
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
|
||||
|
||||
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
|
||||
{
|
||||
Task.Run(() =>
|
||||
var uri = new Uri(request.Url);
|
||||
|
||||
// TODO: Move to globals -> SafeExamBrowserUriScheme, SafeExamBrowserSecureUriScheme
|
||||
if (uri.Scheme == "seb")
|
||||
{
|
||||
var allow = true;
|
||||
var uri = new Uri(request.Url);
|
||||
request.Url = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.ToString();
|
||||
}
|
||||
else if (uri.Scheme == "sebs")
|
||||
{
|
||||
request.Url = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttps }.ToString();
|
||||
}
|
||||
|
||||
if (uri.Scheme == "seb" || uri.Scheme == "sebs" || Path.HasExtension("seb"))
|
||||
{
|
||||
var args = new CancelEventArgs();
|
||||
|
||||
ConfigurationDetected?.Invoke(request.Url, args);
|
||||
|
||||
allow = !args.Cancel;
|
||||
}
|
||||
|
||||
using (callback)
|
||||
{
|
||||
callback.Continue(allow);
|
||||
}
|
||||
});
|
||||
|
||||
return CefReturnValue.ContinueAsync;
|
||||
return base.OnBeforeResourceLoad(browserControl, browser, frame, request, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,10 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
@ -67,6 +70,7 @@
|
|||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="BrowserIconResource.cs" />
|
||||
<Compile Include="Handlers\DownloadHandler.cs" />
|
||||
<Compile Include="Handlers\KeyboardHandler.cs" />
|
||||
<Compile Include="Handlers\RequestHandler.cs" />
|
||||
<Compile Include="Handlers\SchemeHandlerFactory.cs" />
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Browser;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
@ -38,6 +40,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
private IWindowMonitor windowMonitor;
|
||||
private RuntimeInfo runtimeInfo;
|
||||
|
||||
public IBrowserApplicationController Browser { private get; set; }
|
||||
public IClientHost ClientHost { private get; set; }
|
||||
public Guid SessionId { private get; set; }
|
||||
public Settings Settings { private get; set; }
|
||||
|
@ -145,6 +148,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
|
||||
private void RegisterEvents()
|
||||
{
|
||||
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
|
||||
ClientHost.Shutdown += ClientHost_Shutdown;
|
||||
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
||||
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
|
||||
|
@ -155,6 +159,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
|
||||
private void DeregisterEvents()
|
||||
{
|
||||
Browser.ConfigurationDownloadRequested -= Browser_ConfigurationDownloadRequested;
|
||||
ClientHost.Shutdown -= ClientHost_Shutdown;
|
||||
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
||||
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
|
||||
|
@ -183,6 +188,53 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
logger.Info("Desktop successfully restored.");
|
||||
}
|
||||
|
||||
private void Browser_ConfigurationDownloadRequested(string fileName, DownloadEventArgs args)
|
||||
{
|
||||
if (Settings.ConfigurationMode == ConfigurationMode.ConfigureClient)
|
||||
{
|
||||
logger.Info($"Detected download request for configuration file '{fileName}'.");
|
||||
|
||||
var result = messageBox.Show(TextKey.MessageBox_ReconfigurationQuestion, TextKey.MessageBox_ReconfigurationQuestionTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question);
|
||||
var reconfigure = result == MessageBoxResult.Yes;
|
||||
|
||||
logger.Info($"The user chose to {(reconfigure ? "start" : "abort")} the reconfiguration.");
|
||||
|
||||
if (reconfigure)
|
||||
{
|
||||
args.AllowDownload = true;
|
||||
args.Callback = Browser_ConfigurationDownloadFinished;
|
||||
args.DownloadPath = Path.Combine(runtimeInfo.DownloadDirectory, fileName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info($"Denied download request for configuration file '{fileName}' due to '{Settings.ConfigurationMode}' mode.");
|
||||
messageBox.Show(TextKey.MessageBox_ReconfigurationDenied, TextKey.MessageBox_ReconfigurationDeniedTitle);
|
||||
}
|
||||
}
|
||||
|
||||
private void Browser_ConfigurationDownloadFinished(bool success, string filePath = null)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
try
|
||||
{
|
||||
runtime.RequestReconfiguration(filePath);
|
||||
logger.Info($"Sent reconfiguration request for '{filePath}' to the runtime.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to communicate reconfiguration request for '{filePath}'!", e);
|
||||
messageBox.Show(TextKey.MessageBox_ReconfigurationError, TextKey.MessageBox_ReconfigurationErrorTitle, icon: MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"Failed to download configuration file '{filePath}'!");
|
||||
messageBox.Show(TextKey.MessageBox_ConfigurationDownloadError, TextKey.MessageBox_ConfigurationDownloadErrorTitle, icon: MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClientHost_Shutdown()
|
||||
{
|
||||
taskbar.Close();
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.Communication.Hosts;
|
||||
|
|
|
@ -17,6 +17,7 @@ using SafeExamBrowser.Client.Notifications;
|
|||
using SafeExamBrowser.Configuration;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Browser;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
@ -47,6 +48,7 @@ namespace SafeExamBrowser.Client
|
|||
private string runtimeHostUri;
|
||||
private Guid startupToken;
|
||||
|
||||
private IBrowserApplicationController browserController;
|
||||
private ClientConfiguration configuration;
|
||||
private IClientHost clientHost;
|
||||
private ILogger logger;
|
||||
|
@ -88,7 +90,6 @@ namespace SafeExamBrowser.Client
|
|||
operations.Enqueue(new RuntimeConnectionOperation(logger, runtimeProxy, startupToken));
|
||||
operations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeProxy));
|
||||
operations.Enqueue(new DelayedInitializationOperation(BuildCommunicationHostOperation));
|
||||
operations.Enqueue(new DelegateOperation(UpdateClientControllerDependencies));
|
||||
// TODO
|
||||
//operations.Enqueue(new DelayedInitializationOperation(BuildKeyboardInterceptorOperation));
|
||||
//operations.Enqueue(new WindowMonitorOperation(logger, windowMonitor));
|
||||
|
@ -98,6 +99,7 @@ namespace SafeExamBrowser.Client
|
|||
operations.Enqueue(new DelayedInitializationOperation(BuildBrowserOperation));
|
||||
operations.Enqueue(new ClipboardOperation(logger, nativeMethods));
|
||||
//operations.Enqueue(new DelayedInitializationOperation(BuildMouseInterceptorOperation));
|
||||
operations.Enqueue(new DelegateOperation(UpdateClientControllerDependencies));
|
||||
|
||||
var sequence = new OperationSequence(logger, operations);
|
||||
|
||||
|
@ -150,10 +152,12 @@ namespace SafeExamBrowser.Client
|
|||
private IOperation BuildBrowserOperation()
|
||||
{
|
||||
var moduleLogger = new ModuleLogger(logger, typeof(BrowserApplicationController));
|
||||
var browserController = new BrowserApplicationController(configuration.Settings.Browser, configuration.RuntimeInfo, moduleLogger, messageBox, runtimeProxy, text, uiFactory);
|
||||
var browserController = new BrowserApplicationController(configuration.Settings.Browser, configuration.RuntimeInfo, moduleLogger, messageBox, text, uiFactory);
|
||||
var browserInfo = new BrowserApplicationInfo();
|
||||
var operation = new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory);
|
||||
|
||||
this.browserController = browserController;
|
||||
|
||||
return operation;
|
||||
}
|
||||
|
||||
|
@ -200,6 +204,7 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
private void UpdateClientControllerDependencies()
|
||||
{
|
||||
ClientController.Browser = browserController;
|
||||
ClientController.ClientHost = clientHost;
|
||||
ClientController.RuntimeInfo = configuration.RuntimeInfo;
|
||||
ClientController.SessionId = configuration.SessionId;
|
||||
|
|
|
@ -44,8 +44,8 @@
|
|||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
|
@ -54,7 +54,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace SafeExamBrowser.Configuration
|
|||
|
||||
public ISessionData CurrentSession { get; private set; }
|
||||
public Settings CurrentSettings { get; private set; }
|
||||
public string ReconfigurationUrl { get; set; }
|
||||
public string ReconfigurationFilePath { get; set; }
|
||||
|
||||
public RuntimeInfo RuntimeInfo
|
||||
{
|
||||
|
@ -66,35 +66,34 @@ namespace SafeExamBrowser.Configuration
|
|||
}
|
||||
}
|
||||
|
||||
public Settings LoadSettings(Uri path)
|
||||
public LoadStatus LoadSettings(Uri resource, string settingsPassword = null, string adminPassword = null)
|
||||
{
|
||||
// TODO: Implement loading mechanism
|
||||
|
||||
return LoadDefaultSettings();
|
||||
LoadDefaultSettings();
|
||||
|
||||
return LoadStatus.Success;
|
||||
}
|
||||
|
||||
public Settings LoadDefaultSettings()
|
||||
public void LoadDefaultSettings()
|
||||
{
|
||||
var settings = new Settings()
|
||||
{
|
||||
// TODO: Implement default settings
|
||||
ServicePolicy = ServicePolicy.Optional
|
||||
};
|
||||
// TODO: Implement default settings
|
||||
|
||||
settings.Browser.StartUrl = "https://www.safeexambrowser.org/testing";
|
||||
settings.Browser.AllowAddressBar = true;
|
||||
settings.Browser.AllowBackwardNavigation = true;
|
||||
settings.Browser.AllowDeveloperConsole = true;
|
||||
settings.Browser.AllowForwardNavigation = true;
|
||||
settings.Browser.AllowReloading = true;
|
||||
CurrentSettings = new Settings();
|
||||
|
||||
settings.Taskbar.AllowApplicationLog = true;
|
||||
settings.Taskbar.AllowKeyboardLayout = true;
|
||||
settings.Taskbar.AllowWirelessNetwork = true;
|
||||
CurrentSettings.ServicePolicy = ServicePolicy.Optional;
|
||||
|
||||
CurrentSettings = settings;
|
||||
CurrentSettings.Browser.StartUrl = "https://www.safeexambrowser.org/testing";
|
||||
CurrentSettings.Browser.AllowAddressBar = true;
|
||||
CurrentSettings.Browser.AllowBackwardNavigation = true;
|
||||
CurrentSettings.Browser.AllowDeveloperConsole = true;
|
||||
CurrentSettings.Browser.AllowForwardNavigation = true;
|
||||
CurrentSettings.Browser.AllowReloading = true;
|
||||
CurrentSettings.Browser.AllowDownloads = true;
|
||||
|
||||
return settings;
|
||||
CurrentSettings.Taskbar.AllowApplicationLog = true;
|
||||
CurrentSettings.Taskbar.AllowKeyboardLayout = true;
|
||||
CurrentSettings.Taskbar.AllowWirelessNetwork = true;
|
||||
}
|
||||
|
||||
private void InitializeRuntimeInfo()
|
||||
|
@ -105,26 +104,26 @@ namespace SafeExamBrowser.Configuration
|
|||
var logFolder = Path.Combine(appDataFolder, "Logs");
|
||||
var logFilePrefix = startTime.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
|
||||
|
||||
runtimeInfo = new RuntimeInfo
|
||||
{
|
||||
ApplicationStartTime = startTime,
|
||||
AppDataFolder = appDataFolder,
|
||||
BrowserCachePath = Path.Combine(appDataFolder, "Cache"),
|
||||
BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt"),
|
||||
ClientId = Guid.NewGuid(),
|
||||
ClientAddress = $"{BASE_ADDRESS}/client/{Guid.NewGuid()}",
|
||||
ClientExecutablePath = Path.Combine(Path.GetDirectoryName(executable.Location), $"{nameof(SafeExamBrowser)}.Client.exe"),
|
||||
ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt"),
|
||||
DefaultSettingsFileName = "SebClientSettings.seb",
|
||||
ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright,
|
||||
ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser)),
|
||||
ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title,
|
||||
ProgramVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion,
|
||||
RuntimeId = Guid.NewGuid(),
|
||||
RuntimeAddress = $"{BASE_ADDRESS}/runtime/{Guid.NewGuid()}",
|
||||
RuntimeLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.txt"),
|
||||
ServiceAddress = $"{BASE_ADDRESS}/service"
|
||||
};
|
||||
runtimeInfo = new RuntimeInfo();
|
||||
runtimeInfo.ApplicationStartTime = startTime;
|
||||
runtimeInfo.AppDataFolder = appDataFolder;
|
||||
runtimeInfo.BrowserCachePath = Path.Combine(appDataFolder, "Cache");
|
||||
runtimeInfo.BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt");
|
||||
runtimeInfo.ClientId = Guid.NewGuid();
|
||||
runtimeInfo.ClientAddress = $"{BASE_ADDRESS}/client/{Guid.NewGuid()}";
|
||||
runtimeInfo.ClientExecutablePath = Path.Combine(Path.GetDirectoryName(executable.Location), $"{nameof(SafeExamBrowser)}.Client.exe");
|
||||
runtimeInfo.ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt");
|
||||
runtimeInfo.ConfigurationFileExtension = ".seb";
|
||||
runtimeInfo.DefaultSettingsFileName = "SebClientSettings.seb";
|
||||
runtimeInfo.DownloadDirectory = Path.Combine(appDataFolder, "Downloads");
|
||||
runtimeInfo.ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright;
|
||||
runtimeInfo.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser));
|
||||
runtimeInfo.ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title;
|
||||
runtimeInfo.ProgramVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
runtimeInfo.RuntimeId = Guid.NewGuid();
|
||||
runtimeInfo.RuntimeAddress = $"{BASE_ADDRESS}/runtime/{Guid.NewGuid()}";
|
||||
runtimeInfo.RuntimeLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.txt");
|
||||
runtimeInfo.ServiceAddress = $"{BASE_ADDRESS}/service";
|
||||
}
|
||||
|
||||
private void UpdateRuntimeInfo()
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Browser;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
|
@ -18,6 +19,11 @@ namespace SafeExamBrowser.Contracts.Behaviour
|
|||
/// </summary>
|
||||
public interface IClientController
|
||||
{
|
||||
/// <summary>
|
||||
/// The controller for the browser application.
|
||||
/// </summary>
|
||||
IBrowserApplicationController Browser { set; }
|
||||
|
||||
/// <summary>
|
||||
/// The client host used for communication handling.
|
||||
/// </summary>
|
||||
|
|
31
SafeExamBrowser.Contracts/Browser/DownloadEventArgs.cs
Normal file
31
SafeExamBrowser.Contracts/Browser/DownloadEventArgs.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Browser
|
||||
{
|
||||
/// <summary>
|
||||
/// TODO
|
||||
/// </summary>
|
||||
public class DownloadEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the specified download is allowed.
|
||||
/// </summary>
|
||||
public bool AllowDownload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Callback executed once a download has been finished.
|
||||
/// </summary>
|
||||
public DownloadFinishedCallback Callback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The full path under which the specified file should be saved.
|
||||
/// </summary>
|
||||
public string DownloadPath { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Browser
|
||||
{
|
||||
public delegate void DownloadFinishedCallback(bool success, string filePath = null);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Browser
|
||||
{
|
||||
public delegate void DownloadRequestedEventHandler(string fileName, DownloadEventArgs args);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.Behaviour;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Browser
|
||||
{
|
||||
/// <summary>
|
||||
/// Controls the lifetime and functionality of the browser application.
|
||||
/// </summary>
|
||||
public interface IBrowserApplicationController : IApplicationController
|
||||
{
|
||||
/// <summary>
|
||||
/// Event fired when the browser application detects a download request for an application configuration file.
|
||||
/// </summary>
|
||||
event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||
}
|
||||
}
|
|
@ -17,13 +17,13 @@ namespace SafeExamBrowser.Contracts.Communication.Data
|
|||
public class ReconfigurationMessage : Message
|
||||
{
|
||||
/// <summary>
|
||||
/// The locator of the new configuration to be used.
|
||||
/// The full path of the configuration file to be used.
|
||||
/// </summary>
|
||||
public string ConfigurationUrl { get; private set; }
|
||||
public string ConfigurationPath { get; private set; }
|
||||
|
||||
public ReconfigurationMessage(string url)
|
||||
public ReconfigurationMessage(string path)
|
||||
{
|
||||
ConfigurationUrl = url;
|
||||
ConfigurationPath = path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class which must be used for all event parameters <c>T</c> of <see cref="CommunicationEventHandler{T}"/>.
|
||||
/// </summary>
|
||||
public abstract class CommunicationEventArgs
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.Threading.Tasks;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// The default handler for communication events of an interlocutor.
|
||||
/// </summary>
|
||||
public delegate void CommunicationEventHandler();
|
||||
|
||||
/// <summary>
|
||||
/// The handler with parameter for communication events of an interlocutor.
|
||||
/// </summary>
|
||||
public delegate void CommunicationEventHandler<T>(T args) where T : CommunicationEventArgs;
|
||||
|
||||
public static class CommunicationEventHandlerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the event handler asynchronously, i.e. on a separate thread.
|
||||
/// </summary>
|
||||
public static async Task InvokeAsync(this CommunicationEventHandler handler)
|
||||
{
|
||||
await Task.Run(() => handler?.Invoke());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the event handler asynchronously, i.e. on a separate thread.
|
||||
/// </summary>
|
||||
public static async Task InvokeAsync<T>(this CommunicationEventHandler<T> handler, T args) where T : CommunicationEventArgs
|
||||
{
|
||||
await Task.Run(() => handler?.Invoke(args));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// The event arguments used for the reconfiguration event fired by the <see cref="Hosts.IRuntimeHost"/>.
|
||||
/// </summary>
|
||||
public class ReconfigurationEventArgs : CommunicationEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The full path to the configuration file to be used for reconfiguration.
|
||||
/// </summary>
|
||||
public string ConfigurationPath { get; set; }
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Hosts
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Hosts
|
||||
{
|
||||
|
@ -31,9 +32,9 @@ namespace SafeExamBrowser.Contracts.Communication.Hosts
|
|||
event CommunicationEventHandler ClientReady;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the client detected a reconfiguration request.
|
||||
/// Event fired when the client requested a reconfiguration of the application.
|
||||
/// </summary>
|
||||
event CommunicationEventHandler ReconfigurationRequested;
|
||||
event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the client requests to shut down the application.
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
namespace SafeExamBrowser.Contracts.Communication
|
||||
{
|
||||
public delegate void CommunicationEventHandler();
|
||||
|
||||
/// <summary>
|
||||
/// Defines the common functionality for all communication hosts. A communication host can be hosted by an application component to
|
||||
/// allow for inter-process communication with other components (e.g. runtime -> client communication).
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication
|
||||
{
|
||||
|
|
|
@ -34,10 +34,9 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies
|
|||
void RequestShutdown();
|
||||
|
||||
/// <summary>
|
||||
/// Requests the runtime to reconfigure the application with the configuration from the given location. Returns <c>true</c> if
|
||||
/// the runtime accepted the request, otherwise <c>false</c>.
|
||||
/// Requests the runtime to reconfigure the application with the specified configuration.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
bool RequestReconfiguration(string url);
|
||||
void RequestReconfiguration(string filePath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
Settings.Settings CurrentSettings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The locator of the configuration to be used when reconfiguring the application.
|
||||
/// The path of the settings file to be used when reconfiguring the application.
|
||||
/// </summary>
|
||||
string ReconfigurationUrl { get; set; }
|
||||
string ReconfigurationFilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The runtime information for the currently running application instance.
|
||||
|
@ -48,14 +48,14 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
void InitializeSessionConfiguration();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load settings from the specified path.
|
||||
/// Attempts to load settings from the specified resource, using the optional passwords. Returns a <see cref="LoadStatus"/>
|
||||
/// indicating the result of the operation.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">Thrown if the given path cannot be resolved to a settings file.</exception>
|
||||
Settings.Settings LoadSettings(Uri path);
|
||||
LoadStatus LoadSettings(Uri resource, string settingsPassword = null, string adminPassword = null);
|
||||
|
||||
/// <summary>
|
||||
/// Loads the default settings.
|
||||
/// </summary>
|
||||
Settings.Settings LoadDefaultSettings();
|
||||
void LoadDefaultSettings();
|
||||
}
|
||||
}
|
||||
|
|
36
SafeExamBrowser.Contracts/Configuration/LoadStatus.cs
Normal file
36
SafeExamBrowser.Contracts/Configuration/LoadStatus.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines all possible results of <see cref="IConfigurationRepository.LoadSettings(System.Uri)"/>.
|
||||
/// </summary>
|
||||
public enum LoadStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that an admin password is needed in order to load the settings.
|
||||
/// </summary>
|
||||
AdminPasswordNeeded = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a resource does not comply with the required data format.
|
||||
/// </summary>
|
||||
InvalidData,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a settings password is needed in order to load the settings.
|
||||
/// </summary>
|
||||
SettingsPasswordNeeded,
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Settings.Settings"/> were loaded successfully.
|
||||
/// </summary>
|
||||
Success
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
{
|
||||
/// <summary>
|
||||
/// Defines the fundamental, global configuration information for all application components.
|
||||
/// TODO: Rename to Globals or GlobalConfiguration or alike!
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class RuntimeInfo
|
||||
|
@ -56,11 +57,21 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
/// </summary>
|
||||
public string ClientLogFile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The file extension of configuration files for the application (including the period).
|
||||
/// </summary>
|
||||
public string ConfigurationFileExtension { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The default file name for application settings.
|
||||
/// </summary>
|
||||
public string DefaultSettingsFileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The default directory for file downloads.
|
||||
/// </summary>
|
||||
public string DownloadDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The copyright information for the application (i.e. the executing assembly).
|
||||
/// </summary>
|
||||
|
|
|
@ -31,6 +31,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
|
|||
/// </summary>
|
||||
public bool AllowDeveloperConsole { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the user should be allowed to download files.
|
||||
/// </summary>
|
||||
public bool AllowDownloads { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the user should be allowed to navigate forwards in a browser window.
|
||||
/// </summary>
|
||||
|
|
|
@ -20,6 +20,8 @@ namespace SafeExamBrowser.Contracts.I18n
|
|||
MessageBox_ApplicationErrorTitle,
|
||||
MessageBox_ClientConfigurationQuestion,
|
||||
MessageBox_ClientConfigurationQuestionTitle,
|
||||
MessageBox_ConfigurationDownloadError,
|
||||
MessageBox_ConfigurationDownloadErrorTitle,
|
||||
MessageBox_Quit,
|
||||
MessageBox_QuitTitle,
|
||||
MessageBox_QuitError,
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
@ -57,6 +56,13 @@
|
|||
<Compile Include="Behaviour\IRuntimeController.cs" />
|
||||
<Compile Include="Behaviour\OperationModel\IOperationSequence.cs" />
|
||||
<Compile Include="Behaviour\OperationModel\OperationResult.cs" />
|
||||
<Compile Include="Browser\DownloadEventArgs.cs" />
|
||||
<Compile Include="Browser\DownloadFinishedCallback.cs" />
|
||||
<Compile Include="Browser\DownloadRequestedEventHandler.cs" />
|
||||
<Compile Include="Browser\IBrowserApplicationController.cs" />
|
||||
<Compile Include="Communication\Events\CommunicationEventArgs.cs" />
|
||||
<Compile Include="Communication\Events\CommunicationEventHandler.cs" />
|
||||
<Compile Include="Communication\Events\ReconfigurationEventArgs.cs" />
|
||||
<Compile Include="Communication\Hosts\IClientHost.cs" />
|
||||
<Compile Include="Communication\Hosts\IHostObject.cs" />
|
||||
<Compile Include="Communication\Hosts\IHostObjectFactory.cs" />
|
||||
|
@ -84,6 +90,7 @@
|
|||
<Compile Include="Communication\Data\SimpleResponsePurport.cs" />
|
||||
<Compile Include="Communication\Data\SimpleResponse.cs" />
|
||||
<Compile Include="Configuration\ClientConfiguration.cs" />
|
||||
<Compile Include="Configuration\LoadStatus.cs" />
|
||||
<Compile Include="Configuration\RuntimeInfo.cs" />
|
||||
<Compile Include="Configuration\ISessionData.cs" />
|
||||
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
|
||||
|
|
|
@ -96,47 +96,56 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
[TestMethod]
|
||||
public void MustCorrectlyRequestReconfiguration()
|
||||
{
|
||||
var url = "sebs://some/url.seb";
|
||||
var response = new ReconfigurationResponse
|
||||
{
|
||||
Accepted = true
|
||||
};
|
||||
//var url = "sebs://some/url.seb";
|
||||
//var response = new ReconfigurationResponse
|
||||
//{
|
||||
// Accepted = true
|
||||
//};
|
||||
|
||||
proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url))).Returns(response);
|
||||
//proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url))).Returns(response);
|
||||
|
||||
var accepted = sut.RequestReconfiguration(url);
|
||||
//var accepted = sut.RequestReconfiguration(url);
|
||||
|
||||
proxy.Verify(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url)), Times.Once);
|
||||
//proxy.Verify(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url)), Times.Once);
|
||||
|
||||
Assert.IsTrue(accepted);
|
||||
//Assert.IsTrue(accepted);
|
||||
|
||||
// TODO
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustCorrectlyHandleDeniedReconfigurationRequest()
|
||||
{
|
||||
var url = "sebs://some/url.seb";
|
||||
var response = new ReconfigurationResponse
|
||||
{
|
||||
Accepted = false
|
||||
};
|
||||
//var url = "sebs://some/url.seb";
|
||||
//var response = new ReconfigurationResponse
|
||||
//{
|
||||
// Accepted = false
|
||||
//};
|
||||
|
||||
proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url))).Returns(response);
|
||||
//proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url))).Returns(response);
|
||||
|
||||
var accepted = sut.RequestReconfiguration(url);
|
||||
//var accepted = sut.RequestReconfiguration(url);
|
||||
|
||||
Assert.IsFalse(accepted);
|
||||
//Assert.IsFalse(accepted);
|
||||
|
||||
// TODO
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailIfIncorrectResponseToReconfigurationRequest()
|
||||
{
|
||||
var url = "sebs://some/url.seb";
|
||||
//var url = "sebs://some/url.seb";
|
||||
|
||||
proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url))).Returns<Response>(null);
|
||||
//proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url))).Returns<Response>(null);
|
||||
|
||||
var accepted = sut.RequestReconfiguration(url);
|
||||
//var accepted = sut.RequestReconfiguration(url);
|
||||
|
||||
Assert.IsFalse(accepted);
|
||||
//Assert.IsFalse(accepted);
|
||||
|
||||
// TODO
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
|
|
|
@ -11,6 +11,7 @@ using System.ServiceModel;
|
|||
using System.Timers;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
|
|
|
@ -45,16 +45,14 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
|||
}
|
||||
}
|
||||
|
||||
public bool RequestReconfiguration(string url)
|
||||
public void RequestReconfiguration(string filePath)
|
||||
{
|
||||
var response = Send(new ReconfigurationMessage(url));
|
||||
var response = Send(new ReconfigurationMessage(filePath));
|
||||
|
||||
if (response is ReconfigurationResponse reconfiguration)
|
||||
if (!IsAcknowledged(response))
|
||||
{
|
||||
return reconfiguration.Accepted;
|
||||
throw new CommunicationException($"Runtime did not acknowledge reconfiguration request! Response: {ToString(response)}.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void RequestShutdown()
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
<Entry key="MessageBox_ClientConfigurationQuestionTitle">
|
||||
Configuration Successful
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ConfigurationDownloadError">
|
||||
Failed to download the new application configuration. Please try again or contact technical support.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ConfigurationDownloadErrorTitle">
|
||||
Download Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_Quit">
|
||||
Would you really like to quit the application?
|
||||
</Entry>
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
|
|
@ -45,8 +45,9 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
info.AppDataFolder = @"C:\Not\Really\AppData";
|
||||
info.DefaultSettingsFileName = "SettingsDummy.txt";
|
||||
info.ProgramDataFolder = @"C:\Not\Really\ProgramData";
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>())).Returns(settings);
|
||||
repository.Setup(r => r.LoadDefaultSettings()).Returns(settings);
|
||||
// TODO
|
||||
//repository.Setup(r => r.LoadSettings(It.IsAny<Uri>())).Returns(settings);
|
||||
//repository.Setup(r => r.LoadDefaultSettings()).Returns(settings);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -88,7 +89,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(path)))), Times.Once);
|
||||
Assert.Fail();
|
||||
//repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(path)))), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -103,7 +105,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||
Assert.Fail();
|
||||
//repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -117,7 +120,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||
Assert.Fail();
|
||||
//repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
|
|
|
@ -75,6 +75,9 @@ namespace SafeExamBrowser.Runtime
|
|||
instances.RuntimeController.Terminate();
|
||||
instances.LogShutdownInformation();
|
||||
|
||||
// TODO: Which UI operation is being cancelled without the timeout? Same problem with client? -> Debug!
|
||||
Thread.Sleep(20);
|
||||
|
||||
base.Shutdown();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
using System.Threading;
|
||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
|
|
@ -50,35 +50,58 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
logger.Info("Initializing application configuration...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration);
|
||||
|
||||
var isValidUri = TryGetSettingsUri(out Uri uri);
|
||||
var isValidUri = TryInitializeSettingsUri(out Uri uri);
|
||||
|
||||
if (isValidUri)
|
||||
{
|
||||
logger.Info($"Loading configuration from '{uri.AbsolutePath}'...");
|
||||
logger.Info($"Loading settings from '{uri.AbsolutePath}'...");
|
||||
|
||||
var abort = LoadSettings(uri);
|
||||
var result = LoadSettings(uri);
|
||||
|
||||
if (abort)
|
||||
if (result == OperationResult.Success && repository.CurrentSettings.ConfigurationMode == ConfigurationMode.ConfigureClient)
|
||||
{
|
||||
return OperationResult.Aborted;
|
||||
var abort = IsConfigurationSufficient();
|
||||
|
||||
logger.Info($"The user chose to {(abort ? "abort" : "continue")} after successful client configuration.");
|
||||
|
||||
if (abort)
|
||||
{
|
||||
return OperationResult.Aborted;
|
||||
}
|
||||
}
|
||||
|
||||
LogOperationResult(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("No valid settings file specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
|
||||
repository.LoadDefaultSettings();
|
||||
}
|
||||
|
||||
logger.Info("No valid settings resource specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
|
||||
repository.LoadDefaultSettings();
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public OperationResult Repeat()
|
||||
{
|
||||
// TODO: How will the new settings be retrieved? Uri passed to the repository? If yes, how does the Uri get here?!
|
||||
// -> IDEA: Use configuration repository as container?
|
||||
// -> IDEA: Introduce IRepeatParams or alike?
|
||||
logger.Info("Initializing new application configuration...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration);
|
||||
|
||||
return OperationResult.Success;
|
||||
var isValidUri = TryValidateSettingsUri(repository.ReconfigurationFilePath, out Uri uri);
|
||||
|
||||
if (isValidUri)
|
||||
{
|
||||
logger.Info($"Loading settings from '{uri.AbsolutePath}'...");
|
||||
|
||||
var result = LoadSettings(uri);
|
||||
|
||||
LogOperationResult(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
logger.Warn($"The resource specified for reconfiguration does not exist or is not a file!");
|
||||
|
||||
return OperationResult.Failed;
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
|
@ -86,7 +109,79 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
// Nothing to do here...
|
||||
}
|
||||
|
||||
private bool TryGetSettingsUri(out Uri uri)
|
||||
private OperationResult LoadSettings(Uri uri)
|
||||
{
|
||||
var adminPassword = default(string);
|
||||
var settingsPassword = default(string);
|
||||
var status = default(LoadStatus);
|
||||
|
||||
for (int adminAttempts = 0, settingsAttempts = 0; adminAttempts < 5 && settingsAttempts < 5;)
|
||||
{
|
||||
status = repository.LoadSettings(uri, settingsPassword, adminPassword);
|
||||
|
||||
if (status == LoadStatus.InvalidData || status == LoadStatus.Success)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (status == LoadStatus.AdminPasswordNeeded || status == LoadStatus.SettingsPasswordNeeded)
|
||||
{
|
||||
var isAdmin = status == LoadStatus.AdminPasswordNeeded;
|
||||
var success = isAdmin ? TryGetAdminPassword(out adminPassword) : TryGetSettingsPassword(out settingsPassword);
|
||||
|
||||
if (success)
|
||||
{
|
||||
adminAttempts += isAdmin ? 1 : 0;
|
||||
settingsAttempts += isAdmin ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OperationResult.Aborted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status == LoadStatus.InvalidData)
|
||||
{
|
||||
if (IsHtmlPage(uri))
|
||||
{
|
||||
repository.LoadDefaultSettings();
|
||||
repository.CurrentSettings.Browser.StartUrl = uri.AbsoluteUri;
|
||||
logger.Info($"The specified URI '{uri.AbsoluteUri}' appears to point to a HTML page, setting it as startup URL.");
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
logger.Error($"The specified settings resource '{uri.AbsoluteUri}' is invalid!");
|
||||
}
|
||||
|
||||
return status == LoadStatus.Success ? OperationResult.Success : OperationResult.Failed;
|
||||
}
|
||||
|
||||
private bool IsHtmlPage(Uri uri)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetAdminPassword(out string password)
|
||||
{
|
||||
password = default(string);
|
||||
|
||||
// TODO
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryGetSettingsPassword(out string password)
|
||||
{
|
||||
password = default(string);
|
||||
|
||||
// TODO
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryInitializeSettingsUri(out Uri uri)
|
||||
{
|
||||
var path = string.Empty;
|
||||
var isValidUri = false;
|
||||
|
@ -119,19 +214,14 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
return isValidUri;
|
||||
}
|
||||
|
||||
private bool LoadSettings(Uri uri)
|
||||
private bool TryValidateSettingsUri(string path, out Uri uri)
|
||||
{
|
||||
var abort = false;
|
||||
var settings = repository.LoadSettings(uri);
|
||||
var isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
||||
|
||||
if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient)
|
||||
{
|
||||
abort = IsConfigurationSufficient();
|
||||
isValidUri &= uri != null && uri.IsFile;
|
||||
isValidUri &= File.Exists(path);
|
||||
|
||||
logger.Info($"The user chose to {(abort ? "abort" : "continue")} after successful client configuration.");
|
||||
}
|
||||
|
||||
return abort;
|
||||
return isValidUri;
|
||||
}
|
||||
|
||||
private bool IsConfigurationSufficient()
|
||||
|
@ -142,5 +232,21 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
|
||||
return abort == MessageBoxResult.Yes;
|
||||
}
|
||||
|
||||
private void LogOperationResult(OperationResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case OperationResult.Aborted:
|
||||
logger.Info("The configuration was aborted by the user.");
|
||||
break;
|
||||
case OperationResult.Failed:
|
||||
logger.Warn("The configuration has failed!");
|
||||
break;
|
||||
case OperationResult.Success:
|
||||
logger.Info("The configuration was successful.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
using System;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
@ -169,13 +170,14 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
|
||||
if (result == OperationResult.Failed)
|
||||
{
|
||||
// TODO: Check if message box is rendered on new desktop as well! -> E.g. if settings for reconfiguration are invalid
|
||||
messageBox.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error);
|
||||
}
|
||||
|
||||
if (!initial)
|
||||
{
|
||||
logger.Info("Terminating application...");
|
||||
shutdown.Invoke();
|
||||
if (!initial)
|
||||
{
|
||||
logger.Info("Terminating application...");
|
||||
shutdown.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -245,10 +247,22 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
shutdown.Invoke();
|
||||
}
|
||||
|
||||
private void RuntimeHost_ReconfigurationRequested()
|
||||
private void RuntimeHost_ReconfigurationRequested(ReconfigurationEventArgs args)
|
||||
{
|
||||
logger.Info($"Starting reconfiguration...");
|
||||
StartSession();
|
||||
var mode = configuration.CurrentSettings.ConfigurationMode;
|
||||
|
||||
if (mode == ConfigurationMode.ConfigureClient)
|
||||
{
|
||||
logger.Info($"Accepted request for reconfiguration with '{args.ConfigurationPath}'.");
|
||||
configuration.ReconfigurationFilePath = args.ConfigurationPath;
|
||||
|
||||
StartSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info($"Denied request for reconfiguration with '{args.ConfigurationPath}' due to '{mode}' mode!");
|
||||
// TODO: configuration.CurrentSession.ClientProxy.InformReconfigurationDenied();
|
||||
}
|
||||
}
|
||||
|
||||
private void RuntimeHost_ShutdownRequested()
|
||||
|
|
|
@ -7,12 +7,10 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.Communication.Hosts;
|
||||
|
||||
|
@ -27,7 +25,7 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
|
||||
public event CommunicationEventHandler ClientDisconnected;
|
||||
public event CommunicationEventHandler ClientReady;
|
||||
public event CommunicationEventHandler ReconfigurationRequested;
|
||||
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
||||
public event CommunicationEventHandler ShutdownRequested;
|
||||
|
||||
public RuntimeHost(string address, IConfigurationRepository configuration, IHostObjectFactory factory, ILogger logger) : base(address, factory, logger)
|
||||
|
@ -64,9 +62,9 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
{
|
||||
switch (message)
|
||||
{
|
||||
case ReconfigurationMessage reconfigurationMessage:
|
||||
// TODO: Not the job of the host, fire event or alike!
|
||||
return Handle(reconfigurationMessage);
|
||||
case ReconfigurationMessage r:
|
||||
ReconfigurationRequested?.InvokeAsync(new ReconfigurationEventArgs { ConfigurationPath = r.ConfigurationPath });
|
||||
return new SimpleResponse(SimpleResponsePurport.Acknowledged);
|
||||
}
|
||||
|
||||
return new SimpleResponse(SimpleResponsePurport.UnknownMessage);
|
||||
|
@ -89,22 +87,5 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
|
||||
return new SimpleResponse(SimpleResponsePurport.UnknownMessage);
|
||||
}
|
||||
|
||||
private Response Handle(ReconfigurationMessage message)
|
||||
{
|
||||
var isExam = configuration.CurrentSettings.ConfigurationMode == ConfigurationMode.Exam;
|
||||
var isValidUri = Uri.TryCreate(message.ConfigurationUrl, UriKind.Absolute, out _);
|
||||
var allowed = !isExam && isValidUri;
|
||||
|
||||
Logger.Info($"Received reconfiguration request for '{message.ConfigurationUrl}', {(allowed ? "accepted" : "denied")} it.");
|
||||
|
||||
if (allowed)
|
||||
{
|
||||
configuration.ReconfigurationUrl = message.ConfigurationUrl;
|
||||
Task.Run(() => ReconfigurationRequested?.Invoke());
|
||||
}
|
||||
|
||||
return new ReconfigurationResponse { Accepted = allowed };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,8 +61,8 @@
|
|||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
|
@ -71,7 +71,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="SimpleWifi, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL">
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
|
|
@ -9,6 +9,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Core", "Saf
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0A9E6674-2FB4-42EA-85DE-B2445B9AE2D9}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
LICENSE.txt = LICENSE.txt
|
||||
EndProjectSection
|
||||
EndProject
|
||||
|
|
Loading…
Reference in a new issue