Update Safe Exam Browser Patch to 3.10.0.826
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="KGySoft.CoreLibraries" publicKeyToken="b45eba277439ddfe" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.3.0.0" newVersion="8.3.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="KGySoft.Drawing.Core" publicKeyToken="b45eba277439ddfe" culture="neutral" />
|
||||
|
@@ -82,6 +82,11 @@ namespace SafeExamBrowser.Client
|
||||
/// </summary>
|
||||
internal IProctoringController Proctoring { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the user already provided the correct quit password.
|
||||
/// </summary>
|
||||
internal bool QuitPasswordValidated { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The client responsibilities.
|
||||
/// </summary>
|
||||
|
@@ -58,6 +58,7 @@ using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
||||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Shared;
|
||||
using SafeExamBrowser.UserInterface.Shared.Activators;
|
||||
using SafeExamBrowser.WindowsApi;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
@@ -92,6 +93,7 @@ namespace SafeExamBrowser.Client
|
||||
private ITaskview taskview;
|
||||
private IUserInfo userInfo;
|
||||
private IText text;
|
||||
private WindowGuard windowGuard;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
|
||||
internal ClientController ClientController { get; private set; }
|
||||
@@ -105,6 +107,7 @@ namespace SafeExamBrowser.Client
|
||||
|
||||
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
|
||||
|
||||
windowGuard = new WindowGuard(ModuleLogger(nameof(WindowGuard)));
|
||||
uiFactory = BuildUserInterfaceFactory();
|
||||
actionCenter = uiFactory.CreateActionCenter();
|
||||
context = new ClientContext();
|
||||
@@ -162,6 +165,7 @@ namespace SafeExamBrowser.Client
|
||||
operations.Enqueue(new I18nOperation(logger, text));
|
||||
operations.Enqueue(new RuntimeConnectionOperation(context, logger, runtimeProxy, authenticationToken));
|
||||
operations.Enqueue(new ConfigurationOperation(context, logger, runtimeProxy));
|
||||
operations.Enqueue(new WindowGuardOperation(context, logger, windowGuard));
|
||||
operations.Enqueue(new DelegateOperation(UpdateAppConfig));
|
||||
operations.Enqueue(new DelegateOperation(BuildIntegrityModule));
|
||||
operations.Enqueue(new DelegateOperation(BuildPowerSupply));
|
||||
@@ -169,6 +173,7 @@ namespace SafeExamBrowser.Client
|
||||
operations.Enqueue(new ClientHostDisconnectionOperation(context, logger, FIVE_SECONDS));
|
||||
operations.Enqueue(new LazyInitializationOperation(BuildKeyboardInterceptorOperation));
|
||||
operations.Enqueue(new LazyInitializationOperation(BuildMouseInterceptorOperation));
|
||||
operations.Enqueue(new PermissionOperation(context, logger, networkAdapter));
|
||||
operations.Enqueue(new ApplicationOperation(context, applicationFactory, fileSystemDialog, logger, messageBox, applicationMonitor, splashScreen, text));
|
||||
operations.Enqueue(new DisplayMonitorOperation(context, displayMonitor, logger, taskbar));
|
||||
operations.Enqueue(new LazyInitializationOperation(BuildShellOperation));
|
||||
@@ -196,7 +201,7 @@ namespace SafeExamBrowser.Client
|
||||
responsibilities.Enqueue(new IntegrityResponsibility(context, ModuleLogger(nameof(IntegrityResponsibility)), text));
|
||||
responsibilities.Enqueue(new MonitoringResponsibility(actionCenter, applicationMonitor, context, coordinator, displayMonitor, explorerShell, ModuleLogger(nameof(MonitoringResponsibility)), sentinel, taskbar, text));
|
||||
responsibilities.Enqueue(new NetworkResponsibility(context, ModuleLogger(nameof(NetworkResponsibility)), networkAdapter, text, uiFactory));
|
||||
responsibilities.Enqueue(new ProctoringResponsibility(context, ModuleLogger(nameof(ProctoringResponsibility)), uiFactory));
|
||||
responsibilities.Enqueue(new ProctoringResponsibility(context, ModuleLogger(nameof(ProctoringResponsibility)), messageBox, uiFactory));
|
||||
responsibilities.Enqueue(new ServerResponsibility(context, coordinator, ModuleLogger(nameof(ServerResponsibility)), text));
|
||||
responsibilities.Enqueue(new ShellResponsibility(actionCenter, context, new HashAlgorithm(), ModuleLogger(nameof(ShellResponsibility)), messageBox, taskbar, uiFactory));
|
||||
|
||||
@@ -337,7 +342,8 @@ namespace SafeExamBrowser.Client
|
||||
{
|
||||
var keyGenerator = new KeyGenerator(context.AppConfig, context.IntegrityModule, ModuleLogger(nameof(KeyGenerator)));
|
||||
var server = new ServerProxy(context.AppConfig, keyGenerator, ModuleLogger(nameof(ServerProxy)), systemInfo, userInfo, powerSupply, networkAdapter);
|
||||
var operation = new ServerOperation(context, logger, server);
|
||||
var invigilator = new Invigilator(ModuleLogger(nameof(Invigilator)), server);
|
||||
var operation = new ServerOperation(actionCenter, context, invigilator, logger, server, taskbar, uiFactory);
|
||||
|
||||
context.Server = server;
|
||||
|
||||
@@ -381,9 +387,9 @@ namespace SafeExamBrowser.Client
|
||||
switch (uiMode)
|
||||
{
|
||||
case UserInterfaceMode.Mobile:
|
||||
return new Mobile.FileSystemDialogFactory(systemInfo, text);
|
||||
return new Mobile.FileSystemDialogFactory(systemInfo, text, windowGuard);
|
||||
default:
|
||||
return new Desktop.FileSystemDialogFactory(systemInfo, text);
|
||||
return new Desktop.FileSystemDialogFactory(systemInfo, text, windowGuard);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,9 +409,9 @@ namespace SafeExamBrowser.Client
|
||||
switch (uiMode)
|
||||
{
|
||||
case UserInterfaceMode.Mobile:
|
||||
return new Mobile.UserInterfaceFactory(text);
|
||||
return new Mobile.UserInterfaceFactory(text, windowGuard);
|
||||
default:
|
||||
return new Desktop.UserInterfaceFactory(text);
|
||||
return new Desktop.UserInterfaceFactory(text, windowGuard);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,12 +16,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||
/// </summary>
|
||||
internal abstract class ClientOperation : IOperation
|
||||
{
|
||||
protected ClientContext Context { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// TODO: In case this event is neither used by the runtime, either remove it completely or then move it to a separate interface!
|
||||
/// </summary>
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
protected ClientContext Context { get; }
|
||||
|
||||
public abstract event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
|
60
SafeExamBrowser.Client/Operations/PermissionOperation.cs
Normal file
60
SafeExamBrowser.Client/Operations/PermissionOperation.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2025 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.SystemComponents.Contracts.Network;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
{
|
||||
internal class PermissionOperation : ClientOperation
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly INetworkAdapter networkAdapter;
|
||||
|
||||
public override event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public PermissionOperation(ClientContext context, ILogger logger, INetworkAdapter networkAdapter) : base(context)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.networkAdapter = networkAdapter;
|
||||
}
|
||||
|
||||
public override OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing permissions...");
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_InitializePermissions);
|
||||
|
||||
RequestNetworkAdapterAccess();
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public override OperationResult Revert()
|
||||
{
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
private void RequestNetworkAdapterAccess()
|
||||
{
|
||||
var granted = networkAdapter.RequestAccess();
|
||||
|
||||
if (granted)
|
||||
{
|
||||
logger.Info("Permission to access the wireless networking functionality has been granted.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Permission to access the wireless networking functionality has not been granted! " +
|
||||
"If required, please grant the location permission manually under 'Privacy & Security' in the system settings.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,7 +11,6 @@ using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Proctoring.Contracts;
|
||||
using SafeExamBrowser.Settings;
|
||||
using SafeExamBrowser.UserInterface.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
|
||||
@@ -51,12 +50,6 @@ namespace SafeExamBrowser.Client.Operations
|
||||
|
||||
controller.Initialize(Context.Settings.Proctoring);
|
||||
|
||||
if (Context.Settings.SessionMode == SessionMode.Server && Context.Settings.Proctoring.ShowRaiseHandNotification)
|
||||
{
|
||||
actionCenter.AddNotificationControl(uiFactory.CreateRaiseHandControl(controller, Location.ActionCenter, Context.Settings.Proctoring));
|
||||
taskbar.AddNotificationControl(uiFactory.CreateRaiseHandControl(controller, Location.Taskbar, Context.Settings.Proctoring));
|
||||
}
|
||||
|
||||
foreach (var notification in controller.Notifications)
|
||||
{
|
||||
actionCenter.AddNotificationControl(uiFactory.CreateNotificationControl(notification, Location.ActionCenter));
|
||||
|
@@ -12,20 +12,37 @@ using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Server.Contracts;
|
||||
using SafeExamBrowser.Settings;
|
||||
using SafeExamBrowser.UserInterface.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
{
|
||||
internal class ServerOperation : ClientOperation
|
||||
{
|
||||
private readonly IActionCenter actionCenter;
|
||||
private readonly IInvigilator invigilator;
|
||||
private readonly ILogger logger;
|
||||
private readonly IServerProxy server;
|
||||
private readonly ITaskbar taskbar;
|
||||
private readonly IUserInterfaceFactory uiFactory;
|
||||
|
||||
public override event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ServerOperation(ClientContext context, ILogger logger, IServerProxy server) : base(context)
|
||||
public ServerOperation(
|
||||
IActionCenter actionCenter,
|
||||
ClientContext context,
|
||||
IInvigilator invigilator,
|
||||
ILogger logger,
|
||||
IServerProxy server,
|
||||
ITaskbar taskbar,
|
||||
IUserInterfaceFactory uiFactory) : base(context)
|
||||
{
|
||||
this.actionCenter = actionCenter;
|
||||
this.invigilator = invigilator;
|
||||
this.logger = logger;
|
||||
this.server = server;
|
||||
this.taskbar = taskbar;
|
||||
this.uiFactory = uiFactory;
|
||||
}
|
||||
|
||||
public override OperationResult Perform()
|
||||
@@ -42,6 +59,14 @@ namespace SafeExamBrowser.Client.Operations
|
||||
Context.AppConfig.ServerOauth2Token,
|
||||
Context.Settings.Server);
|
||||
server.StartConnectivity();
|
||||
|
||||
if (Context.Settings.Server.Invigilation.ShowRaiseHandNotification)
|
||||
{
|
||||
invigilator.Initialize(Context.Settings.Server.Invigilation);
|
||||
|
||||
actionCenter.AddNotificationControl(uiFactory.CreateRaiseHandControl(invigilator, Location.ActionCenter, Context.Settings.Server.Invigilation));
|
||||
taskbar.AddNotificationControl(uiFactory.CreateRaiseHandControl(invigilator, Location.Taskbar, Context.Settings.Server.Invigilation));
|
||||
}
|
||||
}
|
||||
|
||||
return OperationResult.Success;
|
||||
|
@@ -83,7 +83,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||
InitializeSystemComponents();
|
||||
InitializeActionCenter();
|
||||
InitializeTaskbar();
|
||||
InitializeTaskview();
|
||||
//InitializeTaskview();
|
||||
InitializeActivators();
|
||||
InitializeAlwaysOnState();
|
||||
|
||||
@@ -112,11 +112,11 @@ namespace SafeExamBrowser.Client.Operations
|
||||
actionCenterActivator.Start();
|
||||
}
|
||||
|
||||
if (Context.Settings.Keyboard.AllowAltTab && activator is ITaskviewActivator taskViewActivator)
|
||||
{
|
||||
taskview.Register(taskViewActivator);
|
||||
taskViewActivator.Start();
|
||||
}
|
||||
//if (Context.Settings.Keyboard.AllowAltTab && activator is ITaskviewActivator taskViewActivator)
|
||||
//{
|
||||
// taskview.Register(taskViewActivator);
|
||||
// taskViewActivator.Start();
|
||||
//}
|
||||
|
||||
if (Context.Settings.Security.AllowTermination && activator is ITerminationActivator terminationActivator)
|
||||
{
|
||||
|
54
SafeExamBrowser.Client/Operations/WindowGuardOperation.cs
Normal file
54
SafeExamBrowser.Client/Operations/WindowGuardOperation.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2025 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.UserInterface.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
{
|
||||
internal class WindowGuardOperation : ClientOperation
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly IWindowGuard guard;
|
||||
|
||||
public WindowGuardOperation(ClientContext context, ILogger logger, IWindowGuard guard) : base(context)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.guard = guard;
|
||||
}
|
||||
|
||||
public override event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public override OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing window guard...");
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeWindowGuard);
|
||||
|
||||
if (Context.Settings.Proctoring.Enabled || Context.Settings.Security.AllowWindowCapture)
|
||||
{
|
||||
guard.Deactivate();
|
||||
logger.Info($"Deactivated window guard because {(Context.Settings.Proctoring.Enabled ? "proctoring" : "window capturing")} is enabled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
guard.Activate();
|
||||
logger.Info("Activated window guard.");
|
||||
}
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public override OperationResult Revert()
|
||||
{
|
||||
return OperationResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
@@ -51,6 +51,6 @@ using System.Windows;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("3.9.0.787")]
|
||||
[assembly: AssemblyFileVersion("3.9.0.787")]
|
||||
[assembly: AssemblyVersion("3.10.0.826")]
|
||||
[assembly: AssemblyFileVersion("3.10.0.826")]
|
||||
[assembly: AssemblyInformationalVersion("1.0.0.0")]
|
||||
|
@@ -40,6 +40,20 @@ namespace SafeExamBrowser.Client.Responsibilities
|
||||
}
|
||||
}
|
||||
|
||||
protected bool IsValidQuitPassword(string password)
|
||||
{
|
||||
var actual = Context.HashAlgorithm.GenerateHashFor(password);
|
||||
var expected = Settings.Security.QuitPasswordHash;
|
||||
var valid = expected.Equals(actual, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (valid)
|
||||
{
|
||||
Context.QuitPasswordValidated = true;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
protected void PrepareShutdown()
|
||||
{
|
||||
Context.Responsibilities.Delegate(ClientTask.PrepareShutdown_Wave1);
|
||||
@@ -56,72 +70,30 @@ namespace SafeExamBrowser.Client.Responsibilities
|
||||
|
||||
protected LockScreenResult ShowLockScreen(string message, string title, IEnumerable<LockScreenOption> options)
|
||||
{
|
||||
var hasQuitPassword = !string.IsNullOrEmpty(Settings.Security.QuitPasswordHash);
|
||||
var result = default(LockScreenResult);
|
||||
|
||||
Context.LockScreen = Context.UserInterfaceFactory.CreateLockScreen(message, title, options, Settings.UserInterface.LockScreen);
|
||||
Logger.Info("Showing lock screen...");
|
||||
|
||||
PauseActivators();
|
||||
Context.LockScreen = Context.UserInterfaceFactory.CreateLockScreen(message, title, options, Settings.UserInterface.LockScreen);
|
||||
Context.LockScreen.Show();
|
||||
|
||||
if (Settings.SessionMode == SessionMode.Server)
|
||||
{
|
||||
var response = Context.Server.LockScreen(message);
|
||||
|
||||
if (!response.Success)
|
||||
{
|
||||
Logger.Error($"Failed to send lock screen notification to server! Message: {response.Message}.");
|
||||
}
|
||||
SendLockScreenNotification(message);
|
||||
}
|
||||
|
||||
for (var unlocked = false; !unlocked;)
|
||||
{
|
||||
result = Context.LockScreen.WaitForResult();
|
||||
|
||||
if (result.Canceled)
|
||||
{
|
||||
Logger.Info("The lock screen has been automaticaly canceled.");
|
||||
unlocked = true;
|
||||
}
|
||||
else if (hasQuitPassword)
|
||||
{
|
||||
var passwordHash = Context.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.");
|
||||
Context.MessageBox.Show(TextKey.MessageBox_InvalidUnlockPassword, TextKey.MessageBox_InvalidUnlockPasswordTitle, icon: MessageBoxIcon.Warning, parent: Context.LockScreen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warn($"No unlock password is defined, allowing user to resume session!");
|
||||
unlocked = true;
|
||||
}
|
||||
}
|
||||
var result = WaitForLockScreenResolution();
|
||||
|
||||
Context.LockScreen.Close();
|
||||
Context.LockScreen = default;
|
||||
ResumeActivators();
|
||||
|
||||
Logger.Info("Closed lock screen.");
|
||||
|
||||
if (Settings.SessionMode == SessionMode.Server)
|
||||
{
|
||||
var response = Context.Server.ConfirmLockScreen();
|
||||
|
||||
if (!response.Success)
|
||||
{
|
||||
Logger.Error($"Failed to send lock screen confirm notification to server! Message: {response.Message}.");
|
||||
}
|
||||
SendLockScreenConfirmation();
|
||||
}
|
||||
|
||||
Logger.Info("Closed lock screen.");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -139,5 +111,65 @@ namespace SafeExamBrowser.Client.Responsibilities
|
||||
|
||||
return communication.Success;
|
||||
}
|
||||
|
||||
private void SendLockScreenConfirmation()
|
||||
{
|
||||
var response = Context.Server.ConfirmLockScreen();
|
||||
|
||||
if (!response.Success)
|
||||
{
|
||||
Logger.Error($"Failed to send lock screen confirmation to server! Message: {response.Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
private void SendLockScreenNotification(string message)
|
||||
{
|
||||
var response = Context.Server.LockScreen(message);
|
||||
|
||||
if (!response.Success)
|
||||
{
|
||||
Logger.Error($"Failed to send lock screen notification to server! Message: {response.Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
private LockScreenResult WaitForLockScreenResolution()
|
||||
{
|
||||
var hasQuitPassword = !string.IsNullOrEmpty(Settings.Security.QuitPasswordHash);
|
||||
var result = default(LockScreenResult);
|
||||
|
||||
for (var unlocked = false; !unlocked;)
|
||||
{
|
||||
result = Context.LockScreen.WaitForResult();
|
||||
|
||||
if (result.Canceled)
|
||||
{
|
||||
Logger.Info("The lock screen has been canceled automatically.");
|
||||
unlocked = true;
|
||||
}
|
||||
else if (hasQuitPassword)
|
||||
{
|
||||
var passwordHash = Context.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 a wrong unlock password.");
|
||||
Context.MessageBox.Show(TextKey.MessageBox_InvalidUnlockPassword, TextKey.MessageBox_InvalidUnlockPasswordTitle, icon: MessageBoxIcon.Warning, parent: Context.LockScreen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warn($"No unlock password is defined, allowing user to resume session!");
|
||||
unlocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Win32;
|
||||
using SafeExamBrowser.Client.Contracts;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
@@ -251,23 +252,29 @@ namespace SafeExamBrowser.Client.Responsibilities
|
||||
}
|
||||
}
|
||||
|
||||
private void Sentinel_SessionChanged()
|
||||
private void Sentinel_SessionChanged(SessionSwitchReason reason)
|
||||
{
|
||||
var allow = !Settings.Service.IgnoreService && (!Settings.Service.DisableUserLock || !Settings.Service.DisableUserSwitch);
|
||||
var disable = Settings.Security.DisableSessionChangeLockScreen;
|
||||
|
||||
if (allow || disable)
|
||||
var allowed = !Settings.Service.IgnoreService && (!Settings.Service.DisableUserLock || !Settings.Service.DisableUserSwitch);
|
||||
var disabled = Settings.Security.DisableSessionChangeLockScreen;
|
||||
var ignore = Settings.Service.IgnoreService && (reason == SessionSwitchReason.SessionLock || reason == SessionSwitchReason.SessionUnlock);
|
||||
|
||||
if (allowed || disabled)
|
||||
{
|
||||
Logger.Info($"Detected user session change, but {(allow ? "session locking and/or switching is allowed" : "lock screen is deactivated")}.");
|
||||
Logger.Info($"Detected user session change ({reason}), but {(allowed ? "session locking and/or switching is allowed" : "lock screen is disabled")}.");
|
||||
}
|
||||
else if (ignore)
|
||||
{
|
||||
Logger.Info($"Ignoring user session change ({reason}).");
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = text.Get(TextKey.LockScreen_UserSessionMessage);
|
||||
var message = text.Get(Settings.Service.IgnoreService ? TextKey.LockScreen_UserSwitchMessage : 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("User session changed! Attempting to show lock screen...");
|
||||
Logger.Warn($"User session changed ({reason})! Attempting to show lock screen...");
|
||||
|
||||
if (coordinator.RequestSessionLock())
|
||||
{
|
||||
|
@@ -7,21 +7,33 @@
|
||||
*/
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Proctoring.Contracts;
|
||||
using SafeExamBrowser.Proctoring.Contracts.Events;
|
||||
using SafeExamBrowser.UserInterface.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Proctoring;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Proctoring.Events;
|
||||
|
||||
namespace SafeExamBrowser.Client.Responsibilities
|
||||
{
|
||||
internal class ProctoringResponsibility : ClientResponsibility
|
||||
{
|
||||
private readonly IMessageBox messageBox;
|
||||
private readonly IUserInterfaceFactory uiFactory;
|
||||
|
||||
private bool cancel;
|
||||
|
||||
private IProctoringController Proctoring => Context.Proctoring;
|
||||
|
||||
public ProctoringResponsibility(ClientContext context, ILogger logger, IUserInterfaceFactory uiFactory) : base(context, logger)
|
||||
public ProctoringResponsibility(
|
||||
ClientContext context,
|
||||
ILogger logger,
|
||||
IMessageBox messageBox,
|
||||
IUserInterfaceFactory uiFactory) : base(context, logger)
|
||||
{
|
||||
this.messageBox = messageBox;
|
||||
this.uiFactory = uiFactory;
|
||||
}
|
||||
|
||||
@@ -37,8 +49,10 @@ namespace SafeExamBrowser.Client.Responsibilities
|
||||
{
|
||||
if (Proctoring != default && Proctoring.HasRemainingWork())
|
||||
{
|
||||
var dialog = uiFactory.CreateProctoringFinalizationDialog();
|
||||
var handler = new RemainingWorkUpdatedEventHandler((args) => dialog.Update(args));
|
||||
var dialog = uiFactory.CreateProctoringFinalizationDialog(!Context.QuitPasswordValidated);
|
||||
var handler = new RemainingWorkUpdatedEventHandler((args) => Proctoring_RemainingWorkUpdated(dialog, args));
|
||||
|
||||
dialog.CancellationRequested += new CancellationRequestedEventHandler(() => Dialog_CancellationRequested(dialog));
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
@@ -50,5 +64,28 @@ namespace SafeExamBrowser.Client.Responsibilities
|
||||
dialog.Show();
|
||||
}
|
||||
}
|
||||
|
||||
private void Dialog_CancellationRequested(IProctoringFinalizationDialog dialog)
|
||||
{
|
||||
var alreadyValidated = Context.QuitPasswordValidated;
|
||||
|
||||
if (alreadyValidated || IsValidQuitPassword(dialog.QuitPassword))
|
||||
{
|
||||
cancel = true;
|
||||
Logger.Info($"The user {(alreadyValidated ? "already " : "")}entered the correct quit password, cancelling remaining work...");
|
||||
}
|
||||
else
|
||||
{
|
||||
cancel = false;
|
||||
Logger.Info("The user entered the wrong quit password, remaining work will continue.");
|
||||
messageBox.Show(TextKey.MessageBox_InvalidQuitPassword, TextKey.MessageBox_InvalidQuitPasswordTitle, icon: MessageBoxIcon.Warning, parent: dialog);
|
||||
}
|
||||
}
|
||||
|
||||
private void Proctoring_RemainingWorkUpdated(IProctoringFinalizationDialog dialog, RemainingWorkUpdatedEventArgs args)
|
||||
{
|
||||
dialog.Update(args);
|
||||
args.CancellationRequested = cancel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using SafeExamBrowser.Configuration.Contracts.Cryptography;
|
||||
@@ -134,14 +133,14 @@ namespace SafeExamBrowser.Client.Responsibilities
|
||||
{
|
||||
var hasQuitPassword = !string.IsNullOrEmpty(Settings.Security.QuitPasswordHash);
|
||||
var initiateShutdown = hasQuitPassword ? TryValidateQuitPassword() : TryConfirmShutdown();
|
||||
var succes = false;
|
||||
var success = false;
|
||||
|
||||
if (initiateShutdown)
|
||||
{
|
||||
succes = TryRequestShutdown();
|
||||
success = TryRequestShutdown();
|
||||
}
|
||||
|
||||
return succes;
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TryConfirmShutdown()
|
||||
@@ -161,26 +160,20 @@ namespace SafeExamBrowser.Client.Responsibilities
|
||||
{
|
||||
var dialog = uiFactory.CreatePasswordDialog(TextKey.PasswordDialog_QuitPasswordRequired, TextKey.PasswordDialog_QuitPasswordRequiredTitle);
|
||||
var result = dialog.Show();
|
||||
var success = false;
|
||||
|
||||
if (result.Success)
|
||||
if (result.Success && IsValidQuitPassword(result.Password))
|
||||
{
|
||||
var passwordHash = hashAlgorithm.GenerateHashFor(result.Password);
|
||||
var isCorrect = Settings.Security.QuitPasswordHash.Equals(passwordHash, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (isCorrect)
|
||||
{
|
||||
Logger.Info("The user entered the correct quit password, the application will now terminate.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info("The user entered the wrong quit password.");
|
||||
messageBox.Show(TextKey.MessageBox_InvalidQuitPassword, TextKey.MessageBox_InvalidQuitPasswordTitle, icon: MessageBoxIcon.Warning);
|
||||
}
|
||||
|
||||
return isCorrect;
|
||||
success = true;
|
||||
Logger.Info("The user entered the correct quit password, the application will now terminate.");
|
||||
}
|
||||
else if (result.Success)
|
||||
{
|
||||
Logger.Info("The user entered the wrong quit password.");
|
||||
messageBox.Show(TextKey.MessageBox_InvalidQuitPassword, TextKey.MessageBox_InvalidQuitPasswordTitle, icon: MessageBoxIcon.Warning);
|
||||
}
|
||||
|
||||
return false;
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -80,6 +80,7 @@
|
||||
<Compile Include="Operations\ClientOperation.cs" />
|
||||
<Compile Include="Operations\ClientOperationSequence.cs" />
|
||||
<Compile Include="Operations\ConfigurationOperation.cs" />
|
||||
<Compile Include="Operations\PermissionOperation.cs" />
|
||||
<Compile Include="Operations\ProctoringOperation.cs" />
|
||||
<Compile Include="Operations\RuntimeConnectionOperation.cs" />
|
||||
<Compile Include="Communication\ClientHost.cs" />
|
||||
@@ -94,6 +95,7 @@
|
||||
<Compile Include="Operations\ApplicationOperation.cs" />
|
||||
<Compile Include="Operations\ServerOperation.cs" />
|
||||
<Compile Include="Operations\ShellOperation.cs" />
|
||||
<Compile Include="Operations\WindowGuardOperation.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
Reference in New Issue
Block a user