SEBWIN-414: Implemented lock screen for user session switch.

This commit is contained in:
Damian Büchel 2020-06-29 19:29:48 +02:00
parent 44a7275f40
commit 9599102b9e
15 changed files with 391 additions and 49 deletions

View file

@ -27,6 +27,7 @@ using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.Applications; using SafeExamBrowser.Monitoring.Contracts.Applications;
using SafeExamBrowser.Monitoring.Contracts.Display; using SafeExamBrowser.Monitoring.Contracts.Display;
using SafeExamBrowser.Monitoring.Contracts.System;
using SafeExamBrowser.Settings; using SafeExamBrowser.Settings;
using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts;
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
@ -59,6 +60,7 @@ namespace SafeExamBrowser.Client.UnitTests
private AppSettings settings; private AppSettings settings;
private Mock<Action> shutdown; private Mock<Action> shutdown;
private Mock<ISplashScreen> splashScreen; private Mock<ISplashScreen> splashScreen;
private Mock<ISystemMonitor> systemMonitor;
private Mock<ITaskbar> taskbar; private Mock<ITaskbar> taskbar;
private Mock<IText> text; private Mock<IText> text;
private Mock<IUserInterfaceFactory> uiFactory; private Mock<IUserInterfaceFactory> uiFactory;
@ -86,6 +88,7 @@ namespace SafeExamBrowser.Client.UnitTests
settings = new AppSettings(); settings = new AppSettings();
shutdown = new Mock<Action>(); shutdown = new Mock<Action>();
splashScreen = new Mock<ISplashScreen>(); splashScreen = new Mock<ISplashScreen>();
systemMonitor = new Mock<ISystemMonitor>();
taskbar = new Mock<ITaskbar>(); taskbar = new Mock<ITaskbar>();
text = new Mock<IText>(); text = new Mock<IText>();
uiFactory = new Mock<IUserInterfaceFactory>(); uiFactory = new Mock<IUserInterfaceFactory>();
@ -108,6 +111,7 @@ namespace SafeExamBrowser.Client.UnitTests
runtimeProxy.Object, runtimeProxy.Object,
shutdown.Object, shutdown.Object,
splashScreen.Object, splashScreen.Object,
systemMonitor.Object,
taskbar.Object, taskbar.Object,
text.Object, text.Object,
uiFactory.Object); uiFactory.Object);

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2020 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.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.System;
namespace SafeExamBrowser.Client.UnitTests.Operations
{
[TestClass]
public class SystemMonitorOperationTests
{
private ClientContext context;
private Mock<ISystemMonitor> systemMonitor;
private Mock<ILogger> logger;
private SystemMonitorOperation sut;
[TestInitialize]
public void Initialize()
{
context = new ClientContext();
systemMonitor = new Mock<ISystemMonitor>();
logger = new Mock<ILogger>();
sut = new SystemMonitorOperation(context, systemMonitor.Object, logger.Object);
}
[TestMethod]
public void Perform_MustStartMonitor()
{
sut.Perform();
systemMonitor.Verify(s => s.Start(), Times.Once);
systemMonitor.VerifyNoOtherCalls();
}
[TestMethod]
public void Revert_MustStopMonitor()
{
sut.Revert();
systemMonitor.Verify(s => s.Stop(), Times.Once);
systemMonitor.VerifyNoOtherCalls();
}
}
}

View file

@ -95,6 +95,7 @@
<Compile Include="Communication\ClientHostTests.cs" /> <Compile Include="Communication\ClientHostTests.cs" />
<Compile Include="Notifications\AboutNotificationControllerTests.cs" /> <Compile Include="Notifications\AboutNotificationControllerTests.cs" />
<Compile Include="Notifications\LogNotificationControllerTests.cs" /> <Compile Include="Notifications\LogNotificationControllerTests.cs" />
<Compile Include="Operations\SystemMonitorOperationTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ClientControllerTests.cs" /> <Compile Include="ClientControllerTests.cs" />
</ItemGroup> </ItemGroup>

View file

@ -25,6 +25,7 @@ using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.Applications; using SafeExamBrowser.Monitoring.Contracts.Applications;
using SafeExamBrowser.Monitoring.Contracts.Display; using SafeExamBrowser.Monitoring.Contracts.Display;
using SafeExamBrowser.Monitoring.Contracts.System;
using SafeExamBrowser.Settings; using SafeExamBrowser.Settings;
using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts;
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
@ -49,8 +50,10 @@ namespace SafeExamBrowser.Client
private IMessageBox messageBox; private IMessageBox messageBox;
private IOperationSequence operations; private IOperationSequence operations;
private IRuntimeProxy runtime; private IRuntimeProxy runtime;
private bool sessionLocked;
private Action shutdown; private Action shutdown;
private ISplashScreen splashScreen; private ISplashScreen splashScreen;
private ISystemMonitor systemMonitor;
private ITaskbar taskbar; private ITaskbar taskbar;
private IText text; private IText text;
private IUserInterfaceFactory uiFactory; private IUserInterfaceFactory uiFactory;
@ -73,6 +76,7 @@ namespace SafeExamBrowser.Client
IRuntimeProxy runtime, IRuntimeProxy runtime,
Action shutdown, Action shutdown,
ISplashScreen splashScreen, ISplashScreen splashScreen,
ISystemMonitor systemMonitor,
ITaskbar taskbar, ITaskbar taskbar,
IText text, IText text,
IUserInterfaceFactory uiFactory) IUserInterfaceFactory uiFactory)
@ -90,6 +94,7 @@ namespace SafeExamBrowser.Client
this.runtime = runtime; this.runtime = runtime;
this.shutdown = shutdown; this.shutdown = shutdown;
this.splashScreen = splashScreen; this.splashScreen = splashScreen;
this.systemMonitor = systemMonitor;
this.taskbar = taskbar; this.taskbar = taskbar;
this.text = text; this.text = text;
this.uiFactory = uiFactory; this.uiFactory = uiFactory;
@ -184,6 +189,7 @@ namespace SafeExamBrowser.Client
ClientHost.Shutdown += ClientHost_Shutdown; ClientHost.Shutdown += ClientHost_Shutdown;
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged; displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
runtime.ConnectionLost += Runtime_ConnectionLost; runtime.ConnectionLost += Runtime_ConnectionLost;
systemMonitor.SessionSwitched += SystemMonitor_SessionSwitched;
taskbar.QuitButtonClicked += Shell_QuitButtonClicked; taskbar.QuitButtonClicked += Shell_QuitButtonClicked;
foreach (var activator in context.Activators.OfType<ITerminationActivator>()) foreach (var activator in context.Activators.OfType<ITerminationActivator>())
@ -199,6 +205,7 @@ namespace SafeExamBrowser.Client
applicationMonitor.TerminationFailed -= ApplicationMonitor_TerminationFailed; applicationMonitor.TerminationFailed -= ApplicationMonitor_TerminationFailed;
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged; displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
runtime.ConnectionLost -= Runtime_ConnectionLost; runtime.ConnectionLost -= Runtime_ConnectionLost;
systemMonitor.SessionSwitched -= SystemMonitor_SessionSwitched;
taskbar.QuitButtonClicked -= Shell_QuitButtonClicked; taskbar.QuitButtonClicked -= Shell_QuitButtonClicked;
if (Browser != null) if (Browser != null)
@ -280,48 +287,14 @@ namespace SafeExamBrowser.Client
private void ApplicationMonitor_TerminationFailed(IEnumerable<RunningApplication> applications) private void ApplicationMonitor_TerminationFailed(IEnumerable<RunningApplication> applications)
{ {
var applicationList = string.Join(Environment.NewLine, applications.Select(a => $"- {a.Name}")); var applicationList = string.Join(Environment.NewLine, applications.Select(a => $"- {a.Name}"));
var message = $"{text.Get(TextKey.LockScreen_Message)}{Environment.NewLine}{Environment.NewLine}{applicationList}"; var message = $"{text.Get(TextKey.LockScreen_ApplicationsMessage)}{Environment.NewLine}{Environment.NewLine}{applicationList}";
var title = text.Get(TextKey.LockScreen_Title); var title = text.Get(TextKey.LockScreen_Title);
var hasQuitPassword = !string.IsNullOrEmpty(Settings.Security.QuitPasswordHash); var allowOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_ApplicationsAllowOption) };
var allowOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_AllowOption) }; var terminateOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_ApplicationsTerminateOption) };
var terminateOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_TerminateOption) };
var lockScreen = uiFactory.CreateLockScreen(message, title, new [] { allowOption, terminateOption });
var result = default(LockScreenResult);
logger.Warn("Showing lock screen due to failed termination of blacklisted application(s)!"); logger.Warn("Detected termination failure of blacklisted application(s)!");
PauseActivators();
lockScreen.Show();
for (var unlocked = false; !unlocked;) var result = ShowLockScreen(message, title, new[] { allowOption, terminateOption });
{
result = lockScreen.WaitForResult();
if (hasQuitPassword)
{
var passwordHash = hashAlgorithm.GenerateHashFor(result.Password);
var isCorrect = Settings.Security.QuitPasswordHash.Equals(passwordHash, StringComparison.OrdinalIgnoreCase);
if (isCorrect)
{
logger.Info("The user entered the correct unlock password.");
unlocked = true;
}
else
{
logger.Info("The user entered the wrong unlock password.");
messageBox.Show(TextKey.MessageBox_InvalidUnlockPassword, TextKey.MessageBox_InvalidUnlockPasswordTitle, icon: MessageBoxIcon.Warning, parent: lockScreen);
}
}
else
{
logger.Warn($"No unlock password is defined, allowing user to resume session!");
unlocked = true;
}
}
lockScreen.Close();
ResumeActivators();
logger.Info("Closed lock screen.");
if (result.OptionId == allowOption.Id) if (result.OptionId == allowOption.Id)
{ {
@ -524,6 +497,35 @@ namespace SafeExamBrowser.Client
ResumeActivators(); ResumeActivators();
} }
private void SystemMonitor_SessionSwitched()
{
var message = text.Get(TextKey.LockScreen_UserSessionMessage);
var title = text.Get(TextKey.LockScreen_Title);
var continueOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_UserSessionContinueOption) };
var terminateOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_UserSessionTerminateOption) };
logger.Warn("Detected user session switch!");
if (!sessionLocked)
{
sessionLocked = true;
var result = ShowLockScreen(message, title, new[] { continueOption, terminateOption });
if (result.OptionId == terminateOption.Id)
{
logger.Info("Attempting to shutdown as requested by the user...");
TryRequestShutdown();
}
sessionLocked = false;
}
else
{
logger.Info("Lock screen is already active.");
}
}
private void TerminationActivator_Activated() private void TerminationActivator_Activated()
{ {
PauseActivators(); PauseActivators();
@ -599,6 +601,50 @@ namespace SafeExamBrowser.Client
} }
} }
private LockScreenResult ShowLockScreen(string message, string title, IEnumerable<LockScreenOption> options)
{
var hasQuitPassword = !string.IsNullOrEmpty(Settings.Security.QuitPasswordHash);
var lockScreen = uiFactory.CreateLockScreen(message, title, options);
var result = default(LockScreenResult);
logger.Info("Showing lock screen...");
PauseActivators();
lockScreen.Show();
for (var unlocked = false; !unlocked;)
{
result = lockScreen.WaitForResult();
if (hasQuitPassword)
{
var passwordHash = hashAlgorithm.GenerateHashFor(result.Password);
var isCorrect = Settings.Security.QuitPasswordHash.Equals(passwordHash, StringComparison.OrdinalIgnoreCase);
if (isCorrect)
{
logger.Info("The user entered the correct unlock password.");
unlocked = true;
}
else
{
logger.Info("The user entered the wrong unlock password.");
messageBox.Show(TextKey.MessageBox_InvalidUnlockPassword, TextKey.MessageBox_InvalidUnlockPasswordTitle, icon: MessageBoxIcon.Warning, parent: lockScreen);
}
}
else
{
logger.Warn($"No unlock password is defined, allowing user to resume session!");
unlocked = true;
}
}
lockScreen.Close();
ResumeActivators();
logger.Info("Closed lock screen.");
return result;
}
private bool TryInitiateShutdown() private bool TryInitiateShutdown()
{ {
var hasQuitPassword = !string.IsNullOrEmpty(Settings.Security.QuitPasswordHash); var hasQuitPassword = !string.IsNullOrEmpty(Settings.Security.QuitPasswordHash);

View file

@ -30,6 +30,7 @@ using SafeExamBrowser.Monitoring.Applications;
using SafeExamBrowser.Monitoring.Display; using SafeExamBrowser.Monitoring.Display;
using SafeExamBrowser.Monitoring.Keyboard; using SafeExamBrowser.Monitoring.Keyboard;
using SafeExamBrowser.Monitoring.Mouse; using SafeExamBrowser.Monitoring.Mouse;
using SafeExamBrowser.Monitoring.System;
using SafeExamBrowser.Settings.Logging; using SafeExamBrowser.Settings.Logging;
using SafeExamBrowser.Settings.UserInterface; using SafeExamBrowser.Settings.UserInterface;
using SafeExamBrowser.SystemComponents; using SafeExamBrowser.SystemComponents;
@ -100,6 +101,7 @@ namespace SafeExamBrowser.Client
var fileSystemDialog = BuildFileSystemDialog(); var fileSystemDialog = BuildFileSystemDialog();
var hashAlgorithm = new HashAlgorithm(); var hashAlgorithm = new HashAlgorithm();
var splashScreen = uiFactory.CreateSplashScreen(); var splashScreen = uiFactory.CreateSplashScreen();
var systemMonitor = new SystemMonitor(ModuleLogger(nameof(SystemMonitor)));
var operations = new Queue<IOperation>(); var operations = new Queue<IOperation>();
@ -113,6 +115,7 @@ namespace SafeExamBrowser.Client
operations.Enqueue(new LazyInitializationOperation(BuildMouseInterceptorOperation)); operations.Enqueue(new LazyInitializationOperation(BuildMouseInterceptorOperation));
operations.Enqueue(new ApplicationOperation(context, applicationFactory, applicationMonitor, logger, text)); operations.Enqueue(new ApplicationOperation(context, applicationFactory, applicationMonitor, logger, text));
operations.Enqueue(new DisplayMonitorOperation(context, displayMonitor, logger, taskbar)); operations.Enqueue(new DisplayMonitorOperation(context, displayMonitor, logger, taskbar));
operations.Enqueue(new SystemMonitorOperation(context, systemMonitor, logger));
operations.Enqueue(new LazyInitializationOperation(BuildShellOperation)); operations.Enqueue(new LazyInitializationOperation(BuildShellOperation));
operations.Enqueue(new LazyInitializationOperation(BuildBrowserOperation)); operations.Enqueue(new LazyInitializationOperation(BuildBrowserOperation));
operations.Enqueue(new ClipboardOperation(context, logger, nativeMethods)); operations.Enqueue(new ClipboardOperation(context, logger, nativeMethods));
@ -133,6 +136,7 @@ namespace SafeExamBrowser.Client
runtimeProxy, runtimeProxy,
shutdown, shutdown,
splashScreen, splashScreen,
systemMonitor,
taskbar, taskbar,
text, text,
uiFactory); uiFactory);

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2020 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;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.System;
namespace SafeExamBrowser.Client.Operations
{
internal class SystemMonitorOperation : ClientOperation
{
private readonly ILogger logger;
private readonly ISystemMonitor systemMonitor;
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
public override event StatusChangedEventHandler StatusChanged;
public SystemMonitorOperation(ClientContext context, ISystemMonitor systemMonitor, ILogger logger) : base(context)
{
this.logger = logger;
this.systemMonitor = systemMonitor;
}
public override OperationResult Perform()
{
logger.Info("Initializing system events...");
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeSystemEvents);
systemMonitor.Start();
return OperationResult.Success;
}
public override OperationResult Revert()
{
logger.Info("Finalizing system events...");
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeSystemEvents);
systemMonitor.Stop();
return OperationResult.Success;
}
}
}

View file

@ -95,6 +95,7 @@
<Compile Include="Operations\MouseInterceptorOperation.cs" /> <Compile Include="Operations\MouseInterceptorOperation.cs" />
<Compile Include="Operations\ApplicationOperation.cs" /> <Compile Include="Operations\ApplicationOperation.cs" />
<Compile Include="Operations\ShellOperation.cs" /> <Compile Include="Operations\ShellOperation.cs" />
<Compile Include="Operations\SystemMonitorOperation.cs" />
<Compile Include="Properties\AssemblyInfo.cs"> <Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>

View file

@ -44,9 +44,12 @@ namespace SafeExamBrowser.I18n.Contracts
FileSystemDialog_Select, FileSystemDialog_Select,
FileSystemDialog_Title, FileSystemDialog_Title,
FolderDialog_ApplicationLocation, FolderDialog_ApplicationLocation,
LockScreen_AllowOption, LockScreen_ApplicationsAllowOption,
LockScreen_Message, LockScreen_ApplicationsMessage,
LockScreen_TerminateOption, LockScreen_ApplicationsTerminateOption,
LockScreen_UserSessionContinueOption,
LockScreen_UserSessionMessage,
LockScreen_UserSessionTerminateOption,
LockScreen_Title, LockScreen_Title,
LockScreen_UnlockButton, LockScreen_UnlockButton,
LogWindow_AlwaysOnTop, LogWindow_AlwaysOnTop,
@ -117,13 +120,16 @@ namespace SafeExamBrowser.I18n.Contracts
OperationStatus_EmptyClipboard, OperationStatus_EmptyClipboard,
OperationStatus_FinalizeApplications, OperationStatus_FinalizeApplications,
OperationStatus_FinalizeServiceSession, OperationStatus_FinalizeServiceSession,
OperationStatus_FinalizeSystemEvents,
OperationStatus_InitializeApplications, OperationStatus_InitializeApplications,
OperationStatus_InitializeBrowser, OperationStatus_InitializeBrowser,
OperationStatus_InitializeConfiguration, OperationStatus_InitializeConfiguration,
OperationStatus_InitializeKioskMode, OperationStatus_InitializeKioskMode,
OperationStatus_InitializeRuntimeConnection, OperationStatus_InitializeRuntimeConnection,
OperationStatus_InitializeServiceSession, OperationStatus_InitializeServiceSession,
OperationStatus_InitializeSession,
OperationStatus_InitializeShell, OperationStatus_InitializeShell,
OperationStatus_InitializeSystemEvents,
OperationStatus_InitializeWorkingArea, OperationStatus_InitializeWorkingArea,
OperationStatus_RestartCommunicationHost, OperationStatus_RestartCommunicationHost,
OperationStatus_RestoreWorkingArea, OperationStatus_RestoreWorkingArea,
@ -132,7 +138,6 @@ namespace SafeExamBrowser.I18n.Contracts
OperationStatus_StartCommunicationHost, OperationStatus_StartCommunicationHost,
OperationStatus_StartKeyboardInterception, OperationStatus_StartKeyboardInterception,
OperationStatus_StartMouseInterception, OperationStatus_StartMouseInterception,
OperationStatus_InitializeSession,
OperationStatus_StopClient, OperationStatus_StopClient,
OperationStatus_StopCommunicationHost, OperationStatus_StopCommunicationHost,
OperationStatus_StopKeyboardInterception, OperationStatus_StopKeyboardInterception,

View file

@ -90,13 +90,13 @@
<Entry key="FolderDialog_ApplicationLocation"> <Entry key="FolderDialog_ApplicationLocation">
Applikation "%%NAME%%" konnte nicht gefunden werden auf dem System! Bitte geben Sie an, wo die ausführbare Datei "%%EXECUTABLE%%" liegt. Applikation "%%NAME%%" konnte nicht gefunden werden auf dem System! Bitte geben Sie an, wo die ausführbare Datei "%%EXECUTABLE%%" liegt.
</Entry> </Entry>
<Entry key="LockScreen_AllowOption"> <Entry key="LockScreen_ApplicationsAllowOption">
Verbotene Applikationen temporär erlauben. Dies gilt nur für die momentan laufenden Instanzen der aktuellen Sitzung! Verbotene Applikationen temporär erlauben. Dies gilt nur für die momentan laufenden Instanzen der aktuellen Sitzung!
</Entry> </Entry>
<Entry key="LockScreen_Message"> <Entry key="LockScreen_ApplicationsMessage">
Die unten aufgelisteten, verbotenen Applikationen wurden gestartet und konnten nicht automatisch beendet werden! Bitte wählen Sie eine der verfügbaren Optionen aus und geben Sie das korrekte Passwort ein, um SEB zu entsperren. Die unten aufgelisteten, verbotenen Applikationen wurden gestartet und konnten nicht automatisch beendet werden! Bitte wählen Sie eine der verfügbaren Optionen aus und geben Sie das korrekte Passwort ein, um SEB zu entsperren.
</Entry> </Entry>
<Entry key="LockScreen_TerminateOption"> <Entry key="LockScreen_ApplicationsTerminateOption">
Safe Exam Browser beenden. WARNUNG: Sie werden keine Möglichkeit haben, Daten zu speichern oder weitere Aktionen auszuführen, SEB wird sofort beendet! Safe Exam Browser beenden. WARNUNG: Sie werden keine Möglichkeit haben, Daten zu speichern oder weitere Aktionen auszuführen, SEB wird sofort beendet!
</Entry> </Entry>
<Entry key="LockScreen_Title"> <Entry key="LockScreen_Title">
@ -105,6 +105,15 @@
<Entry key="LockScreen_UnlockButton"> <Entry key="LockScreen_UnlockButton">
Entsperren Entsperren
</Entry> </Entry>
<Entry key="LockScreen_UserSessionContinueOption">
Safe Exam Browser entsperren.
</Entry>
<Entry key="LockScreen_UserSessionMessage">
Der aktive Benutzer hat sich geändert oder der Computer wurde gesperrt! Bitte wählen Sie eine der verfügbaren Optionen aus und geben Sie das korrekte Passwort ein, um SEB zu entsperren.
</Entry>
<Entry key="LockScreen_UserSessionTerminateOption">
Safe Exam Browser beenden. WARNUNG: Sie werden keine Möglichkeit haben, Daten zu speichern oder weitere Aktionen auszuführen, SEB wird sofort beendet!
</Entry>
<Entry key="LogWindow_AlwaysOnTop"> <Entry key="LogWindow_AlwaysOnTop">
Immer zuoberst Immer zuoberst
</Entry> </Entry>
@ -309,6 +318,9 @@
<Entry key="OperationStatus_FinalizeServiceSession"> <Entry key="OperationStatus_FinalizeServiceSession">
Beende Service-Sitzung Beende Service-Sitzung
</Entry> </Entry>
<Entry key="OperationStatus_FinalizeSystemEvents">
Finalisiere System-Ereignisse
</Entry>
<Entry key="OperationStatus_InitializeApplications"> <Entry key="OperationStatus_InitializeApplications">
Initialisiere Applikationen Initialisiere Applikationen
</Entry> </Entry>
@ -333,6 +345,9 @@
<Entry key="OperationStatus_InitializeShell"> <Entry key="OperationStatus_InitializeShell">
Initialisiere Benutzeroberfläche Initialisiere Benutzeroberfläche
</Entry> </Entry>
<Entry key="OperationStatus_InitializeSystemEvents">
Initialisiere System-Ereignisse
</Entry>
<Entry key="OperationStatus_InitializeWorkingArea"> <Entry key="OperationStatus_InitializeWorkingArea">
Initialisiere Arbeitsbereich Initialisiere Arbeitsbereich
</Entry> </Entry>

View file

@ -90,13 +90,13 @@
<Entry key="FolderDialog_ApplicationLocation"> <Entry key="FolderDialog_ApplicationLocation">
Application "%%NAME%%" could not be found on the system! Please locate the folder containing the main executable "%%EXECUTABLE%%". Application "%%NAME%%" could not be found on the system! Please locate the folder containing the main executable "%%EXECUTABLE%%".
</Entry> </Entry>
<Entry key="LockScreen_AllowOption"> <Entry key="LockScreen_ApplicationsAllowOption">
Temporarily allow the blacklisted applications. This applies only to the currently running instances and session! Temporarily allow the blacklisted applications. This applies only to the currently running instances and session!
</Entry> </Entry>
<Entry key="LockScreen_Message"> <Entry key="LockScreen_ApplicationsMessage">
The blacklisted applications listed below were started and could not be automatically terminated! In order to unlock SEB, please select one of the available options and enter the correct unlock password. The blacklisted applications listed below were started and could not be automatically terminated! In order to unlock SEB, please select one of the available options and enter the correct unlock password.
</Entry> </Entry>
<Entry key="LockScreen_TerminateOption"> <Entry key="LockScreen_ApplicationsTerminateOption">
Terminate Safe Exam Browser. WARNING: There will be no possibility to save data or perform any further actions, the shutdown will be initiated immediately! Terminate Safe Exam Browser. WARNING: There will be no possibility to save data or perform any further actions, the shutdown will be initiated immediately!
</Entry> </Entry>
<Entry key="LockScreen_Title"> <Entry key="LockScreen_Title">
@ -105,6 +105,15 @@
<Entry key="LockScreen_UnlockButton"> <Entry key="LockScreen_UnlockButton">
Unlock Unlock
</Entry> </Entry>
<Entry key="LockScreen_UserSessionContinueOption">
Unlock Safe Exam Browser.
</Entry>
<Entry key="LockScreen_UserSessionMessage">
The active user has changed or the computer has been locked! In order to unlock SEB, please select one of the available options and enter the correct unlock password.
</Entry>
<Entry key="LockScreen_UserSessionTerminateOption">
Terminate Safe Exam Browser. WARNING: There will be no possibility to save data or perform any further actions, the shutdown will be initiated immediately!
</Entry>
<Entry key="LogWindow_AlwaysOnTop"> <Entry key="LogWindow_AlwaysOnTop">
Always on top Always on top
</Entry> </Entry>
@ -309,6 +318,9 @@
<Entry key="OperationStatus_FinalizeServiceSession"> <Entry key="OperationStatus_FinalizeServiceSession">
Finalizing service session Finalizing service session
</Entry> </Entry>
<Entry key="OperationStatus_FinalizeSystemEvents">
Finalizing system events
</Entry>
<Entry key="OperationStatus_InitializeApplications"> <Entry key="OperationStatus_InitializeApplications">
Initializing applications Initializing applications
</Entry> </Entry>
@ -333,6 +345,9 @@
<Entry key="OperationStatus_InitializeShell"> <Entry key="OperationStatus_InitializeShell">
Initializing user interface Initializing user interface
</Entry> </Entry>
<Entry key="OperationStatus_InitializeSystemEvents">
Initializing system events
</Entry>
<Entry key="OperationStatus_InitializeWorkingArea"> <Entry key="OperationStatus_InitializeWorkingArea">
Initializing working area Initializing working area
</Entry> </Entry>

View file

@ -65,6 +65,8 @@
<Compile Include="Applications\InitializationResult.cs" /> <Compile Include="Applications\InitializationResult.cs" />
<Compile Include="Applications\IApplicationMonitor.cs" /> <Compile Include="Applications\IApplicationMonitor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="System\Events\SessionSwitchedEventHandler.cs" />
<Compile Include="System\ISystemMonitor.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj"> <ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj">

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2020 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.Monitoring.Contracts.System.Events
{
/// <summary>
/// Indicates that the active user session of the operating system has changed.
/// </summary>
public delegate void SessionSwitchedEventHandler();
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2020 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.Monitoring.Contracts.System.Events;
namespace SafeExamBrowser.Monitoring.Contracts.System
{
/// <summary>
/// Monitors the operating system, e.g. for user account related events.
/// </summary>
public interface ISystemMonitor
{
/// <summary>
/// Event fired when the active user session has changed.
/// </summary>
event SessionSwitchedEventHandler SessionSwitched;
/// <summary>
/// Starts the monitoring.
/// </summary>
void Start();
/// <summary>
/// Stops the monitoring.
/// </summary>
void Stop();
}
}

View file

@ -63,6 +63,7 @@
<Compile Include="Mouse\MouseInterceptor.cs" /> <Compile Include="Mouse\MouseInterceptor.cs" />
<Compile Include="Applications\ApplicationMonitor.cs" /> <Compile Include="Applications\ApplicationMonitor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="System\SystemMonitor.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj"> <ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj">

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2020 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.Threading.Tasks;
using Microsoft.Win32;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.System;
using SafeExamBrowser.Monitoring.Contracts.System.Events;
namespace SafeExamBrowser.Monitoring.System
{
public class SystemMonitor : ISystemMonitor
{
private readonly ILogger logger;
public event SessionSwitchedEventHandler SessionSwitched;
public SystemMonitor(ILogger logger)
{
this.logger = logger;
}
public void Start()
{
SystemEvents.EventsThreadShutdown += SystemEvents_EventsThreadShutdown;
SystemEvents.InstalledFontsChanged += SystemEvents_InstalledFontsChanged;
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
SystemEvents.SessionEnded += SystemEvents_SessionEnded;
SystemEvents.SessionEnding += SystemEvents_SessionEnding;
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
SystemEvents.TimeChanged += SystemEvents_TimeChanged;
SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
logger.Info("Started monitoring the operating system.");
}
public void Stop()
{
SystemEvents.EventsThreadShutdown -= SystemEvents_EventsThreadShutdown;
SystemEvents.InstalledFontsChanged -= SystemEvents_InstalledFontsChanged;
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
SystemEvents.SessionEnded -= SystemEvents_SessionEnded;
SystemEvents.SessionEnding -= SystemEvents_SessionEnding;
SystemEvents.SessionSwitch -= SystemEvents_SessionSwitch;
SystemEvents.TimeChanged -= SystemEvents_TimeChanged;
SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged;
logger.Info("Stopped monitoring the operating system.");
}
private void SystemEvents_EventsThreadShutdown(object sender, EventArgs e)
{
logger.Warn("System event thread is about to be terminated!");
}
private void SystemEvents_InstalledFontsChanged(object sender, EventArgs e)
{
logger.Info("Installed fonts changed.");
}
private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
logger.Info($"Power mode changed: {e.Mode}");
}
private void SystemEvents_SessionEnded(object sender, SessionEndedEventArgs e)
{
logger.Warn($"User session ended! Reason: {e.Reason}");
}
private void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
logger.Warn($"User session is ending! Reason: {e.Reason}");
}
private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
logger.Info($"User session switch detected! Reason: {e.Reason}");
Task.Run(() => SessionSwitched?.Invoke());
}
private void SystemEvents_TimeChanged(object sender, EventArgs e)
{
logger.Info("Time changed.");
}
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
logger.Info($"User preference changed. Category: {e.Category}");
}
}
}