SEBWIN-310: Implemented quit URL.
This commit is contained in:
		
							parent
							
								
									4b415a5f45
								
							
						
					
					
						commit
						130dd45ff6
					
				
					 17 changed files with 213 additions and 88 deletions
				
			
		|  | @ -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(); | ||||||
|  | } | ||||||
|  | @ -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; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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" /> | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
|  | @ -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} ***"); | ||||||
|  |  | ||||||
|  | @ -8,5 +8,5 @@ | ||||||
| 
 | 
 | ||||||
| namespace SafeExamBrowser.Browser.Events | namespace SafeExamBrowser.Browser.Events | ||||||
| { | { | ||||||
| 	internal delegate void RequestBlockedEventHandler(string url); | 	internal delegate void UrlEventHandler(string url); | ||||||
| } | } | ||||||
|  | @ -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) | ||||||
|  |  | ||||||
|  | @ -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" /> | ||||||
|  |  | ||||||
|  | @ -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() | ||||||
| 		{ | 		{ | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|  |  | ||||||
|  | @ -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>)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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"; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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, | ||||||
|  |  | ||||||
|  | @ -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> | ||||||
|  |  | ||||||
|  | @ -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> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 dbuechel
						dbuechel