diff --git a/SafeExamBrowser.Client/ClientController.cs b/SafeExamBrowser.Client/ClientController.cs index 18e3e77b..b8983f5c 100644 --- a/SafeExamBrowser.Client/ClientController.cs +++ b/SafeExamBrowser.Client/ClientController.cs @@ -14,6 +14,7 @@ using SafeExamBrowser.Contracts.Communication.Events; using SafeExamBrowser.Contracts.Communication.Hosts; using SafeExamBrowser.Contracts.Communication.Proxies; using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.Configuration.Cryptography; using SafeExamBrowser.Contracts.Configuration.Settings; using SafeExamBrowser.Contracts.Core; using SafeExamBrowser.Contracts.Core.OperationModel; @@ -33,6 +34,7 @@ namespace SafeExamBrowser.Client { private IDisplayMonitor displayMonitor; private IExplorerShell explorerShell; + private IHashAlgorithm hashAlgorithm; private ILogger logger; private IMessageBox messageBox; private IOperationSequence operations; @@ -67,6 +69,7 @@ namespace SafeExamBrowser.Client public ClientController( IDisplayMonitor displayMonitor, IExplorerShell explorerShell, + IHashAlgorithm hashAlgorithm, ILogger logger, IMessageBox messageBox, IOperationSequence operations, @@ -80,6 +83,7 @@ namespace SafeExamBrowser.Client { this.displayMonitor = displayMonitor; this.explorerShell = explorerShell; + this.hashAlgorithm = hashAlgorithm; this.logger = logger; this.messageBox = messageBox; this.operations = operations; @@ -342,9 +346,19 @@ namespace SafeExamBrowser.Client private void Taskbar_QuitButtonClicked(System.ComponentModel.CancelEventArgs args) { - var result = messageBox.Show(TextKey.MessageBox_Quit, TextKey.MessageBox_QuitTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question); + var hasQuitPassword = !String.IsNullOrEmpty(Settings.QuitPasswordHash); + var requestShutdown = false; - if (result == MessageBoxResult.Yes) + if (hasQuitPassword) + { + requestShutdown = TryValidateQuitPassword(); + } + else + { + requestShutdown = TryConfirmShutdown(); + } + + if (requestShutdown) { var communication = runtime.RequestShutdown(); @@ -374,5 +388,44 @@ namespace SafeExamBrowser.Client } } } + + private bool TryConfirmShutdown() + { + var result = messageBox.Show(TextKey.MessageBox_Quit, TextKey.MessageBox_QuitTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question); + var quit = result == MessageBoxResult.Yes; + + if (quit) + { + logger.Info("The user chose to terminate the application."); + } + + return quit; + } + + private bool TryValidateQuitPassword() + { + var dialog = uiFactory.CreatePasswordDialog(TextKey.PasswordDialog_QuitPasswordRequired, TextKey.PasswordDialog_QuitPasswordRequiredTitle); + var result = dialog.Show(); + + if (result.Success) + { + var passwordHash = hashAlgorithm.GenerateHashFor(result.Password); + var isCorrect = Settings.QuitPasswordHash.Equals(passwordHash, StringComparison.OrdinalIgnoreCase); + + if (isCorrect) + { + logger.Info("The user entered the correct quit password, the application will now terminate."); + } + else + { + logger.Info("The user entered the wrong quit password."); + messageBox.Show(TextKey.MessageBox_InvalidQuitPassword, TextKey.MessageBox_InvalidQuitPasswordTitle, icon: MessageBoxIcon.Warning); + } + + return isCorrect; + } + + return false; + } } } diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 0086dc3a..c3cfc453 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -18,6 +18,7 @@ using SafeExamBrowser.Client.Operations; using SafeExamBrowser.Communication.Hosts; using SafeExamBrowser.Communication.Proxies; using SafeExamBrowser.Configuration; +using SafeExamBrowser.Configuration.Cryptography; using SafeExamBrowser.Contracts.Browser; using SafeExamBrowser.Contracts.Communication.Hosts; using SafeExamBrowser.Contracts.Communication.Proxies; @@ -88,6 +89,7 @@ namespace SafeExamBrowser.Client var displayMonitor = new DisplayMonitor(new ModuleLogger(logger, nameof(DisplayMonitor)), nativeMethods); var explorerShell = new ExplorerShell(new ModuleLogger(logger, nameof(ExplorerShell)), nativeMethods); + var hashAlgorithm = new HashAlgorithm(); Taskbar = new Taskbar(new ModuleLogger(logger, nameof(Taskbar))); @@ -111,7 +113,7 @@ namespace SafeExamBrowser.Client var sequence = new OperationSequence(logger, operations); - ClientController = new ClientController(displayMonitor, explorerShell, logger, messageBox, sequence, processMonitor, runtimeProxy, shutdown, Taskbar, text, uiFactory, windowMonitor); + ClientController = new ClientController(displayMonitor, explorerShell, hashAlgorithm, logger, messageBox, sequence, processMonitor, runtimeProxy, shutdown, Taskbar, text, uiFactory, windowMonitor); } internal void LogStartupInformation() diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.General.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.General.cs index a116da61..5d1f7046 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.General.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.General.cs @@ -20,6 +20,14 @@ namespace SafeExamBrowser.Configuration.ConfigurationData } } + private void MapQuitPasswordHash(Settings settings, object value) + { + if (value is string hash) + { + settings.QuitPasswordHash = hash; + } + } + private void MapStartUrl(Settings settings, object value) { if (value is string url) diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs index 77b32b44..14052b45 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs @@ -31,6 +31,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData case Keys.General.AdminPasswordHash: MapAdminPasswordHash(settings, value); break; + case Keys.General.QuitPasswordHash: + MapQuitPasswordHash(settings, value); + break; case Keys.General.StartUrl: MapStartUrl(settings, value); break; diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs index 975f3aa6..5dce77d0 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs @@ -89,12 +89,47 @@ namespace SafeExamBrowser.Configuration.ConfigurationData { var settings = new Settings(); - // TODO: Specify default settings + settings.Browser.StartUrl = "https://www.safeexambrowser.org/start"; + settings.Browser.AllowAddressBar = false; + settings.Browser.AllowBackwardNavigation = false; + settings.Browser.AllowConfigurationDownloads = true; + settings.Browser.AllowDeveloperConsole = false; + settings.Browser.AllowDownloads = false; + settings.Browser.AllowForwardNavigation = false; + settings.Browser.AllowReloading = true; + + settings.Keyboard.AllowAltEsc = false; + settings.Keyboard.AllowAltF4 = false; + settings.Keyboard.AllowAltTab = true; + settings.Keyboard.AllowCtrlEsc = false; + settings.Keyboard.AllowEsc = true; + settings.Keyboard.AllowF1 = true; + settings.Keyboard.AllowF2 = true; + settings.Keyboard.AllowF3 = true; + settings.Keyboard.AllowF4 = true; + settings.Keyboard.AllowF5 = true; + settings.Keyboard.AllowF6 = true; + settings.Keyboard.AllowF7 = true; + settings.Keyboard.AllowF8 = true; + settings.Keyboard.AllowF9 = true; + settings.Keyboard.AllowF10 = true; + settings.Keyboard.AllowF11 = true; + settings.Keyboard.AllowF12 = true; + settings.Keyboard.AllowPrintScreen = false; + settings.Keyboard.AllowSystemKey = false; + + settings.KioskMode = KioskMode.CreateNewDesktop; + + settings.Mouse.AllowMiddleButton = false; + settings.Mouse.AllowRightButton = true; - settings.KioskMode = KioskMode.None; settings.ServicePolicy = ServicePolicy.Optional; - settings.Browser.StartUrl = "https://www.safeexambrowser.org/testing"; + settings.Taskbar.AllowApplicationLog = false; + settings.Taskbar.AllowKeyboardLayout = true; + settings.Taskbar.AllowWirelessNetwork = false; + + // TODO: Default values for alpha version only, remove for final release! settings.Browser.AllowAddressBar = true; settings.Browser.AllowBackwardNavigation = true; settings.Browser.AllowConfigurationDownloads = true; @@ -102,9 +137,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData settings.Browser.AllowDownloads = true; settings.Browser.AllowForwardNavigation = true; settings.Browser.AllowReloading = true; - + settings.KioskMode = KioskMode.None; + settings.ServicePolicy = ServicePolicy.Optional; settings.Taskbar.AllowApplicationLog = true; - settings.Taskbar.AllowKeyboardLayout = true; settings.Taskbar.AllowWirelessNetwork = true; return settings; diff --git a/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs b/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs index 698a068e..702c2c32 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs @@ -35,6 +35,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData internal static class General { internal const string AdminPasswordHash = "hashedAdminPassword"; + internal const string QuitPasswordHash = "hashedQuitPassword"; internal const string StartUrl = "startURL"; } @@ -42,30 +43,30 @@ namespace SafeExamBrowser.Configuration.ConfigurationData { internal static class Keyboard { - public const string EnableAltEsc = "enableAltEsc"; - public const string EnableAltTab = "enableAltTab"; - public const string EnableAltF4 = "enableAltF4"; - public const string EnableCtrlEsc = "enableCtrlEsc"; - public const string EnableEsc = "enableEsc"; - public const string EnableF1 = "enableF1"; - public const string EnableF2 = "enableF2"; - public const string EnableF3 = "enableF3"; - public const string EnableF4 = "enableF4"; - public const string EnableF5 = "enableF5"; - public const string EnableF6 = "enableF6"; - public const string EnableF7 = "enableF7"; - public const string EnableF8 = "enableF8"; - public const string EnableF9 = "enableF9"; - public const string EnableF10 = "enableF10"; - public const string EnableF11 = "enableF11"; - public const string EnableF12 = "enableF12"; - public const string EnablePrintScreen = "enablePrintScreen"; - public 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 { - public const string EnableRightMouse = "enableRightMouse"; + internal const string EnableRightMouse = "enableRightMouse"; } } diff --git a/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs b/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs index efca2e41..c4fcf1ef 100644 --- a/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs +++ b/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs @@ -46,6 +46,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings /// public MouseSettings Mouse { get; set; } + /// + /// The hash code of the quit password. + /// + public string QuitPasswordHash { get; set; } + /// /// The active policy for the service component. /// @@ -62,10 +67,6 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings Keyboard = new KeyboardSettings(); Mouse = new MouseSettings(); Taskbar = new TaskbarSettings(); - - // TODO: For version 3.0 Alpha only, remove for final release! - ServicePolicy = ServicePolicy.Optional; - Taskbar.AllowApplicationLog = true; } } } diff --git a/SafeExamBrowser.Contracts/I18n/TextKey.cs b/SafeExamBrowser.Contracts/I18n/TextKey.cs index 28ad1dc7..670fa473 100644 --- a/SafeExamBrowser.Contracts/I18n/TextKey.cs +++ b/SafeExamBrowser.Contracts/I18n/TextKey.cs @@ -28,6 +28,8 @@ namespace SafeExamBrowser.Contracts.I18n MessageBox_InvalidConfigurationDataTitle, MessageBox_InvalidPasswordError, MessageBox_InvalidPasswordErrorTitle, + MessageBox_InvalidQuitPassword, + MessageBox_InvalidQuitPasswordTitle, MessageBox_NotSupportedConfigurationResource, MessageBox_NotSupportedConfigurationResourceTitle, MessageBox_Quit, @@ -88,6 +90,8 @@ namespace SafeExamBrowser.Contracts.I18n PasswordDialog_AdminPasswordRequiredTitle, PasswordDialog_Cancel, PasswordDialog_Confirm, + PasswordDialog_QuitPasswordRequired, + PasswordDialog_QuitPasswordRequiredTitle, PasswordDialog_SettingsPasswordRequired, PasswordDialog_SettingsPasswordRequiredTitle, RuntimeWindow_ApplicationRunning, diff --git a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs index 50c7e96c..400400e9 100644 --- a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs +++ b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs @@ -8,6 +8,7 @@ using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration.Settings; +using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface.Browser; using SafeExamBrowser.Contracts.UserInterface.Taskbar; @@ -57,6 +58,11 @@ namespace SafeExamBrowser.Contracts.UserInterface /// IPasswordDialog CreatePasswordDialog(string message, string title); + /// + /// Creates a password dialog with the given message and title. + /// + IPasswordDialog CreatePasswordDialog(TextKey message, TextKey title); + /// /// Creates a system control displaying the power supply status of the computer. /// diff --git a/SafeExamBrowser.I18n/Text.xml b/SafeExamBrowser.I18n/Text.xml index 810b609e..a1926ce7 100644 --- a/SafeExamBrowser.I18n/Text.xml +++ b/SafeExamBrowser.I18n/Text.xml @@ -42,6 +42,12 @@ Invalid Password + + The application can only be terminated by entering the correct quit password. + + + Invalid Quit Password + The configuration resource '%%URI%%' is not supported! @@ -216,6 +222,12 @@ Confirm + + Please enter the quit password in order to terminate the application: + + + Quit Password Required + Please enter the settings password for the application configuration: diff --git a/SafeExamBrowser.UserInterface.Classic/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Classic/UserInterfaceFactory.cs index b556ab53..c57a94b5 100644 --- a/SafeExamBrowser.UserInterface.Classic/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Classic/UserInterfaceFactory.cs @@ -87,6 +87,11 @@ namespace SafeExamBrowser.UserInterface.Classic return Application.Current.Dispatcher.Invoke(() => new PasswordDialog(message, title, text)); } + public IPasswordDialog CreatePasswordDialog(TextKey message, TextKey title) + { + return Application.Current.Dispatcher.Invoke(() => new PasswordDialog(text.Get(message), text.Get(title), text)); + } + public ISystemPowerSupplyControl CreatePowerSupplyControl() { return new PowerSupplyControl(); diff --git a/SafeExamBrowser.UserInterface.Windows10/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Windows10/UserInterfaceFactory.cs index 999eff4e..f0cac923 100644 --- a/SafeExamBrowser.UserInterface.Windows10/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Windows10/UserInterfaceFactory.cs @@ -86,6 +86,12 @@ namespace SafeExamBrowser.UserInterface.Windows10 throw new System.NotImplementedException(); } + public IPasswordDialog CreatePasswordDialog(TextKey message, TextKey title) + { + // TODO + throw new System.NotImplementedException(); + } + public ISystemPowerSupplyControl CreatePowerSupplyControl() { return new PowerSupplyControl();