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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using SafeExamBrowser.Browser.Handlers;
|
using SafeExamBrowser.Browser.Handlers;
|
||||||
using SafeExamBrowser.Contracts.Behaviour;
|
using SafeExamBrowser.Contracts.Browser;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
@ -24,30 +22,30 @@ using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.Browser
|
||||||
|
|
||||||
namespace SafeExamBrowser.Browser
|
namespace SafeExamBrowser.Browser
|
||||||
{
|
{
|
||||||
public class BrowserApplicationController : IApplicationController
|
public class BrowserApplicationController : IBrowserApplicationController
|
||||||
{
|
{
|
||||||
private IApplicationButton button;
|
private IApplicationButton button;
|
||||||
private IList<IApplicationInstance> instances = new List<IApplicationInstance>();
|
private IList<IApplicationInstance> instances;
|
||||||
private BrowserSettings settings;
|
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private IMessageBox messageBox;
|
private IMessageBox messageBox;
|
||||||
private IRuntimeProxy runtime;
|
|
||||||
private RuntimeInfo runtimeInfo;
|
private RuntimeInfo runtimeInfo;
|
||||||
private IUserInterfaceFactory uiFactory;
|
private BrowserSettings settings;
|
||||||
private IText text;
|
private IText text;
|
||||||
|
private IUserInterfaceFactory uiFactory;
|
||||||
|
|
||||||
|
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||||
|
|
||||||
public BrowserApplicationController(
|
public BrowserApplicationController(
|
||||||
BrowserSettings settings,
|
BrowserSettings settings,
|
||||||
RuntimeInfo runtimeInfo,
|
RuntimeInfo runtimeInfo,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IMessageBox messageBox,
|
IMessageBox messageBox,
|
||||||
IRuntimeProxy runtime,
|
|
||||||
IText text,
|
IText text,
|
||||||
IUserInterfaceFactory uiFactory)
|
IUserInterfaceFactory uiFactory)
|
||||||
{
|
{
|
||||||
|
this.instances = new List<IApplicationInstance>();
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.messageBox = messageBox;
|
this.messageBox = messageBox;
|
||||||
this.runtime = runtime;
|
|
||||||
this.runtimeInfo = runtimeInfo;
|
this.runtimeInfo = runtimeInfo;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
@ -84,15 +82,14 @@ namespace SafeExamBrowser.Browser
|
||||||
|
|
||||||
private void CreateNewInstance()
|
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.Initialize();
|
||||||
instance.ConfigurationDetected += Instance_ConfigurationDetected;
|
instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
|
||||||
instance.Terminated += Instance_Terminated;
|
instance.Terminated += Instance_Terminated;
|
||||||
|
|
||||||
button.RegisterInstance(instance);
|
button.RegisterInstance(instance);
|
||||||
instances.Add(instance);
|
instances.Add(instance);
|
||||||
|
|
||||||
instance.Window.Show();
|
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)
|
private void Instance_Terminated(Guid id)
|
||||||
{
|
{
|
||||||
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
|
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using SafeExamBrowser.Browser.Handlers;
|
using SafeExamBrowser.Browser.Handlers;
|
||||||
|
using SafeExamBrowser.Contracts.Browser;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
|
@ -22,6 +23,7 @@ namespace SafeExamBrowser.Browser
|
||||||
private IBrowserControl control;
|
private IBrowserControl control;
|
||||||
private IBrowserWindow window;
|
private IBrowserWindow window;
|
||||||
private bool isMainInstance;
|
private bool isMainInstance;
|
||||||
|
private RuntimeInfo runtimeInfo;
|
||||||
private BrowserSettings settings;
|
private BrowserSettings settings;
|
||||||
private IText text;
|
private IText text;
|
||||||
private IUserInterfaceFactory uiFactory;
|
private IUserInterfaceFactory uiFactory;
|
||||||
|
@ -30,13 +32,19 @@ namespace SafeExamBrowser.Browser
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
public IWindow Window { get { return window; } }
|
public IWindow Window { get { return window; } }
|
||||||
|
|
||||||
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
|
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||||
public event TerminatedEventHandler Terminated;
|
|
||||||
public event NameChangedEventHandler NameChanged;
|
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.isMainInstance = isMainInstance;
|
||||||
|
this.runtimeInfo = runtimeInfo;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.uiFactory = uiFactory;
|
this.uiFactory = uiFactory;
|
||||||
|
@ -44,13 +52,17 @@ namespace SafeExamBrowser.Browser
|
||||||
|
|
||||||
internal void Initialize()
|
internal void Initialize()
|
||||||
{
|
{
|
||||||
|
var downloadHandler = new DownloadHandler(settings, runtimeInfo);
|
||||||
|
|
||||||
Id = Guid.NewGuid();
|
Id = Guid.NewGuid();
|
||||||
|
downloadHandler.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
|
||||||
|
|
||||||
control = new BrowserControl(settings, text);
|
control = new BrowserControl(settings, text);
|
||||||
control.AddressChanged += Control_AddressChanged;
|
control.AddressChanged += Control_AddressChanged;
|
||||||
(control as BrowserControl).ConfigurationDetected += (url, args) => ConfigurationDetected?.Invoke(url, args);
|
|
||||||
control.LoadingStateChanged += Control_LoadingStateChanged;
|
control.LoadingStateChanged += Control_LoadingStateChanged;
|
||||||
control.TitleChanged += Control_TitleChanged;
|
control.TitleChanged += Control_TitleChanged;
|
||||||
|
(control as BrowserControl).DownloadHandler = downloadHandler;
|
||||||
|
(control as BrowserControl).Initialize();
|
||||||
|
|
||||||
window = uiFactory.CreateBrowserWindow(control, settings);
|
window = uiFactory.CreateBrowserWindow(control, settings);
|
||||||
window.IsMainWindow = isMainInstance;
|
window.IsMainWindow = isMainInstance;
|
||||||
|
|
|
@ -24,8 +24,6 @@ namespace SafeExamBrowser.Browser
|
||||||
private LoadingStateChangedEventHandler loadingStateChanged;
|
private LoadingStateChangedEventHandler loadingStateChanged;
|
||||||
private TitleChangedEventHandler titleChanged;
|
private TitleChangedEventHandler titleChanged;
|
||||||
|
|
||||||
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
|
|
||||||
|
|
||||||
event AddressChangedEventHandler IBrowserControl.AddressChanged
|
event AddressChangedEventHandler IBrowserControl.AddressChanged
|
||||||
{
|
{
|
||||||
add { addressChanged += value; }
|
add { addressChanged += value; }
|
||||||
|
@ -48,8 +46,17 @@ namespace SafeExamBrowser.Browser
|
||||||
{
|
{
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.text = text;
|
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()
|
public void NavigateBackwards()
|
||||||
|
@ -74,19 +81,5 @@ namespace SafeExamBrowser.Browser
|
||||||
{
|
{
|
||||||
GetBrowser().Reload();
|
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;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using CefSharp.Handler;
|
using CefSharp.Handler;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Browser.Handlers
|
namespace SafeExamBrowser.Browser.Handlers
|
||||||
{
|
{
|
||||||
internal delegate void ConfigurationDetectedEventHandler(string url, CancelEventArgs args);
|
|
||||||
|
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_Handler_DefaultRequestHandler.htm.
|
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_Handler_DefaultRequestHandler.htm.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal class RequestHandler : DefaultRequestHandler
|
internal class RequestHandler : DefaultRequestHandler
|
||||||
{
|
{
|
||||||
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
|
|
||||||
|
|
||||||
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
|
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;
|
request.Url = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.ToString();
|
||||||
var uri = new Uri(request.Url);
|
}
|
||||||
|
else if (uri.Scheme == "sebs")
|
||||||
|
{
|
||||||
|
request.Url = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttps }.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
if (uri.Scheme == "seb" || uri.Scheme == "sebs" || Path.HasExtension("seb"))
|
return base.OnBeforeResourceLoad(browserControl, browser, frame, request, callback);
|
||||||
{
|
|
||||||
var args = new CancelEventArgs();
|
|
||||||
|
|
||||||
ConfigurationDetected?.Invoke(request.Url, args);
|
|
||||||
|
|
||||||
allow = !args.Cancel;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (callback)
|
|
||||||
{
|
|
||||||
callback.Continue(allow);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return CefReturnValue.ContinueAsync;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,10 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
@ -67,6 +70,7 @@
|
||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="BrowserIconResource.cs" />
|
<Compile Include="BrowserIconResource.cs" />
|
||||||
|
<Compile Include="Handlers\DownloadHandler.cs" />
|
||||||
<Compile Include="Handlers\KeyboardHandler.cs" />
|
<Compile Include="Handlers\KeyboardHandler.cs" />
|
||||||
<Compile Include="Handlers\RequestHandler.cs" />
|
<Compile Include="Handlers\RequestHandler.cs" />
|
||||||
<Compile Include="Handlers\SchemeHandlerFactory.cs" />
|
<Compile Include="Handlers\SchemeHandlerFactory.cs" />
|
||||||
|
|
|
@ -53,7 +53,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using SafeExamBrowser.Contracts.Behaviour;
|
using SafeExamBrowser.Contracts.Behaviour;
|
||||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||||
|
using SafeExamBrowser.Contracts.Browser;
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
@ -38,6 +40,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
private IWindowMonitor windowMonitor;
|
private IWindowMonitor windowMonitor;
|
||||||
private RuntimeInfo runtimeInfo;
|
private RuntimeInfo runtimeInfo;
|
||||||
|
|
||||||
|
public IBrowserApplicationController Browser { private get; set; }
|
||||||
public IClientHost ClientHost { private get; set; }
|
public IClientHost ClientHost { private get; set; }
|
||||||
public Guid SessionId { private get; set; }
|
public Guid SessionId { private get; set; }
|
||||||
public Settings Settings { private get; set; }
|
public Settings Settings { private get; set; }
|
||||||
|
@ -145,6 +148,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
|
|
||||||
private void RegisterEvents()
|
private void RegisterEvents()
|
||||||
{
|
{
|
||||||
|
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
|
||||||
ClientHost.Shutdown += ClientHost_Shutdown;
|
ClientHost.Shutdown += ClientHost_Shutdown;
|
||||||
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
||||||
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
|
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
|
||||||
|
@ -155,6 +159,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
|
|
||||||
private void DeregisterEvents()
|
private void DeregisterEvents()
|
||||||
{
|
{
|
||||||
|
Browser.ConfigurationDownloadRequested -= Browser_ConfigurationDownloadRequested;
|
||||||
ClientHost.Shutdown -= ClientHost_Shutdown;
|
ClientHost.Shutdown -= ClientHost_Shutdown;
|
||||||
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
||||||
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
|
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
|
||||||
|
@ -183,6 +188,53 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
logger.Info("Desktop successfully restored.");
|
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()
|
private void ClientHost_Shutdown()
|
||||||
{
|
{
|
||||||
taskbar.Close();
|
taskbar.Close();
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
|
||||||
using SafeExamBrowser.Contracts.Communication.Data;
|
using SafeExamBrowser.Contracts.Communication.Data;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Core.Communication.Hosts;
|
using SafeExamBrowser.Core.Communication.Hosts;
|
||||||
|
|
|
@ -17,6 +17,7 @@ using SafeExamBrowser.Client.Notifications;
|
||||||
using SafeExamBrowser.Configuration;
|
using SafeExamBrowser.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Behaviour;
|
using SafeExamBrowser.Contracts.Behaviour;
|
||||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||||
|
using SafeExamBrowser.Contracts.Browser;
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
@ -47,6 +48,7 @@ namespace SafeExamBrowser.Client
|
||||||
private string runtimeHostUri;
|
private string runtimeHostUri;
|
||||||
private Guid startupToken;
|
private Guid startupToken;
|
||||||
|
|
||||||
|
private IBrowserApplicationController browserController;
|
||||||
private ClientConfiguration configuration;
|
private ClientConfiguration configuration;
|
||||||
private IClientHost clientHost;
|
private IClientHost clientHost;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
|
@ -88,7 +90,6 @@ namespace SafeExamBrowser.Client
|
||||||
operations.Enqueue(new RuntimeConnectionOperation(logger, runtimeProxy, startupToken));
|
operations.Enqueue(new RuntimeConnectionOperation(logger, runtimeProxy, startupToken));
|
||||||
operations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeProxy));
|
operations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeProxy));
|
||||||
operations.Enqueue(new DelayedInitializationOperation(BuildCommunicationHostOperation));
|
operations.Enqueue(new DelayedInitializationOperation(BuildCommunicationHostOperation));
|
||||||
operations.Enqueue(new DelegateOperation(UpdateClientControllerDependencies));
|
|
||||||
// TODO
|
// TODO
|
||||||
//operations.Enqueue(new DelayedInitializationOperation(BuildKeyboardInterceptorOperation));
|
//operations.Enqueue(new DelayedInitializationOperation(BuildKeyboardInterceptorOperation));
|
||||||
//operations.Enqueue(new WindowMonitorOperation(logger, windowMonitor));
|
//operations.Enqueue(new WindowMonitorOperation(logger, windowMonitor));
|
||||||
|
@ -98,6 +99,7 @@ namespace SafeExamBrowser.Client
|
||||||
operations.Enqueue(new DelayedInitializationOperation(BuildBrowserOperation));
|
operations.Enqueue(new DelayedInitializationOperation(BuildBrowserOperation));
|
||||||
operations.Enqueue(new ClipboardOperation(logger, nativeMethods));
|
operations.Enqueue(new ClipboardOperation(logger, nativeMethods));
|
||||||
//operations.Enqueue(new DelayedInitializationOperation(BuildMouseInterceptorOperation));
|
//operations.Enqueue(new DelayedInitializationOperation(BuildMouseInterceptorOperation));
|
||||||
|
operations.Enqueue(new DelegateOperation(UpdateClientControllerDependencies));
|
||||||
|
|
||||||
var sequence = new OperationSequence(logger, operations);
|
var sequence = new OperationSequence(logger, operations);
|
||||||
|
|
||||||
|
@ -150,10 +152,12 @@ namespace SafeExamBrowser.Client
|
||||||
private IOperation BuildBrowserOperation()
|
private IOperation BuildBrowserOperation()
|
||||||
{
|
{
|
||||||
var moduleLogger = new ModuleLogger(logger, typeof(BrowserApplicationController));
|
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 browserInfo = new BrowserApplicationInfo();
|
||||||
var operation = new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory);
|
var operation = new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory);
|
||||||
|
|
||||||
|
this.browserController = browserController;
|
||||||
|
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,6 +204,7 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
private void UpdateClientControllerDependencies()
|
private void UpdateClientControllerDependencies()
|
||||||
{
|
{
|
||||||
|
ClientController.Browser = browserController;
|
||||||
ClientController.ClientHost = clientHost;
|
ClientController.ClientHost = clientHost;
|
||||||
ClientController.RuntimeInfo = configuration.RuntimeInfo;
|
ClientController.RuntimeInfo = configuration.RuntimeInfo;
|
||||||
ClientController.SessionId = configuration.SessionId;
|
ClientController.SessionId = configuration.SessionId;
|
||||||
|
|
|
@ -44,8 +44,8 @@
|
||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
<OutputPath>bin\x86\Release\</OutputPath>
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
|
@ -54,7 +54,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace SafeExamBrowser.Configuration
|
||||||
|
|
||||||
public ISessionData CurrentSession { get; private set; }
|
public ISessionData CurrentSession { get; private set; }
|
||||||
public Settings CurrentSettings { get; private set; }
|
public Settings CurrentSettings { get; private set; }
|
||||||
public string ReconfigurationUrl { get; set; }
|
public string ReconfigurationFilePath { get; set; }
|
||||||
|
|
||||||
public RuntimeInfo RuntimeInfo
|
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
|
// TODO: Implement loading mechanism
|
||||||
|
|
||||||
return LoadDefaultSettings();
|
LoadDefaultSettings();
|
||||||
|
|
||||||
|
return LoadStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Settings LoadDefaultSettings()
|
public void LoadDefaultSettings()
|
||||||
{
|
{
|
||||||
var settings = new Settings()
|
// TODO: Implement default settings
|
||||||
{
|
|
||||||
// TODO: Implement default settings
|
|
||||||
ServicePolicy = ServicePolicy.Optional
|
|
||||||
};
|
|
||||||
|
|
||||||
settings.Browser.StartUrl = "https://www.safeexambrowser.org/testing";
|
CurrentSettings = new Settings();
|
||||||
settings.Browser.AllowAddressBar = true;
|
|
||||||
settings.Browser.AllowBackwardNavigation = true;
|
|
||||||
settings.Browser.AllowDeveloperConsole = true;
|
|
||||||
settings.Browser.AllowForwardNavigation = true;
|
|
||||||
settings.Browser.AllowReloading = true;
|
|
||||||
|
|
||||||
settings.Taskbar.AllowApplicationLog = true;
|
CurrentSettings.ServicePolicy = ServicePolicy.Optional;
|
||||||
settings.Taskbar.AllowKeyboardLayout = true;
|
|
||||||
settings.Taskbar.AllowWirelessNetwork = true;
|
|
||||||
|
|
||||||
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()
|
private void InitializeRuntimeInfo()
|
||||||
|
@ -105,26 +104,26 @@ namespace SafeExamBrowser.Configuration
|
||||||
var logFolder = Path.Combine(appDataFolder, "Logs");
|
var logFolder = Path.Combine(appDataFolder, "Logs");
|
||||||
var logFilePrefix = startTime.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
|
var logFilePrefix = startTime.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
|
||||||
|
|
||||||
runtimeInfo = new RuntimeInfo
|
runtimeInfo = new RuntimeInfo();
|
||||||
{
|
runtimeInfo.ApplicationStartTime = startTime;
|
||||||
ApplicationStartTime = startTime,
|
runtimeInfo.AppDataFolder = appDataFolder;
|
||||||
AppDataFolder = appDataFolder,
|
runtimeInfo.BrowserCachePath = Path.Combine(appDataFolder, "Cache");
|
||||||
BrowserCachePath = Path.Combine(appDataFolder, "Cache"),
|
runtimeInfo.BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt");
|
||||||
BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt"),
|
runtimeInfo.ClientId = Guid.NewGuid();
|
||||||
ClientId = Guid.NewGuid(),
|
runtimeInfo.ClientAddress = $"{BASE_ADDRESS}/client/{Guid.NewGuid()}";
|
||||||
ClientAddress = $"{BASE_ADDRESS}/client/{Guid.NewGuid()}",
|
runtimeInfo.ClientExecutablePath = Path.Combine(Path.GetDirectoryName(executable.Location), $"{nameof(SafeExamBrowser)}.Client.exe");
|
||||||
ClientExecutablePath = Path.Combine(Path.GetDirectoryName(executable.Location), $"{nameof(SafeExamBrowser)}.Client.exe"),
|
runtimeInfo.ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt");
|
||||||
ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt"),
|
runtimeInfo.ConfigurationFileExtension = ".seb";
|
||||||
DefaultSettingsFileName = "SebClientSettings.seb",
|
runtimeInfo.DefaultSettingsFileName = "SebClientSettings.seb";
|
||||||
ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright,
|
runtimeInfo.DownloadDirectory = Path.Combine(appDataFolder, "Downloads");
|
||||||
ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser)),
|
runtimeInfo.ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright;
|
||||||
ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title,
|
runtimeInfo.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser));
|
||||||
ProgramVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion,
|
runtimeInfo.ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title;
|
||||||
RuntimeId = Guid.NewGuid(),
|
runtimeInfo.ProgramVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||||
RuntimeAddress = $"{BASE_ADDRESS}/runtime/{Guid.NewGuid()}",
|
runtimeInfo.RuntimeId = Guid.NewGuid();
|
||||||
RuntimeLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.txt"),
|
runtimeInfo.RuntimeAddress = $"{BASE_ADDRESS}/runtime/{Guid.NewGuid()}";
|
||||||
ServiceAddress = $"{BASE_ADDRESS}/service"
|
runtimeInfo.RuntimeLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.txt");
|
||||||
};
|
runtimeInfo.ServiceAddress = $"{BASE_ADDRESS}/service";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateRuntimeInfo()
|
private void UpdateRuntimeInfo()
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using SafeExamBrowser.Contracts.Browser;
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
|
@ -18,6 +19,11 @@ namespace SafeExamBrowser.Contracts.Behaviour
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IClientController
|
public interface IClientController
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The controller for the browser application.
|
||||||
|
/// </summary>
|
||||||
|
IBrowserApplicationController Browser { set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The client host used for communication handling.
|
/// The client host used for communication handling.
|
||||||
/// </summary>
|
/// </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
|
public class ReconfigurationMessage : Message
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The locator of the new configuration to be used.
|
/// The full path of the configuration file to be used.
|
||||||
/// </summary>
|
/// </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 System;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication.Hosts
|
namespace SafeExamBrowser.Contracts.Communication.Hosts
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication.Hosts
|
namespace SafeExamBrowser.Contracts.Communication.Hosts
|
||||||
{
|
{
|
||||||
|
@ -31,9 +32,9 @@ namespace SafeExamBrowser.Contracts.Communication.Hosts
|
||||||
event CommunicationEventHandler ClientReady;
|
event CommunicationEventHandler ClientReady;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event fired when the client detected a reconfiguration request.
|
/// Event fired when the client requested a reconfiguration of the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event CommunicationEventHandler ReconfigurationRequested;
|
event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event fired when the client requests to shut down the application.
|
/// Event fired when the client requests to shut down the application.
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication
|
namespace SafeExamBrowser.Contracts.Communication
|
||||||
{
|
{
|
||||||
public delegate void CommunicationEventHandler();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the common functionality for all communication hosts. A communication host can be hosted by an application component to
|
/// 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).
|
/// allow for inter-process communication with other components (e.g. runtime -> client communication).
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication
|
namespace SafeExamBrowser.Contracts.Communication
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,10 +34,9 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies
|
||||||
void RequestShutdown();
|
void RequestShutdown();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Requests the runtime to reconfigure the application with the configuration from the given location. Returns <c>true</c> if
|
/// Requests the runtime to reconfigure the application with the specified configuration.
|
||||||
/// the runtime accepted the request, otherwise <c>false</c>.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
/// <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; }
|
Settings.Settings CurrentSettings { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
string ReconfigurationUrl { get; set; }
|
string ReconfigurationFilePath { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The runtime information for the currently running application instance.
|
/// The runtime information for the currently running application instance.
|
||||||
|
@ -48,14 +48,14 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
void InitializeSessionConfiguration();
|
void InitializeSessionConfiguration();
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <exception cref="ArgumentException">Thrown if the given path cannot be resolved to a settings file.</exception>
|
LoadStatus LoadSettings(Uri resource, string settingsPassword = null, string adminPassword = null);
|
||||||
Settings.Settings LoadSettings(Uri path);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads the default settings.
|
/// Loads the default settings.
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Defines the fundamental, global configuration information for all application components.
|
/// Defines the fundamental, global configuration information for all application components.
|
||||||
|
/// TODO: Rename to Globals or GlobalConfiguration or alike!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RuntimeInfo
|
public class RuntimeInfo
|
||||||
|
@ -56,11 +57,21 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ClientLogFile { get; set; }
|
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>
|
/// <summary>
|
||||||
/// The default file name for application settings.
|
/// The default file name for application settings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DefaultSettingsFileName { get; set; }
|
public string DefaultSettingsFileName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default directory for file downloads.
|
||||||
|
/// </summary>
|
||||||
|
public string DownloadDirectory { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The copyright information for the application (i.e. the executing assembly).
|
/// The copyright information for the application (i.e. the executing assembly).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -31,6 +31,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowDeveloperConsole { get; set; }
|
public bool AllowDeveloperConsole { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the user should be allowed to download files.
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowDownloads { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user should be allowed to navigate forwards in a browser window.
|
/// Determines whether the user should be allowed to navigate forwards in a browser window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -20,6 +20,8 @@ namespace SafeExamBrowser.Contracts.I18n
|
||||||
MessageBox_ApplicationErrorTitle,
|
MessageBox_ApplicationErrorTitle,
|
||||||
MessageBox_ClientConfigurationQuestion,
|
MessageBox_ClientConfigurationQuestion,
|
||||||
MessageBox_ClientConfigurationQuestionTitle,
|
MessageBox_ClientConfigurationQuestionTitle,
|
||||||
|
MessageBox_ConfigurationDownloadError,
|
||||||
|
MessageBox_ConfigurationDownloadErrorTitle,
|
||||||
MessageBox_Quit,
|
MessageBox_Quit,
|
||||||
MessageBox_QuitTitle,
|
MessageBox_QuitTitle,
|
||||||
MessageBox_QuitError,
|
MessageBox_QuitError,
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
@ -57,6 +56,13 @@
|
||||||
<Compile Include="Behaviour\IRuntimeController.cs" />
|
<Compile Include="Behaviour\IRuntimeController.cs" />
|
||||||
<Compile Include="Behaviour\OperationModel\IOperationSequence.cs" />
|
<Compile Include="Behaviour\OperationModel\IOperationSequence.cs" />
|
||||||
<Compile Include="Behaviour\OperationModel\OperationResult.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\IClientHost.cs" />
|
||||||
<Compile Include="Communication\Hosts\IHostObject.cs" />
|
<Compile Include="Communication\Hosts\IHostObject.cs" />
|
||||||
<Compile Include="Communication\Hosts\IHostObjectFactory.cs" />
|
<Compile Include="Communication\Hosts\IHostObjectFactory.cs" />
|
||||||
|
@ -84,6 +90,7 @@
|
||||||
<Compile Include="Communication\Data\SimpleResponsePurport.cs" />
|
<Compile Include="Communication\Data\SimpleResponsePurport.cs" />
|
||||||
<Compile Include="Communication\Data\SimpleResponse.cs" />
|
<Compile Include="Communication\Data\SimpleResponse.cs" />
|
||||||
<Compile Include="Configuration\ClientConfiguration.cs" />
|
<Compile Include="Configuration\ClientConfiguration.cs" />
|
||||||
|
<Compile Include="Configuration\LoadStatus.cs" />
|
||||||
<Compile Include="Configuration\RuntimeInfo.cs" />
|
<Compile Include="Configuration\RuntimeInfo.cs" />
|
||||||
<Compile Include="Configuration\ISessionData.cs" />
|
<Compile Include="Configuration\ISessionData.cs" />
|
||||||
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
|
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
|
||||||
|
|
|
@ -96,47 +96,56 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustCorrectlyRequestReconfiguration()
|
public void MustCorrectlyRequestReconfiguration()
|
||||||
{
|
{
|
||||||
var url = "sebs://some/url.seb";
|
//var url = "sebs://some/url.seb";
|
||||||
var response = new ReconfigurationResponse
|
//var response = new ReconfigurationResponse
|
||||||
{
|
//{
|
||||||
Accepted = true
|
// 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]
|
[TestMethod]
|
||||||
public void MustCorrectlyHandleDeniedReconfigurationRequest()
|
public void MustCorrectlyHandleDeniedReconfigurationRequest()
|
||||||
{
|
{
|
||||||
var url = "sebs://some/url.seb";
|
//var url = "sebs://some/url.seb";
|
||||||
var response = new ReconfigurationResponse
|
//var response = new ReconfigurationResponse
|
||||||
{
|
//{
|
||||||
Accepted = false
|
// 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]
|
[TestMethod]
|
||||||
public void MustNotFailIfIncorrectResponseToReconfigurationRequest()
|
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]
|
[TestMethod]
|
||||||
|
|
|
@ -53,7 +53,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
<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 System.Timers;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
using SafeExamBrowser.Contracts.Communication.Data;
|
using SafeExamBrowser.Contracts.Communication.Data;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
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()
|
public void RequestShutdown()
|
||||||
|
|
|
@ -18,6 +18,12 @@
|
||||||
<Entry key="MessageBox_ClientConfigurationQuestionTitle">
|
<Entry key="MessageBox_ClientConfigurationQuestionTitle">
|
||||||
Configuration Successful
|
Configuration Successful
|
||||||
</Entry>
|
</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">
|
<Entry key="MessageBox_Quit">
|
||||||
Would you really like to quit the application?
|
Would you really like to quit the application?
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|
|
@ -45,8 +45,9 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
info.AppDataFolder = @"C:\Not\Really\AppData";
|
info.AppDataFolder = @"C:\Not\Really\AppData";
|
||||||
info.DefaultSettingsFileName = "SettingsDummy.txt";
|
info.DefaultSettingsFileName = "SettingsDummy.txt";
|
||||||
info.ProgramDataFolder = @"C:\Not\Really\ProgramData";
|
info.ProgramDataFolder = @"C:\Not\Really\ProgramData";
|
||||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>())).Returns(settings);
|
// TODO
|
||||||
repository.Setup(r => r.LoadDefaultSettings()).Returns(settings);
|
//repository.Setup(r => r.LoadSettings(It.IsAny<Uri>())).Returns(settings);
|
||||||
|
//repository.Setup(r => r.LoadDefaultSettings()).Returns(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -88,7 +89,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
|
|
||||||
sut.Perform();
|
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]
|
[TestMethod]
|
||||||
|
@ -103,7 +105,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
|
|
||||||
sut.Perform();
|
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]
|
[TestMethod]
|
||||||
|
@ -117,7 +120,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
|
|
||||||
sut.Perform();
|
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]
|
[TestMethod]
|
||||||
|
|
|
@ -53,7 +53,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
<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.RuntimeController.Terminate();
|
||||||
instances.LogShutdownInformation();
|
instances.LogShutdownInformation();
|
||||||
|
|
||||||
|
// TODO: Which UI operation is being cancelled without the timeout? Same problem with client? -> Debug!
|
||||||
|
Thread.Sleep(20);
|
||||||
|
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
|
|
@ -50,35 +50,58 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
logger.Info("Initializing application configuration...");
|
logger.Info("Initializing application configuration...");
|
||||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration);
|
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration);
|
||||||
|
|
||||||
var isValidUri = TryGetSettingsUri(out Uri uri);
|
var isValidUri = TryInitializeSettingsUri(out Uri uri);
|
||||||
|
|
||||||
if (isValidUri)
|
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 resource specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
|
||||||
logger.Info("No valid settings file specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
|
repository.LoadDefaultSettings();
|
||||||
repository.LoadDefaultSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Repeat()
|
||||||
{
|
{
|
||||||
// TODO: How will the new settings be retrieved? Uri passed to the repository? If yes, how does the Uri get here?!
|
logger.Info("Initializing new application configuration...");
|
||||||
// -> IDEA: Use configuration repository as container?
|
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration);
|
||||||
// -> IDEA: Introduce IRepeatParams or alike?
|
|
||||||
|
|
||||||
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()
|
public void Revert()
|
||||||
|
@ -86,7 +109,79 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
// Nothing to do here...
|
// 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 path = string.Empty;
|
||||||
var isValidUri = false;
|
var isValidUri = false;
|
||||||
|
@ -119,19 +214,14 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
return isValidUri;
|
return isValidUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool LoadSettings(Uri uri)
|
private bool TryValidateSettingsUri(string path, out Uri uri)
|
||||||
{
|
{
|
||||||
var abort = false;
|
var isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
||||||
var settings = repository.LoadSettings(uri);
|
|
||||||
|
|
||||||
if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient)
|
isValidUri &= uri != null && uri.IsFile;
|
||||||
{
|
isValidUri &= File.Exists(path);
|
||||||
abort = IsConfigurationSufficient();
|
|
||||||
|
|
||||||
logger.Info($"The user chose to {(abort ? "abort" : "continue")} after successful client configuration.");
|
return isValidUri;
|
||||||
}
|
|
||||||
|
|
||||||
return abort;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsConfigurationSufficient()
|
private bool IsConfigurationSufficient()
|
||||||
|
@ -142,5 +232,21 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
|
|
||||||
return abort == MessageBoxResult.Yes;
|
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 System;
|
||||||
using SafeExamBrowser.Contracts.Behaviour;
|
using SafeExamBrowser.Contracts.Behaviour;
|
||||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
@ -169,13 +170,14 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
||||||
|
|
||||||
if (result == OperationResult.Failed)
|
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);
|
messageBox.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error);
|
||||||
}
|
|
||||||
|
|
||||||
if (!initial)
|
if (!initial)
|
||||||
{
|
{
|
||||||
logger.Info("Terminating application...");
|
logger.Info("Terminating application...");
|
||||||
shutdown.Invoke();
|
shutdown.Invoke();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,10 +247,22 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
||||||
shutdown.Invoke();
|
shutdown.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RuntimeHost_ReconfigurationRequested()
|
private void RuntimeHost_ReconfigurationRequested(ReconfigurationEventArgs args)
|
||||||
{
|
{
|
||||||
logger.Info($"Starting reconfiguration...");
|
var mode = configuration.CurrentSettings.ConfigurationMode;
|
||||||
StartSession();
|
|
||||||
|
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()
|
private void RuntimeHost_ShutdownRequested()
|
||||||
|
|
|
@ -7,12 +7,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
|
||||||
using SafeExamBrowser.Contracts.Communication.Data;
|
using SafeExamBrowser.Contracts.Communication.Data;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Core.Communication.Hosts;
|
using SafeExamBrowser.Core.Communication.Hosts;
|
||||||
|
|
||||||
|
@ -27,7 +25,7 @@ namespace SafeExamBrowser.Runtime.Communication
|
||||||
|
|
||||||
public event CommunicationEventHandler ClientDisconnected;
|
public event CommunicationEventHandler ClientDisconnected;
|
||||||
public event CommunicationEventHandler ClientReady;
|
public event CommunicationEventHandler ClientReady;
|
||||||
public event CommunicationEventHandler ReconfigurationRequested;
|
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
||||||
public event CommunicationEventHandler ShutdownRequested;
|
public event CommunicationEventHandler ShutdownRequested;
|
||||||
|
|
||||||
public RuntimeHost(string address, IConfigurationRepository configuration, IHostObjectFactory factory, ILogger logger) : base(address, factory, logger)
|
public RuntimeHost(string address, IConfigurationRepository configuration, IHostObjectFactory factory, ILogger logger) : base(address, factory, logger)
|
||||||
|
@ -64,9 +62,9 @@ namespace SafeExamBrowser.Runtime.Communication
|
||||||
{
|
{
|
||||||
switch (message)
|
switch (message)
|
||||||
{
|
{
|
||||||
case ReconfigurationMessage reconfigurationMessage:
|
case ReconfigurationMessage r:
|
||||||
// TODO: Not the job of the host, fire event or alike!
|
ReconfigurationRequested?.InvokeAsync(new ReconfigurationEventArgs { ConfigurationPath = r.ConfigurationPath });
|
||||||
return Handle(reconfigurationMessage);
|
return new SimpleResponse(SimpleResponsePurport.Acknowledged);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SimpleResponse(SimpleResponsePurport.UnknownMessage);
|
return new SimpleResponse(SimpleResponsePurport.UnknownMessage);
|
||||||
|
@ -89,22 +87,5 @@ namespace SafeExamBrowser.Runtime.Communication
|
||||||
|
|
||||||
return new SimpleResponse(SimpleResponsePurport.UnknownMessage);
|
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>
|
<DebugType>full</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
<OutputPath>bin\x86\Release\</OutputPath>
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
|
@ -71,7 +71,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="SimpleWifi, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="SimpleWifi, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL">
|
<Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL">
|
||||||
|
|
|
@ -46,7 +46,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|
|
@ -9,6 +9,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Core", "Saf
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0A9E6674-2FB4-42EA-85DE-B2445B9AE2D9}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0A9E6674-2FB4-42EA-85DE-B2445B9AE2D9}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
.editorconfig = .editorconfig
|
||||||
LICENSE.txt = LICENSE.txt
|
LICENSE.txt = LICENSE.txt
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
|
Loading…
Reference in a new issue