SEBWIN-310: Implemented quit URL.

This commit is contained in:
dbuechel 2019-12-19 15:02:40 +01:00
parent 4b415a5f45
commit 130dd45ff6
17 changed files with 213 additions and 88 deletions

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2019 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.Browser.Contracts.Events
{
/// <summary>
/// Event handler used to indicate that a termination request has been detected.
/// </summary>
public delegate void TerminationRequestedEventHandler();
}

View file

@ -20,5 +20,10 @@ namespace SafeExamBrowser.Browser.Contracts
/// Event fired when the browser application detects a download request for an application configuration file. /// Event fired when the browser application detects a download request for an application configuration file.
/// </summary> /// </summary>
event DownloadRequestedEventHandler ConfigurationDownloadRequested; event DownloadRequestedEventHandler ConfigurationDownloadRequested;
/// <summary>
/// Event fired when the browser application detects a request to terminate SEB.
/// </summary>
event TerminationRequestedEventHandler TerminationRequested;
} }
} }

View file

@ -57,6 +57,7 @@
<Compile Include="Events\DownloadEventArgs.cs" /> <Compile Include="Events\DownloadEventArgs.cs" />
<Compile Include="Events\DownloadFinishedCallback.cs" /> <Compile Include="Events\DownloadFinishedCallback.cs" />
<Compile Include="Events\DownloadRequestedEventHandler.cs" /> <Compile Include="Events\DownloadRequestedEventHandler.cs" />
<Compile Include="Events\TerminationRequestedEventHandler.cs" />
<Compile Include="Filters\IRequestFilter.cs" /> <Compile Include="Filters\IRequestFilter.cs" />
<Compile Include="Filters\IRule.cs" /> <Compile Include="Filters\IRule.cs" />
<Compile Include="Filters\IRuleFactory.cs" /> <Compile Include="Filters\IRuleFactory.cs" />

View file

@ -20,7 +20,6 @@ using SafeExamBrowser.Browser.Events;
using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Settings.Browser;
using SafeExamBrowser.Settings.Browser.Proxy; using SafeExamBrowser.Settings.Browser.Proxy;
using SafeExamBrowser.Settings.Logging; using SafeExamBrowser.Settings.Logging;
using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts;
@ -49,6 +48,7 @@ namespace SafeExamBrowser.Browser
public event DownloadRequestedEventHandler ConfigurationDownloadRequested; public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
public event WindowsChangedEventHandler WindowsChanged; public event WindowsChangedEventHandler WindowsChanged;
public event TerminationRequestedEventHandler TerminationRequested;
public BrowserApplication( public BrowserApplication(
AppConfig appConfig, AppConfig appConfig,
@ -127,6 +127,7 @@ namespace SafeExamBrowser.Browser
instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args); instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
instance.PopupRequested += Instance_PopupRequested; instance.PopupRequested += Instance_PopupRequested;
instance.Terminated += Instance_Terminated; instance.Terminated += Instance_Terminated;
instance.TerminationRequested += () => TerminationRequested?.Invoke();
instance.Initialize(); instance.Initialize();
instances.Add(instance); instances.Add(instance);

View file

@ -40,9 +40,9 @@ namespace SafeExamBrowser.Browser
private IMessageBox messageBox; private IMessageBox messageBox;
private IModuleLogger logger; private IModuleLogger logger;
private BrowserSettings settings; private BrowserSettings settings;
private string startUrl;
private IText text; private IText text;
private IUserInterfaceFactory uiFactory; private IUserInterfaceFactory uiFactory;
private string url;
private double zoomLevel; private double zoomLevel;
private WindowSettings WindowSettings private WindowSettings WindowSettings
@ -59,6 +59,7 @@ namespace SafeExamBrowser.Browser
internal event DownloadRequestedEventHandler ConfigurationDownloadRequested; internal event DownloadRequestedEventHandler ConfigurationDownloadRequested;
internal event PopupRequestedEventHandler PopupRequested; internal event PopupRequestedEventHandler PopupRequested;
internal event InstanceTerminatedEventHandler Terminated; internal event InstanceTerminatedEventHandler Terminated;
internal event TerminationRequestedEventHandler TerminationRequested;
public event IconChangedEventHandler IconChanged; public event IconChangedEventHandler IconChanged;
public event TitleChangedEventHandler TitleChanged; public event TitleChangedEventHandler TitleChanged;
@ -72,7 +73,7 @@ namespace SafeExamBrowser.Browser
IModuleLogger logger, IModuleLogger logger,
IText text, IText text,
IUserInterfaceFactory uiFactory, IUserInterfaceFactory uiFactory,
string url) string startUrl)
{ {
this.appConfig = appConfig; this.appConfig = appConfig;
this.Id = id; this.Id = id;
@ -83,7 +84,7 @@ namespace SafeExamBrowser.Browser
this.settings = settings; this.settings = settings;
this.text = text; this.text = text;
this.uiFactory = uiFactory; this.uiFactory = uiFactory;
this.url = url; this.startUrl = startUrl;
} }
public void Activate() public void Activate()
@ -106,12 +107,12 @@ namespace SafeExamBrowser.Browser
{ {
var contextMenuHandler = new ContextMenuHandler(); var contextMenuHandler = new ContextMenuHandler();
var displayHandler = new DisplayHandler(); var displayHandler = new DisplayHandler();
var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} {Id}"); var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} #{Id}");
var downloadHandler = new DownloadHandler(appConfig, settings, downloadLogger); var downloadHandler = new DownloadHandler(appConfig, settings, downloadLogger);
var keyboardHandler = new KeyboardHandler(); var keyboardHandler = new KeyboardHandler();
var lifeSpanHandler = new LifeSpanHandler(); var lifeSpanHandler = new LifeSpanHandler();
var requestFilter = new RequestFilter(); var requestFilter = new RequestFilter();
var requestLogger = logger.CloneFor($"{nameof(RequestHandler)} {Id}"); var requestLogger = logger.CloneFor($"{nameof(RequestHandler)} #{Id}");
var requestHandler = new RequestHandler(appConfig, requestFilter, requestLogger, settings, text); var requestHandler = new RequestHandler(appConfig, requestFilter, requestLogger, settings, text);
Icon = new BrowserIconResource(); Icon = new BrowserIconResource();
@ -124,11 +125,12 @@ namespace SafeExamBrowser.Browser
keyboardHandler.ZoomOutRequested += ZoomOutRequested; keyboardHandler.ZoomOutRequested += ZoomOutRequested;
keyboardHandler.ZoomResetRequested += ZoomResetRequested; keyboardHandler.ZoomResetRequested += ZoomResetRequested;
lifeSpanHandler.PopupRequested += LifeSpanHandler_PopupRequested; lifeSpanHandler.PopupRequested += LifeSpanHandler_PopupRequested;
requestHandler.QuitUrlVisited += RequestHandler_QuitUrlVisited;
requestHandler.RequestBlocked += RequestHandler_RequestBlocked; requestHandler.RequestBlocked += RequestHandler_RequestBlocked;
InitializeRequestFilter(requestFilter); InitializeRequestFilter(requestFilter);
control = new BrowserControl(contextMenuHandler, displayHandler, downloadHandler, keyboardHandler, lifeSpanHandler, requestHandler, url); control = new BrowserControl(contextMenuHandler, displayHandler, downloadHandler, keyboardHandler, lifeSpanHandler, requestHandler, startUrl);
control.AddressChanged += Control_AddressChanged; control.AddressChanged += Control_AddressChanged;
control.LoadingStateChanged += Control_LoadingStateChanged; control.LoadingStateChanged += Control_LoadingStateChanged;
control.TitleChanged += Control_TitleChanged; control.TitleChanged += Control_TitleChanged;
@ -276,6 +278,35 @@ namespace SafeExamBrowser.Browser
} }
} }
private void RequestHandler_QuitUrlVisited(string url)
{
Task.Run(() =>
{
if (settings.ConfirmQuitUrl)
{
var message = text.Get(TextKey.MessageBox_BrowserQuitUrlConfirmation);
var title = text.Get(TextKey.MessageBox_BrowserQuitUrlConfirmationTitle);
var result = messageBox.Show(message, title, MessageBoxAction.YesNo, MessageBoxIcon.Question, window);
var terminate = result == MessageBoxResult.Yes;
if (terminate)
{
logger.Info($"User confirmed termination via quit URL '{url}', forwarding request...");
TerminationRequested?.Invoke();
}
else
{
logger.Info($"User aborted termination via quit URL '{url}'.");
}
}
else
{
logger.Info($"Automatically requesting termination due to quit URL '{url}'...");
TerminationRequested?.Invoke();
}
});
}
private void RequestHandler_RequestBlocked(string url) private void RequestHandler_RequestBlocked(string url)
{ {
Task.Run(() => Task.Run(() =>
@ -285,7 +316,7 @@ namespace SafeExamBrowser.Browser
control.TitleChanged -= Control_TitleChanged; control.TitleChanged -= Control_TitleChanged;
if (url == this.url) if (url.Equals(startUrl, StringComparison.OrdinalIgnoreCase))
{ {
window.UpdateTitle($"*** {title} ***"); window.UpdateTitle($"*** {title} ***");
TitleChanged?.Invoke($"*** {title} ***"); TitleChanged?.Invoke($"*** {title} ***");

View file

@ -8,5 +8,5 @@
namespace SafeExamBrowser.Browser.Events namespace SafeExamBrowser.Browser.Events
{ {
internal delegate void RequestBlockedEventHandler(string url); internal delegate void UrlEventHandler(string url);
} }

View file

@ -25,7 +25,8 @@ namespace SafeExamBrowser.Browser.Handlers
private ResourceHandler resourceHandler; private ResourceHandler resourceHandler;
private BrowserSettings settings; private BrowserSettings settings;
internal event RequestBlockedEventHandler RequestBlocked; internal event UrlEventHandler QuitUrlVisited;
internal event UrlEventHandler RequestBlocked;
internal RequestHandler(AppConfig appConfig, IRequestFilter filter, ILogger logger, BrowserSettings settings, IText text) internal RequestHandler(AppConfig appConfig, IRequestFilter filter, ILogger logger, BrowserSettings settings, IText text)
{ {
@ -60,6 +61,13 @@ namespace SafeExamBrowser.Browser.Handlers
protected override bool OnBeforeBrowse(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect) protected override bool OnBeforeBrowse(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect)
{ {
if (IsQuitUrl(request))
{
QuitUrlVisited?.Invoke(request.Url);
return true;
}
if (Block(request)) if (Block(request))
{ {
RequestBlocked?.Invoke(request.Url); RequestBlocked?.Invoke(request.Url);
@ -70,6 +78,18 @@ namespace SafeExamBrowser.Browser.Handlers
return base.OnBeforeBrowse(webBrowser, browser, frame, request, userGesture, isRedirect); return base.OnBeforeBrowse(webBrowser, browser, frame, request, userGesture, isRedirect);
} }
private bool IsQuitUrl(IRequest request)
{
var isQuitUrl = settings.QuitUrl?.Equals(request.Url, StringComparison.OrdinalIgnoreCase) == true;
if (isQuitUrl)
{
logger.Debug($"Detected quit URL '{request.Url}'.");
}
return isQuitUrl;
}
private bool Block(IRequest request) private bool Block(IRequest request)
{ {
if (settings.Filter.ProcessMainRequests) if (settings.Filter.ProcessMainRequests)

View file

@ -68,7 +68,7 @@
<Compile Include="Events\PopupRequestedEventArgs.cs" /> <Compile Include="Events\PopupRequestedEventArgs.cs" />
<Compile Include="Events\PopupRequestedEventHandler.cs" /> <Compile Include="Events\PopupRequestedEventHandler.cs" />
<Compile Include="Events\ProgressChangedEventHandler.cs" /> <Compile Include="Events\ProgressChangedEventHandler.cs" />
<Compile Include="Events\RequestBlockedEventHandler.cs" /> <Compile Include="Events\UrlEventHandler.cs" />
<Compile Include="Filters\RequestFilter.cs" /> <Compile Include="Filters\RequestFilter.cs" />
<Compile Include="Filters\Rules\RegexRule.cs" /> <Compile Include="Filters\Rules\RegexRule.cs" />
<Compile Include="Filters\RuleFactory.cs" /> <Compile Include="Filters\RuleFactory.cs" />

View file

@ -232,6 +232,17 @@ namespace SafeExamBrowser.Client.UnitTests
It.Is<IWindow>(w => w == lockScreen.Object)), Times.Exactly(attempt - 1)); It.Is<IWindow>(w => w == lockScreen.Object)), Times.Exactly(attempt - 1));
} }
[TestMethod]
public void Browser_MustTerminateIfRequested()
{
runtimeProxy.Setup(p => p.RequestShutdown()).Returns(new CommunicationResult(true));
sut.TryStart();
browser.Raise(b => b.TerminationRequested += null);
runtimeProxy.Verify(p => p.RequestShutdown(), Times.Once);
}
[TestMethod] [TestMethod]
public void Communication_MustCorrectlyHandleMessageBoxRequest() public void Communication_MustCorrectlyHandleMessageBoxRequest()
{ {

View file

@ -171,6 +171,7 @@ namespace SafeExamBrowser.Client
applicationMonitor.ExplorerStarted += ApplicationMonitor_ExplorerStarted; applicationMonitor.ExplorerStarted += ApplicationMonitor_ExplorerStarted;
applicationMonitor.TerminationFailed += ApplicationMonitor_TerminationFailed; applicationMonitor.TerminationFailed += ApplicationMonitor_TerminationFailed;
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested; Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
Browser.TerminationRequested += Browser_TerminationRequested;
ClientHost.MessageBoxRequested += ClientHost_MessageBoxRequested; ClientHost.MessageBoxRequested += ClientHost_MessageBoxRequested;
ClientHost.PasswordRequested += ClientHost_PasswordRequested; ClientHost.PasswordRequested += ClientHost_PasswordRequested;
ClientHost.ReconfigurationDenied += ClientHost_ReconfigurationDenied; ClientHost.ReconfigurationDenied += ClientHost_ReconfigurationDenied;
@ -321,8 +322,7 @@ namespace SafeExamBrowser.Client
} }
else if (result.OptionId == terminateOption.Id) else if (result.OptionId == terminateOption.Id)
{ {
logger.Info("Initiating shutdown request..."); logger.Info("Attempting to shutdown as requested by the user...");
TryRequestShutdown(); TryRequestShutdown();
} }
} }
@ -343,6 +343,12 @@ namespace SafeExamBrowser.Client
} }
} }
private void Browser_TerminationRequested()
{
logger.Info("Attempting to shutdown as requested by the browser...");
TryRequestShutdown();
}
private void Browser_ConfigurationDownloadFinished(bool success, string filePath = null) private void Browser_ConfigurationDownloadFinished(bool success, string filePath = null)
{ {
if (success) if (success)

View file

@ -94,8 +94,8 @@ namespace SafeExamBrowser.Configuration.UnitTests.DataFormats
Assert.AreEqual(true, result.RawData[Keys.Browser.AllowConfigurationDownloads]); Assert.AreEqual(true, result.RawData[Keys.Browser.AllowConfigurationDownloads]);
Assert.AreEqual(0, result.RawData[Keys.ConfigurationFile.ConfigurationPurpose]); Assert.AreEqual(0, result.RawData[Keys.ConfigurationFile.ConfigurationPurpose]);
Assert.AreEqual("https://safeexambrowser.org/start", result.RawData[Keys.General.StartUrl]); Assert.AreEqual("https://safeexambrowser.org/start", result.RawData[Keys.Browser.StartUrl]);
Assert.AreEqual(true, result.RawData[Keys.Input.Keyboard.EnableF5]); Assert.AreEqual(true, result.RawData[Keys.Keyboard.EnableF5]);
Assert.IsInstanceOfType(result.RawData[Keys.Network.Certificates.EmbeddedCertificates], typeof(List<object>)); Assert.IsInstanceOfType(result.RawData[Keys.Network.Certificates.EmbeddedCertificates], typeof(List<object>));
} }

View file

@ -133,6 +133,22 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
} }
} }
private void MapQuitUrl(AppSettings settings, object value)
{
if (value is string url)
{
settings.Browser.QuitUrl = url;
}
}
private void MapQuitUrlConfirmation(AppSettings settings, object value)
{
if (value is bool confirm)
{
settings.Browser.ConfirmQuitUrl = confirm;
}
}
private void MapRequestFilter(IDictionary<string, object> rawData, AppSettings settings) private void MapRequestFilter(IDictionary<string, object> rawData, AppSettings settings)
{ {
var processMainRequests = rawData.TryGetValue(Keys.Browser.Filter.EnableMainRequestFilter, out var value) && value as bool? == true; var processMainRequests = rawData.TryGetValue(Keys.Browser.Filter.EnableMainRequestFilter, out var value) && value as bool? == true;

View file

@ -22,7 +22,8 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
MapBrowserSettings(item.Key, item.Value, settings); MapBrowserSettings(item.Key, item.Value, settings);
MapConfigurationFileSettings(item.Key, item.Value, settings); MapConfigurationFileSettings(item.Key, item.Value, settings);
MapGeneralSettings(item.Key, item.Value, settings); MapGeneralSettings(item.Key, item.Value, settings);
MapInputSettings(item.Key, item.Value, settings); MapKeyboardSettings(item.Key, item.Value, settings);
MapMouseSettings(item.Key, item.Value, settings);
MapSecuritySettings(item.Key, item.Value, settings); MapSecuritySettings(item.Key, item.Value, settings);
MapUserInterfaceSettings(item.Key, item.Value, settings); MapUserInterfaceSettings(item.Key, item.Value, settings);
} }
@ -133,6 +134,15 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
case Keys.Browser.Proxy.Settings: case Keys.Browser.Proxy.Settings:
MapProxySettings(settings, value); MapProxySettings(settings, value);
break; break;
case Keys.Browser.QuitUrl:
MapQuitUrl(settings, value);
break;
case Keys.Browser.QuitUrlConfirmation:
MapQuitUrlConfirmation(settings, value);
break;
case Keys.Browser.StartUrl:
MapStartUrl(settings, value);
break;
} }
} }
@ -140,6 +150,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
{ {
switch (key) switch (key)
{ {
case Keys.ConfigurationFile.AdminPasswordHash:
MapAdminPasswordHash(settings, value);
break;
case Keys.ConfigurationFile.ConfigurationPurpose: case Keys.ConfigurationFile.ConfigurationPurpose:
MapConfigurationMode(settings, value); MapConfigurationMode(settings, value);
break; break;
@ -150,83 +163,81 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
{ {
switch (key) switch (key)
{ {
case Keys.General.AdminPasswordHash:
MapAdminPasswordHash(settings, value);
break;
case Keys.General.LogLevel: case Keys.General.LogLevel:
MapLogLevel(settings, value); MapLogLevel(settings, value);
break; break;
case Keys.General.QuitPasswordHash:
MapQuitPasswordHash(settings, value);
break;
case Keys.General.StartUrl:
MapStartUrl(settings, value);
break;
} }
} }
private void MapInputSettings(string key, object value, AppSettings settings) private void MapKeyboardSettings(string key, object value, AppSettings settings)
{ {
switch (key) switch (key)
{ {
case Keys.Input.Keyboard.EnableAltEsc: case Keys.Keyboard.EnableAltEsc:
MapEnableAltEsc(settings, value); MapEnableAltEsc(settings, value);
break; break;
case Keys.Input.Keyboard.EnableAltF4: case Keys.Keyboard.EnableAltF4:
MapEnableAltF4(settings, value); MapEnableAltF4(settings, value);
break; break;
case Keys.Input.Keyboard.EnableAltTab: case Keys.Keyboard.EnableAltTab:
MapEnableAltTab(settings, value); MapEnableAltTab(settings, value);
break; break;
case Keys.Input.Keyboard.EnableCtrlEsc: case Keys.Keyboard.EnableCtrlEsc:
MapEnableCtrlEsc(settings, value); MapEnableCtrlEsc(settings, value);
break; break;
case Keys.Input.Keyboard.EnableEsc: case Keys.Keyboard.EnableEsc:
MapEnableEsc(settings, value); MapEnableEsc(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF1: case Keys.Keyboard.EnableF1:
MapEnableF1(settings, value); MapEnableF1(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF2: case Keys.Keyboard.EnableF2:
MapEnableF2(settings, value); MapEnableF2(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF3: case Keys.Keyboard.EnableF3:
MapEnableF3(settings, value); MapEnableF3(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF4: case Keys.Keyboard.EnableF4:
MapEnableF4(settings, value); MapEnableF4(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF5: case Keys.Keyboard.EnableF5:
MapEnableF5(settings, value); MapEnableF5(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF6: case Keys.Keyboard.EnableF6:
MapEnableF6(settings, value); MapEnableF6(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF7: case Keys.Keyboard.EnableF7:
MapEnableF7(settings, value); MapEnableF7(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF8: case Keys.Keyboard.EnableF8:
MapEnableF8(settings, value); MapEnableF8(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF9: case Keys.Keyboard.EnableF9:
MapEnableF9(settings, value); MapEnableF9(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF10: case Keys.Keyboard.EnableF10:
MapEnableF10(settings, value); MapEnableF10(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF11: case Keys.Keyboard.EnableF11:
MapEnableF11(settings, value); MapEnableF11(settings, value);
break; break;
case Keys.Input.Keyboard.EnableF12: case Keys.Keyboard.EnableF12:
MapEnableF12(settings, value); MapEnableF12(settings, value);
break; break;
case Keys.Input.Keyboard.EnablePrintScreen: case Keys.Keyboard.EnablePrintScreen:
MapEnablePrintScreen(settings, value); MapEnablePrintScreen(settings, value);
break; break;
case Keys.Input.Keyboard.EnableSystemKey: case Keys.Keyboard.EnableSystemKey:
MapEnableSystemKey(settings, value); MapEnableSystemKey(settings, value);
break; break;
case Keys.Input.Mouse.EnableRightMouse: }
}
private void MapMouseSettings(string key, object value, AppSettings settings)
{
switch (key)
{
case Keys.Mouse.EnableRightMouse:
MapEnableRightMouse(settings, value); MapEnableRightMouse(settings, value);
break; break;
} }
@ -236,6 +247,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
{ {
switch (key) switch (key)
{ {
case Keys.Security.QuitPasswordHash:
MapQuitPasswordHash(settings, value);
break;
case Keys.Security.ServicePolicy: case Keys.Security.ServicePolicy:
MapServicePolicy(settings, value); MapServicePolicy(settings, value);
break; break;

View file

@ -12,10 +12,6 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
{ {
internal const int WINDOWS = 1; internal const int WINDOWS = 1;
internal static class AdditionalResources
{
}
internal static class Applications internal static class Applications
{ {
internal const string Active = "active"; internal const string Active = "active";
@ -53,6 +49,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
internal const string CustomUserAgentMobile = "browserUserAgentWinTouchModeCustom"; internal const string CustomUserAgentMobile = "browserUserAgentWinTouchModeCustom";
internal const string PopupPolicy = "newBrowserWindowByLinkPolicy"; internal const string PopupPolicy = "newBrowserWindowByLinkPolicy";
internal const string PopupBlockForeignHost = "newBrowserWindowByLinkBlockForeign"; internal const string PopupBlockForeignHost = "newBrowserWindowByLinkBlockForeign";
internal const string QuitUrl = "quitURL";
internal const string QuitUrlConfirmation = "quitURLConfirm";
internal const string StartUrl = "startURL";
internal const string UserAgentModeDesktop = "browserUserAgentWinDesktopMode"; internal const string UserAgentModeDesktop = "browserUserAgentWinDesktopMode";
internal const string UserAgentModeMobile = "browserUserAgentWinTouchMode"; internal const string UserAgentModeMobile = "browserUserAgentWinTouchMode";
@ -143,52 +142,43 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
internal static class ConfigurationFile internal static class ConfigurationFile
{ {
internal const string AdminPasswordHash = "hashedAdminPassword";
internal const string ConfigurationPurpose = "sebConfigPurpose"; internal const string ConfigurationPurpose = "sebConfigPurpose";
internal const string KeepClientConfigEncryption = "clientConfigKeepEncryption"; internal const string KeepClientConfigEncryption = "clientConfigKeepEncryption";
} }
internal static class Exam
{
}
internal static class General internal static class General
{ {
internal const string AdminPasswordHash = "hashedAdminPassword";
internal const string AllowApplicationLog = "allowApplicationLog"; internal const string AllowApplicationLog = "allowApplicationLog";
internal const string LogLevel = "logLevel"; internal const string LogLevel = "logLevel";
internal const string QuitPasswordHash = "hashedQuitPassword";
internal const string StartUrl = "startURL";
} }
internal static class Input internal static class Keyboard
{ {
internal static class Keyboard internal const string EnableAltEsc = "enableAltEsc";
{ internal const string EnableAltTab = "enableAltTab";
internal const string EnableAltEsc = "enableAltEsc"; internal const string EnableAltF4 = "enableAltF4";
internal const string EnableAltTab = "enableAltTab"; internal const string EnableCtrlEsc = "enableCtrlEsc";
internal const string EnableAltF4 = "enableAltF4"; internal const string EnableEsc = "enableEsc";
internal const string EnableCtrlEsc = "enableCtrlEsc"; internal const string EnableF1 = "enableF1";
internal const string EnableEsc = "enableEsc"; internal const string EnableF2 = "enableF2";
internal const string EnableF1 = "enableF1"; internal const string EnableF3 = "enableF3";
internal const string EnableF2 = "enableF2"; internal const string EnableF4 = "enableF4";
internal const string EnableF3 = "enableF3"; internal const string EnableF5 = "enableF5";
internal const string EnableF4 = "enableF4"; internal const string EnableF6 = "enableF6";
internal const string EnableF5 = "enableF5"; internal const string EnableF7 = "enableF7";
internal const string EnableF6 = "enableF6"; internal const string EnableF8 = "enableF8";
internal const string EnableF7 = "enableF7"; internal const string EnableF9 = "enableF9";
internal const string EnableF8 = "enableF8"; internal const string EnableF10 = "enableF10";
internal const string EnableF9 = "enableF9"; internal const string EnableF11 = "enableF11";
internal const string EnableF10 = "enableF10"; internal const string EnableF12 = "enableF12";
internal const string EnableF11 = "enableF11"; internal const string EnablePrintScreen = "enablePrintScreen";
internal const string EnableF12 = "enableF12"; internal const string EnableSystemKey = "enableStartMenu";
internal const string EnablePrintScreen = "enablePrintScreen"; }
internal const string EnableSystemKey = "enableStartMenu";
}
internal static class Mouse internal static class Mouse
{ {
internal const string EnableRightMouse = "enableRightMouse"; internal const string EnableRightMouse = "enableRightMouse";
}
} }
internal static class Network internal static class Network
@ -201,14 +191,11 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
} }
} }
internal static class Registry
{
}
internal static class Security internal static class Security
{ {
internal const string KioskModeCreateNewDesktop = "createNewDesktop"; internal const string KioskModeCreateNewDesktop = "createNewDesktop";
internal const string KioskModeDisableExplorerShell = "killExplorerShell"; internal const string KioskModeDisableExplorerShell = "killExplorerShell";
internal const string QuitPasswordHash = "hashedQuitPassword";
internal const string ServicePolicy = "sebServicePolicy"; internal const string ServicePolicy = "sebServicePolicy";
} }

View file

@ -45,6 +45,8 @@ namespace SafeExamBrowser.I18n.Contracts
MessageBox_ApplicationTerminationFailureTitle, MessageBox_ApplicationTerminationFailureTitle,
MessageBox_BrowserNavigationBlocked, MessageBox_BrowserNavigationBlocked,
MessageBox_BrowserNavigationBlockedTitle, MessageBox_BrowserNavigationBlockedTitle,
MessageBox_BrowserQuitUrlConfirmation,
MessageBox_BrowserQuitUrlConfirmationTitle,
MessageBox_CancelButton, MessageBox_CancelButton,
MessageBox_ClientConfigurationError, MessageBox_ClientConfigurationError,
MessageBox_ClientConfigurationErrorTitle, MessageBox_ClientConfigurationErrorTitle,

View file

@ -93,6 +93,12 @@
<Entry key="MessageBox_BrowserNavigationBlockedTitle"> <Entry key="MessageBox_BrowserNavigationBlockedTitle">
Page Blocked Page Blocked
</Entry> </Entry>
<Entry key="MessageBox_BrowserQuitUrlConfirmation">
The browser application has detected a quit URL! Would you like to terminate SEB now?
</Entry>
<Entry key="MessageBox_BrowserQuitUrlConfirmationTitle">
Quit URL Detected
</Entry>
<Entry key="MessageBox_CancelButton"> <Entry key="MessageBox_CancelButton">
Cancel Cancel
</Entry> </Entry>

View file

@ -36,6 +36,11 @@ namespace SafeExamBrowser.Settings.Browser
/// </summary> /// </summary>
public bool AllowPageZoom { get; set; } public bool AllowPageZoom { get; set; }
/// <summary>
/// Determines whether the user needs to confirm the termination of SEB by <see cref="QuitUrl"/>.
/// </summary>
public bool ConfirmQuitUrl { get; set; }
/// <summary> /// <summary>
/// The custom user agent to optionally be used for all requests. /// The custom user agent to optionally be used for all requests.
/// </summary> /// </summary>
@ -61,6 +66,11 @@ namespace SafeExamBrowser.Settings.Browser
/// </summary> /// </summary>
public ProxySettings Proxy { get; set; } public ProxySettings Proxy { get; set; }
/// <summary>
/// An URL which will initiate the termination of SEB if visited by the user.
/// </summary>
public string QuitUrl { get; set; }
/// <summary> /// <summary>
/// The URL with which the main browser window will be loaded. /// The URL with which the main browser window will be loaded.
/// </summary> /// </summary>