From da2c7093602ea18798510d03f42fd340655b83e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Damian=20B=C3=BCchel?= <damian.buechel@let.ethz.ch>
Date: Mon, 19 Jul 2021 14:59:57 +0200
Subject: [PATCH] Extended unit tests for browser handlers.

---
 .../Handlers/DisplayHandlerTests.cs           |   3 +
 .../Handlers/KeyboardHandlerTests.cs          |  42 ++++++-
 .../Handlers/RequestHandlerTests.cs           |  58 ++++++++++
 .../Handlers/ResourceHandlerTests.cs          | 107 ++++++++++++++++++
 4 files changed, 208 insertions(+), 2 deletions(-)

diff --git a/SafeExamBrowser.Browser.UnitTests/Handlers/DisplayHandlerTests.cs b/SafeExamBrowser.Browser.UnitTests/Handlers/DisplayHandlerTests.cs
index cb724139..443d6d81 100644
--- a/SafeExamBrowser.Browser.UnitTests/Handlers/DisplayHandlerTests.cs
+++ b/SafeExamBrowser.Browser.UnitTests/Handlers/DisplayHandlerTests.cs
@@ -6,8 +6,10 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+using System;
 using System.Collections.Generic;
 using CefSharp;
+using CefSharp.Enums;
 using CefSharp.Structs;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using SafeExamBrowser.Browser.Handlers;
@@ -32,6 +34,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
 
 			Assert.IsFalse(sut.OnAutoResize(default(IWebBrowser), default(IBrowser), default(Size)));
 			Assert.IsFalse(sut.OnConsoleMessage(default(IWebBrowser), default(ConsoleMessageEventArgs)));
+			Assert.IsFalse(sut.OnCursorChange(default(IWebBrowser), default(IBrowser), default(IntPtr), default(CursorType), default(CursorInfo)));
 			Assert.IsFalse(sut.OnTooltipChanged(default(IWebBrowser), ref text));
 		}
 
diff --git a/SafeExamBrowser.Browser.UnitTests/Handlers/KeyboardHandlerTests.cs b/SafeExamBrowser.Browser.UnitTests/Handlers/KeyboardHandlerTests.cs
index df4cfcc1..d0e2430d 100644
--- a/SafeExamBrowser.Browser.UnitTests/Handlers/KeyboardHandlerTests.cs
+++ b/SafeExamBrowser.Browser.UnitTests/Handlers/KeyboardHandlerTests.cs
@@ -25,14 +25,52 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
 		}
 
 		[TestMethod]
-		public void MustDetectReload()
+		public void MustDetectFindCommand()
+		{
+			var findRequested = false;
+
+			sut.FindRequested += () => findRequested = true;
+
+			var handled = sut.OnKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int) Keys.F, default(int), CefEventFlags.ControlDown, default(bool));
+
+			Assert.IsTrue(findRequested);
+			Assert.IsFalse(handled);
+
+			findRequested = false;
+			handled = sut.OnKeyEvent(default(IWebBrowser), default(IBrowser), default(KeyType), default(int), default(int), CefEventFlags.ControlDown, default(bool));
+
+			Assert.IsFalse(findRequested);
+			Assert.IsFalse(handled);
+		}
+
+		[TestMethod]
+		public void MustDetectHomeNavigationCommand()
+		{
+			var homeRequested = false;
+
+			sut.HomeNavigationRequested += () => homeRequested = true;
+
+			var handled = sut.OnKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int) Keys.Home, default(int), default(CefEventFlags), default(bool));
+
+			Assert.IsTrue(homeRequested);
+			Assert.IsFalse(handled);
+
+			homeRequested = false;
+			handled = sut.OnKeyEvent(default(IWebBrowser), default(IBrowser), default(KeyType), default(int), default(int), default(CefEventFlags), default(bool));
+
+			Assert.IsFalse(homeRequested);
+			Assert.IsFalse(handled);
+		}
+
+		[TestMethod]
+		public void MustDetectReloadCommand()
 		{
 			var isShortcut = default(bool);
 			var reloadRequested = false;
 
 			sut.ReloadRequested += () => reloadRequested = true;
 
-			var handled = sut.OnPreKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int)Keys.F5, default(int), default(CefEventFlags), default(bool), ref isShortcut);
+			var handled = sut.OnPreKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int) Keys.F5, default(int), default(CefEventFlags), default(bool), ref isShortcut);
 
 			Assert.IsTrue(reloadRequested);
 			Assert.IsTrue(handled);
diff --git a/SafeExamBrowser.Browser.UnitTests/Handlers/RequestHandlerTests.cs b/SafeExamBrowser.Browser.UnitTests/Handlers/RequestHandlerTests.cs
index 45c9eae8..1b528c93 100644
--- a/SafeExamBrowser.Browser.UnitTests/Handlers/RequestHandlerTests.cs
+++ b/SafeExamBrowser.Browser.UnitTests/Handlers/RequestHandlerTests.cs
@@ -6,6 +6,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+using System;
 using CefSharp;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -49,6 +50,15 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
 			sut = new TestableRequestHandler(appConfig, filter.Object, logger.Object, resourceHandler, settings, windowSettings, text.Object);
 		}
 
+		[TestMethod]
+		public void MustBlockSpecialWindowDispositions()
+		{
+			Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.NewBackgroundTab, default(bool)));
+			Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.NewPopup, default(bool)));
+			Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.NewWindow, default(bool)));
+			Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.SaveToDisk, default(bool)));
+		}
+
 		[TestMethod]
 		public void MustDetectQuitUrl()
 		{
@@ -168,6 +178,44 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
 			Assert.IsFalse(eventFired);
 		}
 
+		[TestMethod]
+		public void MustInitiateConfigurationFileDownload()
+		{
+			var browser = new Mock<IBrowser>();
+			var host = new Mock<IBrowserHost>();
+			var request = new Mock<IRequest>();
+
+			appConfig.ConfigurationFileExtension = ".xyz";
+			appConfig.SebUriScheme = "abc";
+			appConfig.SebUriSchemeSecure = "abcd";
+			browser.Setup(b => b.GetHost()).Returns(host.Object);
+			request.SetupGet(r => r.Url).Returns($"{appConfig.SebUriScheme}://host.com/path/file{appConfig.ConfigurationFileExtension}");
+
+			var handled = sut.OnBeforeBrowse(Mock.Of<IWebBrowser>(), browser.Object, Mock.Of<IFrame>(), request.Object, false, false);
+
+			host.Verify(h => h.StartDownload(It.Is<string>(u => u == $"{Uri.UriSchemeHttp}://host.com/path/file{appConfig.ConfigurationFileExtension}")));
+			Assert.IsTrue(handled);
+
+			handled = false;
+			host.Reset();
+			request.Reset();
+			request.SetupGet(r => r.Url).Returns($"{appConfig.SebUriSchemeSecure}://host.com/path/file{appConfig.ConfigurationFileExtension}");
+
+			handled = sut.OnBeforeBrowse(Mock.Of<IWebBrowser>(), browser.Object, Mock.Of<IFrame>(), request.Object, false, false);
+
+			host.Verify(h => h.StartDownload(It.Is<string>(u => u == $"{Uri.UriSchemeHttps}://host.com/path/file{appConfig.ConfigurationFileExtension}")));
+			Assert.IsTrue(handled);
+		}
+
+		[TestMethod]
+		public void MustReturnResourceHandler()
+		{
+			var disableDefaultHandling = default(bool);
+			var handler = sut.GetResourceRequestHandler(default(IWebBrowser), default(IBrowser), default(IFrame), default(IRequest), default(bool), default(bool), default(string), ref disableDefaultHandling);
+
+			Assert.AreSame(resourceHandler, handler);
+		}
+
 		[TestMethod]
 		public void MustUseProxyCredentials()
 		{
@@ -216,10 +264,20 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
 				return base.GetAuthCredentials(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback);
 			}
 
+			public new IResourceRequestHandler GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
+			{
+				return base.GetResourceRequestHandler(webBrowser, browser, frame, request, isNavigation, isDownload, requestInitiator, ref disableDefaultHandling);
+			}
+
 			public new bool OnBeforeBrowse(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect)
 			{
 				return base.OnBeforeBrowse(webBrowser, browser, frame, request, userGesture, isRedirect);
 			}
+
+			public new bool OnOpenUrlFromTab(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
+			{
+				return base.OnOpenUrlFromTab(webBrowser, browser, frame, targetUrl, targetDisposition, userGesture);
+			}
 		}
 	}
 }
diff --git a/SafeExamBrowser.Browser.UnitTests/Handlers/ResourceHandlerTests.cs b/SafeExamBrowser.Browser.UnitTests/Handlers/ResourceHandlerTests.cs
index 5057e882..1665bee0 100644
--- a/SafeExamBrowser.Browser.UnitTests/Handlers/ResourceHandlerTests.cs
+++ b/SafeExamBrowser.Browser.UnitTests/Handlers/ResourceHandlerTests.cs
@@ -9,6 +9,7 @@
 using System;
 using System.Collections.Specialized;
 using System.Net.Mime;
+using System.Threading;
 using CefSharp;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -128,6 +129,12 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
 			Assert.IsNotNull(resourceHandler);
 		}
 
+		[TestMethod]
+		public void MustLetOperatingSystemHandleUnknownProtocols()
+		{
+			Assert.IsTrue(sut.OnProtocolExecution(default(IWebBrowser), default(IBrowser), default(IFrame), default(IRequest)));
+		}
+
 		[TestMethod]
 		public void MustRedirectToDisablePdfToolbar()
 		{
@@ -183,6 +190,96 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
 			Assert.AreEqual("https://www.host.org/", url);
 		}
 
+		[TestMethod]
+		public void MustSearchGenericLmsSessionIdentifier()
+		{
+			var @event = new AutoResetEvent(false);
+			var headers = new NameValueCollection();
+			var newUrl = default(string);
+			var request = new Mock<IRequest>();
+			var response = new Mock<IResponse>();
+			var sessionId = default(string);
+
+			headers.Add("X-LMS-USER-ID", "some-session-id-123");
+			request.SetupGet(r => r.Url).Returns("https://www.somelms.org");
+			response.SetupGet(r => r.Headers).Returns(headers);
+			sut.SessionIdentifierDetected += (id) =>
+			{
+				sessionId = id;
+				@event.Set();
+			};
+
+			sut.OnResourceRedirect(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), Mock.Of<IRequest>(), response.Object, ref newUrl);
+			@event.WaitOne();
+			Assert.AreEqual("some-session-id-123", sessionId);
+
+			sessionId = default(string);
+
+			sut.OnResourceResponse(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), request.Object, response.Object);
+			@event.WaitOne();
+			Assert.AreEqual("some-session-id-123", sessionId);
+		}
+
+		[TestMethod]
+		public void MustSearchEdxSessionIdentifier()
+		{
+			var @event = new AutoResetEvent(false);
+			var headers = new NameValueCollection();
+			var newUrl = default(string);
+			var request = new Mock<IRequest>();
+			var response = new Mock<IResponse>();
+			var sessionId = default(string);
+
+			headers.Add("Set-Cookie", "edx-user-info=\"{\\\"username\\\": \\\"edx-123\\\"}\"; expires");
+			request.SetupGet(r => r.Url).Returns("https://www.somelms.org");
+			response.SetupGet(r => r.Headers).Returns(headers);
+			sut.SessionIdentifierDetected += (id) =>
+			{
+				sessionId = id;
+				@event.Set();
+			};
+
+			sut.OnResourceRedirect(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), Mock.Of<IRequest>(), response.Object, ref newUrl);
+			@event.WaitOne();
+			Assert.AreEqual("edx-123", sessionId);
+
+			sessionId = default(string);
+
+			sut.OnResourceResponse(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), request.Object, response.Object);
+			@event.WaitOne();
+			Assert.AreEqual("edx-123", sessionId);
+		}
+
+		[TestMethod]
+		public void MustSearchMoodleSessionIdentifier()
+		{
+			var @event = new AutoResetEvent(false);
+			var headers = new NameValueCollection();
+			var newUrl = default(string);
+			var request = new Mock<IRequest>();
+			var response = new Mock<IResponse>();
+			var sessionId = default(string);
+
+			headers.Add("Location", "https://www.some-moodle-instance.org/moodle/login/index.php?testsession=123");
+			request.SetupGet(r => r.Url).Returns("https://www.some-moodle-instance.org");
+			response.SetupGet(r => r.Headers).Returns(headers);
+			sut.SessionIdentifierDetected += (id) =>
+			{
+				sessionId = id;
+				@event.Set();
+			};
+
+			sut.OnResourceRedirect(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), Mock.Of<IRequest>(), response.Object, ref newUrl);
+			@event.WaitOne();
+			Assert.AreEqual("123", sessionId);
+
+			sessionId = default(string);
+
+			sut.OnResourceResponse(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), request.Object, response.Object);
+			@event.WaitOne();
+			Assert.AreEqual("123", sessionId);
+		}
+
 		private class TestableResourceHandler : ResourceHandler
 		{
 			internal TestableResourceHandler(
@@ -205,6 +302,16 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
 				return base.OnBeforeResourceLoad(webBrowser, browser, frame, request, callback);
 			}
 
+			public new bool OnProtocolExecution(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request)
+			{
+				return base.OnProtocolExecution(webBrowser, browser, frame, request);
+			}
+
+			public new void OnResourceRedirect(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response, ref string newUrl)
+			{
+				base.OnResourceRedirect(webBrowser, browser, frame, request, response, ref newUrl);
+			}
+
 			public new bool OnResourceResponse(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response)
 			{
 				return base.OnResourceResponse(webBrowser, browser, frame, request, response);