diff --git a/SafeExamBrowser.Client.Contracts/IClientController.cs b/SafeExamBrowser.Client.Contracts/IClientController.cs
index 2e974175..b9fe22b1 100644
--- a/SafeExamBrowser.Client.Contracts/IClientController.cs
+++ b/SafeExamBrowser.Client.Contracts/IClientController.cs
@@ -10,6 +10,7 @@ using System;
using SafeExamBrowser.Browser.Contracts;
using SafeExamBrowser.Communication.Contracts.Hosts;
using SafeExamBrowser.Configuration.Contracts;
+using SafeExamBrowser.Settings;
namespace SafeExamBrowser.Client.Contracts
{
@@ -41,7 +42,7 @@ namespace SafeExamBrowser.Client.Contracts
///
/// The settings to be used during application execution.
///
- Settings.ApplicationSettings Settings { set; }
+ AppSettings Settings { set; }
///
/// Reverts any changes, releases all used resources and terminates the client.
diff --git a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs
index e312ac27..39206dba 100644
--- a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs
+++ b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs
@@ -17,14 +17,13 @@ using SafeExamBrowser.Communication.Contracts.Hosts;
using SafeExamBrowser.Communication.Contracts.Proxies;
using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.Configuration.Contracts.Cryptography;
-using SafeExamBrowser.Settings;
using SafeExamBrowser.Core.Contracts.OperationModel;
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
+using SafeExamBrowser.Monitoring.Contracts.Applications;
using SafeExamBrowser.Monitoring.Contracts.Display;
-using SafeExamBrowser.Monitoring.Contracts.Processes;
-using SafeExamBrowser.Monitoring.Contracts.Windows;
+using SafeExamBrowser.Settings;
using SafeExamBrowser.UserInterface.Contracts;
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
using SafeExamBrowser.UserInterface.Contracts.Shell;
@@ -38,6 +37,7 @@ namespace SafeExamBrowser.Client.UnitTests
{
private AppConfig appConfig;
private Mock actionCenter;
+ private Mock applicationMonitor;
private Mock browserController;
private Mock clientHost;
private Mock displayMonitor;
@@ -45,17 +45,15 @@ namespace SafeExamBrowser.Client.UnitTests
private Mock hashAlgorithm;
private Mock logger;
private Mock messageBox;
- private Mock processMonitor;
private Mock operationSequence;
private Mock runtimeProxy;
private Guid sessionId;
- private ApplicationSettings settings;
+ private AppSettings settings;
private Mock shutdown;
private Mock taskbar;
private Mock terminationActivator;
private Mock text;
private Mock uiFactory;
- private Mock windowMonitor;
private ClientController sut;
@@ -64,6 +62,7 @@ namespace SafeExamBrowser.Client.UnitTests
{
appConfig = new AppConfig();
actionCenter = new Mock();
+ applicationMonitor = new Mock();
browserController = new Mock();
clientHost = new Mock();
displayMonitor = new Mock();
@@ -71,17 +70,15 @@ namespace SafeExamBrowser.Client.UnitTests
hashAlgorithm = new Mock();
logger = new Mock();
messageBox = new Mock();
- processMonitor = new Mock();
operationSequence = new Mock();
runtimeProxy = new Mock();
sessionId = Guid.NewGuid();
- settings = new ApplicationSettings();
+ settings = new AppSettings();
shutdown = new Mock();
taskbar = new Mock();
terminationActivator = new Mock();
text = new Mock();
uiFactory = new Mock();
- windowMonitor = new Mock();
operationSequence.Setup(o => o.TryPerform()).Returns(OperationResult.Success);
runtimeProxy.Setup(r => r.InformClientReady()).Returns(new CommunicationResult(true));
@@ -89,20 +86,19 @@ namespace SafeExamBrowser.Client.UnitTests
sut = new ClientController(
actionCenter.Object,
+ applicationMonitor.Object,
displayMonitor.Object,
explorerShell.Object,
hashAlgorithm.Object,
logger.Object,
messageBox.Object,
operationSequence.Object,
- processMonitor.Object,
runtimeProxy.Object,
shutdown.Object,
taskbar.Object,
terminationActivator.Object,
text.Object,
- uiFactory.Object,
- windowMonitor.Object);
+ uiFactory.Object);
sut.AppConfig = appConfig;
sut.Browser = browserController.Object;
@@ -111,6 +107,30 @@ namespace SafeExamBrowser.Client.UnitTests
sut.Settings = settings;
}
+ [TestMethod]
+ public void ApplicationMonitor_MustHandleExplorerStartCorrectly()
+ {
+ var order = 0;
+ var shell = 0;
+ var workingArea = 0;
+ var bounds = 0;
+
+ explorerShell.Setup(e => e.Terminate()).Callback(() => shell = ++order);
+ displayMonitor.Setup(w => w.InitializePrimaryDisplay(taskbar.Object.GetAbsoluteHeight())).Callback(() => workingArea = ++order);
+ taskbar.Setup(t => t.InitializeBounds()).Callback(() => bounds = ++order);
+
+ sut.TryStart();
+ applicationMonitor.Raise(p => p.ExplorerStarted += null);
+
+ explorerShell.Verify(p => p.Terminate(), Times.Once);
+ displayMonitor.Verify(w => w.InitializePrimaryDisplay(taskbar.Object.GetAbsoluteHeight()), Times.Once);
+ taskbar.Verify(t => t.InitializeBounds(), Times.Once);
+
+ Assert.IsTrue(shell == 1);
+ Assert.IsTrue(workingArea == 2);
+ Assert.IsTrue(bounds == 3);
+ }
+
[TestMethod]
public void Communication_MustCorrectlyHandleMessageBoxRequest()
{
@@ -265,30 +285,6 @@ namespace SafeExamBrowser.Client.UnitTests
splashScreen.Verify(s => s.UpdateStatus(It.Is(k => k == key), It.IsAny()), Times.Once);
}
- [TestMethod]
- public void ProcessMonitor_MustHandleExplorerStartCorrectly()
- {
- var order = 0;
- var shell = 0;
- var workingArea = 0;
- var bounds = 0;
-
- explorerShell.Setup(e => e.Terminate()).Callback(() => shell = ++order);
- displayMonitor.Setup(w => w.InitializePrimaryDisplay(taskbar.Object.GetAbsoluteHeight())).Callback(() => workingArea = ++order);
- taskbar.Setup(t => t.InitializeBounds()).Callback(() => bounds = ++order);
-
- sut.TryStart();
- processMonitor.Raise(p => p.ExplorerStarted += null);
-
- explorerShell.Verify(p => p.Terminate(), Times.Once);
- displayMonitor.Verify(w => w.InitializePrimaryDisplay(taskbar.Object.GetAbsoluteHeight()), Times.Once);
- taskbar.Verify(t => t.InitializeBounds(), Times.Once);
-
- Assert.IsTrue(shell == 1);
- Assert.IsTrue(workingArea == 2);
- Assert.IsTrue(bounds == 3);
- }
-
[TestMethod]
public void Reconfiguration_MustDenyIfInExamMode()
{
@@ -642,67 +638,5 @@ namespace SafeExamBrowser.Client.UnitTests
terminationActivator.Verify(t => t.Resume(), Times.Once);
runtimeProxy.Verify(p => p.RequestShutdown(), Times.Once);
}
-
- [TestMethod]
- public void WindowMonitor_MustHandleAllowedWindowChangeCorrectly()
- {
- var window = new IntPtr(12345);
-
- processMonitor.Setup(p => p.BelongsToAllowedProcess(window)).Returns(true);
-
- sut.TryStart();
- windowMonitor.Raise(w => w.WindowChanged += null, window);
-
- processMonitor.Verify(p => p.BelongsToAllowedProcess(window), Times.Once);
- windowMonitor.Verify(w => w.Hide(window), Times.Never);
- windowMonitor.Verify(w => w.Close(window), Times.Never);
- }
-
- [TestMethod]
- public void WindowMonitor_MustHandleUnallowedWindowHideCorrectly()
- {
- var order = 0;
- var belongs = 0;
- var hide = 0;
- var window = new IntPtr(12345);
-
- processMonitor.Setup(p => p.BelongsToAllowedProcess(window)).Returns(false).Callback(() => belongs = ++order);
- windowMonitor.Setup(w => w.Hide(window)).Returns(true).Callback(() => hide = ++order);
-
- sut.TryStart();
- windowMonitor.Raise(w => w.WindowChanged += null, window);
-
- processMonitor.Verify(p => p.BelongsToAllowedProcess(window), Times.Once);
- windowMonitor.Verify(w => w.Hide(window), Times.Once);
- windowMonitor.Verify(w => w.Close(window), Times.Never);
-
- Assert.IsTrue(belongs == 1);
- Assert.IsTrue(hide == 2);
- }
-
- [TestMethod]
- public void WindowMonitor_MustHandleUnallowedWindowCloseCorrectly()
- {
- var order = 0;
- var belongs = 0;
- var hide = 0;
- var close = 0;
- var window = new IntPtr(12345);
-
- processMonitor.Setup(p => p.BelongsToAllowedProcess(window)).Returns(false).Callback(() => belongs = ++order);
- windowMonitor.Setup(w => w.Hide(window)).Returns(false).Callback(() => hide = ++order);
- windowMonitor.Setup(w => w.Close(window)).Callback(() => close = ++order);
-
- sut.TryStart();
- windowMonitor.Raise(w => w.WindowChanged += null, window);
-
- processMonitor.Verify(p => p.BelongsToAllowedProcess(window), Times.Once);
- windowMonitor.Verify(w => w.Hide(window), Times.Once);
- windowMonitor.Verify(w => w.Close(window), Times.Once);
-
- Assert.IsTrue(belongs == 1);
- Assert.IsTrue(hide == 2);
- Assert.IsTrue(close == 3);
- }
}
}
diff --git a/SafeExamBrowser.Client.UnitTests/Operations/ApplicationOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/ApplicationOperationTests.cs
new file mode 100644
index 00000000..97813441
--- /dev/null
+++ b/SafeExamBrowser.Client.UnitTests/Operations/ApplicationOperationTests.cs
@@ -0,0 +1,22 @@
+/*
+ * 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/.
+ */
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace SafeExamBrowser.Client.UnitTests.Operations
+{
+ [TestClass]
+ public class ApplicationOperationTests
+ {
+ [TestMethod]
+ public void TODO()
+ {
+ Assert.Fail();
+ }
+ }
+}
diff --git a/SafeExamBrowser.Client.UnitTests/Operations/ConfigurationOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/ConfigurationOperationTests.cs
index 24ec5469..20cfd1a8 100644
--- a/SafeExamBrowser.Client.UnitTests/Operations/ConfigurationOperationTests.cs
+++ b/SafeExamBrowser.Client.UnitTests/Operations/ConfigurationOperationTests.cs
@@ -13,9 +13,9 @@ using SafeExamBrowser.Client.Operations;
using SafeExamBrowser.Communication.Contracts.Data;
using SafeExamBrowser.Communication.Contracts.Proxies;
using SafeExamBrowser.Configuration.Contracts;
-using SafeExamBrowser.Settings;
using SafeExamBrowser.Core.Contracts.OperationModel;
using SafeExamBrowser.Logging.Contracts;
+using SafeExamBrowser.Settings;
namespace SafeExamBrowser.Client.UnitTests.Operations
{
@@ -23,6 +23,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
public class ConfigurationOperationTests
{
private ClientConfiguration configuration;
+ private ClientContext context;
private Mock logger;
private Mock runtime;
private ConfigurationOperation sut;
@@ -31,10 +32,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
public void Initialize()
{
configuration = new ClientConfiguration();
+ context = new ClientContext();
logger = new Mock();
runtime = new Mock();
- sut = new ConfigurationOperation(configuration, logger.Object, runtime.Object);
+ sut = new ConfigurationOperation(configuration, context, logger.Object, runtime.Object);
}
[TestMethod]
@@ -46,7 +48,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
AppConfig = new AppConfig(),
SessionId = Guid.NewGuid(),
- Settings = new ApplicationSettings()
+ Settings = new AppSettings()
}
};
diff --git a/SafeExamBrowser.Client.UnitTests/Operations/KeyboardInterceptorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/KeyboardInterceptorOperationTests.cs
index e49cd135..b1181644 100644
--- a/SafeExamBrowser.Client.UnitTests/Operations/KeyboardInterceptorOperationTests.cs
+++ b/SafeExamBrowser.Client.UnitTests/Operations/KeyboardInterceptorOperationTests.cs
@@ -11,7 +11,6 @@ using Moq;
using SafeExamBrowser.Client.Operations;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.Keyboard;
-using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.Client.UnitTests.Operations
{
@@ -20,7 +19,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
private Mock keyboardInterceptorMock;
private Mock loggerMock;
- private Mock nativeMethodsMock;
private KeyboardInterceptorOperation sut;
@@ -29,9 +27,8 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
keyboardInterceptorMock = new Mock();
loggerMock = new Mock();
- nativeMethodsMock = new Mock();
- sut = new KeyboardInterceptorOperation(keyboardInterceptorMock.Object, loggerMock.Object, nativeMethodsMock.Object);
+ sut = new KeyboardInterceptorOperation(keyboardInterceptorMock.Object, loggerMock.Object);
}
[TestMethod]
@@ -39,7 +36,8 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
sut.Perform();
- nativeMethodsMock.Verify(n => n.RegisterKeyboardHook(It.IsAny()), Times.Once);
+ keyboardInterceptorMock.Verify(i => i.Start(), Times.Once);
+ keyboardInterceptorMock.Verify(i => i.Stop(), Times.Never);
}
[TestMethod]
@@ -47,7 +45,8 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
sut.Revert();
- nativeMethodsMock.Verify(n => n.DeregisterKeyboardHook(It.IsAny()), Times.Once);
+ keyboardInterceptorMock.Verify(i => i.Start(), Times.Never);
+ keyboardInterceptorMock.Verify(i => i.Stop(), Times.Once);
}
}
}
diff --git a/SafeExamBrowser.Client.UnitTests/Operations/MouseInterceptorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/MouseInterceptorOperationTests.cs
index 73800b1f..89505bb3 100644
--- a/SafeExamBrowser.Client.UnitTests/Operations/MouseInterceptorOperationTests.cs
+++ b/SafeExamBrowser.Client.UnitTests/Operations/MouseInterceptorOperationTests.cs
@@ -11,7 +11,6 @@ using Moq;
using SafeExamBrowser.Client.Operations;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.Mouse;
-using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.Client.UnitTests.Operations
{
@@ -20,7 +19,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
private Mock mouseInterceptorMock;
private Mock loggerMock;
- private Mock nativeMethodsMock;
private MouseInterceptorOperation sut;
@@ -29,9 +27,8 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
mouseInterceptorMock = new Mock();
loggerMock = new Mock();
- nativeMethodsMock = new Mock();
- sut = new MouseInterceptorOperation(loggerMock.Object, mouseInterceptorMock.Object, nativeMethodsMock.Object);
+ sut = new MouseInterceptorOperation(loggerMock.Object, mouseInterceptorMock.Object);
}
[TestMethod]
@@ -39,7 +36,8 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
sut.Perform();
- nativeMethodsMock.Verify(n => n.RegisterMouseHook(It.IsAny()), Times.Once);
+ mouseInterceptorMock.Verify(i => i.Start(), Times.Once);
+ mouseInterceptorMock.Verify(i => i.Stop(), Times.Never);
}
[TestMethod]
@@ -47,7 +45,8 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
sut.Revert();
- nativeMethodsMock.Verify(n => n.DeregisterMouseHook(It.IsAny()), Times.Once);
+ mouseInterceptorMock.Verify(i => i.Start(), Times.Never);
+ mouseInterceptorMock.Verify(i => i.Stop(), Times.Once);
}
}
}
diff --git a/SafeExamBrowser.Client.UnitTests/Operations/ProcessMonitorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/ProcessMonitorOperationTests.cs
deleted file mode 100644
index c2095667..00000000
--- a/SafeExamBrowser.Client.UnitTests/Operations/ProcessMonitorOperationTests.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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/.
- */
-
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-using SafeExamBrowser.Client.Operations;
-using SafeExamBrowser.Settings;
-using SafeExamBrowser.Logging.Contracts;
-using SafeExamBrowser.Monitoring.Contracts.Processes;
-
-namespace SafeExamBrowser.Client.UnitTests.Operations
-{
- [TestClass]
- public class ProcessMonitorOperationTests
- {
- private Mock logger;
- private Mock processMonitor;
- private ApplicationSettings settings;
- private ProcessMonitorOperation sut;
-
- [TestInitialize]
- public void Initialize()
- {
- logger = new Mock();
- processMonitor = new Mock();
- settings = new ApplicationSettings();
-
- sut = new ProcessMonitorOperation(logger.Object, processMonitor.Object,settings);
- }
-
- [TestMethod]
- public void MustObserveExplorerWithDisableExplorerShell()
- {
- var counter = 0;
- var start = 0;
- var stop = 0;
-
- settings.KioskMode = KioskMode.DisableExplorerShell;
- processMonitor.Setup(p => p.StartMonitoringExplorer()).Callback(() => start = ++counter);
- processMonitor.Setup(p => p.StopMonitoringExplorer()).Callback(() => stop = ++counter);
-
- sut.Perform();
- sut.Revert();
-
- processMonitor.Verify(p => p.StartMonitoringExplorer(), Times.Once);
- processMonitor.Verify(p => p.StopMonitoringExplorer(), Times.Once);
-
- Assert.AreEqual(1, start);
- Assert.AreEqual(2, stop);
- }
-
- [TestMethod]
- public void MustNotObserveExplorerWithOtherKioskModes()
- {
- settings.KioskMode = KioskMode.CreateNewDesktop;
-
- sut.Perform();
- sut.Revert();
-
- settings.KioskMode = KioskMode.None;
-
- sut.Perform();
- sut.Revert();
-
- processMonitor.Verify(p => p.StartMonitoringExplorer(), Times.Never);
- processMonitor.Verify(p => p.StopMonitoringExplorer(), Times.Never);
- }
- }
-}
diff --git a/SafeExamBrowser.Client.UnitTests/Operations/WindowMonitorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/WindowMonitorOperationTests.cs
deleted file mode 100644
index f92fac30..00000000
--- a/SafeExamBrowser.Client.UnitTests/Operations/WindowMonitorOperationTests.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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/.
- */
-
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-using SafeExamBrowser.Client.Operations;
-using SafeExamBrowser.Settings;
-using SafeExamBrowser.Logging.Contracts;
-using SafeExamBrowser.Monitoring.Contracts.Windows;
-
-namespace SafeExamBrowser.Client.UnitTests.Operations
-{
- [TestClass]
- public class WindowMonitorOperationTests
- {
- private Mock loggerMock;
- private Mock windowMonitorMock;
-
- [TestInitialize]
- public void Initialize()
- {
- loggerMock = new Mock();
- windowMonitorMock = new Mock();
- }
-
- [TestMethod]
- public void MustPerformCorrectlyForCreateNewDesktop()
- {
- var sut = new WindowMonitorOperation(KioskMode.CreateNewDesktop, loggerMock.Object, windowMonitorMock.Object);
-
- sut.Perform();
-
- windowMonitorMock.Verify(w => w.StartMonitoringWindows(), Times.Once);
- }
-
- [TestMethod]
- public void MustRevertCorrectlyForCreateNewDesktop()
- {
- var sut = new WindowMonitorOperation(KioskMode.CreateNewDesktop, loggerMock.Object, windowMonitorMock.Object);
-
- sut.Revert();
-
- windowMonitorMock.Verify(w => w.StopMonitoringWindows(), Times.Once);
- }
-
- [TestMethod]
- public void MustPerformCorrectlyForDisableExplorerShell()
- {
- var sut = new WindowMonitorOperation(KioskMode.DisableExplorerShell, loggerMock.Object, windowMonitorMock.Object);
-
- sut.Perform();
-
- windowMonitorMock.Verify(w => w.StartMonitoringWindows(), Times.Once);
- }
-
- [TestMethod]
- public void MustRevertCorrectlyForDisableExplorerShell()
- {
- var sut = new WindowMonitorOperation(KioskMode.DisableExplorerShell, loggerMock.Object, windowMonitorMock.Object);
-
- sut.Revert();
-
- windowMonitorMock.Verify(w => w.StopMonitoringWindows(), Times.Once);
- }
-
- [TestMethod]
- public void MustDoNothingWithoutKioskMode()
- {
- var sut = new WindowMonitorOperation(KioskMode.None, loggerMock.Object, windowMonitorMock.Object);
-
- sut.Perform();
- sut.Revert();
-
- windowMonitorMock.VerifyNoOtherCalls();
- }
- }
-}
diff --git a/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj b/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj
index ec181aeb..7804c8ff 100644
--- a/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj
+++ b/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj
@@ -81,6 +81,7 @@
+
@@ -88,10 +89,8 @@
-
-
diff --git a/SafeExamBrowser.Client/ClientContext.cs b/SafeExamBrowser.Client/ClientContext.cs
new file mode 100644
index 00000000..f780b278
--- /dev/null
+++ b/SafeExamBrowser.Client/ClientContext.cs
@@ -0,0 +1,29 @@
+/*
+ * 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/.
+ */
+
+using SafeExamBrowser.Configuration.Contracts;
+using SafeExamBrowser.Settings;
+
+namespace SafeExamBrowser.Client
+{
+ ///
+ /// Holds all configuration and runtime data for the client.
+ ///
+ internal class ClientContext
+ {
+ ///
+ /// The global application configuration.
+ ///
+ internal AppConfig AppConfig { get; set; }
+
+ ///
+ /// The settings for the current session.
+ ///
+ internal AppSettings Settings { get; set; }
+ }
+}
diff --git a/SafeExamBrowser.Client/ClientController.cs b/SafeExamBrowser.Client/ClientController.cs
index 2d3749b6..2d278072 100644
--- a/SafeExamBrowser.Client/ClientController.cs
+++ b/SafeExamBrowser.Client/ClientController.cs
@@ -17,14 +17,13 @@ using SafeExamBrowser.Communication.Contracts.Hosts;
using SafeExamBrowser.Communication.Contracts.Proxies;
using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.Configuration.Contracts.Cryptography;
-using SafeExamBrowser.Settings;
using SafeExamBrowser.Core.Contracts.OperationModel;
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
+using SafeExamBrowser.Monitoring.Contracts.Applications;
using SafeExamBrowser.Monitoring.Contracts.Display;
-using SafeExamBrowser.Monitoring.Contracts.Processes;
-using SafeExamBrowser.Monitoring.Contracts.Windows;
+using SafeExamBrowser.Settings;
using SafeExamBrowser.UserInterface.Contracts;
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
using SafeExamBrowser.UserInterface.Contracts.Shell;
@@ -36,13 +35,13 @@ namespace SafeExamBrowser.Client
internal class ClientController : IClientController
{
private IActionCenter actionCenter;
+ private IApplicationMonitor applicationMonitor;
private IDisplayMonitor displayMonitor;
private IExplorerShell explorerShell;
private IHashAlgorithm hashAlgorithm;
private ILogger logger;
private IMessageBox messageBox;
private IOperationSequence operations;
- private IProcessMonitor processMonitor;
private IRuntimeProxy runtime;
private Action shutdown;
private ISplashScreen splashScreen;
@@ -50,13 +49,12 @@ namespace SafeExamBrowser.Client
private ITerminationActivator terminationActivator;
private IText text;
private IUserInterfaceFactory uiFactory;
- private IWindowMonitor windowMonitor;
private AppConfig appConfig;
public IBrowserApplication Browser { private get; set; }
public IClientHost ClientHost { private get; set; }
public Guid SessionId { private get; set; }
- public ApplicationSettings Settings { private get; set; }
+ public AppSettings Settings { private get; set; }
public AppConfig AppConfig
{
@@ -73,36 +71,34 @@ namespace SafeExamBrowser.Client
public ClientController(
IActionCenter actionCenter,
+ IApplicationMonitor applicationMonitor,
IDisplayMonitor displayMonitor,
IExplorerShell explorerShell,
IHashAlgorithm hashAlgorithm,
ILogger logger,
IMessageBox messageBox,
IOperationSequence operations,
- IProcessMonitor processMonitor,
IRuntimeProxy runtime,
Action shutdown,
ITaskbar taskbar,
ITerminationActivator terminationActivator,
IText text,
- IUserInterfaceFactory uiFactory,
- IWindowMonitor windowMonitor)
+ IUserInterfaceFactory uiFactory)
{
this.actionCenter = actionCenter;
+ this.applicationMonitor = applicationMonitor;
this.displayMonitor = displayMonitor;
this.explorerShell = explorerShell;
this.hashAlgorithm = hashAlgorithm;
this.logger = logger;
this.messageBox = messageBox;
this.operations = operations;
- this.processMonitor = processMonitor;
this.runtime = runtime;
this.shutdown = shutdown;
this.taskbar = taskbar;
this.terminationActivator = terminationActivator;
this.text = text;
this.uiFactory = uiFactory;
- this.windowMonitor = windowMonitor;
}
public bool TryStart()
@@ -110,6 +106,7 @@ namespace SafeExamBrowser.Client
logger.Info("Initiating startup procedure...");
splashScreen = uiFactory.CreateSplashScreen();
+ operations.ActionRequired += Operations_ActionRequired;
operations.ProgressChanged += Operations_ProgressChanged;
operations.StatusChanged += Operations_StatusChanged;
@@ -175,28 +172,26 @@ namespace SafeExamBrowser.Client
private void RegisterEvents()
{
actionCenter.QuitButtonClicked += Shell_QuitButtonClicked;
+ applicationMonitor.ExplorerStarted += ApplicationMonitor_ExplorerStarted;
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
ClientHost.MessageBoxRequested += ClientHost_MessageBoxRequested;
ClientHost.PasswordRequested += ClientHost_PasswordRequested;
ClientHost.ReconfigurationDenied += ClientHost_ReconfigurationDenied;
ClientHost.Shutdown += ClientHost_Shutdown;
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
- processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
runtime.ConnectionLost += Runtime_ConnectionLost;
taskbar.QuitButtonClicked += Shell_QuitButtonClicked;
terminationActivator.Activated += TerminationActivator_Activated;
- windowMonitor.WindowChanged += WindowMonitor_WindowChanged;
}
private void DeregisterEvents()
{
actionCenter.QuitButtonClicked -= Shell_QuitButtonClicked;
+ applicationMonitor.ExplorerStarted -= ApplicationMonitor_ExplorerStarted;
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
- processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
runtime.ConnectionLost -= Runtime_ConnectionLost;
taskbar.QuitButtonClicked -= Shell_QuitButtonClicked;
terminationActivator.Activated -= TerminationActivator_Activated;
- windowMonitor.WindowChanged -= WindowMonitor_WindowChanged;
if (Browser != null)
{
@@ -226,6 +221,18 @@ namespace SafeExamBrowser.Client
Browser.Start();
}
+ private void ApplicationMonitor_ExplorerStarted()
+ {
+ logger.Info("Trying to terminate Windows explorer...");
+ explorerShell.Terminate();
+ logger.Info("Reinitializing working area...");
+ displayMonitor.InitializePrimaryDisplay(taskbar.GetAbsoluteHeight());
+ logger.Info("Reinitializing shell...");
+ actionCenter.InitializeBounds();
+ taskbar.InitializeBounds();
+ logger.Info("Desktop successfully restored.");
+ }
+
private void Browser_ConfigurationDownloadRequested(string fileName, DownloadEventArgs args)
{
if (Settings.ConfigurationMode == ConfigurationMode.ConfigureClient)
@@ -339,6 +346,11 @@ namespace SafeExamBrowser.Client
logger.Info("Desktop successfully restored.");
}
+ private void Operations_ActionRequired(ActionRequiredEventArgs args)
+ {
+ // TODO
+ }
+
private void Operations_ProgressChanged(ProgressChangedEventArgs args)
{
if (args.CurrentValue.HasValue)
@@ -372,18 +384,6 @@ namespace SafeExamBrowser.Client
splashScreen?.UpdateStatus(status, true);
}
- private void ProcessMonitor_ExplorerStarted()
- {
- logger.Info("Trying to terminate Windows explorer...");
- explorerShell.Terminate();
- logger.Info("Reinitializing working area...");
- displayMonitor.InitializePrimaryDisplay(taskbar.GetAbsoluteHeight());
- logger.Info("Reinitializing shell...");
- actionCenter.InitializeBounds();
- taskbar.InitializeBounds();
- logger.Info("Desktop successfully restored.");
- }
-
private void Runtime_ConnectionLost()
{
logger.Error("Lost connection to the runtime!");
@@ -406,21 +406,6 @@ namespace SafeExamBrowser.Client
terminationActivator.Resume();
}
- private void WindowMonitor_WindowChanged(IntPtr window)
- {
- var allowed = processMonitor.BelongsToAllowedProcess(window);
-
- if (!allowed)
- {
- var success = windowMonitor.Hide(window);
-
- if (!success)
- {
- windowMonitor.Close(window);
- }
- }
- }
-
private bool TryInitiateShutdown()
{
var hasQuitPassword = !String.IsNullOrEmpty(Settings.QuitPasswordHash);
diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs
index 0c4298a9..c350287b 100644
--- a/SafeExamBrowser.Client/CompositionRoot.cs
+++ b/SafeExamBrowser.Client/CompositionRoot.cs
@@ -23,7 +23,6 @@ using SafeExamBrowser.Communication.Contracts.Proxies;
using SafeExamBrowser.Communication.Hosts;
using SafeExamBrowser.Communication.Proxies;
using SafeExamBrowser.Configuration.Contracts;
-using SafeExamBrowser.Settings.UserInterface;
using SafeExamBrowser.Configuration.Cryptography;
using SafeExamBrowser.Core.Contracts.OperationModel;
using SafeExamBrowser.Core.OperationModel;
@@ -32,13 +31,13 @@ using SafeExamBrowser.I18n;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging;
using SafeExamBrowser.Logging.Contracts;
-using SafeExamBrowser.Monitoring.Contracts.Processes;
-using SafeExamBrowser.Monitoring.Contracts.Windows;
+using SafeExamBrowser.Monitoring.Applications;
+using SafeExamBrowser.Monitoring.Contracts.Applications;
using SafeExamBrowser.Monitoring.Display;
using SafeExamBrowser.Monitoring.Keyboard;
using SafeExamBrowser.Monitoring.Mouse;
-using SafeExamBrowser.Monitoring.Processes;
-using SafeExamBrowser.Monitoring.Windows;
+using SafeExamBrowser.Settings.Logging;
+using SafeExamBrowser.Settings.UserInterface;
using SafeExamBrowser.SystemComponents;
using SafeExamBrowser.SystemComponents.Audio;
using SafeExamBrowser.SystemComponents.Contracts;
@@ -52,7 +51,6 @@ using SafeExamBrowser.WindowsApi;
using SafeExamBrowser.WindowsApi.Contracts;
using Desktop = SafeExamBrowser.UserInterface.Desktop;
using Mobile = SafeExamBrowser.UserInterface.Mobile;
-using SafeExamBrowser.Settings.Logging;
namespace SafeExamBrowser.Client
{
@@ -60,17 +58,18 @@ namespace SafeExamBrowser.Client
{
private Guid authenticationToken;
private ClientConfiguration configuration;
+ private ClientContext context;
private string logFilePath;
private LogLevel logLevel;
private string runtimeHostUri;
private UserInterfaceMode uiMode;
private IActionCenter actionCenter;
+ private IApplicationMonitor applicationMonitor;
private IBrowserApplication browser;
private IClientHost clientHost;
private ILogger logger;
private IMessageBox messageBox;
- private IProcessMonitor processMonitor;
private INativeMethods nativeMethods;
private IRuntimeProxy runtimeProxy;
private ISystemInfo systemInfo;
@@ -79,7 +78,6 @@ namespace SafeExamBrowser.Client
private IText text;
private ITextResource textResource;
private IUserInterfaceFactory uiFactory;
- private IWindowMonitor windowMonitor;
internal IClientController ClientController { get; private set; }
@@ -96,13 +94,13 @@ namespace SafeExamBrowser.Client
InitializeText();
actionCenter = BuildActionCenter();
+ applicationMonitor = new ApplicationMonitor(new ModuleLogger(logger, nameof(ApplicationMonitor)), nativeMethods);
+ context = new ClientContext();
messageBox = BuildMessageBox();
- processMonitor = new ProcessMonitor(new ModuleLogger(logger, nameof(ProcessMonitor)), nativeMethods);
uiFactory = BuildUserInterfaceFactory();
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(RuntimeProxy)), Interlocutor.Client);
taskbar = BuildTaskbar();
terminationActivator = new TerminationActivator(new ModuleLogger(logger, nameof(TerminationActivator)));
- windowMonitor = new WindowMonitor(new ModuleLogger(logger, nameof(WindowMonitor)), nativeMethods);
var displayMonitor = new DisplayMonitor(new ModuleLogger(logger, nameof(DisplayMonitor)), nativeMethods, systemInfo);
var explorerShell = new ExplorerShell(new ModuleLogger(logger, nameof(ExplorerShell)), nativeMethods);
@@ -112,14 +110,13 @@ namespace SafeExamBrowser.Client
operations.Enqueue(new I18nOperation(logger, text, textResource));
operations.Enqueue(new RuntimeConnectionOperation(logger, runtimeProxy, authenticationToken));
- operations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeProxy));
+ operations.Enqueue(new ConfigurationOperation(configuration, context, logger, runtimeProxy));
operations.Enqueue(new DelegateOperation(UpdateAppConfig));
operations.Enqueue(new LazyInitializationOperation(BuildClientHostOperation));
operations.Enqueue(new LazyInitializationOperation(BuildClientHostDisconnectionOperation));
operations.Enqueue(new LazyInitializationOperation(BuildKeyboardInterceptorOperation));
operations.Enqueue(new LazyInitializationOperation(BuildMouseInterceptorOperation));
- operations.Enqueue(new LazyInitializationOperation(BuildWindowMonitorOperation));
- operations.Enqueue(new LazyInitializationOperation(BuildProcessMonitorOperation));
+ operations.Enqueue(new LazyInitializationOperation(BuildApplicationOperation));
operations.Enqueue(new DisplayMonitorOperation(displayMonitor, logger, taskbar));
operations.Enqueue(new LazyInitializationOperation(BuildShellOperation));
operations.Enqueue(new LazyInitializationOperation(BuildBrowserOperation));
@@ -130,20 +127,19 @@ namespace SafeExamBrowser.Client
ClientController = new ClientController(
actionCenter,
+ applicationMonitor,
displayMonitor,
explorerShell,
hashAlgorithm,
logger,
messageBox,
sequence,
- processMonitor,
runtimeProxy,
shutdown,
taskbar,
terminationActivator,
text,
- uiFactory,
- windowMonitor);
+ uiFactory);
}
internal void LogStartupInformation()
@@ -202,6 +198,11 @@ namespace SafeExamBrowser.Client
textResource = new XmlTextResource(path);
}
+ private IOperation BuildApplicationOperation()
+ {
+ return new ApplicationOperation(applicationMonitor, context, logger);
+ }
+
private IOperation BuildBrowserOperation()
{
var moduleLogger = new ModuleLogger(logger, nameof(BrowserApplication));
@@ -238,25 +239,20 @@ namespace SafeExamBrowser.Client
private IOperation BuildKeyboardInterceptorOperation()
{
- var keyboardInterceptor = new KeyboardInterceptor(configuration.Settings.Keyboard, new ModuleLogger(logger, nameof(KeyboardInterceptor)));
- var operation = new KeyboardInterceptorOperation(keyboardInterceptor, logger, nativeMethods);
+ var keyboardInterceptor = new KeyboardInterceptor(configuration.Settings.Keyboard, new ModuleLogger(logger, nameof(KeyboardInterceptor)), nativeMethods);
+ var operation = new KeyboardInterceptorOperation(keyboardInterceptor, logger);
return operation;
}
private IOperation BuildMouseInterceptorOperation()
{
- var mouseInterceptor = new MouseInterceptor(new ModuleLogger(logger, nameof(MouseInterceptor)), configuration.Settings.Mouse);
- var operation = new MouseInterceptorOperation(logger, mouseInterceptor, nativeMethods);
+ var mouseInterceptor = new MouseInterceptor(new ModuleLogger(logger, nameof(MouseInterceptor)), configuration.Settings.Mouse, nativeMethods);
+ var operation = new MouseInterceptorOperation(logger, mouseInterceptor);
return operation;
}
- private IOperation BuildProcessMonitorOperation()
- {
- return new ProcessMonitorOperation(logger, processMonitor, configuration.Settings);
- }
-
private IOperation BuildShellOperation()
{
var aboutInfo = new AboutNotificationInfo(text);
@@ -295,11 +291,6 @@ namespace SafeExamBrowser.Client
return operation;
}
- private IOperation BuildWindowMonitorOperation()
- {
- return new WindowMonitorOperation(configuration.Settings.KioskMode, logger, windowMonitor);
- }
-
private IActionCenter BuildActionCenter()
{
switch (uiMode)
diff --git a/SafeExamBrowser.Client/Operations/ApplicationOperation.cs b/SafeExamBrowser.Client/Operations/ApplicationOperation.cs
new file mode 100644
index 00000000..61afe9c1
--- /dev/null
+++ b/SafeExamBrowser.Client/Operations/ApplicationOperation.cs
@@ -0,0 +1,136 @@
+/*
+ * 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/.
+ */
+
+using System.Collections.Generic;
+using System.Linq;
+using SafeExamBrowser.Client.Operations.Events;
+using SafeExamBrowser.Core.Contracts.OperationModel;
+using SafeExamBrowser.Core.Contracts.OperationModel.Events;
+using SafeExamBrowser.I18n.Contracts;
+using SafeExamBrowser.Logging.Contracts;
+using SafeExamBrowser.Monitoring.Contracts.Applications;
+using SafeExamBrowser.Settings;
+using SafeExamBrowser.Settings.Applications;
+
+namespace SafeExamBrowser.Client.Operations
+{
+ internal class ApplicationOperation : ClientOperation
+ {
+ private ILogger logger;
+ private IApplicationMonitor applicationMonitor;
+
+ public override event ActionRequiredEventHandler ActionRequired;
+ public override event StatusChangedEventHandler StatusChanged;
+
+ public ApplicationOperation(IApplicationMonitor applicationMonitor, ClientContext context, ILogger logger) : base(context)
+ {
+ this.applicationMonitor = applicationMonitor;
+ this.logger = logger;
+ }
+
+ public override OperationResult Perform()
+ {
+ logger.Info("Initializing applications...");
+ StatusChanged?.Invoke(TextKey.OperationStatus_InitializeProcessMonitoring);
+
+ var result = InitializeApplications();
+
+ if (result == OperationResult.Success)
+ {
+ StartMonitor();
+ }
+
+ return result;
+ }
+
+ public override OperationResult Revert()
+ {
+ logger.Info("Finalizing applications...");
+ StatusChanged?.Invoke(TextKey.OperationStatus_StopProcessMonitoring);
+
+ TerminateApplications();
+ StopMonitor();
+
+ return OperationResult.Success;
+ }
+
+ private OperationResult InitializeApplications()
+ {
+ var initialization = applicationMonitor.Initialize(Context.Settings.Applications);
+ var result = OperationResult.Success;
+
+ if (initialization.RunningApplications.Any())
+ {
+ result = TryTerminate(initialization.RunningApplications);
+ }
+
+ if (result == OperationResult.Success)
+ {
+ foreach (var application in Context.Settings.Applications.Whitelist)
+ {
+ Create(application);
+ }
+ }
+
+ return result;
+ }
+
+ private void Create(WhitelistApplication application)
+ {
+ // TODO: Use IApplicationFactory to create new application according to configuration, load into Context.Applications
+ }
+
+ private void StartMonitor()
+ {
+ if (Context.Settings.KioskMode != KioskMode.None)
+ {
+ applicationMonitor.Start();
+ }
+ }
+
+ private void StopMonitor()
+ {
+ if (Context.Settings.KioskMode != KioskMode.None)
+ {
+ applicationMonitor.Stop();
+ }
+ }
+
+ private void TerminateApplications()
+ {
+
+ }
+
+ private OperationResult TryTerminate(IEnumerable runningApplications)
+ {
+ var args = new ProcessTerminationEventArgs();
+ var result = OperationResult.Success;
+
+ ActionRequired?.Invoke(args);
+
+ if (args.TerminateProcesses)
+ {
+ // TODO: Terminate all processes of all running applications
+
+ //foreach (var application in runningApplications)
+ //{
+ // foreach (var process in application.Processes)
+ // {
+ // process.Kill();
+ // }
+ //}
+ }
+ else
+ {
+ result = OperationResult.Aborted;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/SafeExamBrowser.Client/Operations/ClientOperation.cs b/SafeExamBrowser.Client/Operations/ClientOperation.cs
new file mode 100644
index 00000000..6a799459
--- /dev/null
+++ b/SafeExamBrowser.Client/Operations/ClientOperation.cs
@@ -0,0 +1,32 @@
+/*
+ * 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/.
+ */
+
+using SafeExamBrowser.Core.Contracts.OperationModel;
+using SafeExamBrowser.Core.Contracts.OperationModel.Events;
+
+namespace SafeExamBrowser.Client.Operations
+{
+ ///
+ /// The base implementation to be used for all operations in the client operation sequence.
+ ///
+ internal abstract class ClientOperation : IOperation
+ {
+ protected ClientContext Context { get; private set; }
+
+ public abstract event ActionRequiredEventHandler ActionRequired;
+ public abstract event StatusChangedEventHandler StatusChanged;
+
+ public ClientOperation(ClientContext context)
+ {
+ Context = context;
+ }
+
+ public abstract OperationResult Perform();
+ public abstract OperationResult Revert();
+ }
+}
diff --git a/SafeExamBrowser.Client/Operations/ConfigurationOperation.cs b/SafeExamBrowser.Client/Operations/ConfigurationOperation.cs
index f8534fc9..96120b82 100644
--- a/SafeExamBrowser.Client/Operations/ConfigurationOperation.cs
+++ b/SafeExamBrowser.Client/Operations/ConfigurationOperation.cs
@@ -15,23 +15,24 @@ using SafeExamBrowser.Logging.Contracts;
namespace SafeExamBrowser.Client.Operations
{
- internal class ConfigurationOperation : IOperation
+ internal class ConfigurationOperation : ClientOperation
{
private ClientConfiguration configuration;
private ILogger logger;
private IRuntimeProxy runtime;
- public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
- public event StatusChangedEventHandler StatusChanged;
+ public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
+ public override event StatusChangedEventHandler StatusChanged;
- public ConfigurationOperation(ClientConfiguration configuration, ILogger logger, IRuntimeProxy runtime)
+ // TODO: Remove and delete ClientConfiguration!
+ public ConfigurationOperation(ClientConfiguration configuration, ClientContext context, ILogger logger, IRuntimeProxy runtime) : base(context)
{
this.configuration = configuration;
this.logger = logger;
this.runtime = runtime;
}
- public OperationResult Perform()
+ public override OperationResult Perform()
{
logger.Info("Initializing application configuration...");
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration);
@@ -43,6 +44,9 @@ namespace SafeExamBrowser.Client.Operations
configuration.SessionId = config.SessionId;
configuration.Settings = config.Settings;
+ Context.AppConfig = config.AppConfig;
+ Context.Settings = config.Settings;
+
logger.Info("Successfully retrieved the application configuration from the runtime.");
logger.Info($" -> Client-ID: {configuration.AppConfig.ClientId}");
logger.Info($" -> Runtime-ID: {configuration.AppConfig.RuntimeId}");
@@ -51,7 +55,7 @@ namespace SafeExamBrowser.Client.Operations
return OperationResult.Success;
}
- public OperationResult Revert()
+ public override OperationResult Revert()
{
return OperationResult.Success;
}
diff --git a/SafeExamBrowser.Client/Operations/Events/ProcessTerminationEventArgs.cs b/SafeExamBrowser.Client/Operations/Events/ProcessTerminationEventArgs.cs
new file mode 100644
index 00000000..93ef0062
--- /dev/null
+++ b/SafeExamBrowser.Client/Operations/Events/ProcessTerminationEventArgs.cs
@@ -0,0 +1,17 @@
+/*
+ * 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/.
+ */
+
+using SafeExamBrowser.Core.Contracts.OperationModel.Events;
+
+namespace SafeExamBrowser.Client.Operations.Events
+{
+ internal class ProcessTerminationEventArgs : ActionRequiredEventArgs
+ {
+ public bool TerminateProcesses { get; set; }
+ }
+}
diff --git a/SafeExamBrowser.Client/Operations/KeyboardInterceptorOperation.cs b/SafeExamBrowser.Client/Operations/KeyboardInterceptorOperation.cs
index c43dddd6..3fb8fd3a 100644
--- a/SafeExamBrowser.Client/Operations/KeyboardInterceptorOperation.cs
+++ b/SafeExamBrowser.Client/Operations/KeyboardInterceptorOperation.cs
@@ -11,7 +11,6 @@ using SafeExamBrowser.Core.Contracts.OperationModel.Events;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.Keyboard;
-using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.Client.Operations
{
@@ -19,19 +18,14 @@ namespace SafeExamBrowser.Client.Operations
{
private IKeyboardInterceptor keyboardInterceptor;
private ILogger logger;
- private INativeMethods nativeMethods;
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
public event StatusChangedEventHandler StatusChanged;
- public KeyboardInterceptorOperation(
- IKeyboardInterceptor keyboardInterceptor,
- ILogger logger,
- INativeMethods nativeMethods)
+ public KeyboardInterceptorOperation(IKeyboardInterceptor keyboardInterceptor, ILogger logger)
{
this.keyboardInterceptor = keyboardInterceptor;
this.logger = logger;
- this.nativeMethods = nativeMethods;
}
public OperationResult Perform()
@@ -39,7 +33,7 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Starting keyboard interception...");
StatusChanged?.Invoke(TextKey.OperationStatus_StartKeyboardInterception);
- nativeMethods.RegisterKeyboardHook(keyboardInterceptor);
+ keyboardInterceptor.Start();
return OperationResult.Success;
}
@@ -49,7 +43,7 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Stopping keyboard interception...");
StatusChanged?.Invoke(TextKey.OperationStatus_StopKeyboardInterception);
- nativeMethods.DeregisterKeyboardHook(keyboardInterceptor);
+ keyboardInterceptor.Stop();
return OperationResult.Success;
}
diff --git a/SafeExamBrowser.Client/Operations/MouseInterceptorOperation.cs b/SafeExamBrowser.Client/Operations/MouseInterceptorOperation.cs
index 1c352fa0..e77dc2d8 100644
--- a/SafeExamBrowser.Client/Operations/MouseInterceptorOperation.cs
+++ b/SafeExamBrowser.Client/Operations/MouseInterceptorOperation.cs
@@ -11,7 +11,6 @@ using SafeExamBrowser.Core.Contracts.OperationModel.Events;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.Mouse;
-using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.Client.Operations
{
@@ -19,19 +18,14 @@ namespace SafeExamBrowser.Client.Operations
{
private ILogger logger;
private IMouseInterceptor mouseInterceptor;
- private INativeMethods nativeMethods;
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
public event StatusChangedEventHandler StatusChanged;
- public MouseInterceptorOperation(
- ILogger logger,
- IMouseInterceptor mouseInterceptor,
- INativeMethods nativeMethods)
+ public MouseInterceptorOperation(ILogger logger, IMouseInterceptor mouseInterceptor)
{
this.logger = logger;
this.mouseInterceptor = mouseInterceptor;
- this.nativeMethods = nativeMethods;
}
public OperationResult Perform()
@@ -39,7 +33,7 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Starting mouse interception...");
StatusChanged?.Invoke(TextKey.OperationStatus_StartMouseInterception);
- nativeMethods.RegisterMouseHook(mouseInterceptor);
+ mouseInterceptor.Start();
return OperationResult.Success;
}
@@ -49,7 +43,7 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Stopping mouse interception...");
StatusChanged?.Invoke(TextKey.OperationStatus_StopMouseInterception);
- nativeMethods.DeregisterMouseHook(mouseInterceptor);
+ mouseInterceptor.Stop();
return OperationResult.Success;
}
diff --git a/SafeExamBrowser.Client/Operations/ProcessMonitorOperation.cs b/SafeExamBrowser.Client/Operations/ProcessMonitorOperation.cs
deleted file mode 100644
index 83875b01..00000000
--- a/SafeExamBrowser.Client/Operations/ProcessMonitorOperation.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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/.
- */
-
-using SafeExamBrowser.Settings;
-using SafeExamBrowser.Core.Contracts.OperationModel;
-using SafeExamBrowser.Core.Contracts.OperationModel.Events;
-using SafeExamBrowser.I18n.Contracts;
-using SafeExamBrowser.Logging.Contracts;
-using SafeExamBrowser.Monitoring.Contracts.Processes;
-
-namespace SafeExamBrowser.Client.Operations
-{
- internal class ProcessMonitorOperation : IOperation
- {
- private ILogger logger;
- private IProcessMonitor processMonitor;
- private ApplicationSettings settings;
-
- public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
- public event StatusChangedEventHandler StatusChanged;
-
- public ProcessMonitorOperation(ILogger logger, IProcessMonitor processMonitor, ApplicationSettings settings)
- {
- this.logger = logger;
- this.processMonitor = processMonitor;
- this.settings = settings;
- }
-
- public OperationResult Perform()
- {
- logger.Info("Initializing process monitoring...");
- StatusChanged?.Invoke(TextKey.OperationStatus_InitializeProcessMonitoring);
-
- if (settings.KioskMode == KioskMode.DisableExplorerShell)
- {
- processMonitor.StartMonitoringExplorer();
- }
-
- return OperationResult.Success;
- }
-
- public OperationResult Revert()
- {
- logger.Info("Stopping process monitoring...");
- StatusChanged?.Invoke(TextKey.OperationStatus_StopProcessMonitoring);
-
- if (settings.KioskMode == KioskMode.DisableExplorerShell)
- {
- processMonitor.StopMonitoringExplorer();
- }
-
- return OperationResult.Success;
- }
- }
-}
diff --git a/SafeExamBrowser.Client/Operations/WindowMonitorOperation.cs b/SafeExamBrowser.Client/Operations/WindowMonitorOperation.cs
deleted file mode 100644
index 0df4659c..00000000
--- a/SafeExamBrowser.Client/Operations/WindowMonitorOperation.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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/.
- */
-
-using SafeExamBrowser.Settings;
-using SafeExamBrowser.Core.Contracts.OperationModel;
-using SafeExamBrowser.Core.Contracts.OperationModel.Events;
-using SafeExamBrowser.I18n.Contracts;
-using SafeExamBrowser.Logging.Contracts;
-using SafeExamBrowser.Monitoring.Contracts.Windows;
-
-namespace SafeExamBrowser.Client.Operations
-{
- internal class WindowMonitorOperation : IOperation
- {
- private KioskMode kioskMode;
- private ILogger logger;
- private IWindowMonitor windowMonitor;
-
- public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
- public event StatusChangedEventHandler StatusChanged;
-
- public WindowMonitorOperation(KioskMode kioskMode, ILogger logger, IWindowMonitor windowMonitor)
- {
- this.kioskMode = kioskMode;
- this.logger = logger;
- this.windowMonitor = windowMonitor;
- }
-
- public OperationResult Perform()
- {
- logger.Info("Initializing window monitoring...");
- StatusChanged?.Invoke(TextKey.OperationStatus_InitializeWindowMonitoring);
-
- if (kioskMode != KioskMode.None)
- {
- windowMonitor.StartMonitoringWindows();
- }
-
- return OperationResult.Success;
- }
-
- public OperationResult Revert()
- {
- logger.Info("Stopping window monitoring...");
- StatusChanged?.Invoke(TextKey.OperationStatus_StopWindowMonitoring);
-
- if (kioskMode != KioskMode.None)
- {
- windowMonitor.StopMonitoringWindows();
- }
-
- return OperationResult.Success;
- }
- }
-}
diff --git a/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj b/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj
index 1f2452f7..52504529 100644
--- a/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj
+++ b/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj
@@ -71,9 +71,12 @@
+
+
+
@@ -88,9 +91,8 @@
-
+
-
Code
@@ -220,6 +222,7 @@
+
robocopy "$(SolutionDir)SafeExamBrowser.Browser\bin\$(PlatformName)\$(ConfigurationName)" "$(ProjectDir)bin\$(PlatformName)\$(ConfigurationName)" /e /np
diff --git a/SafeExamBrowser.Configuration.Contracts/ClientConfiguration.cs b/SafeExamBrowser.Configuration.Contracts/ClientConfiguration.cs
index b51ab020..139fb714 100644
--- a/SafeExamBrowser.Configuration.Contracts/ClientConfiguration.cs
+++ b/SafeExamBrowser.Configuration.Contracts/ClientConfiguration.cs
@@ -7,6 +7,7 @@
*/
using System;
+using SafeExamBrowser.Settings;
namespace SafeExamBrowser.Configuration.Contracts
{
@@ -29,6 +30,6 @@ namespace SafeExamBrowser.Configuration.Contracts
///
/// The application settings to be used by the client.
///
- public Settings.ApplicationSettings Settings { get; set; }
+ public AppSettings Settings { get; set; }
}
}
diff --git a/SafeExamBrowser.Configuration.Contracts/IConfigurationRepository.cs b/SafeExamBrowser.Configuration.Contracts/IConfigurationRepository.cs
index 3e277f19..9e6448fd 100644
--- a/SafeExamBrowser.Configuration.Contracts/IConfigurationRepository.cs
+++ b/SafeExamBrowser.Configuration.Contracts/IConfigurationRepository.cs
@@ -10,6 +10,7 @@ using System;
using SafeExamBrowser.Configuration.Contracts.Cryptography;
using SafeExamBrowser.Configuration.Contracts.DataFormats;
using SafeExamBrowser.Configuration.Contracts.DataResources;
+using SafeExamBrowser.Settings;
namespace SafeExamBrowser.Configuration.Contracts
{
@@ -36,7 +37,7 @@ namespace SafeExamBrowser.Configuration.Contracts
///
/// Loads the default settings.
///
- Settings.ApplicationSettings LoadDefaultSettings();
+ AppSettings LoadDefaultSettings();
///
/// Registers the specified to be used to parse configuration data.
@@ -61,6 +62,6 @@ namespace SafeExamBrowser.Configuration.Contracts
///
/// Attempts to load settings from the specified resource.
///
- LoadStatus TryLoadSettings(Uri resource, out Settings.ApplicationSettings settings, PasswordParameters password = null);
+ LoadStatus TryLoadSettings(Uri resource, out AppSettings settings, PasswordParameters password = null);
}
}
diff --git a/SafeExamBrowser.Configuration.Contracts/ServiceConfiguration.cs b/SafeExamBrowser.Configuration.Contracts/ServiceConfiguration.cs
index c428327a..2714e0c6 100644
--- a/SafeExamBrowser.Configuration.Contracts/ServiceConfiguration.cs
+++ b/SafeExamBrowser.Configuration.Contracts/ServiceConfiguration.cs
@@ -7,6 +7,7 @@
*/
using System;
+using SafeExamBrowser.Settings;
namespace SafeExamBrowser.Configuration.Contracts
{
@@ -29,7 +30,7 @@ namespace SafeExamBrowser.Configuration.Contracts
///
/// The application settings to be used by the service.
///
- public Settings.ApplicationSettings Settings { get; set; }
+ public AppSettings Settings { get; set; }
///
/// The user name of the currently logged in user.
diff --git a/SafeExamBrowser.Configuration.Contracts/SessionConfiguration.cs b/SafeExamBrowser.Configuration.Contracts/SessionConfiguration.cs
index efc1ac3a..9dbb5314 100644
--- a/SafeExamBrowser.Configuration.Contracts/SessionConfiguration.cs
+++ b/SafeExamBrowser.Configuration.Contracts/SessionConfiguration.cs
@@ -7,6 +7,7 @@
*/
using System;
+using SafeExamBrowser.Settings;
namespace SafeExamBrowser.Configuration.Contracts
{
@@ -16,7 +17,7 @@ namespace SafeExamBrowser.Configuration.Contracts
public class SessionConfiguration
{
///
- /// The active application configuration for this session.
+ /// The application configuration for this session.
///
public AppConfig AppConfig { get; set; }
@@ -33,6 +34,6 @@ namespace SafeExamBrowser.Configuration.Contracts
///
/// The settings used for this session.
///
- public Settings.ApplicationSettings Settings { get; set; }
+ public AppSettings Settings { get; set; }
}
}
diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Applications.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Applications.cs
new file mode 100644
index 00000000..0c45fd62
--- /dev/null
+++ b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Applications.cs
@@ -0,0 +1,74 @@
+/*
+ * 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/.
+ */
+
+using System.Collections.Generic;
+using SafeExamBrowser.Settings;
+using SafeExamBrowser.Settings.Applications;
+
+namespace SafeExamBrowser.Configuration.ConfigurationData
+{
+ internal partial class DataMapper
+ {
+ private void MapApplicationBlacklist(AppSettings settings, object value)
+ {
+ if (value is IList
+
-
-
+
-
-
-
-
-
-
+
+
+
+
+ {30b2d907-5861-4f39-abad-c4abf1b3470e}
+ SafeExamBrowser.Settings
+
+
+ {7016f080-9aa5-41b2-a225-385ad877c171}
+ SafeExamBrowser.WindowsApi.Contracts
+
+
\ No newline at end of file
diff --git a/SafeExamBrowser.Monitoring.Contracts/Windows/IWindowMonitor.cs b/SafeExamBrowser.Monitoring.Contracts/Windows/IWindowMonitor.cs
deleted file mode 100644
index 4b09ff44..00000000
--- a/SafeExamBrowser.Monitoring.Contracts/Windows/IWindowMonitor.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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/.
- */
-
-using System;
-using SafeExamBrowser.Monitoring.Contracts.Windows.Events;
-
-namespace SafeExamBrowser.Monitoring.Contracts.Windows
-{
- ///
- /// Monitors the windows associated with the current desktop and provides window-related functionality.
- ///
- public interface IWindowMonitor
- {
- ///
- /// Event fired when the window monitor observes that the foreground window has changed.
- ///
- event WindowChangedEventHandler WindowChanged;
-
- ///
- /// Forcefully closes the specified window.
- ///
- void Close(IntPtr window);
-
- ///
- /// Hides the specified window. Returns true if the window was successfully hidden, otherwise false.
- ///
- bool Hide(IntPtr window);
-
- ///
- /// Starts monitoring application windows by subscribing to specific system events.
- /// If a window is shown which is not supposed to do so, it will be automatically hidden.
- ///
- void StartMonitoringWindows();
-
- ///
- /// Stops monitoring windows and deregisters from any subscribed system events.
- ///
- void StopMonitoringWindows();
- }
-}
diff --git a/SafeExamBrowser.Monitoring/Applications/ApplicationMonitor.cs b/SafeExamBrowser.Monitoring/Applications/ApplicationMonitor.cs
new file mode 100644
index 00000000..4a524388
--- /dev/null
+++ b/SafeExamBrowser.Monitoring/Applications/ApplicationMonitor.cs
@@ -0,0 +1,177 @@
+/*
+ * 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/.
+ */
+
+using System;
+using System.Diagnostics;
+using System.Management;
+using SafeExamBrowser.Logging.Contracts;
+using SafeExamBrowser.Monitoring.Contracts.Applications;
+using SafeExamBrowser.Monitoring.Contracts.Applications.Events;
+using SafeExamBrowser.Settings.Applications;
+using SafeExamBrowser.WindowsApi.Contracts;
+
+namespace SafeExamBrowser.Monitoring.Applications
+{
+ public class ApplicationMonitor : IApplicationMonitor
+ {
+ private IntPtr activeWindow;
+ private Guid? captureHookId;
+ private Guid? foregroundHookId;
+ private ILogger logger;
+ private INativeMethods nativeMethods;
+ private ManagementEventWatcher explorerWatcher;
+
+ public event ExplorerStartedEventHandler ExplorerStarted;
+
+ public ApplicationMonitor(ILogger logger, INativeMethods nativeMethods)
+ {
+ this.logger = logger;
+ this.nativeMethods = nativeMethods;
+ }
+
+ public InitializationResult Initialize(ApplicationSettings settings)
+ {
+ // TODO
+ // Initialize blacklist
+ // Initialize whitelist
+ // Check for running processes
+
+ return new InitializationResult();
+ }
+
+ public void Start()
+ {
+ // TODO: Start monitoring blacklist...
+
+ explorerWatcher = new ManagementEventWatcher(@"\\.\root\CIMV2", GetQueryFor("explorer.exe"));
+ explorerWatcher.EventArrived += new EventArrivedEventHandler(ExplorerWatcher_EventArrived);
+ explorerWatcher.Start();
+ logger.Info("Started monitoring process 'explorer.exe'.");
+
+ captureHookId = nativeMethods.RegisterSystemCaptureStartEvent(SystemEvent_WindowChanged);
+ logger.Info($"Registered system capture start event with ID = {captureHookId}.");
+
+ foregroundHookId = nativeMethods.RegisterSystemForegroundEvent(SystemEvent_WindowChanged);
+ logger.Info($"Registered system foreground event with ID = {foregroundHookId}.");
+ }
+
+ public void Stop()
+ {
+ explorerWatcher?.Stop();
+ logger.Info("Stopped monitoring 'explorer.exe'.");
+
+ if (captureHookId.HasValue)
+ {
+ nativeMethods.DeregisterSystemEventHook(captureHookId.Value);
+ logger.Info($"Unregistered system capture start event with ID = {captureHookId}.");
+ }
+
+ if (foregroundHookId.HasValue)
+ {
+ nativeMethods.DeregisterSystemEventHook(foregroundHookId.Value);
+ logger.Info($"Unregistered system foreground event with ID = {foregroundHookId}.");
+ }
+ }
+
+ public bool Terminate(int processId)
+ {
+ return false;
+ }
+
+ private void Check(IntPtr window)
+ {
+ var allowed = IsAllowed(window);
+
+ if (!allowed)
+ {
+ var success = TryHide(window);
+
+ if (!success)
+ {
+ Close(window);
+ }
+ }
+ }
+
+ private void Close(IntPtr window)
+ {
+ var title = nativeMethods.GetWindowTitle(window);
+
+ nativeMethods.SendCloseMessageTo(window);
+ logger.Info($"Sent close message to window '{title}' with handle = {window}.");
+ }
+
+ private bool IsAllowed(IntPtr window)
+ {
+ var processId = nativeMethods.GetProcessIdFor(window);
+ var process = Process.GetProcessById(Convert.ToInt32(processId));
+
+ if (process != null)
+ {
+ var allowed = process.ProcessName == "SafeExamBrowser" || process.ProcessName == "SafeExamBrowser.Client";
+
+ if (!allowed)
+ {
+ logger.Warn($"Window with handle = {window} belongs to not allowed process '{process.ProcessName}'!");
+ }
+
+ return allowed;
+ }
+
+ return true;
+ }
+
+ private bool TryHide(IntPtr window)
+ {
+ var title = nativeMethods.GetWindowTitle(window);
+ var success = nativeMethods.HideWindow(window);
+
+ if (success)
+ {
+ logger.Info($"Hid window '{title}' with handle = {window}.");
+ }
+ else
+ {
+ logger.Warn($"Failed to hide window '{title}' with handle = {window}!");
+ }
+
+ return success;
+ }
+
+ private void ExplorerWatcher_EventArrived(object sender, EventArrivedEventArgs e)
+ {
+ var eventName = e.NewEvent.ClassPath.ClassName;
+
+ if (eventName == "__InstanceCreationEvent")
+ {
+ logger.Warn("A new instance of Windows explorer has been started!");
+ ExplorerStarted?.Invoke();
+ }
+ }
+
+ private void SystemEvent_WindowChanged(IntPtr window)
+ {
+ if (window != IntPtr.Zero && activeWindow != window)
+ {
+ logger.Debug($"Window has changed from {activeWindow} to {window}.");
+ activeWindow = window;
+ Check(window);
+ }
+ }
+
+ private string GetQueryFor(string processName)
+ {
+ return $@"
+ SELECT *
+ FROM __InstanceOperationEvent
+ WITHIN 2
+ WHERE TargetInstance ISA 'Win32_Process'
+ AND TargetInstance.Name = '{processName}'";
+ }
+ }
+}
diff --git a/SafeExamBrowser.Monitoring/Keyboard/KeyboardInterceptor.cs b/SafeExamBrowser.Monitoring/Keyboard/KeyboardInterceptor.cs
index 8d983ba3..86b3b19c 100644
--- a/SafeExamBrowser.Monitoring/Keyboard/KeyboardInterceptor.cs
+++ b/SafeExamBrowser.Monitoring/Keyboard/KeyboardInterceptor.cs
@@ -9,24 +9,42 @@
using System;
using System.Linq;
using System.Windows.Input;
-using SafeExamBrowser.Settings.Monitoring;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.Keyboard;
+using SafeExamBrowser.Settings.Monitoring;
+using SafeExamBrowser.WindowsApi.Contracts;
+using SafeExamBrowser.WindowsApi.Contracts.Events;
namespace SafeExamBrowser.Monitoring.Keyboard
{
public class KeyboardInterceptor : IKeyboardInterceptor
{
- private KeyboardSettings settings;
+ private Guid? hookId;
private ILogger logger;
+ private INativeMethods nativeMethods;
+ private KeyboardSettings settings;
- public KeyboardInterceptor(KeyboardSettings settings, ILogger logger)
+ public KeyboardInterceptor(KeyboardSettings settings, ILogger logger, INativeMethods nativeMethods)
{
this.logger = logger;
+ this.nativeMethods = nativeMethods;
this.settings = settings;
}
- public bool Block(int keyCode, KeyModifier modifier, KeyState state)
+ public void Start()
+ {
+ hookId = nativeMethods.RegisterKeyboardHook(KeyboardHookCallback);
+ }
+
+ public void Stop()
+ {
+ if (hookId.HasValue)
+ {
+ nativeMethods.DeregisterKeyboardHook(hookId.Value);
+ }
+ }
+
+ private bool KeyboardHookCallback(int keyCode, KeyModifier modifier, KeyState state)
{
var block = false;
var key = KeyInterop.KeyFromVirtualKey(keyCode);
diff --git a/SafeExamBrowser.Monitoring/Mouse/MouseInterceptor.cs b/SafeExamBrowser.Monitoring/Mouse/MouseInterceptor.cs
index 17f160bf..99bd65d9 100644
--- a/SafeExamBrowser.Monitoring/Mouse/MouseInterceptor.cs
+++ b/SafeExamBrowser.Monitoring/Mouse/MouseInterceptor.cs
@@ -6,24 +6,43 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-using SafeExamBrowser.Settings.Monitoring;
+using System;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.Mouse;
+using SafeExamBrowser.Settings.Monitoring;
+using SafeExamBrowser.WindowsApi.Contracts;
+using SafeExamBrowser.WindowsApi.Contracts.Events;
namespace SafeExamBrowser.Monitoring.Mouse
{
public class MouseInterceptor : IMouseInterceptor
{
+ private Guid? hookId;
private ILogger logger;
+ private INativeMethods nativeMethods;
private MouseSettings settings;
- public MouseInterceptor(ILogger logger, MouseSettings settings)
+ public MouseInterceptor(ILogger logger, MouseSettings settings, INativeMethods nativeMethods)
{
this.logger = logger;
+ this.nativeMethods = nativeMethods;
this.settings = settings;
}
- public bool Block(MouseButton button, MouseButtonState state)
+ public void Start()
+ {
+ hookId = nativeMethods.RegisterMouseHook(MouseHookCallback);
+ }
+
+ public void Stop()
+ {
+ if (hookId.HasValue)
+ {
+ nativeMethods.DeregisterMouseHook(hookId.Value);
+ }
+ }
+
+ private bool MouseHookCallback(MouseButton button, MouseButtonState state)
{
var block = false;
diff --git a/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs b/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs
deleted file mode 100644
index 4d4f175c..00000000
--- a/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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/.
- */
-
-using System;
-using System.Diagnostics;
-using System.Management;
-using SafeExamBrowser.Logging.Contracts;
-using SafeExamBrowser.Monitoring.Contracts.Processes;
-using SafeExamBrowser.Monitoring.Contracts.Processes.Events;
-using SafeExamBrowser.WindowsApi.Contracts;
-
-namespace SafeExamBrowser.Monitoring.Processes
-{
- public class ProcessMonitor : IProcessMonitor
- {
- private ILogger logger;
- private INativeMethods nativeMethods;
- private ManagementEventWatcher explorerWatcher;
-
- public event ExplorerStartedEventHandler ExplorerStarted;
-
- public ProcessMonitor(ILogger logger, INativeMethods nativeMethods)
- {
- this.logger = logger;
- this.nativeMethods = nativeMethods;
- }
-
- public bool BelongsToAllowedProcess(IntPtr window)
- {
- var processId = nativeMethods.GetProcessIdFor(window);
- var process = Process.GetProcessById(Convert.ToInt32(processId));
-
- if (process != null)
- {
- var allowed = process.ProcessName == "SafeExamBrowser" || process.ProcessName == "SafeExamBrowser.Client";
-
- if (!allowed)
- {
- logger.Warn($"Window with handle = {window} belongs to not allowed process '{process.ProcessName}'!");
- }
-
- return allowed;
- }
-
- return true;
- }
-
- public void StartMonitoringExplorer()
- {
- explorerWatcher = new ManagementEventWatcher(@"\\.\root\CIMV2", GetQueryFor("explorer.exe"));
- explorerWatcher.EventArrived += new EventArrivedEventHandler(ExplorerWatcher_EventArrived);
- explorerWatcher.Start();
-
- logger.Info("Started monitoring process 'explorer.exe'.");
- }
-
- public void StopMonitoringExplorer()
- {
- explorerWatcher?.Stop();
- logger.Info("Stopped monitoring 'explorer.exe'.");
- }
-
- private void ExplorerWatcher_EventArrived(object sender, EventArrivedEventArgs e)
- {
- var eventName = e.NewEvent.ClassPath.ClassName;
-
- if (eventName == "__InstanceCreationEvent")
- {
- logger.Warn("A new instance of Windows explorer has been started!");
- ExplorerStarted?.Invoke();
- }
- }
-
- private string GetQueryFor(string processName)
- {
- return $@"
- SELECT *
- FROM __InstanceOperationEvent
- WITHIN 2
- WHERE TargetInstance ISA 'Win32_Process'
- AND TargetInstance.Name = '{processName}'";
- }
- }
-}
diff --git a/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj b/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj
index 162bacaa..01f4c292 100644
--- a/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj
+++ b/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj
@@ -60,9 +60,8 @@
-
+
-
diff --git a/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs b/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs
deleted file mode 100644
index 90bc26cb..00000000
--- a/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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/.
- */
-
-using System;
-using SafeExamBrowser.Logging.Contracts;
-using SafeExamBrowser.Monitoring.Contracts.Windows;
-using SafeExamBrowser.Monitoring.Contracts.Windows.Events;
-using SafeExamBrowser.WindowsApi.Contracts;
-
-namespace SafeExamBrowser.Monitoring.Windows
-{
- public class WindowMonitor : IWindowMonitor
- {
- private IntPtr activeWindow;
- private Guid? captureHookId;
- private Guid? foregroundHookId;
- private ILogger logger;
- private INativeMethods nativeMethods;
-
- public event WindowChangedEventHandler WindowChanged;
-
- public WindowMonitor(ILogger logger, INativeMethods nativeMethods)
- {
- this.logger = logger;
- this.nativeMethods = nativeMethods;
- }
-
- public void Close(IntPtr window)
- {
- var title = nativeMethods.GetWindowTitle(window);
-
- nativeMethods.SendCloseMessageTo(window);
- logger.Info($"Sent close message to window '{title}' with handle = {window}.");
- }
-
- public bool Hide(IntPtr window)
- {
- var title = nativeMethods.GetWindowTitle(window);
- var success = nativeMethods.HideWindow(window);
-
- if (success)
- {
- logger.Info($"Hid window '{title}' with handle = {window}.");
- }
- else
- {
- logger.Warn($"Failed to hide window '{title}' with handle = {window}!");
- }
-
- return success;
- }
-
- public void StartMonitoringWindows()
- {
- captureHookId = nativeMethods.RegisterSystemCaptureStartEvent(OnWindowChanged);
- logger.Info($"Registered system capture start event with ID = {captureHookId}.");
-
- foregroundHookId = nativeMethods.RegisterSystemForegroundEvent(OnWindowChanged);
- logger.Info($"Registered system foreground event with ID = {foregroundHookId}.");
- }
-
- public void StopMonitoringWindows()
- {
- if (captureHookId.HasValue)
- {
- nativeMethods.DeregisterSystemEventHook(captureHookId.Value);
- logger.Info($"Unregistered system capture start event with ID = {captureHookId}.");
- }
-
- if (foregroundHookId.HasValue)
- {
- nativeMethods.DeregisterSystemEventHook(foregroundHookId.Value);
- logger.Info($"Unregistered system foreground event with ID = {foregroundHookId}.");
- }
- }
-
- private void OnWindowChanged(IntPtr window)
- {
- if (window != IntPtr.Zero && activeWindow != window)
- {
- logger.Debug($"Window has changed from {activeWindow} to {window}.");
- activeWindow = window;
- WindowChanged?.Invoke(window);
- }
- }
- }
-}
diff --git a/SafeExamBrowser.Runtime.UnitTests/Communication/RuntimeHostTests.cs b/SafeExamBrowser.Runtime.UnitTests/Communication/RuntimeHostTests.cs
index dcfd6878..b9d2a239 100644
--- a/SafeExamBrowser.Runtime.UnitTests/Communication/RuntimeHostTests.cs
+++ b/SafeExamBrowser.Runtime.UnitTests/Communication/RuntimeHostTests.cs
@@ -171,7 +171,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Communication
public void MustHandleConfigurationRequestCorrectly()
{
var args = default(ClientConfigurationEventArgs);
- var configuration = new ClientConfiguration { Settings = new ApplicationSettings { AdminPasswordHash = "12345" } };
+ var configuration = new ClientConfiguration { Settings = new AppSettings { AdminPasswordHash = "12345" } };
sut.AllowConnection = true;
sut.ClientConfigurationNeeded += (a) => { args = a; args.ClientConfiguration = configuration; };
diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/ClientOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/ClientOperationTests.cs
index a43d5e47..7d9dc8d6 100644
--- a/SafeExamBrowser.Runtime.UnitTests/Operations/ClientOperationTests.cs
+++ b/SafeExamBrowser.Runtime.UnitTests/Operations/ClientOperationTests.cs
@@ -37,7 +37,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
private Mock runtimeHost;
private SessionConfiguration session;
private SessionContext sessionContext;
- private ApplicationSettings settings;
+ private AppSettings settings;
private ClientOperation sut;
[TestInitialize]
@@ -53,7 +53,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
runtimeHost = new Mock();
session = new SessionConfiguration();
sessionContext = new SessionContext();
- settings = new ApplicationSettings();
+ settings = new AppSettings();
terminated = new Action(() =>
{
runtimeHost.Raise(h => h.ClientDisconnected += null);
diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs
index 7ea63312..46ec7ac2 100644
--- a/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs
+++ b/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs
@@ -56,7 +56,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustUseCommandLineArgumentAs1stPrio()
{
- var settings = new ApplicationSettings { ConfigurationMode = ConfigurationMode.Exam };
+ var settings = new AppSettings { ConfigurationMode = ConfigurationMode.Exam };
var url = @"http://www.safeexambrowser.org/whatever.seb";
var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
@@ -77,7 +77,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Perform_MustUseProgramDataAs2ndPrio()
{
var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
- var settings = default(ApplicationSettings);
+ var settings = default(AppSettings);
appConfig.ProgramDataFilePath = location;
@@ -94,7 +94,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Perform_MustUseAppDataAs3rdPrio()
{
var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
- var settings = default(ApplicationSettings);
+ var settings = default(AppSettings);
appConfig.AppDataFilePath = location;
repository.Setup(r => r.TryLoadSettings(It.IsAny(), out settings, It.IsAny())).Returns(LoadStatus.Success);
@@ -109,7 +109,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustTestdatalyHandleBrowserResource()
{
- var settings = new ApplicationSettings { ConfigurationMode = ConfigurationMode.Exam };
+ var settings = new AppSettings { ConfigurationMode = ConfigurationMode.Exam };
var url = @"http://www.safeexambrowser.org/whatever.seb";
nextSession.Settings = settings;
@@ -125,7 +125,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustFallbackToDefaultsAsLastPrio()
{
- var defaultSettings = new ApplicationSettings();
+ var defaultSettings = new AppSettings();
repository.Setup(r => r.LoadDefaultSettings()).Returns(defaultSettings);
@@ -141,7 +141,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustAbortIfWishedByUser()
{
- var settings = new ApplicationSettings();
+ var settings = new AppSettings();
var url = @"http://www.safeexambrowser.org/whatever.seb";
sessionContext.Current = null;
@@ -166,7 +166,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustNotAbortIfNotWishedByUser()
{
- var settings = new ApplicationSettings();
+ var settings = new AppSettings();
var url = @"http://www.safeexambrowser.org/whatever.seb";
settings.ConfigurationMode = ConfigurationMode.ConfigureClient;
@@ -191,7 +191,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Perform_MustInformAboutClientConfigurationError()
{
var informed = false;
- var settings = new ApplicationSettings();
+ var settings = new AppSettings();
var url = @"http://www.safeexambrowser.org/whatever.seb";
settings.ConfigurationMode = ConfigurationMode.ConfigureClient;
@@ -216,7 +216,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustNotAllowToAbortIfNotInConfigureClientMode()
{
- var settings = new ApplicationSettings();
+ var settings = new AppSettings();
settings.ConfigurationMode = ConfigurationMode.Exam;
repository.Setup(r => r.TryLoadSettings(It.IsAny(), out settings, It.IsAny())).Returns(LoadStatus.Success);
@@ -238,7 +238,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustNotFailWithoutCommandLineArgs()
{
- var defaultSettings = new ApplicationSettings();
+ var defaultSettings = new AppSettings();
var result = OperationResult.Failed;
repository.Setup(r => r.LoadDefaultSettings()).Returns(defaultSettings);
@@ -272,8 +272,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Perform_MustOnlyAllowToEnterAdminPasswordFiveTimes()
{
var count = 0;
- var localSettings = new ApplicationSettings { AdminPasswordHash = "1234" };
- var settings = new ApplicationSettings { AdminPasswordHash = "9876", ConfigurationMode = ConfigurationMode.ConfigureClient };
+ var localSettings = new AppSettings { AdminPasswordHash = "1234" };
+ var settings = new AppSettings { AdminPasswordHash = "9876", ConfigurationMode = ConfigurationMode.ConfigureClient };
var url = @"http://www.safeexambrowser.org/whatever.seb";
appConfig.AppDataFilePath = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
@@ -302,7 +302,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Perform_MustOnlyAllowToEnterSettingsPasswordFiveTimes()
{
var count = 0;
- var settings = default(ApplicationSettings);
+ var settings = default(AppSettings);
var url = @"http://www.safeexambrowser.org/whatever.seb";
repository.Setup(r => r.TryLoadSettings(It.IsAny(), out settings, It.IsAny())).Returns(LoadStatus.PasswordNeeded);
@@ -329,8 +329,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Perform_MustSucceedIfAdminPasswordTestdata()
{
var password = "test";
- var currentSettings = new ApplicationSettings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.ConfigureClient };
- var nextSettings = new ApplicationSettings { AdminPasswordHash = "9876", ConfigurationMode = ConfigurationMode.ConfigureClient };
+ var currentSettings = new AppSettings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.ConfigureClient };
+ var nextSettings = new AppSettings { AdminPasswordHash = "9876", ConfigurationMode = ConfigurationMode.ConfigureClient };
var url = @"http://www.safeexambrowser.org/whatever.seb";
nextSession.Settings = nextSettings;
@@ -359,8 +359,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustNotAuthenticateIfSameAdminPassword()
{
- var currentSettings = new ApplicationSettings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.ConfigureClient };
- var nextSettings = new ApplicationSettings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.ConfigureClient };
+ var currentSettings = new AppSettings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.ConfigureClient };
+ var nextSettings = new AppSettings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.ConfigureClient };
var url = @"http://www.safeexambrowser.org/whatever.seb";
nextSession.Settings = nextSettings;
@@ -388,7 +388,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Perform_MustSucceedIfSettingsPasswordTestdata()
{
var password = "test";
- var settings = new ApplicationSettings { ConfigurationMode = ConfigurationMode.Exam };
+ var settings = new AppSettings { ConfigurationMode = ConfigurationMode.Exam };
var url = @"http://www.safeexambrowser.org/whatever.seb";
repository.Setup(r => r.TryLoadSettings(It.IsAny(), out settings, It.IsAny())).Returns(LoadStatus.PasswordNeeded);
@@ -416,7 +416,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
{
var url = @"http://www.safeexambrowser.org/whatever.seb";
var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
- var settings = new ApplicationSettings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.Exam };
+ var settings = new AppSettings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.Exam };
appConfig.AppDataFilePath = location;
@@ -442,8 +442,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Perform_MustAbortAskingForAdminPasswordIfDecidedByUser()
{
var password = "test";
- var currentSettings = new ApplicationSettings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.ConfigureClient };
- var nextSettings = new ApplicationSettings { AdminPasswordHash = "9876", ConfigurationMode = ConfigurationMode.ConfigureClient };
+ var currentSettings = new AppSettings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.ConfigureClient };
+ var nextSettings = new AppSettings { AdminPasswordHash = "9876", ConfigurationMode = ConfigurationMode.ConfigureClient };
var url = @"http://www.safeexambrowser.org/whatever.seb";
appConfig.AppDataFilePath = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
@@ -472,7 +472,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustAbortAskingForSettingsPasswordIfDecidedByUser()
{
- var settings = default(ApplicationSettings);
+ var settings = default(AppSettings);
var url = @"http://www.safeexambrowser.org/whatever.seb";
repository.Setup(r => r.TryLoadSettings(It.IsAny(), out settings, It.IsAny())).Returns(LoadStatus.PasswordNeeded);
@@ -494,10 +494,10 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Repeat_MustPerformForExamWithTestdataUri()
{
- var currentSettings = new ApplicationSettings();
+ var currentSettings = new AppSettings();
var location = Path.GetDirectoryName(GetType().Assembly.Location);
var resource = new Uri(Path.Combine(location, nameof(Operations), "Testdata", FILE_NAME));
- var settings = new ApplicationSettings { ConfigurationMode = ConfigurationMode.Exam };
+ var settings = new AppSettings { ConfigurationMode = ConfigurationMode.Exam };
currentSession.Settings = currentSettings;
sessionContext.ReconfigurationFilePath = resource.LocalPath;
@@ -515,10 +515,10 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Repeat_MustPerformForClientConfigurationWithTestdataUri()
{
- var currentSettings = new ApplicationSettings();
+ var currentSettings = new AppSettings();
var location = Path.GetDirectoryName(GetType().Assembly.Location);
var resource = new Uri(Path.Combine(location, nameof(Operations), "Testdata", FILE_NAME));
- var settings = new ApplicationSettings { ConfigurationMode = ConfigurationMode.ConfigureClient };
+ var settings = new AppSettings { ConfigurationMode = ConfigurationMode.ConfigureClient };
currentSession.Settings = currentSettings;
sessionContext.ReconfigurationFilePath = resource.LocalPath;
@@ -538,7 +538,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Repeat_MustFailWithInvalidUri()
{
var resource = new Uri("file:///C:/does/not/exist.txt");
- var settings = default(ApplicationSettings);
+ var settings = default(AppSettings);
sessionContext.ReconfigurationFilePath = null;
repository.Setup(r => r.TryLoadSettings(It.IsAny(), out settings, It.IsAny())).Returns(LoadStatus.Success);
@@ -559,10 +559,10 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Repeat_MustAbortForSettingsPasswordIfWishedByUser()
{
- var currentSettings = new ApplicationSettings();
+ var currentSettings = new AppSettings();
var location = Path.GetDirectoryName(GetType().Assembly.Location);
var resource = new Uri(Path.Combine(location, nameof(Operations), "Testdata", FILE_NAME));
- var settings = new ApplicationSettings { ConfigurationMode = ConfigurationMode.ConfigureClient };
+ var settings = new AppSettings { ConfigurationMode = ConfigurationMode.ConfigureClient };
currentSession.Settings = currentSettings;
sessionContext.ReconfigurationFilePath = resource.LocalPath;
diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs
index 5863e4a8..c16ef398 100644
--- a/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs
+++ b/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs
@@ -21,12 +21,12 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public class KioskModeOperationTests
{
private SessionConfiguration currentSession;
- private ApplicationSettings currentSettings;
+ private AppSettings currentSettings;
private Mock desktopFactory;
private Mock explorerShell;
private Mock logger;
private SessionConfiguration nextSession;
- private ApplicationSettings nextSettings;
+ private AppSettings nextSettings;
private Mock processFactory;
private SessionContext sessionContext;
@@ -36,12 +36,12 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Initialize()
{
currentSession = new SessionConfiguration();
- currentSettings = new ApplicationSettings();
+ currentSettings = new AppSettings();
desktopFactory = new Mock();
explorerShell = new Mock();
logger = new Mock();
nextSession = new SessionConfiguration();
- nextSettings = new ApplicationSettings();
+ nextSettings = new AppSettings();
processFactory = new Mock();
sessionContext = new SessionContext();
diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/ServiceOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/ServiceOperationTests.cs
index 1e4a3418..7364a409 100644
--- a/SafeExamBrowser.Runtime.UnitTests/Operations/ServiceOperationTests.cs
+++ b/SafeExamBrowser.Runtime.UnitTests/Operations/ServiceOperationTests.cs
@@ -34,7 +34,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
private EventWaitHandle serviceEvent;
private SessionConfiguration session;
private SessionContext sessionContext;
- private ApplicationSettings settings;
+ private AppSettings settings;
private Mock userInfo;
private ServiceOperation sut;
@@ -50,7 +50,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
serviceEvent = new EventWaitHandle(false, EventResetMode.AutoReset, serviceEventName);
session = new SessionConfiguration();
sessionContext = new SessionContext();
- settings = new ApplicationSettings();
+ settings = new AppSettings();
userInfo = new Mock();
appConfig.ServiceEventName = serviceEventName;
diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/SessionActivationOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/SessionActivationOperationTests.cs
index 62c8abb4..f117c49a 100644
--- a/SafeExamBrowser.Runtime.UnitTests/Operations/SessionActivationOperationTests.cs
+++ b/SafeExamBrowser.Runtime.UnitTests/Operations/SessionActivationOperationTests.cs
@@ -9,10 +9,10 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SafeExamBrowser.Configuration.Contracts;
-using SafeExamBrowser.Settings;
using SafeExamBrowser.Core.Contracts.OperationModel;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Runtime.Operations;
+using SafeExamBrowser.Settings;
using SafeExamBrowser.Settings.Logging;
namespace SafeExamBrowser.Runtime.UnitTests.Operations
@@ -23,7 +23,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
private SessionConfiguration currentSession;
private Mock logger;
private SessionConfiguration nextSession;
- private ApplicationSettings nextSettings;
+ private AppSettings nextSettings;
private SessionContext sessionContext;
private SessionActivationOperation sut;
@@ -34,7 +34,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
currentSession = new SessionConfiguration();
logger = new Mock();
nextSession = new SessionConfiguration();
- nextSettings = new ApplicationSettings();
+ nextSettings = new AppSettings();
sessionContext = new SessionContext();
nextSession.Settings = nextSettings;
diff --git a/SafeExamBrowser.Runtime.UnitTests/RuntimeControllerTests.cs b/SafeExamBrowser.Runtime.UnitTests/RuntimeControllerTests.cs
index 2f76fca5..a16b7df6 100644
--- a/SafeExamBrowser.Runtime.UnitTests/RuntimeControllerTests.cs
+++ b/SafeExamBrowser.Runtime.UnitTests/RuntimeControllerTests.cs
@@ -36,11 +36,11 @@ namespace SafeExamBrowser.Runtime.UnitTests
private Mock clientProcess;
private Mock clientProxy;
private SessionConfiguration currentSession;
- private ApplicationSettings currentSettings;
+ private AppSettings currentSettings;
private Mock logger;
private Mock messageBox;
private SessionConfiguration nextSession;
- private ApplicationSettings nextSettings;
+ private AppSettings nextSettings;
private Mock shutdown;
private Mock text;
private Mock uiFactory;
@@ -58,11 +58,11 @@ namespace SafeExamBrowser.Runtime.UnitTests
clientProcess = new Mock();
clientProxy = new Mock();
currentSession = new SessionConfiguration();
- currentSettings = new ApplicationSettings();
+ currentSettings = new AppSettings();
logger = new Mock();
messageBox = new Mock();
nextSession = new SessionConfiguration();
- nextSettings = new ApplicationSettings();
+ nextSettings = new AppSettings();
runtimeHost = new Mock();
service = new Mock();
sessionContext = new SessionContext();
@@ -134,7 +134,7 @@ namespace SafeExamBrowser.Runtime.UnitTests
var args = new ClientConfigurationEventArgs();
var nextAppConfig = new AppConfig();
var nextSessionId = Guid.NewGuid();
- var nextSettings = new ApplicationSettings();
+ var nextSettings = new AppSettings();
nextSession.AppConfig = nextAppConfig;
nextSession.SessionId = nextSessionId;
diff --git a/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs b/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs
index 6da4cf7b..c44b83fa 100644
--- a/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs
+++ b/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs
@@ -107,7 +107,7 @@ namespace SafeExamBrowser.Runtime.Operations
{
var currentPassword = default(string);
var passwordParams = default(PasswordParameters);
- var settings = default(ApplicationSettings);
+ var settings = default(AppSettings);
var status = default(LoadStatus?);
if (source == UriSource.CommandLine)
@@ -161,7 +161,7 @@ namespace SafeExamBrowser.Runtime.Operations
}
}
- private OperationResult DetermineLoadResult(Uri uri, UriSource source, ApplicationSettings settings, LoadStatus status, PasswordParameters passwordParams, string currentPassword = default(string))
+ private OperationResult DetermineLoadResult(Uri uri, UriSource source, AppSettings settings, LoadStatus status, PasswordParameters passwordParams, string currentPassword = default(string))
{
if (status == LoadStatus.LoadWithBrowser || status == LoadStatus.Success)
{
@@ -218,7 +218,7 @@ namespace SafeExamBrowser.Runtime.Operations
return OperationResult.Failed;
}
- private LoadStatus? TryLoadSettings(Uri uri, UriSource source, out PasswordParameters passwordParams, out ApplicationSettings settings, string currentPassword = default(string))
+ private LoadStatus? TryLoadSettings(Uri uri, UriSource source, out PasswordParameters passwordParams, out AppSettings settings, string currentPassword = default(string))
{
passwordParams = new PasswordParameters { Password = string.Empty, IsHash = true };
diff --git a/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs b/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs
index 963f0452..20c555e8 100644
--- a/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs
+++ b/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs
@@ -6,11 +6,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-using SafeExamBrowser.Settings;
using SafeExamBrowser.Core.Contracts.OperationModel;
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
+using SafeExamBrowser.Settings;
using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.Runtime.Operations
diff --git a/SafeExamBrowser.Runtime/Operations/SessionOperation.cs b/SafeExamBrowser.Runtime/Operations/SessionOperation.cs
index 39c91be9..9c4c3476 100644
--- a/SafeExamBrowser.Runtime/Operations/SessionOperation.cs
+++ b/SafeExamBrowser.Runtime/Operations/SessionOperation.cs
@@ -21,9 +21,9 @@ namespace SafeExamBrowser.Runtime.Operations
public abstract event ActionRequiredEventHandler ActionRequired;
public abstract event StatusChangedEventHandler StatusChanged;
- public SessionOperation(SessionContext sessionContext)
+ public SessionOperation(SessionContext context)
{
- Context = sessionContext;
+ Context = context;
}
public abstract OperationResult Perform();
diff --git a/SafeExamBrowser.Service.UnitTests/Operations/LockdownOperationTests.cs b/SafeExamBrowser.Service.UnitTests/Operations/LockdownOperationTests.cs
index a92c9fe7..66d1702c 100644
--- a/SafeExamBrowser.Service.UnitTests/Operations/LockdownOperationTests.cs
+++ b/SafeExamBrowser.Service.UnitTests/Operations/LockdownOperationTests.cs
@@ -27,7 +27,7 @@ namespace SafeExamBrowser.Service.UnitTests.Operations
private Mock factory;
private Mock monitor;
private Mock logger;
- private ApplicationSettings settings;
+ private AppSettings settings;
private SessionContext sessionContext;
private LockdownOperation sut;
@@ -38,7 +38,7 @@ namespace SafeExamBrowser.Service.UnitTests.Operations
factory = new Mock();
monitor = new Mock();
logger = new Mock();
- settings = new ApplicationSettings();
+ settings = new AppSettings();
sessionContext = new SessionContext
{
Configuration = new ServiceConfiguration { Settings = settings, UserName = "TestName", UserSid = "S-1-234-TEST" }
diff --git a/SafeExamBrowser.Service.UnitTests/Operations/SessionInitializationOperationTests.cs b/SafeExamBrowser.Service.UnitTests/Operations/SessionInitializationOperationTests.cs
index f544942c..373bb7f9 100644
--- a/SafeExamBrowser.Service.UnitTests/Operations/SessionInitializationOperationTests.cs
+++ b/SafeExamBrowser.Service.UnitTests/Operations/SessionInitializationOperationTests.cs
@@ -42,7 +42,7 @@ namespace SafeExamBrowser.Service.UnitTests.Operations
sessionContext.Configuration = new ServiceConfiguration
{
AppConfig = new AppConfig { ServiceEventName = $"{nameof(SafeExamBrowser)}-{nameof(SessionInitializationOperationTests)}" },
- Settings = new ApplicationSettings()
+ Settings = new AppSettings()
};
sut = new SessionInitializationOperation(logger.Object, serviceEventFactory.Object, sessionContext);
diff --git a/SafeExamBrowser.Service.UnitTests/ServiceControllerTests.cs b/SafeExamBrowser.Service.UnitTests/ServiceControllerTests.cs
index 738adbf0..24080c5b 100644
--- a/SafeExamBrowser.Service.UnitTests/ServiceControllerTests.cs
+++ b/SafeExamBrowser.Service.UnitTests/ServiceControllerTests.cs
@@ -82,7 +82,7 @@ namespace SafeExamBrowser.Service.UnitTests
{
AppConfig = new AppConfig { ServiceLogFilePath = "Test.log" },
SessionId = Guid.NewGuid(),
- Settings = new ApplicationSettings { LogLevel = LogLevel.Warning }
+ Settings = new AppSettings { LogLevel = LogLevel.Warning }
}
};
diff --git a/SafeExamBrowser.Settings/ApplicationSettings.cs b/SafeExamBrowser.Settings/AppSettings.cs
similarity index 90%
rename from SafeExamBrowser.Settings/ApplicationSettings.cs
rename to SafeExamBrowser.Settings/AppSettings.cs
index 4478cff8..edc46336 100644
--- a/SafeExamBrowser.Settings/ApplicationSettings.cs
+++ b/SafeExamBrowser.Settings/AppSettings.cs
@@ -7,6 +7,7 @@
*/
using System;
+using SafeExamBrowser.Settings.Applications;
using SafeExamBrowser.Settings.Browser;
using SafeExamBrowser.Settings.Logging;
using SafeExamBrowser.Settings.Monitoring;
@@ -20,7 +21,7 @@ namespace SafeExamBrowser.Settings
/// Defines all settings for the application.
///
[Serializable]
- public class ApplicationSettings
+ public class AppSettings
{
///
/// All action center-related settings.
@@ -37,6 +38,11 @@ namespace SafeExamBrowser.Settings
///
public bool AllowApplicationLogAccess { get; set; }
+ ///
+ /// All settings related to third-party applications.
+ ///
+ public ApplicationSettings Applications { get; set; }
+
///
/// All audio-related settings.
///
@@ -92,9 +98,10 @@ namespace SafeExamBrowser.Settings
///
public UserInterfaceMode UserInterfaceMode { get; set; }
- public ApplicationSettings()
+ public AppSettings()
{
ActionCenter = new ActionCenterSettings();
+ Applications = new ApplicationSettings();
Audio = new AudioSettings();
Browser = new BrowserSettings();
Keyboard = new KeyboardSettings();
diff --git a/SafeExamBrowser.Settings/Applications/ApplicationSettings.cs b/SafeExamBrowser.Settings/Applications/ApplicationSettings.cs
new file mode 100644
index 00000000..4af0c563
--- /dev/null
+++ b/SafeExamBrowser.Settings/Applications/ApplicationSettings.cs
@@ -0,0 +1,36 @@
+/*
+ * 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/.
+ */
+
+using System;
+using System.Collections.Generic;
+
+namespace SafeExamBrowser.Settings.Applications
+{
+ ///
+ /// TODO
+ ///
+ [Serializable]
+ public class ApplicationSettings
+ {
+ ///
+ ///
+ ///
+ public IList Blacklist { get; set; }
+
+ ///
+ ///
+ ///
+ public IList Whitelist { get; set; }
+
+ public ApplicationSettings()
+ {
+ Blacklist = new List();
+ Whitelist = new List();
+ }
+ }
+}
diff --git a/SafeExamBrowser.Settings/Applications/BlacklistApplication.cs b/SafeExamBrowser.Settings/Applications/BlacklistApplication.cs
new file mode 100644
index 00000000..b7e19013
--- /dev/null
+++ b/SafeExamBrowser.Settings/Applications/BlacklistApplication.cs
@@ -0,0 +1,34 @@
+/*
+ * 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/.
+ */
+
+using System;
+
+namespace SafeExamBrowser.Settings.Applications
+{
+ ///
+ /// TODO
+ ///
+ [Serializable]
+ public class BlacklistApplication
+ {
+ ///
+ ///
+ ///
+ public bool AutoTerminate { get; set; }
+
+ ///
+ ///
+ ///
+ public string ExecutableName { get; set; }
+
+ ///
+ ///
+ ///
+ public string ExecutableOriginalName { get; set; }
+ }
+}
diff --git a/SafeExamBrowser.Monitoring.Contracts/Windows/Events/WindowChangedEventHandler.cs b/SafeExamBrowser.Settings/Applications/WhitelistApplication.cs
similarity index 61%
rename from SafeExamBrowser.Monitoring.Contracts/Windows/Events/WindowChangedEventHandler.cs
rename to SafeExamBrowser.Settings/Applications/WhitelistApplication.cs
index b3d34b3d..db36d35e 100644
--- a/SafeExamBrowser.Monitoring.Contracts/Windows/Events/WindowChangedEventHandler.cs
+++ b/SafeExamBrowser.Settings/Applications/WhitelistApplication.cs
@@ -8,10 +8,13 @@
using System;
-namespace SafeExamBrowser.Monitoring.Contracts.Windows.Events
+namespace SafeExamBrowser.Settings.Applications
{
///
- /// Indicates that the input focus has changed to the window with the specified handle.
+ /// TODO
///
- public delegate void WindowChangedEventHandler(IntPtr window);
+ [Serializable]
+ public class WhitelistApplication
+ {
+ }
}
diff --git a/SafeExamBrowser.Settings/SafeExamBrowser.Settings.csproj b/SafeExamBrowser.Settings/SafeExamBrowser.Settings.csproj
index da22b7b5..a3886e84 100644
--- a/SafeExamBrowser.Settings/SafeExamBrowser.Settings.csproj
+++ b/SafeExamBrowser.Settings/SafeExamBrowser.Settings.csproj
@@ -53,6 +53,9 @@
+
+
+
@@ -67,11 +70,12 @@
-
+
+
\ No newline at end of file
diff --git a/SafeExamBrowser.Monitoring.Contracts/Keyboard/KeyModifier.cs b/SafeExamBrowser.WindowsApi.Contracts/Events/KeyModifier.cs
similarity index 74%
rename from SafeExamBrowser.Monitoring.Contracts/Keyboard/KeyModifier.cs
rename to SafeExamBrowser.WindowsApi.Contracts/Events/KeyModifier.cs
index ca905929..a1031cec 100644
--- a/SafeExamBrowser.Monitoring.Contracts/Keyboard/KeyModifier.cs
+++ b/SafeExamBrowser.WindowsApi.Contracts/Events/KeyModifier.cs
@@ -8,10 +8,10 @@
using System;
-namespace SafeExamBrowser.Monitoring.Contracts.Keyboard
+namespace SafeExamBrowser.WindowsApi.Contracts.Events
{
///
- /// The key modifiers which can be detected by the .
+ /// The key modifiers which can be detected by a keyboard hook.
///
[Flags]
public enum KeyModifier
diff --git a/SafeExamBrowser.Monitoring.Contracts/Keyboard/KeyState.cs b/SafeExamBrowser.WindowsApi.Contracts/Events/KeyState.cs
similarity index 73%
rename from SafeExamBrowser.Monitoring.Contracts/Keyboard/KeyState.cs
rename to SafeExamBrowser.WindowsApi.Contracts/Events/KeyState.cs
index ee005c53..73d8c3c1 100644
--- a/SafeExamBrowser.Monitoring.Contracts/Keyboard/KeyState.cs
+++ b/SafeExamBrowser.WindowsApi.Contracts/Events/KeyState.cs
@@ -6,10 +6,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-namespace SafeExamBrowser.Monitoring.Contracts.Keyboard
+namespace SafeExamBrowser.WindowsApi.Contracts.Events
{
///
- /// The key states which can be detected by the .
+ /// The key states which can be detected by a keyboard hook.
///
public enum KeyState
{
diff --git a/SafeExamBrowser.WindowsApi.Contracts/Events/KeyboardHookCallback.cs b/SafeExamBrowser.WindowsApi.Contracts/Events/KeyboardHookCallback.cs
new file mode 100644
index 00000000..03188623
--- /dev/null
+++ b/SafeExamBrowser.WindowsApi.Contracts/Events/KeyboardHookCallback.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.WindowsApi.Contracts.Events
+{
+ ///
+ /// The callback for a keyboard hook. Return true to consume (i.e. block) the user input, otherwise false.
+ ///
+ public delegate bool KeyboardHookCallback(int keyCode, KeyModifier modifier, KeyState state);
+}
diff --git a/SafeExamBrowser.Monitoring.Contracts/Mouse/MouseButton.cs b/SafeExamBrowser.WindowsApi.Contracts/Events/MouseButton.cs
similarity index 75%
rename from SafeExamBrowser.Monitoring.Contracts/Mouse/MouseButton.cs
rename to SafeExamBrowser.WindowsApi.Contracts/Events/MouseButton.cs
index 0b3d29f6..e91494cc 100644
--- a/SafeExamBrowser.Monitoring.Contracts/Mouse/MouseButton.cs
+++ b/SafeExamBrowser.WindowsApi.Contracts/Events/MouseButton.cs
@@ -6,10 +6,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-namespace SafeExamBrowser.Monitoring.Contracts.Mouse
+namespace SafeExamBrowser.WindowsApi.Contracts.Events
{
///
- /// The mouse buttons which can be detected by the .
+ /// The mouse buttons which can be detected by a mouse hook.
///
public enum MouseButton
{
diff --git a/SafeExamBrowser.Monitoring.Contracts/Mouse/MouseButtonState.cs b/SafeExamBrowser.WindowsApi.Contracts/Events/MouseButtonState.cs
similarity index 73%
rename from SafeExamBrowser.Monitoring.Contracts/Mouse/MouseButtonState.cs
rename to SafeExamBrowser.WindowsApi.Contracts/Events/MouseButtonState.cs
index 9af16397..a4e9e4a1 100644
--- a/SafeExamBrowser.Monitoring.Contracts/Mouse/MouseButtonState.cs
+++ b/SafeExamBrowser.WindowsApi.Contracts/Events/MouseButtonState.cs
@@ -6,10 +6,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-namespace SafeExamBrowser.Monitoring.Contracts.Mouse
+namespace SafeExamBrowser.WindowsApi.Contracts.Events
{
///
- /// The mouse button states which can be detected by the .
+ /// The mouse button states which can be detected a mouse hook.
///
public enum MouseButtonState
{
diff --git a/SafeExamBrowser.WindowsApi.Contracts/Events/MouseHookCallback.cs b/SafeExamBrowser.WindowsApi.Contracts/Events/MouseHookCallback.cs
new file mode 100644
index 00000000..1a5c9f65
--- /dev/null
+++ b/SafeExamBrowser.WindowsApi.Contracts/Events/MouseHookCallback.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.WindowsApi.Contracts.Events
+{
+ ///
+ /// The callback for a mouse hook. Return true to consume (i.e. block) the user input, otherwise false.
+ ///
+ public delegate bool MouseHookCallback(MouseButton button, MouseButtonState state);
+}
diff --git a/SafeExamBrowser.WindowsApi.Contracts/IDesktopFactory.cs b/SafeExamBrowser.WindowsApi.Contracts/IDesktopFactory.cs
index 1db3b063..164b12a3 100644
--- a/SafeExamBrowser.WindowsApi.Contracts/IDesktopFactory.cs
+++ b/SafeExamBrowser.WindowsApi.Contracts/IDesktopFactory.cs
@@ -6,7 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-
namespace SafeExamBrowser.WindowsApi.Contracts
{
///
diff --git a/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs b/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs
index 040217c9..255e3a56 100644
--- a/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs
+++ b/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs
@@ -8,8 +8,6 @@
using System;
using System.Collections.Generic;
-using SafeExamBrowser.Monitoring.Contracts.Keyboard;
-using SafeExamBrowser.Monitoring.Contracts.Mouse;
using SafeExamBrowser.WindowsApi.Contracts.Events;
namespace SafeExamBrowser.WindowsApi.Contracts
@@ -20,20 +18,20 @@ namespace SafeExamBrowser.WindowsApi.Contracts
public interface INativeMethods
{
///
- /// Deregisters the system hook for the given keyboard interceptor.
+ /// Deregisters a previously registered keyboard hook.
///
///
- /// If the hook for the given interceptor could not be successfully removed.
+ /// If the hook could not be successfully removed.
///
- void DeregisterKeyboardHook(IKeyboardInterceptor interceptor);
+ void DeregisterKeyboardHook(Guid hookId);
///
- /// Deregisters the system hook for the given mouse interceptor.
+ /// Deregisters a previously registered mouse hook.
///
///
- /// If the hook for the given interceptor could not be successfully removed.
+ /// If the hook could not be successfully removed.
///
- void DeregisterMouseHook(IMouseInterceptor interceptor);
+ void DeregisterMouseHook(Guid hookId);
///
/// Deregisters a previously registered system event hook.
@@ -65,14 +63,12 @@ namespace SafeExamBrowser.WindowsApi.Contracts
uint GetProcessIdFor(IntPtr window);
///
- /// Retrieves a window handle to the Windows taskbar. Returns IntPtr.Zero
- /// if the taskbar could not be found (i.e. if it isn't running).
+ /// Retrieves a window handle to the Windows taskbar. Returns IntPtr.Zero if the taskbar could not be found (i.e. if it isn't running).
///
IntPtr GetShellWindowHandle();
///
- /// Retrieves the process ID of the main Windows explorer instance controlling
- /// desktop and taskbar or 0, if the process isn't running.
+ /// Retrieves the process identifier of the main Windows explorer instance controlling desktop and taskbar or 0, if the process isn't running.
///
uint GetShellProcessId();
@@ -121,24 +117,24 @@ namespace SafeExamBrowser.WindowsApi.Contracts
void PreventSleepMode();
///
- /// Registers a system hook for the given keyboard interceptor.
+ /// Registers a keyboard hook for the given callback. Returns the identifier of the newly registered hook.
///
- void RegisterKeyboardHook(IKeyboardInterceptor interceptor);
+ Guid RegisterKeyboardHook(KeyboardHookCallback callback);
///
- /// Registers a system hook for the given mouse interceptor.
+ /// Registers a mouse hook for the given callback. Returns the identifier of the newly registered hook.
///
- void RegisterMouseHook(IMouseInterceptor interceptor);
+ Guid RegisterMouseHook(MouseHookCallback callback);
///
- /// Registers a system event which will invoke the specified callback when a window has received mouse capture.
- /// Returns the ID of the newly registered Windows event hook.
+ /// Registers a system event which will invoke the specified callback when a window has received mouse capture. Returns the identifier of
+ /// the newly registered Windows event hook.
///
Guid RegisterSystemCaptureStartEvent(SystemEventCallback callback);
///
- /// Registers a system event which will invoke the specified callback when the foreground window has changed.
- /// Returns a handle to the newly registered Windows event hook.
+ /// Registers a system event which will invoke the specified callback when the foreground window has changed. Returns the identifier of the
+ /// newly registered Windows event hook.
///
Guid RegisterSystemForegroundEvent(SystemEventCallback callback);
@@ -156,7 +152,7 @@ namespace SafeExamBrowser.WindowsApi.Contracts
void RestoreWindow(IntPtr window);
///
- /// Attempts to resume the thread referenced by the given thread ID. Returns true if the thread was successfully resumed,
+ /// Attempts to resume the thread referenced by the given thread identifier. Returns true if the thread was successfully resumed,
/// otherwise false.
///
bool ResumeThread(int threadId);
@@ -183,7 +179,7 @@ namespace SafeExamBrowser.WindowsApi.Contracts
void SetWorkingArea(IBounds bounds);
///
- /// Attempts to suspend the thread referenced by the given thread ID. Returns true if the thread was successfully suspended,
+ /// Attempts to suspend the thread referenced by the given thread identifier. Returns true if the thread was successfully suspended,
/// otherwise false.
///
bool SuspendThread(int threadId);
diff --git a/SafeExamBrowser.WindowsApi.Contracts/SafeExamBrowser.WindowsApi.Contracts.csproj b/SafeExamBrowser.WindowsApi.Contracts/SafeExamBrowser.WindowsApi.Contracts.csproj
index d75f417f..1207dd11 100644
--- a/SafeExamBrowser.WindowsApi.Contracts/SafeExamBrowser.WindowsApi.Contracts.csproj
+++ b/SafeExamBrowser.WindowsApi.Contracts/SafeExamBrowser.WindowsApi.Contracts.csproj
@@ -53,6 +53,12 @@
+
+
+
+
+
+
@@ -66,11 +72,5 @@
-
-
- {6d563a30-366d-4c35-815b-2c9e6872278b}
- SafeExamBrowser.Monitoring.Contracts
-
-
\ No newline at end of file
diff --git a/SafeExamBrowser.WindowsApi/Hooks/KeyboardHook.cs b/SafeExamBrowser.WindowsApi/Hooks/KeyboardHook.cs
index c99a1f2a..16d945af 100644
--- a/SafeExamBrowser.WindowsApi/Hooks/KeyboardHook.cs
+++ b/SafeExamBrowser.WindowsApi/Hooks/KeyboardHook.cs
@@ -8,8 +8,8 @@
using System;
using System.Runtime.InteropServices;
-using SafeExamBrowser.Monitoring.Contracts.Keyboard;
using SafeExamBrowser.WindowsApi.Constants;
+using SafeExamBrowser.WindowsApi.Contracts.Events;
using SafeExamBrowser.WindowsApi.Delegates;
using SafeExamBrowser.WindowsApi.Types;
@@ -18,14 +18,16 @@ namespace SafeExamBrowser.WindowsApi.Hooks
internal class KeyboardHook
{
private bool altPressed, ctrlPressed;
+ private KeyboardHookCallback callback;
+ private IntPtr handle;
private HookDelegate hookDelegate;
- internal IntPtr Handle { get; private set; }
- internal IKeyboardInterceptor Interceptor { get; private set; }
+ internal Guid Id { get; private set; }
- internal KeyboardHook(IKeyboardInterceptor interceptor)
+ internal KeyboardHook(KeyboardHookCallback callback)
{
- Interceptor = interceptor;
+ this.callback = callback;
+ this.Id = Guid.NewGuid();
}
internal void Attach()
@@ -38,13 +40,12 @@ namespace SafeExamBrowser.WindowsApi.Hooks
// Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code.
// Not doing so will result in a CallbackOnCollectedDelegate error and subsequent application crash!
hookDelegate = new HookDelegate(LowLevelKeyboardProc);
-
- Handle = User32.SetWindowsHookEx(HookType.WH_KEYBOARD_LL, hookDelegate, moduleHandle, 0);
+ handle = User32.SetWindowsHookEx(HookType.WH_KEYBOARD_LL, hookDelegate, moduleHandle, 0);
}
internal bool Detach()
{
- return User32.UnhookWindowsHookEx(Handle);
+ return User32.UnhookWindowsHookEx(handle);
}
private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
@@ -55,13 +56,13 @@ namespace SafeExamBrowser.WindowsApi.Hooks
var modifier = GetModifiers(keyData, wParam.ToInt32());
var state = GetState(wParam.ToInt32());
- if (Interceptor.Block((int) keyData.KeyCode, modifier, state))
+ if (callback((int) keyData.KeyCode, modifier, state))
{
return (IntPtr) 1;
}
}
- return User32.CallNextHookEx(Handle, nCode, wParam, lParam);
+ return User32.CallNextHookEx(handle, nCode, wParam, lParam);
}
private KeyState GetState(int wParam)
diff --git a/SafeExamBrowser.WindowsApi/Hooks/MouseHook.cs b/SafeExamBrowser.WindowsApi/Hooks/MouseHook.cs
index 532ecebc..815bb8e0 100644
--- a/SafeExamBrowser.WindowsApi/Hooks/MouseHook.cs
+++ b/SafeExamBrowser.WindowsApi/Hooks/MouseHook.cs
@@ -8,8 +8,8 @@
using System;
using System.Runtime.InteropServices;
-using SafeExamBrowser.Monitoring.Contracts.Mouse;
using SafeExamBrowser.WindowsApi.Constants;
+using SafeExamBrowser.WindowsApi.Contracts.Events;
using SafeExamBrowser.WindowsApi.Delegates;
using SafeExamBrowser.WindowsApi.Types;
@@ -17,14 +17,16 @@ namespace SafeExamBrowser.WindowsApi.Hooks
{
internal class MouseHook
{
+ private MouseHookCallback callback;
+ private IntPtr handle;
private HookDelegate hookDelegate;
- internal IntPtr Handle { get; private set; }
- internal IMouseInterceptor Interceptor { get; private set; }
+ internal Guid Id { get; private set; }
- internal MouseHook(IMouseInterceptor interceptor)
+ internal MouseHook(MouseHookCallback callback)
{
- Interceptor = interceptor;
+ this.callback = callback;
+ this.Id = Guid.NewGuid();
}
internal void Attach()
@@ -37,13 +39,12 @@ namespace SafeExamBrowser.WindowsApi.Hooks
// Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code.
// Not doing so will result in a CallbackOnCollectedDelegate error and subsequent application crash!
hookDelegate = new HookDelegate(LowLevelMouseProc);
-
- Handle = User32.SetWindowsHookEx(HookType.WH_MOUSE_LL, hookDelegate, moduleHandle, 0);
+ handle = User32.SetWindowsHookEx(HookType.WH_MOUSE_LL, hookDelegate, moduleHandle, 0);
}
internal bool Detach()
{
- return User32.UnhookWindowsHookEx(Handle);
+ return User32.UnhookWindowsHookEx(handle);
}
private IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
@@ -54,13 +55,13 @@ namespace SafeExamBrowser.WindowsApi.Hooks
var button = GetButton(wParam.ToInt32());
var state = GetState(wParam.ToInt32());
- if (Interceptor.Block(button, state))
+ if (callback(button, state))
{
return (IntPtr) 1;
}
}
- return User32.CallNextHookEx(Handle, nCode, wParam, lParam);
+ return User32.CallNextHookEx(handle, nCode, wParam, lParam);
}
private bool Ignore(int wParam)
diff --git a/SafeExamBrowser.WindowsApi/Hooks/SystemHook.cs b/SafeExamBrowser.WindowsApi/Hooks/SystemHook.cs
index 95073852..2e4d1867 100644
--- a/SafeExamBrowser.WindowsApi/Hooks/SystemHook.cs
+++ b/SafeExamBrowser.WindowsApi/Hooks/SystemHook.cs
@@ -8,8 +8,8 @@
using System;
using System.Threading;
-using SafeExamBrowser.WindowsApi.Contracts.Events;
using SafeExamBrowser.WindowsApi.Constants;
+using SafeExamBrowser.WindowsApi.Contracts.Events;
using SafeExamBrowser.WindowsApi.Delegates;
namespace SafeExamBrowser.WindowsApi.Hooks
@@ -21,8 +21,8 @@ namespace SafeExamBrowser.WindowsApi.Hooks
private bool detachSuccess;
private EventDelegate eventDelegate;
private uint eventId;
+ private IntPtr handle;
- internal IntPtr Handle { get; private set; }
internal Guid Id { get; private set; }
public SystemHook(SystemEventCallback callback, uint eventId)
@@ -40,14 +40,13 @@ namespace SafeExamBrowser.WindowsApi.Hooks
// Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code.
// Not doing so will result in a CallbackOnCollectedDelegate error and subsequent application crash!
eventDelegate = new EventDelegate(LowLevelSystemProc);
-
- Handle = User32.SetWinEventHook(eventId, eventId, IntPtr.Zero, eventDelegate, 0, 0, Constant.WINEVENT_OUTOFCONTEXT);
+ handle = User32.SetWinEventHook(eventId, eventId, IntPtr.Zero, eventDelegate, 0, 0, Constant.WINEVENT_OUTOFCONTEXT);
}
internal void AwaitDetach()
{
detachEvent.WaitOne();
- detachSuccess = User32.UnhookWinEvent(Handle);
+ detachSuccess = User32.UnhookWinEvent(handle);
detachResultAvailableEvent.Set();
}
diff --git a/SafeExamBrowser.WindowsApi/NativeMethods.cs b/SafeExamBrowser.WindowsApi/NativeMethods.cs
index 09eac477..70402fa7 100644
--- a/SafeExamBrowser.WindowsApi/NativeMethods.cs
+++ b/SafeExamBrowser.WindowsApi/NativeMethods.cs
@@ -14,8 +14,6 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
-using SafeExamBrowser.Monitoring.Contracts.Keyboard;
-using SafeExamBrowser.Monitoring.Contracts.Mouse;
using SafeExamBrowser.WindowsApi.Constants;
using SafeExamBrowser.WindowsApi.Contracts;
using SafeExamBrowser.WindowsApi.Contracts.Events;
@@ -26,34 +24,34 @@ namespace SafeExamBrowser.WindowsApi
{
public class NativeMethods : INativeMethods
{
- private ConcurrentDictionary KeyboardHooks = new ConcurrentDictionary();
- private ConcurrentDictionary MouseHooks = new ConcurrentDictionary();
- private ConcurrentDictionary SystemHooks = new ConcurrentDictionary();
+ private ConcurrentBag KeyboardHooks = new ConcurrentBag();
+ private ConcurrentBag MouseHooks = new ConcurrentBag();
+ private ConcurrentBag SystemHooks = new ConcurrentBag();
///
/// Upon finalization, unregister all active system events and hooks...
///
~NativeMethods()
{
- foreach (var hook in SystemHooks.Values)
+ foreach (var hook in SystemHooks)
{
hook.Detach();
}
- foreach (var hook in KeyboardHooks.Values)
+ foreach (var hook in KeyboardHooks)
{
hook.Detach();
}
- foreach (var hook in MouseHooks.Values)
+ foreach (var hook in MouseHooks)
{
hook.Detach();
}
}
- public void DeregisterKeyboardHook(IKeyboardInterceptor interceptor)
+ public void DeregisterKeyboardHook(Guid hookId)
{
- var hook = KeyboardHooks.Values.FirstOrDefault(h => h.Interceptor == interceptor);
+ var hook = KeyboardHooks.FirstOrDefault(h => h.Id == hookId);
if (hook != null)
{
@@ -64,13 +62,13 @@ namespace SafeExamBrowser.WindowsApi
throw new Win32Exception(Marshal.GetLastWin32Error());
}
- KeyboardHooks.TryRemove(hook.Handle, out _);
+ KeyboardHooks.TryTake(out _);
}
}
- public void DeregisterMouseHook(IMouseInterceptor interceptor)
+ public void DeregisterMouseHook(Guid hookId)
{
- var hook = MouseHooks.Values.FirstOrDefault(h => h.Interceptor == interceptor);
+ var hook = MouseHooks.FirstOrDefault(h => h.Id == hookId);
if (hook != null)
{
@@ -81,13 +79,13 @@ namespace SafeExamBrowser.WindowsApi
throw new Win32Exception(Marshal.GetLastWin32Error());
}
- MouseHooks.TryRemove(hook.Handle, out _);
+ MouseHooks.TryTake(out _);
}
}
public void DeregisterSystemEventHook(Guid hookId)
{
- var hook = SystemHooks.Values.FirstOrDefault(h => h.Id == hookId);
+ var hook = SystemHooks.FirstOrDefault(h => h.Id == hookId);
if (hook != null)
{
@@ -98,7 +96,7 @@ namespace SafeExamBrowser.WindowsApi
throw new Win32Exception(Marshal.GetLastWin32Error());
}
- SystemHooks.TryRemove(hook.Handle, out _);
+ SystemHooks.TryTake(out _);
}
}
@@ -236,16 +234,18 @@ namespace SafeExamBrowser.WindowsApi
Kernel32.SetThreadExecutionState(EXECUTION_STATE.CONTINUOUS | EXECUTION_STATE.DISPLAY_REQUIRED | EXECUTION_STATE.SYSTEM_REQUIRED);
}
- public void RegisterKeyboardHook(IKeyboardInterceptor interceptor)
+ public Guid RegisterKeyboardHook(KeyboardHookCallback callback)
{
+ var hookId = default(Guid);
var hookReadyEvent = new AutoResetEvent(false);
var hookThread = new Thread(() =>
{
- var hook = new KeyboardHook(interceptor);
+ var hook = new KeyboardHook(callback);
var sleepEvent = new AutoResetEvent(false);
hook.Attach();
- KeyboardHooks[hook.Handle] = hook;
+ hookId = hook.Id;
+ KeyboardHooks.Add(hook);
hookReadyEvent.Set();
while (true)
@@ -259,18 +259,22 @@ namespace SafeExamBrowser.WindowsApi
hookThread.Start();
hookReadyEvent.WaitOne();
+
+ return hookId;
}
- public void RegisterMouseHook(IMouseInterceptor interceptor)
+ public Guid RegisterMouseHook(MouseHookCallback callback)
{
+ var hookId = default(Guid);
var hookReadyEvent = new AutoResetEvent(false);
var hookThread = new Thread(() =>
{
- var hook = new MouseHook(interceptor);
+ var hook = new MouseHook(callback);
var sleepEvent = new AutoResetEvent(false);
hook.Attach();
- MouseHooks[hook.Handle] = hook;
+ hookId = hook.Id;
+ MouseHooks.Add(hook);
hookReadyEvent.Set();
while (true)
@@ -284,6 +288,8 @@ namespace SafeExamBrowser.WindowsApi
hookThread.Start();
hookReadyEvent.WaitOne();
+
+ return hookId;
}
public Guid RegisterSystemCaptureStartEvent(SystemEventCallback callback)
@@ -306,7 +312,7 @@ namespace SafeExamBrowser.WindowsApi
hook.Attach();
hookId = hook.Id;
- SystemHooks[hook.Handle] = hook;
+ SystemHooks.Add(hook);
hookReadyEvent.Set();
hook.AwaitDetach();
});
diff --git a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
index 9475f2b3..13b13469 100644
--- a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
+++ b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
@@ -96,10 +96,6 @@
{64ea30fb-11d4-436a-9c2b-88566285363e}
SafeExamBrowser.Logging.Contracts
-
- {6d563a30-366d-4c35-815b-2c9e6872278b}
- SafeExamBrowser.Monitoring.Contracts
-
{c7889e97-6ff6-4a58-b7cb-521ed276b316}
SafeExamBrowser.UserInterface.Contracts