diff --git a/SafeExamBrowser.Browser.Contracts/Events/TerminationRequestedEventHandler.cs b/SafeExamBrowser.Browser.Contracts/Events/TerminationRequestedEventHandler.cs new file mode 100644 index 00000000..ba423a11 --- /dev/null +++ b/SafeExamBrowser.Browser.Contracts/Events/TerminationRequestedEventHandler.cs @@ -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 +{ + /// + /// Event handler used to indicate that a termination request has been detected. + /// + public delegate void TerminationRequestedEventHandler(); +} diff --git a/SafeExamBrowser.Browser.Contracts/IBrowserApplication.cs b/SafeExamBrowser.Browser.Contracts/IBrowserApplication.cs index 8604a660..29ca0e1e 100644 --- a/SafeExamBrowser.Browser.Contracts/IBrowserApplication.cs +++ b/SafeExamBrowser.Browser.Contracts/IBrowserApplication.cs @@ -20,5 +20,10 @@ namespace SafeExamBrowser.Browser.Contracts /// Event fired when the browser application detects a download request for an application configuration file. /// event DownloadRequestedEventHandler ConfigurationDownloadRequested; + + /// + /// Event fired when the browser application detects a request to terminate SEB. + /// + event TerminationRequestedEventHandler TerminationRequested; } } diff --git a/SafeExamBrowser.Browser.Contracts/SafeExamBrowser.Browser.Contracts.csproj b/SafeExamBrowser.Browser.Contracts/SafeExamBrowser.Browser.Contracts.csproj index 1810bd3f..9702d106 100644 --- a/SafeExamBrowser.Browser.Contracts/SafeExamBrowser.Browser.Contracts.csproj +++ b/SafeExamBrowser.Browser.Contracts/SafeExamBrowser.Browser.Contracts.csproj @@ -57,6 +57,7 @@ + diff --git a/SafeExamBrowser.Browser/BrowserApplication.cs b/SafeExamBrowser.Browser/BrowserApplication.cs index 0b18ecf9..91deaee4 100644 --- a/SafeExamBrowser.Browser/BrowserApplication.cs +++ b/SafeExamBrowser.Browser/BrowserApplication.cs @@ -20,7 +20,6 @@ using SafeExamBrowser.Browser.Events; using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; -using SafeExamBrowser.Settings.Browser; using SafeExamBrowser.Settings.Browser.Proxy; using SafeExamBrowser.Settings.Logging; using SafeExamBrowser.UserInterface.Contracts; @@ -49,6 +48,7 @@ namespace SafeExamBrowser.Browser public event DownloadRequestedEventHandler ConfigurationDownloadRequested; public event WindowsChangedEventHandler WindowsChanged; + public event TerminationRequestedEventHandler TerminationRequested; public BrowserApplication( AppConfig appConfig, @@ -127,6 +127,7 @@ namespace SafeExamBrowser.Browser instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args); instance.PopupRequested += Instance_PopupRequested; instance.Terminated += Instance_Terminated; + instance.TerminationRequested += () => TerminationRequested?.Invoke(); instance.Initialize(); instances.Add(instance); diff --git a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs index b3dc3e78..f3856519 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs @@ -40,9 +40,9 @@ namespace SafeExamBrowser.Browser private IMessageBox messageBox; private IModuleLogger logger; private BrowserSettings settings; + private string startUrl; private IText text; private IUserInterfaceFactory uiFactory; - private string url; private double zoomLevel; private WindowSettings WindowSettings @@ -59,6 +59,7 @@ namespace SafeExamBrowser.Browser internal event DownloadRequestedEventHandler ConfigurationDownloadRequested; internal event PopupRequestedEventHandler PopupRequested; internal event InstanceTerminatedEventHandler Terminated; + internal event TerminationRequestedEventHandler TerminationRequested; public event IconChangedEventHandler IconChanged; public event TitleChangedEventHandler TitleChanged; @@ -72,7 +73,7 @@ namespace SafeExamBrowser.Browser IModuleLogger logger, IText text, IUserInterfaceFactory uiFactory, - string url) + string startUrl) { this.appConfig = appConfig; this.Id = id; @@ -83,7 +84,7 @@ namespace SafeExamBrowser.Browser this.settings = settings; this.text = text; this.uiFactory = uiFactory; - this.url = url; + this.startUrl = startUrl; } public void Activate() @@ -106,12 +107,12 @@ namespace SafeExamBrowser.Browser { var contextMenuHandler = new ContextMenuHandler(); 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 keyboardHandler = new KeyboardHandler(); var lifeSpanHandler = new LifeSpanHandler(); 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); Icon = new BrowserIconResource(); @@ -124,11 +125,12 @@ namespace SafeExamBrowser.Browser keyboardHandler.ZoomOutRequested += ZoomOutRequested; keyboardHandler.ZoomResetRequested += ZoomResetRequested; lifeSpanHandler.PopupRequested += LifeSpanHandler_PopupRequested; + requestHandler.QuitUrlVisited += RequestHandler_QuitUrlVisited; requestHandler.RequestBlocked += RequestHandler_RequestBlocked; 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.LoadingStateChanged += Control_LoadingStateChanged; 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) { Task.Run(() => @@ -285,7 +316,7 @@ namespace SafeExamBrowser.Browser control.TitleChanged -= Control_TitleChanged; - if (url == this.url) + if (url.Equals(startUrl, StringComparison.OrdinalIgnoreCase)) { window.UpdateTitle($"*** {title} ***"); TitleChanged?.Invoke($"*** {title} ***"); diff --git a/SafeExamBrowser.Browser/Events/RequestBlockedEventHandler.cs b/SafeExamBrowser.Browser/Events/UrlEventHandler.cs similarity index 84% rename from SafeExamBrowser.Browser/Events/RequestBlockedEventHandler.cs rename to SafeExamBrowser.Browser/Events/UrlEventHandler.cs index 0c28057a..cf3e3b8a 100644 --- a/SafeExamBrowser.Browser/Events/RequestBlockedEventHandler.cs +++ b/SafeExamBrowser.Browser/Events/UrlEventHandler.cs @@ -8,5 +8,5 @@ namespace SafeExamBrowser.Browser.Events { - internal delegate void RequestBlockedEventHandler(string url); + internal delegate void UrlEventHandler(string url); } diff --git a/SafeExamBrowser.Browser/Handlers/RequestHandler.cs b/SafeExamBrowser.Browser/Handlers/RequestHandler.cs index cfbcddd8..b33f3aa5 100644 --- a/SafeExamBrowser.Browser/Handlers/RequestHandler.cs +++ b/SafeExamBrowser.Browser/Handlers/RequestHandler.cs @@ -25,7 +25,8 @@ namespace SafeExamBrowser.Browser.Handlers private ResourceHandler resourceHandler; 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) { @@ -60,6 +61,13 @@ namespace SafeExamBrowser.Browser.Handlers 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)) { RequestBlocked?.Invoke(request.Url); @@ -70,6 +78,18 @@ namespace SafeExamBrowser.Browser.Handlers 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) { if (settings.Filter.ProcessMainRequests) diff --git a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj index 877dec92..8b4324f4 100644 --- a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj +++ b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj @@ -68,7 +68,7 @@ - + diff --git a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs index a728f056..9c1e240b 100644 --- a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs +++ b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs @@ -232,6 +232,17 @@ namespace SafeExamBrowser.Client.UnitTests It.Is(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] public void Communication_MustCorrectlyHandleMessageBoxRequest() { diff --git a/SafeExamBrowser.Client/ClientController.cs b/SafeExamBrowser.Client/ClientController.cs index ef6eb1e9..7a174efb 100644 --- a/SafeExamBrowser.Client/ClientController.cs +++ b/SafeExamBrowser.Client/ClientController.cs @@ -171,6 +171,7 @@ namespace SafeExamBrowser.Client applicationMonitor.ExplorerStarted += ApplicationMonitor_ExplorerStarted; applicationMonitor.TerminationFailed += ApplicationMonitor_TerminationFailed; Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested; + Browser.TerminationRequested += Browser_TerminationRequested; ClientHost.MessageBoxRequested += ClientHost_MessageBoxRequested; ClientHost.PasswordRequested += ClientHost_PasswordRequested; ClientHost.ReconfigurationDenied += ClientHost_ReconfigurationDenied; @@ -321,8 +322,7 @@ namespace SafeExamBrowser.Client } else if (result.OptionId == terminateOption.Id) { - logger.Info("Initiating shutdown request..."); - + logger.Info("Attempting to shutdown as requested by the user..."); 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) { if (success) diff --git a/SafeExamBrowser.Configuration.UnitTests/DataFormats/XmlParserTests.cs b/SafeExamBrowser.Configuration.UnitTests/DataFormats/XmlParserTests.cs index d5d88d4f..76618163 100644 --- a/SafeExamBrowser.Configuration.UnitTests/DataFormats/XmlParserTests.cs +++ b/SafeExamBrowser.Configuration.UnitTests/DataFormats/XmlParserTests.cs @@ -94,8 +94,8 @@ namespace SafeExamBrowser.Configuration.UnitTests.DataFormats Assert.AreEqual(true, result.RawData[Keys.Browser.AllowConfigurationDownloads]); Assert.AreEqual(0, result.RawData[Keys.ConfigurationFile.ConfigurationPurpose]); - Assert.AreEqual("https://safeexambrowser.org/start", result.RawData[Keys.General.StartUrl]); - Assert.AreEqual(true, result.RawData[Keys.Input.Keyboard.EnableF5]); + Assert.AreEqual("https://safeexambrowser.org/start", result.RawData[Keys.Browser.StartUrl]); + Assert.AreEqual(true, result.RawData[Keys.Keyboard.EnableF5]); Assert.IsInstanceOfType(result.RawData[Keys.Network.Certificates.EmbeddedCertificates], typeof(List)); } diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Browser.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Browser.cs index bf0e8e4d..4fc92648 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Browser.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Browser.cs @@ -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 rawData, AppSettings settings) { var processMainRequests = rawData.TryGetValue(Keys.Browser.Filter.EnableMainRequestFilter, out var value) && value as bool? == true; diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs index 4436b017..e17fcef3 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs @@ -22,7 +22,8 @@ namespace SafeExamBrowser.Configuration.ConfigurationData MapBrowserSettings(item.Key, item.Value, settings); MapConfigurationFileSettings(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); MapUserInterfaceSettings(item.Key, item.Value, settings); } @@ -133,6 +134,15 @@ namespace SafeExamBrowser.Configuration.ConfigurationData case Keys.Browser.Proxy.Settings: MapProxySettings(settings, value); 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) { + case Keys.ConfigurationFile.AdminPasswordHash: + MapAdminPasswordHash(settings, value); + break; case Keys.ConfigurationFile.ConfigurationPurpose: MapConfigurationMode(settings, value); break; @@ -150,83 +163,81 @@ namespace SafeExamBrowser.Configuration.ConfigurationData { switch (key) { - case Keys.General.AdminPasswordHash: - MapAdminPasswordHash(settings, value); - break; case Keys.General.LogLevel: MapLogLevel(settings, value); 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) { - case Keys.Input.Keyboard.EnableAltEsc: + case Keys.Keyboard.EnableAltEsc: MapEnableAltEsc(settings, value); break; - case Keys.Input.Keyboard.EnableAltF4: + case Keys.Keyboard.EnableAltF4: MapEnableAltF4(settings, value); break; - case Keys.Input.Keyboard.EnableAltTab: + case Keys.Keyboard.EnableAltTab: MapEnableAltTab(settings, value); break; - case Keys.Input.Keyboard.EnableCtrlEsc: + case Keys.Keyboard.EnableCtrlEsc: MapEnableCtrlEsc(settings, value); break; - case Keys.Input.Keyboard.EnableEsc: + case Keys.Keyboard.EnableEsc: MapEnableEsc(settings, value); break; - case Keys.Input.Keyboard.EnableF1: + case Keys.Keyboard.EnableF1: MapEnableF1(settings, value); break; - case Keys.Input.Keyboard.EnableF2: + case Keys.Keyboard.EnableF2: MapEnableF2(settings, value); break; - case Keys.Input.Keyboard.EnableF3: + case Keys.Keyboard.EnableF3: MapEnableF3(settings, value); break; - case Keys.Input.Keyboard.EnableF4: + case Keys.Keyboard.EnableF4: MapEnableF4(settings, value); break; - case Keys.Input.Keyboard.EnableF5: + case Keys.Keyboard.EnableF5: MapEnableF5(settings, value); break; - case Keys.Input.Keyboard.EnableF6: + case Keys.Keyboard.EnableF6: MapEnableF6(settings, value); break; - case Keys.Input.Keyboard.EnableF7: + case Keys.Keyboard.EnableF7: MapEnableF7(settings, value); break; - case Keys.Input.Keyboard.EnableF8: + case Keys.Keyboard.EnableF8: MapEnableF8(settings, value); break; - case Keys.Input.Keyboard.EnableF9: + case Keys.Keyboard.EnableF9: MapEnableF9(settings, value); break; - case Keys.Input.Keyboard.EnableF10: + case Keys.Keyboard.EnableF10: MapEnableF10(settings, value); break; - case Keys.Input.Keyboard.EnableF11: + case Keys.Keyboard.EnableF11: MapEnableF11(settings, value); break; - case Keys.Input.Keyboard.EnableF12: + case Keys.Keyboard.EnableF12: MapEnableF12(settings, value); break; - case Keys.Input.Keyboard.EnablePrintScreen: + case Keys.Keyboard.EnablePrintScreen: MapEnablePrintScreen(settings, value); break; - case Keys.Input.Keyboard.EnableSystemKey: + case Keys.Keyboard.EnableSystemKey: MapEnableSystemKey(settings, value); break; - case Keys.Input.Mouse.EnableRightMouse: + } + } + + private void MapMouseSettings(string key, object value, AppSettings settings) + { + switch (key) + { + case Keys.Mouse.EnableRightMouse: MapEnableRightMouse(settings, value); break; } @@ -236,6 +247,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData { switch (key) { + case Keys.Security.QuitPasswordHash: + MapQuitPasswordHash(settings, value); + break; case Keys.Security.ServicePolicy: MapServicePolicy(settings, value); break; diff --git a/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs b/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs index 57f7dbdb..7a8f6ff5 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs @@ -12,10 +12,6 @@ namespace SafeExamBrowser.Configuration.ConfigurationData { internal const int WINDOWS = 1; - internal static class AdditionalResources - { - } - internal static class Applications { internal const string Active = "active"; @@ -53,6 +49,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData internal const string CustomUserAgentMobile = "browserUserAgentWinTouchModeCustom"; internal const string PopupPolicy = "newBrowserWindowByLinkPolicy"; 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 UserAgentModeMobile = "browserUserAgentWinTouchMode"; @@ -143,52 +142,43 @@ namespace SafeExamBrowser.Configuration.ConfigurationData internal static class ConfigurationFile { + internal const string AdminPasswordHash = "hashedAdminPassword"; internal const string ConfigurationPurpose = "sebConfigPurpose"; internal const string KeepClientConfigEncryption = "clientConfigKeepEncryption"; } - internal static class Exam - { - } - internal static class General { - internal const string AdminPasswordHash = "hashedAdminPassword"; internal const string AllowApplicationLog = "allowApplicationLog"; 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 EnableAltF4 = "enableAltF4"; - internal const string EnableCtrlEsc = "enableCtrlEsc"; - internal const string EnableEsc = "enableEsc"; - internal const string EnableF1 = "enableF1"; - internal const string EnableF2 = "enableF2"; - internal const string EnableF3 = "enableF3"; - internal const string EnableF4 = "enableF4"; - internal const string EnableF5 = "enableF5"; - internal const string EnableF6 = "enableF6"; - internal const string EnableF7 = "enableF7"; - internal const string EnableF8 = "enableF8"; - internal const string EnableF9 = "enableF9"; - internal const string EnableF10 = "enableF10"; - internal const string EnableF11 = "enableF11"; - internal const string EnableF12 = "enableF12"; - internal const string EnablePrintScreen = "enablePrintScreen"; - internal const string EnableSystemKey = "enableStartMenu"; - } + internal const string EnableAltEsc = "enableAltEsc"; + internal const string EnableAltTab = "enableAltTab"; + internal const string EnableAltF4 = "enableAltF4"; + internal const string EnableCtrlEsc = "enableCtrlEsc"; + internal const string EnableEsc = "enableEsc"; + internal const string EnableF1 = "enableF1"; + internal const string EnableF2 = "enableF2"; + internal const string EnableF3 = "enableF3"; + internal const string EnableF4 = "enableF4"; + internal const string EnableF5 = "enableF5"; + internal const string EnableF6 = "enableF6"; + internal const string EnableF7 = "enableF7"; + internal const string EnableF8 = "enableF8"; + internal const string EnableF9 = "enableF9"; + internal const string EnableF10 = "enableF10"; + internal const string EnableF11 = "enableF11"; + internal const string EnableF12 = "enableF12"; + internal const string EnablePrintScreen = "enablePrintScreen"; + internal const string EnableSystemKey = "enableStartMenu"; + } - internal static class Mouse - { - internal const string EnableRightMouse = "enableRightMouse"; - } + internal static class Mouse + { + internal const string EnableRightMouse = "enableRightMouse"; } internal static class Network @@ -201,14 +191,11 @@ namespace SafeExamBrowser.Configuration.ConfigurationData } } - internal static class Registry - { - } - internal static class Security { internal const string KioskModeCreateNewDesktop = "createNewDesktop"; internal const string KioskModeDisableExplorerShell = "killExplorerShell"; + internal const string QuitPasswordHash = "hashedQuitPassword"; internal const string ServicePolicy = "sebServicePolicy"; } diff --git a/SafeExamBrowser.I18n.Contracts/TextKey.cs b/SafeExamBrowser.I18n.Contracts/TextKey.cs index ae3abdc3..5e9dbdb1 100644 --- a/SafeExamBrowser.I18n.Contracts/TextKey.cs +++ b/SafeExamBrowser.I18n.Contracts/TextKey.cs @@ -45,6 +45,8 @@ namespace SafeExamBrowser.I18n.Contracts MessageBox_ApplicationTerminationFailureTitle, MessageBox_BrowserNavigationBlocked, MessageBox_BrowserNavigationBlockedTitle, + MessageBox_BrowserQuitUrlConfirmation, + MessageBox_BrowserQuitUrlConfirmationTitle, MessageBox_CancelButton, MessageBox_ClientConfigurationError, MessageBox_ClientConfigurationErrorTitle, diff --git a/SafeExamBrowser.I18n/Text.xml b/SafeExamBrowser.I18n/Text.xml index 4b8fc263..0bf19976 100644 --- a/SafeExamBrowser.I18n/Text.xml +++ b/SafeExamBrowser.I18n/Text.xml @@ -93,6 +93,12 @@ Page Blocked + + The browser application has detected a quit URL! Would you like to terminate SEB now? + + + Quit URL Detected + Cancel diff --git a/SafeExamBrowser.Settings/Browser/BrowserSettings.cs b/SafeExamBrowser.Settings/Browser/BrowserSettings.cs index 3995efbf..573d292e 100644 --- a/SafeExamBrowser.Settings/Browser/BrowserSettings.cs +++ b/SafeExamBrowser.Settings/Browser/BrowserSettings.cs @@ -36,6 +36,11 @@ namespace SafeExamBrowser.Settings.Browser /// public bool AllowPageZoom { get; set; } + /// + /// Determines whether the user needs to confirm the termination of SEB by . + /// + public bool ConfirmQuitUrl { get; set; } + /// /// The custom user agent to optionally be used for all requests. /// @@ -61,6 +66,11 @@ namespace SafeExamBrowser.Settings.Browser /// public ProxySettings Proxy { get; set; } + /// + /// An URL which will initiate the termination of SEB if visited by the user. + /// + public string QuitUrl { get; set; } + /// /// The URL with which the main browser window will be loaded. ///