SEBWIN-714, #606: Implemented basic cursor functionality. Minor refactoring of registry and file system dialog classes.
This commit is contained in:
parent
fa16710bdb
commit
722d84978c
22 changed files with 392 additions and 202 deletions
|
@ -335,36 +335,50 @@ namespace SafeExamBrowser.Client
|
|||
var timer = new System.Timers.Timer();
|
||||
|
||||
timer.AutoReset = false;
|
||||
timer.Elapsed += (o, args) =>
|
||||
{
|
||||
logger.Info($"Attempting to verify application integrity...");
|
||||
|
||||
if (IntegrityModule.TryVerifyCodeSignature(out var isValid))
|
||||
{
|
||||
if (isValid)
|
||||
{
|
||||
logger.Info("Application integrity successfully verified.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Application integrity is compromised!");
|
||||
ShowLockScreen(text.Get(TextKey.LockScreen_ApplicationIntegrityMessage), text.Get(TextKey.LockScreen_Title), Enumerable.Empty<LockScreenOption>());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Failed to verify application integrity!");
|
||||
}
|
||||
};
|
||||
timer.Elapsed += (o, args) => VerifyApplicationIntegrity();
|
||||
timer.Interval = TEN_MINUTES + (new Random().NextDouble() * FIVE_MINUTES);
|
||||
timer.Start();
|
||||
|
||||
if (registry.TryGetNames(RegistryValue.UserHive.Cursors_Key, out var names))
|
||||
{
|
||||
foreach (var name in names)
|
||||
{
|
||||
registry.StartMonitoring(RegistryValue.UserHive.Cursors_Key, name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Failed to start monitoring cursor registry values!");
|
||||
}
|
||||
|
||||
if (Settings.Service.IgnoreService)
|
||||
{
|
||||
registry.StartMonitoring(RegistryValue.MachineHive.EaseOfAccess_Key, RegistryValue.MachineHive.EaseOfAccess_Name);
|
||||
}
|
||||
}
|
||||
|
||||
private void VerifyApplicationIntegrity()
|
||||
{
|
||||
logger.Info($"Attempting to verify application integrity...");
|
||||
|
||||
if (IntegrityModule.TryVerifyCodeSignature(out var isValid))
|
||||
{
|
||||
if (isValid)
|
||||
{
|
||||
logger.Info("Application integrity successfully verified.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Application integrity is compromised!");
|
||||
ShowLockScreen(text.Get(TextKey.LockScreen_ApplicationIntegrityMessage), text.Get(TextKey.LockScreen_Title), Enumerable.Empty<LockScreenOption>());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Failed to verify application integrity!");
|
||||
}
|
||||
}
|
||||
|
||||
private void VerifySessionIntegrity()
|
||||
{
|
||||
var hasQuitPassword = !string.IsNullOrEmpty(Settings.Security.QuitPasswordHash);
|
||||
|
@ -701,9 +715,55 @@ namespace SafeExamBrowser.Client
|
|||
splashScreen.UpdateStatus(status, true);
|
||||
}
|
||||
|
||||
private void Registry_ValueChanged(object oldValue, object newValue)
|
||||
private void Registry_ValueChanged(string key, string name, object oldValue, object newValue)
|
||||
{
|
||||
logger.Warn($"The ease of access registry value has changed from '{oldValue}' to '{newValue}'! Attempting to show lock screen...");
|
||||
if (key == RegistryValue.UserHive.Cursors_Key)
|
||||
{
|
||||
HandleCursorRegistryChange(key, name, oldValue, newValue);
|
||||
}
|
||||
else if (key == RegistryValue.MachineHive.EaseOfAccess_Key)
|
||||
{
|
||||
HandleEaseOfAccessRegistryChange(key, name, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCursorRegistryChange(string key, string name, object oldValue, object newValue)
|
||||
{
|
||||
logger.Warn($@"The cursor registry value '{key}\{name}' has changed from '{oldValue}' to '{newValue}'! Attempting to show lock screen...");
|
||||
|
||||
if (!sessionLocked)
|
||||
{
|
||||
var message = text.Get(TextKey.LockScreen_CursorMessage);
|
||||
var title = text.Get(TextKey.LockScreen_Title);
|
||||
var continueOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_CursorContinueOption) };
|
||||
var terminateOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_CursorTerminateOption) };
|
||||
|
||||
sessionLocked = true;
|
||||
registry.StopMonitoring(key, name);
|
||||
|
||||
var result = ShowLockScreen(message, title, new[] { continueOption, terminateOption });
|
||||
|
||||
if (result.OptionId == continueOption.Id)
|
||||
{
|
||||
logger.Info("The session will be allowed to resume as requested by the user...");
|
||||
}
|
||||
else 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 HandleEaseOfAccessRegistryChange(string key, string name, object oldValue, object newValue)
|
||||
{
|
||||
logger.Warn($@"The ease of access registry value '{key}\{name}' has changed from '{oldValue}' to '{newValue}'! Attempting to show lock screen...");
|
||||
|
||||
if (!sessionLocked)
|
||||
{
|
||||
|
@ -713,7 +773,7 @@ namespace SafeExamBrowser.Client
|
|||
var terminateOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_EaseOfAccessTerminateOption) };
|
||||
|
||||
sessionLocked = true;
|
||||
registry.StopMonitoring();
|
||||
registry.StopMonitoring(key, name);
|
||||
|
||||
var result = ShowLockScreen(message, title, new[] { continueOption, terminateOption });
|
||||
|
||||
|
|
|
@ -94,8 +94,9 @@ namespace SafeExamBrowser.Client
|
|||
InitializeLogging();
|
||||
InitializeText();
|
||||
|
||||
uiFactory = BuildUserInterfaceFactory();
|
||||
var registry = new Registry(ModuleLogger(nameof(Registry)));
|
||||
|
||||
uiFactory = BuildUserInterfaceFactory();
|
||||
actionCenter = uiFactory.CreateActionCenter();
|
||||
context = new ClientContext();
|
||||
messageBox = BuildMessageBox();
|
||||
|
@ -103,7 +104,7 @@ namespace SafeExamBrowser.Client
|
|||
networkAdapter = new NetworkAdapter(ModuleLogger(nameof(NetworkAdapter)), nativeMethods);
|
||||
powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
|
||||
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), ModuleLogger(nameof(RuntimeProxy)), Interlocutor.Client);
|
||||
systemInfo = new SystemInfo();
|
||||
systemInfo = new SystemInfo(registry);
|
||||
taskbar = uiFactory.CreateTaskbar(ModuleLogger("Taskbar"));
|
||||
taskview = uiFactory.CreateTaskview();
|
||||
userInfo = new UserInfo(ModuleLogger(nameof(UserInfo)));
|
||||
|
@ -116,7 +117,6 @@ namespace SafeExamBrowser.Client
|
|||
var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods);
|
||||
var fileSystemDialog = BuildFileSystemDialog();
|
||||
var hashAlgorithm = new HashAlgorithm();
|
||||
var registry = new Registry(ModuleLogger(nameof(Registry)));
|
||||
var splashScreen = uiFactory.CreateSplashScreen();
|
||||
var systemMonitor = new SystemMonitor(ModuleLogger(nameof(SystemMonitor)));
|
||||
|
||||
|
@ -335,9 +335,9 @@ namespace SafeExamBrowser.Client
|
|||
switch (uiMode)
|
||||
{
|
||||
case UserInterfaceMode.Mobile:
|
||||
return new Mobile.FileSystemDialogFactory(text);
|
||||
return new Mobile.FileSystemDialogFactory(systemInfo, text);
|
||||
default:
|
||||
return new Desktop.FileSystemDialogFactory(text);
|
||||
return new Desktop.FileSystemDialogFactory(systemInfo, text);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,9 @@ namespace SafeExamBrowser.I18n.Contracts
|
|||
LockScreen_ApplicationsAllowOption,
|
||||
LockScreen_ApplicationsMessage,
|
||||
LockScreen_ApplicationsTerminateOption,
|
||||
LockScreen_CursorContinueOption,
|
||||
LockScreen_CursorMessage,
|
||||
LockScreen_CursorTerminateOption,
|
||||
LockScreen_DisplayConfigurationContinueOption,
|
||||
LockScreen_DisplayConfigurationMessage,
|
||||
LockScreen_DisplayConfigurationTerminateOption,
|
||||
|
|
|
@ -162,6 +162,15 @@
|
|||
<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!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorContinueOption">
|
||||
Die Cursor-Konfiguration vorübergehend zulassen. Dies gilt nur für die momentan laufende Sitzung!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorMessage">
|
||||
Eine verbotene Cursor-Konfiguration wurde detektiert. 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_CursorTerminateOption">
|
||||
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="LockScreen_DisplayConfigurationContinueOption">
|
||||
Bildschirm-Konfiguration temporär erlauben. Dies gilt nur für die momentan laufende Sitzung!
|
||||
</Entry>
|
||||
|
|
|
@ -162,6 +162,15 @@
|
|||
<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!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorContinueOption">
|
||||
Temporarily allow the cursor configuration. This applies only to the currently running session!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorMessage">
|
||||
A prohibited cursor configuration has been detected. In order to unlock SEB, please select one of the available options and enter the correct unlock password.
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorTerminateOption">
|
||||
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="LockScreen_DisplayConfigurationContinueOption">
|
||||
Temporarily allow the display configuration. This applies only to the currently running session!
|
||||
</Entry>
|
||||
|
|
|
@ -162,6 +162,15 @@
|
|||
<Entry key="LockScreen_ApplicationsTerminateOption">
|
||||
Finalizar Safe Exam Browser. ADVERTENCIA: No habrá posibilidad de guardar datos o realizar ninguna otra acción, ¡el cierre se iniciará inmediatamente!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorContinueOption">
|
||||
Permitir temporalmente la configuración del cursor. Esto sólo se aplica a la sesión que se está ejecutando en ese momento.
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorMessage">
|
||||
Se ha detectado una configuración de cursor prohibida. Para desbloquear SEB, seleccione una de las opciones disponibles e introduzca la contraseña de desbloqueo correcta.
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorTerminateOption">
|
||||
Finalizar Safe Exam Browser. ADVERTENCIA: No habrá posibilidad de guardar datos o realizar ninguna otra acción, ¡el cierre se iniciará inmediatamente!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_DisplayConfigurationContinueOption">
|
||||
Permitir temporalmente la configuración de la pantalla. Esto sólo se aplica a la sesión que se está ejecutando en ese momento.
|
||||
</Entry>
|
||||
|
|
|
@ -162,6 +162,15 @@
|
|||
<Entry key="LockScreen_ApplicationsTerminateOption">
|
||||
Terminer Safe Exam Browser. AVERTISSEMENT: Il n'y aura aucune possibilité de sauvegarder les données ou d'effectuer d'autres actions, la fermeture sera initiée immédiatement!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorContinueOption">
|
||||
Autoriser temporairement la configuration du curseur. Ceci s'applique uniquement à la session en cours!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorMessage">
|
||||
Une configuration interdite du curseur a été détectée. Pour déverrouiller SEB, veuillez sélectionner l'une des options disponibles et saisir le mot de passe de déverrouillage correct.
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorTerminateOption">
|
||||
Terminer Safe Exam Browser. AVERTISSEMENT: Il n'y aura aucune possibilité de sauvegarder les données ou d'effectuer d'autres actions, la fermeture sera initiée immédiatement!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_DisplayConfigurationContinueOption">
|
||||
Autoriser temporairement la configuration de l'affichage. Ceci s'applique uniquement à la session en cours!
|
||||
</Entry>
|
||||
|
|
|
@ -162,6 +162,15 @@
|
|||
<Entry key="LockScreen_ApplicationsTerminateOption">
|
||||
Terminare Safe Exam Browser. ATTENZIONE: Non sarà possibile salvare i dati o eseguire ulteriori azioni, la chiusura verrà avviata immediatamente!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorContinueOption">
|
||||
Consente temporaneamente la configurazione del cursore. Questo vale solo per la sessione in corso!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorMessage">
|
||||
È stata rilevata una configurazione del cursore non consentita. Per sbloccare SEB, seleziona una delle opzioni disponibili e inserisci la password di sblocco corretta.
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorTerminateOption">
|
||||
Terminare Safe Exam Browser. ATTENZIONE: Non sarà possibile salvare i dati o eseguire ulteriori azioni, la chiusura verrà avviata immediatamente!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_DisplayConfigurationContinueOption">
|
||||
Consenti temporaneamente la configurazione del display. Questo vale solo per la sessione attualmente in esecuzione!
|
||||
</Entry>
|
||||
|
|
|
@ -147,6 +147,15 @@
|
|||
<Entry key="LockScreen_ApplicationsTerminateOption">
|
||||
强制关闭防作弊考试专用浏览器。警告:将无法保存数据或执行任何进一步的操作,关闭操作将立即启动。
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorContinueOption">
|
||||
暂时允许光标配置。这仅适用于当前运行的会话!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorMessage">
|
||||
已检测到禁止的光标配置。要解锁 SEB,请选择一个可用选项并输入正确的解锁密码。
|
||||
</Entry>
|
||||
<Entry key="LockScreen_CursorTerminateOption">
|
||||
终止安全考试浏览器。警告:将无法保存数据或执行任何其他操作,系统将立即关闭!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_DisplayConfigurationContinueOption">
|
||||
暂时允许显示配置。 这仅适用于当前正在运行的会话!
|
||||
</Entry>
|
||||
|
|
|
@ -54,16 +54,18 @@ namespace SafeExamBrowser.Runtime
|
|||
const int THIRTY_SECONDS = 30000;
|
||||
|
||||
logger = new Logger();
|
||||
systemInfo = new SystemInfo();
|
||||
|
||||
InitializeConfiguration();
|
||||
InitializeLogging();
|
||||
InitializeText();
|
||||
|
||||
var nativeMethods = new NativeMethods();
|
||||
var registry = new Registry(ModuleLogger(nameof(Registry)));
|
||||
var uiFactory = new UserInterfaceFactory(text);
|
||||
var userInfo = new UserInfo(ModuleLogger(nameof(UserInfo)));
|
||||
|
||||
systemInfo = new SystemInfo(registry);
|
||||
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
var integrityModule = new IntegrityModule(appConfig, ModuleLogger(nameof(IntegrityModule)));
|
||||
var desktopFactory = new DesktopFactory(ModuleLogger(nameof(DesktopFactory)));
|
||||
|
@ -75,7 +77,6 @@ namespace SafeExamBrowser.Runtime
|
|||
var messageBox = new MessageBoxFactory(text);
|
||||
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
|
||||
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), ModuleLogger(nameof(ProxyFactory)));
|
||||
var registry = new Registry(ModuleLogger(nameof(Registry)));
|
||||
var remoteSessionDetector = new RemoteSessionDetector(ModuleLogger(nameof(RemoteSessionDetector)));
|
||||
var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), ModuleLogger(nameof(RuntimeHost)), FIVE_SECONDS);
|
||||
var runtimeWindow = uiFactory.CreateRuntimeWindow(appConfig);
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
|
@ -32,14 +34,28 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
{
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_VerifySessionIntegrity);
|
||||
|
||||
return VerifyEaseOfAccessConfiguration();
|
||||
var success = VerifyCursorConfiguration();
|
||||
|
||||
if (success)
|
||||
{
|
||||
success = VerifyEaseOfAccessConfiguration();
|
||||
}
|
||||
|
||||
return success ? OperationResult.Success : OperationResult.Failed;
|
||||
}
|
||||
|
||||
public override OperationResult Repeat()
|
||||
{
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_VerifySessionIntegrity);
|
||||
|
||||
return VerifyEaseOfAccessConfiguration();
|
||||
var success = VerifyCursorConfiguration();
|
||||
|
||||
if (success)
|
||||
{
|
||||
success = VerifyEaseOfAccessConfiguration();
|
||||
}
|
||||
|
||||
return success ? OperationResult.Success : OperationResult.Failed;
|
||||
}
|
||||
|
||||
public override OperationResult Revert()
|
||||
|
@ -47,9 +63,44 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
private OperationResult VerifyEaseOfAccessConfiguration()
|
||||
private bool VerifyCursorConfiguration()
|
||||
{
|
||||
var result = OperationResult.Failed;
|
||||
var success = true;
|
||||
var systemPath = $@"{Environment.ExpandEnvironmentVariables("%SystemRoot%")}\cursors\";
|
||||
|
||||
logger.Info($"Attempting to verify cursor configuration...");
|
||||
|
||||
if (registry.TryGetNames(RegistryValue.UserHive.Cursors_Key, out var cursors))
|
||||
{
|
||||
foreach (var cursor in cursors.Where(c => !string.IsNullOrWhiteSpace(c)))
|
||||
{
|
||||
success &= registry.TryRead(RegistryValue.UserHive.Cursors_Key, cursor, out var value);
|
||||
success &= value == default || !(value is string) || (value is string path && (string.IsNullOrWhiteSpace(path) || path.StartsWith(systemPath)));
|
||||
|
||||
if (!success)
|
||||
{
|
||||
logger.Warn($"{(value != default ? $"Cursor configuration is compromised: '{value}'" : $"Failed to verify configuration of cursor '{cursor}'")}! Aborting session initialization...");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
logger.Info("Cursor configuration successfully verified.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error("Failed to verify cursor configuration!");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool VerifyEaseOfAccessConfiguration()
|
||||
{
|
||||
var success = false;
|
||||
|
||||
logger.Info($"Attempting to verify ease of access configuration...");
|
||||
|
||||
|
@ -57,12 +108,12 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
{
|
||||
if (value == default || (value is string s && string.IsNullOrWhiteSpace(s)))
|
||||
{
|
||||
result = OperationResult.Success;
|
||||
success = true;
|
||||
logger.Info("Ease of access configuration successfully verified.");
|
||||
}
|
||||
else if (!Context.Next.Settings.Service.IgnoreService)
|
||||
{
|
||||
result = OperationResult.Success;
|
||||
success = true;
|
||||
logger.Info($"Ease of access configuration is compromised ('{value}'), but service will be active in the next session.");
|
||||
}
|
||||
else
|
||||
|
@ -75,7 +126,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
logger.Error("Failed to verify ease of access configuration!");
|
||||
}
|
||||
|
||||
return result;
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SafeExamBrowser.SystemComponents.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -62,5 +65,10 @@ namespace SafeExamBrowser.SystemComponents.Contracts
|
|||
/// Provides the device ID information of the user's Plug and Play devices.
|
||||
/// </summary>
|
||||
string[] PlugAndPlayDeviceIds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves all logical drives of the computer system.
|
||||
/// </summary>
|
||||
IEnumerable<DriveInfo> GetDrives();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,5 +11,5 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Registry.Events
|
|||
/// <summary>
|
||||
/// Indicates that a registry value has changed.
|
||||
/// </summary>
|
||||
public delegate void RegistryValueChangedEventHandler(object oldValue, object newValue);
|
||||
public delegate void RegistryValueChangedEventHandler(string key, string name, object oldValue, object newValue);
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Registry.Events;
|
||||
using System.Collections.Generic;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Registry.Events;
|
||||
|
||||
namespace SafeExamBrowser.SystemComponents.Contracts.Registry
|
||||
{
|
||||
|
@ -31,6 +31,11 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Registry
|
|||
/// </summary>
|
||||
void StopMonitoring();
|
||||
|
||||
/// <summary>
|
||||
/// Stops the monitoring of the specified registry value.
|
||||
/// </summary>
|
||||
void StopMonitoring(string key, string name);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to read the value of the given name under the specified registry key.
|
||||
/// </summary>
|
||||
|
|
|
@ -22,6 +22,35 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Registry
|
|||
public const string AppPaths_Key = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths";
|
||||
public const string EaseOfAccess_Key = @"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Utilman.exe";
|
||||
public const string EaseOfAccess_Name = "Debugger";
|
||||
public const string HardwareConfig_Key = @"HKEY_LOCAL_MACHINE\SYSTEM\HardwareConfig";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All registry values located in the user hive.
|
||||
/// </summary>
|
||||
public static class UserHive
|
||||
{
|
||||
public const string Cursors_Key = @"HKEY_CURRENT_USER\Control Panel\Cursors";
|
||||
public const string Cursors_AppStarting_Name = "AppStarting";
|
||||
public const string Cursors_Arrow_Name = "Arrow";
|
||||
public const string Cursors_Crosshair_Name = "Crosshair";
|
||||
public const string Cursors_Hand_Name = "Hand";
|
||||
public const string Cursors_Help_Name = "Help";
|
||||
public const string Cursors_IBeam_Name = "IBeam";
|
||||
public const string Cursors_No_Name = "No";
|
||||
public const string Cursors_NWPen_Name = "NWPen";
|
||||
public const string Cursors_Person_Name = "Person";
|
||||
public const string Cursors_Pin_Name = "Pin";
|
||||
public const string Cursors_SizeAll_Name = "SizeAll";
|
||||
public const string Cursors_SizeNESW_Name = "SizeNESW";
|
||||
public const string Cursors_SizeNS_Name = "SizeNS";
|
||||
public const string Cursors_SizeNWSE_Name = "SizeNWSE";
|
||||
public const string Cursors_SizeWE_Name = "SizeWE";
|
||||
public const string Cursors_UpArrow_Name = "UpArrow";
|
||||
public const string Cursors_Wait_Name = "Wait";
|
||||
public const string DeviceCache_Key = @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\TaskFlow\DeviceCache";
|
||||
public const string NoDrives_Key = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer";
|
||||
public const string NoDrives_Name = "NoDrives";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Timers;
|
||||
using Microsoft.Win32;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
@ -21,7 +20,7 @@ namespace SafeExamBrowser.SystemComponents.Registry
|
|||
public class Registry : IRegistry
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly ConcurrentBag<(string key, string name, object value)> values;
|
||||
private readonly ConcurrentDictionary<(string key, string name), object> values;
|
||||
|
||||
private Timer timer;
|
||||
|
||||
|
@ -30,7 +29,7 @@ namespace SafeExamBrowser.SystemComponents.Registry
|
|||
public Registry(ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.values = new ConcurrentBag<(string key, string name, object value)>();
|
||||
this.values = new ConcurrentDictionary<(string key, string name), object>();
|
||||
}
|
||||
|
||||
public void StartMonitoring(string key, string name)
|
||||
|
@ -47,7 +46,7 @@ namespace SafeExamBrowser.SystemComponents.Registry
|
|||
|
||||
if (TryRead(key, name, out var value))
|
||||
{
|
||||
values.Add((key, name, value));
|
||||
values.TryAdd((key, name), value);
|
||||
logger.Debug($"Started monitoring value '{name}' from registry key '{key}'. Initial value: '{value}'.");
|
||||
}
|
||||
else
|
||||
|
@ -58,10 +57,7 @@ namespace SafeExamBrowser.SystemComponents.Registry
|
|||
|
||||
public void StopMonitoring()
|
||||
{
|
||||
while (!values.IsEmpty)
|
||||
{
|
||||
values.TryTake(out _);
|
||||
}
|
||||
values.Clear();
|
||||
|
||||
if (timer != null)
|
||||
{
|
||||
|
@ -70,19 +66,24 @@ namespace SafeExamBrowser.SystemComponents.Registry
|
|||
}
|
||||
}
|
||||
|
||||
public void StopMonitoring(string key, string name)
|
||||
{
|
||||
values.TryRemove((key, name), out _);
|
||||
}
|
||||
|
||||
public bool TryRead(string key, string name, out object value)
|
||||
{
|
||||
var success = true;
|
||||
var success = false;
|
||||
|
||||
value = default;
|
||||
|
||||
try
|
||||
{
|
||||
value = Microsoft.Win32.Registry.GetValue(key, name, default);
|
||||
success = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
success = false;
|
||||
logger.Error($"Failed to read value '{name}' from registry key '{key}'!", e);
|
||||
}
|
||||
|
||||
|
@ -93,155 +94,133 @@ namespace SafeExamBrowser.SystemComponents.Registry
|
|||
{
|
||||
names = default;
|
||||
|
||||
if (!TryOpenKey(keyName, out var key))
|
||||
if (TryOpenKey(keyName, out var key))
|
||||
{
|
||||
return false;
|
||||
using (key)
|
||||
{
|
||||
try
|
||||
{
|
||||
names = key.GetValueNames();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to get registry value names for '{keyName}'!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Failed to get names for '{keyName}'.");
|
||||
}
|
||||
|
||||
var success = true;
|
||||
using (key)
|
||||
{
|
||||
try
|
||||
{
|
||||
names = key.GetValueNames();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to get registry value names '{keyName}'!", e);
|
||||
success = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return success;
|
||||
return names != default;
|
||||
}
|
||||
|
||||
public bool TryGetSubKeys(string keyName, out IEnumerable<string> subKeys)
|
||||
{
|
||||
subKeys = default;
|
||||
|
||||
if (!TryOpenKey(keyName, out var key))
|
||||
if (TryOpenKey(keyName, out var key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var success = true;
|
||||
using (key)
|
||||
{
|
||||
try
|
||||
using (key)
|
||||
{
|
||||
subKeys = key.GetSubKeyNames();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to get registry value names '{keyName}'!", e);
|
||||
success = false;
|
||||
try
|
||||
{
|
||||
subKeys = key.GetSubKeyNames();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to get registry sub key names for '{keyName}'!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Failed to get sub keys for '{keyName}'.");
|
||||
}
|
||||
|
||||
return success;
|
||||
return subKeys != default;
|
||||
}
|
||||
|
||||
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
foreach (var item in values)
|
||||
{
|
||||
if (TryRead(item.key, item.name, out var value))
|
||||
if (TryRead(item.Key.key, item.Key.name, out var value))
|
||||
{
|
||||
if (item.value != value)
|
||||
if (!Equals(item.Value, value))
|
||||
{
|
||||
logger.Debug($"Value '{item.name}' from registry key '{item.key}' has changed from '{item.value}' to '{value}'!");
|
||||
ValueChanged?.Invoke(item.value, value);
|
||||
logger.Debug($"Value '{item.Key.name}' from registry key '{item.Key.key}' has changed from '{item.Value}' to '{value}'!");
|
||||
ValueChanged?.Invoke(item.Key.key, item.Key.name, item.Value, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"Failed to monitor value '{item.name}' from registry key '{item.key}'!");
|
||||
logger.Error($"Failed to monitor value '{item.Key.name}' from registry key '{item.Key.key}'!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetBaseKeyFromKeyName(string keyName, out RegistryKey baseKey, out string subKeyName)
|
||||
{
|
||||
baseKey = default;
|
||||
subKeyName = default;
|
||||
|
||||
string basekeyName;
|
||||
var baseKeyLength = keyName.IndexOf('\\');
|
||||
if (baseKeyLength != -1)
|
||||
{
|
||||
basekeyName = keyName.Substring(0, baseKeyLength).ToUpper(System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
basekeyName = keyName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
switch (basekeyName)
|
||||
{
|
||||
case "HKEY_CURRENT_USER":
|
||||
case "HKCU":
|
||||
baseKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
|
||||
break;
|
||||
case "HKEY_LOCAL_MACHINE":
|
||||
case "HKLM":
|
||||
baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
|
||||
break;
|
||||
case "HKEY_CLASSES_ROOT":
|
||||
case "HKCR":
|
||||
baseKey = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64);
|
||||
break;
|
||||
case "HKEY_USERS":
|
||||
case "HKU":
|
||||
baseKey = RegistryKey.OpenBaseKey(RegistryHive.Users, RegistryView.Registry64);
|
||||
break;
|
||||
case "HKEY_PERFORMANCE_DATA":
|
||||
case "HKPD":
|
||||
baseKey = RegistryKey.OpenBaseKey(RegistryHive.PerformanceData, RegistryView.Registry64);
|
||||
break;
|
||||
case "HKEY_CURRENT_CONFIG":
|
||||
case "HKCC":
|
||||
baseKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentConfig, RegistryView.Registry64);
|
||||
break;
|
||||
case "HKEY_DYN_DATA":
|
||||
case "HKDD":
|
||||
baseKey = RegistryKey.OpenBaseKey(RegistryHive.DynData, RegistryView.Registry64);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (baseKeyLength == -1 || baseKeyLength == keyName.Length)
|
||||
{
|
||||
subKeyName = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
subKeyName = keyName.Substring(baseKeyLength + 1, keyName.Length - baseKeyLength - 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryOpenKey(string keyName, out RegistryKey key)
|
||||
{
|
||||
key = default;
|
||||
|
||||
try
|
||||
{
|
||||
if (TryGetBaseKeyFromKeyName(keyName, out var baseKey, out var subKey))
|
||||
if (TryGetHiveForKey(keyName, out var hive))
|
||||
{
|
||||
key = baseKey.OpenSubKey(subKey);
|
||||
if (keyName == hive.Name)
|
||||
{
|
||||
key = hive;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = hive.OpenSubKey(keyName.Replace($@"{hive.Name}\", ""));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Failed to get hive for key '{keyName}'!");
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to open registry key '{keyName}'!", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return key != default;
|
||||
}
|
||||
|
||||
private bool TryGetHiveForKey(string keyName, out RegistryKey hive)
|
||||
{
|
||||
var length = keyName.IndexOf('\\');
|
||||
var name = length != -1 ? keyName.Substring(0, length).ToUpperInvariant() : keyName.ToUpperInvariant();
|
||||
|
||||
hive = default;
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "HKEY_CLASSES_ROOT":
|
||||
hive = Microsoft.Win32.Registry.ClassesRoot;
|
||||
break;
|
||||
case "HKEY_CURRENT_CONFIG":
|
||||
hive = Microsoft.Win32.Registry.CurrentConfig;
|
||||
break;
|
||||
case "HKEY_CURRENT_USER":
|
||||
hive = Microsoft.Win32.Registry.CurrentUser;
|
||||
break;
|
||||
case "HKEY_LOCAL_MACHINE":
|
||||
hive = Microsoft.Win32.Registry.LocalMachine;
|
||||
break;
|
||||
case "HKEY_PERFORMANCE_DATA":
|
||||
hive = Microsoft.Win32.Registry.PerformanceData;
|
||||
break;
|
||||
case "HKEY_USERS":
|
||||
hive = Microsoft.Win32.Registry.Users;
|
||||
break;
|
||||
}
|
||||
|
||||
return hive != default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Windows.Forms;
|
||||
using SafeExamBrowser.SystemComponents.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Registry;
|
||||
using BatteryChargeStatus = System.Windows.Forms.BatteryChargeStatus;
|
||||
using OperatingSystem = SafeExamBrowser.SystemComponents.Contracts.OperatingSystem;
|
||||
|
||||
|
@ -19,6 +21,8 @@ namespace SafeExamBrowser.SystemComponents
|
|||
{
|
||||
public class SystemInfo : ISystemInfo
|
||||
{
|
||||
private readonly IRegistry registry;
|
||||
|
||||
public string BiosInfo { get; private set; }
|
||||
public string CpuName { get; private set; }
|
||||
public bool HasBattery { get; private set; }
|
||||
|
@ -30,8 +34,10 @@ namespace SafeExamBrowser.SystemComponents
|
|||
public string OperatingSystemInfo => $"{OperatingSystemName()}, {Environment.OSVersion.VersionString} ({Architecture()})";
|
||||
public string[] PlugAndPlayDeviceIds { get; private set; }
|
||||
|
||||
public SystemInfo()
|
||||
public SystemInfo(IRegistry registry)
|
||||
{
|
||||
this.registry = registry;
|
||||
|
||||
InitializeBattery();
|
||||
InitializeBiosInfo();
|
||||
InitializeCpuName();
|
||||
|
@ -41,6 +47,20 @@ namespace SafeExamBrowser.SystemComponents
|
|||
InitializePnPDevices();
|
||||
}
|
||||
|
||||
public IEnumerable<DriveInfo> GetDrives()
|
||||
{
|
||||
var drives = DriveInfo.GetDrives();
|
||||
|
||||
registry.TryRead(RegistryValue.UserHive.NoDrives_Key, RegistryValue.UserHive.NoDrives_Name, out var value);
|
||||
|
||||
if (value is int noDrives && noDrives > 0)
|
||||
{
|
||||
drives = drives.Where(drive => (noDrives & (int) Math.Pow(2, drive.RootDirectory.ToString()[0] - 65)) == 0).ToArray();
|
||||
}
|
||||
|
||||
return drives;
|
||||
}
|
||||
|
||||
private void InitializeBattery()
|
||||
{
|
||||
var status = SystemInformation.PowerStatus.BatteryChargeStatus;
|
||||
|
|
|
@ -136,16 +136,14 @@ namespace SafeExamBrowser.SystemComponents
|
|||
|
||||
private bool HasHistoricVirtualMachineHardwareConfiguration()
|
||||
{
|
||||
const string HARDWARE_ROOT_KEY = @"HKEY_LOCAL_MACHINE\SYSTEM\HardwareConfig";
|
||||
|
||||
var hasHistoricConfiguration = false;
|
||||
|
||||
if (registry.TryGetSubKeys(HARDWARE_ROOT_KEY, out var hardwareConfigSubkeys))
|
||||
if (registry.TryGetSubKeys(RegistryValue.MachineHive.HardwareConfig_Key, out var hardwareConfigSubkeys))
|
||||
{
|
||||
foreach (var configId in hardwareConfigSubkeys)
|
||||
{
|
||||
var hardwareConfigKey = $"{HARDWARE_ROOT_KEY}\\{configId}";
|
||||
var computerIdsKey = $"{hardwareConfigKey}\\ComputerIds";
|
||||
var hardwareConfigKey = $@"{RegistryValue.MachineHive.HardwareConfig_Key}\{configId}";
|
||||
var computerIdsKey = $@"{hardwareConfigKey}\ComputerIds";
|
||||
var success = true;
|
||||
|
||||
success &= registry.TryRead(hardwareConfigKey, "BIOSVendor", out var biosVendor);
|
||||
|
@ -178,17 +176,15 @@ namespace SafeExamBrowser.SystemComponents
|
|||
|
||||
private bool HasLocalVirtualMachineDeviceCache()
|
||||
{
|
||||
const string DEVICE_CACHE_PARENT_KEY = @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\TaskFlow\DeviceCache";
|
||||
|
||||
var deviceName = System.Environment.GetEnvironmentVariable("COMPUTERNAME");
|
||||
var hasDeviceCache = false;
|
||||
var hasDeviceCacheKeys = registry.TryGetSubKeys(DEVICE_CACHE_PARENT_KEY, out var deviceCacheKeys);
|
||||
var hasDeviceCacheKeys = registry.TryGetSubKeys(RegistryValue.UserHive.DeviceCache_Key, out var deviceCacheKeys);
|
||||
|
||||
if (deviceName != default && hasDeviceCacheKeys)
|
||||
{
|
||||
foreach (var cacheId in deviceCacheKeys)
|
||||
{
|
||||
var cacheIdKey = $@"{DEVICE_CACHE_PARENT_KEY}\{cacheId}";
|
||||
var cacheIdKey = $@"{RegistryValue.UserHive.DeviceCache_Key}\{cacheId}";
|
||||
var didReadKeys = true;
|
||||
|
||||
didReadKeys &= registry.TryRead(cacheIdKey, "DeviceName", out var cacheDeviceName);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
using System.Windows;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Desktop.Windows;
|
||||
|
@ -16,10 +17,12 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
|||
{
|
||||
public class FileSystemDialogFactory : IFileSystemDialog
|
||||
{
|
||||
private readonly ISystemInfo systemInfo;
|
||||
private readonly IText text;
|
||||
|
||||
public FileSystemDialogFactory(IText text)
|
||||
public FileSystemDialogFactory(ISystemInfo systemInfo, IText text)
|
||||
{
|
||||
this.systemInfo = systemInfo;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
|
@ -35,11 +38,11 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
|||
{
|
||||
if (parent is Window window)
|
||||
{
|
||||
return window.Dispatcher.Invoke(() => new FileSystemDialog(element, operation, text, initialPath, message, title, parent, restrictNavigation, showElementPath).Show());
|
||||
return window.Dispatcher.Invoke(() => new FileSystemDialog(element, operation, systemInfo, text, initialPath, message, title, parent, restrictNavigation, showElementPath).Show());
|
||||
}
|
||||
else
|
||||
{
|
||||
return new FileSystemDialog(element, operation, text, initialPath, message, title, restrictNavigation: restrictNavigation, showElementPath: showElementPath).Show();
|
||||
return new FileSystemDialog(element, operation, systemInfo, text, initialPath, message, title, restrictNavigation: restrictNavigation, showElementPath: showElementPath).Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ using System.Windows.Controls;
|
|||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using FontAwesome.WPF;
|
||||
using Microsoft.Win32;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
@ -30,6 +30,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
private readonly string message;
|
||||
private readonly FileSystemOperation operation;
|
||||
private readonly IWindow parent;
|
||||
private readonly ISystemInfo systemInfo;
|
||||
private readonly bool restrictNavigation;
|
||||
private readonly bool showElementPath;
|
||||
private readonly IText text;
|
||||
|
@ -38,6 +39,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
internal FileSystemDialog(
|
||||
FileSystemElement element,
|
||||
FileSystemOperation operation,
|
||||
ISystemInfo systemInfo,
|
||||
IText text,
|
||||
string initialPath = default,
|
||||
string message = default,
|
||||
|
@ -50,6 +52,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
this.initialPath = initialPath;
|
||||
this.message = message;
|
||||
this.operation = operation;
|
||||
this.systemInfo = systemInfo;
|
||||
this.parent = parent;
|
||||
this.restrictNavigation = restrictNavigation;
|
||||
this.showElementPath = showElementPath;
|
||||
|
@ -293,20 +296,6 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
InitializeFileSystem();
|
||||
}
|
||||
|
||||
private DriveInfo[] GetDrives()
|
||||
{
|
||||
var drives = DriveInfo.GetDrives();
|
||||
var noDrives = Registry.GetValue("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", "NoDrives", 0) as int?;
|
||||
|
||||
if (noDrives.HasValue && noDrives > 0)
|
||||
{
|
||||
return drives.Where(drive => (noDrives & (int) Math.Pow(2, drive.RootDirectory.ToString()[0] - 65)) == 0).ToArray();
|
||||
}
|
||||
|
||||
return drives;
|
||||
}
|
||||
|
||||
|
||||
private void InitializeFileSystem()
|
||||
{
|
||||
if (restrictNavigation && !string.IsNullOrEmpty(initialPath))
|
||||
|
@ -337,7 +326,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
|
||||
private void InitializeUnrestricted()
|
||||
{
|
||||
foreach (var drive in GetDrives())
|
||||
foreach (var drive in systemInfo.GetDrives())
|
||||
{
|
||||
FileSystem.Items.Add(CreateItem(drive.RootDirectory));
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
using System.Windows;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Mobile.Windows;
|
||||
|
@ -16,10 +17,12 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
|||
{
|
||||
public class FileSystemDialogFactory : IFileSystemDialog
|
||||
{
|
||||
private readonly ISystemInfo systemInfo;
|
||||
private readonly IText text;
|
||||
|
||||
public FileSystemDialogFactory(IText text)
|
||||
public FileSystemDialogFactory(ISystemInfo systemInfo, IText text)
|
||||
{
|
||||
this.systemInfo = systemInfo;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
|
@ -35,11 +38,11 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
|||
{
|
||||
if (parent is Window window)
|
||||
{
|
||||
return window.Dispatcher.Invoke(() => new FileSystemDialog(element, operation, text, initialPath, message, title, parent, restrictNavigation, showElementPath).Show());
|
||||
return window.Dispatcher.Invoke(() => new FileSystemDialog(element, operation, systemInfo, text, initialPath, message, title, parent, restrictNavigation, showElementPath).Show());
|
||||
}
|
||||
else
|
||||
{
|
||||
return new FileSystemDialog(element, operation, text, initialPath, message, title, restrictNavigation: restrictNavigation, showElementPath: showElementPath).Show();
|
||||
return new FileSystemDialog(element, operation, systemInfo, text, initialPath, message, title, restrictNavigation: restrictNavigation, showElementPath: showElementPath).Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ using System.Windows.Controls;
|
|||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using FontAwesome.WPF;
|
||||
using Microsoft.Win32;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
@ -30,6 +30,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
private readonly string message;
|
||||
private readonly FileSystemOperation operation;
|
||||
private readonly IWindow parent;
|
||||
private readonly ISystemInfo systemInfo;
|
||||
private readonly bool restrictNavigation;
|
||||
private readonly bool showElementPath;
|
||||
private readonly IText text;
|
||||
|
@ -38,6 +39,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
internal FileSystemDialog(
|
||||
FileSystemElement element,
|
||||
FileSystemOperation operation,
|
||||
ISystemInfo systemInfo,
|
||||
IText text,
|
||||
string initialPath = default,
|
||||
string message = default,
|
||||
|
@ -50,6 +52,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
this.initialPath = initialPath;
|
||||
this.message = message;
|
||||
this.operation = operation;
|
||||
this.systemInfo = systemInfo;
|
||||
this.parent = parent;
|
||||
this.restrictNavigation = restrictNavigation;
|
||||
this.showElementPath = showElementPath;
|
||||
|
@ -293,20 +296,6 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
InitializeFileSystem();
|
||||
}
|
||||
|
||||
private DriveInfo[] GetDrives()
|
||||
{
|
||||
var drives = DriveInfo.GetDrives();
|
||||
var noDrives = Registry.GetValue("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", "NoDrives", 0) as int?;
|
||||
|
||||
if (noDrives.HasValue && noDrives > 0)
|
||||
{
|
||||
return drives.Where(drive => (noDrives & (int) Math.Pow(2, drive.RootDirectory.ToString()[0] - 65)) == 0).ToArray();
|
||||
}
|
||||
|
||||
return drives;
|
||||
}
|
||||
|
||||
|
||||
private void InitializeFileSystem()
|
||||
{
|
||||
if (restrictNavigation && !string.IsNullOrEmpty(initialPath))
|
||||
|
@ -337,7 +326,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
|
||||
private void InitializeUnrestricted()
|
||||
{
|
||||
foreach (var drive in GetDrives())
|
||||
foreach (var drive in systemInfo.GetDrives())
|
||||
{
|
||||
FileSystem.Items.Add(CreateItem(drive.RootDirectory));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue