SEBWIN-788: Implemented scaffolding for wireless network credentials.
This commit is contained in:
parent
e4a82e2f63
commit
4015e9a574
24 changed files with 395 additions and 35 deletions
|
@ -33,6 +33,7 @@ using SafeExamBrowser.Server.Contracts;
|
||||||
using SafeExamBrowser.Server.Contracts.Data;
|
using SafeExamBrowser.Server.Contracts.Data;
|
||||||
using SafeExamBrowser.Settings;
|
using SafeExamBrowser.Settings;
|
||||||
using SafeExamBrowser.Settings.Monitoring;
|
using SafeExamBrowser.Settings.Monitoring;
|
||||||
|
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Registry;
|
using SafeExamBrowser.SystemComponents.Contracts.Registry;
|
||||||
using SafeExamBrowser.UserInterface.Contracts;
|
using SafeExamBrowser.UserInterface.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
||||||
|
@ -61,6 +62,7 @@ namespace SafeExamBrowser.Client.UnitTests
|
||||||
private Mock<IIntegrityModule> integrityModule;
|
private Mock<IIntegrityModule> integrityModule;
|
||||||
private Mock<ILogger> logger;
|
private Mock<ILogger> logger;
|
||||||
private Mock<IMessageBox> messageBox;
|
private Mock<IMessageBox> messageBox;
|
||||||
|
private Mock<INetworkAdapter> networkAdapter;
|
||||||
private Mock<IOperationSequence> operationSequence;
|
private Mock<IOperationSequence> operationSequence;
|
||||||
private Mock<IRegistry> registry;
|
private Mock<IRegistry> registry;
|
||||||
private Mock<IRuntimeProxy> runtimeProxy;
|
private Mock<IRuntimeProxy> runtimeProxy;
|
||||||
|
@ -94,6 +96,7 @@ namespace SafeExamBrowser.Client.UnitTests
|
||||||
integrityModule = new Mock<IIntegrityModule>();
|
integrityModule = new Mock<IIntegrityModule>();
|
||||||
logger = new Mock<ILogger>();
|
logger = new Mock<ILogger>();
|
||||||
messageBox = new Mock<IMessageBox>();
|
messageBox = new Mock<IMessageBox>();
|
||||||
|
networkAdapter = new Mock<INetworkAdapter>();
|
||||||
operationSequence = new Mock<IOperationSequence>();
|
operationSequence = new Mock<IOperationSequence>();
|
||||||
registry = new Mock<IRegistry>();
|
registry = new Mock<IRegistry>();
|
||||||
runtimeProxy = new Mock<IRuntimeProxy>();
|
runtimeProxy = new Mock<IRuntimeProxy>();
|
||||||
|
@ -122,6 +125,7 @@ namespace SafeExamBrowser.Client.UnitTests
|
||||||
hashAlgorithm.Object,
|
hashAlgorithm.Object,
|
||||||
logger.Object,
|
logger.Object,
|
||||||
messageBox.Object,
|
messageBox.Object,
|
||||||
|
networkAdapter.Object,
|
||||||
operationSequence.Object,
|
operationSequence.Object,
|
||||||
registry.Object,
|
registry.Object,
|
||||||
runtimeProxy.Object,
|
runtimeProxy.Object,
|
||||||
|
|
|
@ -35,6 +35,8 @@ using SafeExamBrowser.Proctoring.Contracts.Events;
|
||||||
using SafeExamBrowser.Server.Contracts;
|
using SafeExamBrowser.Server.Contracts;
|
||||||
using SafeExamBrowser.Server.Contracts.Data;
|
using SafeExamBrowser.Server.Contracts.Data;
|
||||||
using SafeExamBrowser.Settings;
|
using SafeExamBrowser.Settings;
|
||||||
|
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||||
|
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Registry;
|
using SafeExamBrowser.SystemComponents.Contracts.Registry;
|
||||||
using SafeExamBrowser.UserInterface.Contracts;
|
using SafeExamBrowser.UserInterface.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
||||||
|
@ -57,6 +59,7 @@ namespace SafeExamBrowser.Client
|
||||||
private readonly IHashAlgorithm hashAlgorithm;
|
private readonly IHashAlgorithm hashAlgorithm;
|
||||||
private readonly ILogger logger;
|
private readonly ILogger logger;
|
||||||
private readonly IMessageBox messageBox;
|
private readonly IMessageBox messageBox;
|
||||||
|
private readonly INetworkAdapter networkAdapter;
|
||||||
private readonly IOperationSequence operations;
|
private readonly IOperationSequence operations;
|
||||||
private readonly IRegistry registry;
|
private readonly IRegistry registry;
|
||||||
private readonly IRuntimeProxy runtime;
|
private readonly IRuntimeProxy runtime;
|
||||||
|
@ -87,6 +90,7 @@ namespace SafeExamBrowser.Client
|
||||||
IHashAlgorithm hashAlgorithm,
|
IHashAlgorithm hashAlgorithm,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IMessageBox messageBox,
|
IMessageBox messageBox,
|
||||||
|
INetworkAdapter networkAdapter,
|
||||||
IOperationSequence operations,
|
IOperationSequence operations,
|
||||||
IRegistry registry,
|
IRegistry registry,
|
||||||
IRuntimeProxy runtime,
|
IRuntimeProxy runtime,
|
||||||
|
@ -106,6 +110,7 @@ namespace SafeExamBrowser.Client
|
||||||
this.hashAlgorithm = hashAlgorithm;
|
this.hashAlgorithm = hashAlgorithm;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.messageBox = messageBox;
|
this.messageBox = messageBox;
|
||||||
|
this.networkAdapter = networkAdapter;
|
||||||
this.operations = operations;
|
this.operations = operations;
|
||||||
this.registry = registry;
|
this.registry = registry;
|
||||||
this.runtime = runtime;
|
this.runtime = runtime;
|
||||||
|
@ -214,6 +219,7 @@ namespace SafeExamBrowser.Client
|
||||||
ClientHost.ServerFailureActionRequested += ClientHost_ServerFailureActionRequested;
|
ClientHost.ServerFailureActionRequested += ClientHost_ServerFailureActionRequested;
|
||||||
ClientHost.Shutdown += ClientHost_Shutdown;
|
ClientHost.Shutdown += ClientHost_Shutdown;
|
||||||
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
||||||
|
networkAdapter.CredentialsRequired += NetworkAdapter_CredentialsRequired;
|
||||||
registry.ValueChanged += Registry_ValueChanged;
|
registry.ValueChanged += Registry_ValueChanged;
|
||||||
runtime.ConnectionLost += Runtime_ConnectionLost;
|
runtime.ConnectionLost += Runtime_ConnectionLost;
|
||||||
systemMonitor.SessionChanged += SystemMonitor_SessionChanged;
|
systemMonitor.SessionChanged += SystemMonitor_SessionChanged;
|
||||||
|
@ -690,6 +696,16 @@ namespace SafeExamBrowser.Client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void NetworkAdapter_CredentialsRequired(CredentialsRequiredEventArgs args)
|
||||||
|
{
|
||||||
|
var dialog = uiFactory.CreateNetworkDialog("TODO", "TODO");
|
||||||
|
var result = dialog.Show();
|
||||||
|
|
||||||
|
args.Password = result.Password;
|
||||||
|
args.Success = result.Success;
|
||||||
|
args.Username = result.Username;
|
||||||
|
}
|
||||||
|
|
||||||
private void Operations_ActionRequired(ActionRequiredEventArgs args)
|
private void Operations_ActionRequired(ActionRequiredEventArgs args)
|
||||||
{
|
{
|
||||||
switch (args)
|
switch (args)
|
||||||
|
|
|
@ -154,6 +154,7 @@ namespace SafeExamBrowser.Client
|
||||||
hashAlgorithm,
|
hashAlgorithm,
|
||||||
logger,
|
logger,
|
||||||
messageBox,
|
messageBox,
|
||||||
|
networkAdapter,
|
||||||
sequence,
|
sequence,
|
||||||
registry,
|
registry,
|
||||||
runtimeProxy,
|
runtimeProxy,
|
||||||
|
|
|
@ -26,6 +26,26 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
InitializeClipboardSettings(settings);
|
InitializeClipboardSettings(settings);
|
||||||
InitializeProctoringSettings(settings);
|
InitializeProctoringSettings(settings);
|
||||||
RemoveLegacyBrowsers(settings);
|
RemoveLegacyBrowsers(settings);
|
||||||
|
|
||||||
|
settings.Applications.Blacklist.Clear();
|
||||||
|
settings.Applications.Whitelist.Add(new WhitelistApplication { ExecutableName = "mspaint.exe", ShowInShell = true });
|
||||||
|
settings.Browser.AdditionalWindow.AllowAddressBar = true;
|
||||||
|
settings.Browser.MainWindow.AllowAddressBar = true;
|
||||||
|
settings.Browser.MainWindow.AllowDeveloperConsole = true;
|
||||||
|
settings.Browser.MainWindow.AllowBackwardNavigation = true;
|
||||||
|
settings.Browser.MainWindow.AllowForwardNavigation = true;
|
||||||
|
settings.Browser.MainWindow.ShowHomeButton = true;
|
||||||
|
settings.Browser.MainWindow.UrlPolicy = Settings.Browser.UrlPolicy.BeforeTitle;
|
||||||
|
settings.Keyboard.AllowPrintScreen = true;
|
||||||
|
settings.LogLevel = Settings.Logging.LogLevel.Debug;
|
||||||
|
settings.Security.AllowApplicationLogAccess = true;
|
||||||
|
settings.Security.ClipboardPolicy = ClipboardPolicy.Allow;
|
||||||
|
settings.Security.KioskMode = KioskMode.CreateNewDesktop;
|
||||||
|
settings.Security.QuitPasswordHash = default;
|
||||||
|
settings.Service.IgnoreService = true;
|
||||||
|
settings.Service.Policy = Settings.Service.ServicePolicy.Optional;
|
||||||
|
settings.Security.VersionRestrictions.Clear();
|
||||||
|
settings.Taskbar.ShowApplicationLog = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AllowBrowserToolbarForReloading(AppSettings settings)
|
private void AllowBrowserToolbarForReloading(AppSettings settings)
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class CredentialsRequiredEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public bool Success { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Username { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public delegate void CredentialsRequiredEventHandler(CredentialsRequiredEventArgs args);
|
||||||
|
}
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
|
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
|
||||||
|
|
||||||
|
@ -33,9 +32,14 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Network
|
||||||
event ChangedEventHandler Changed;
|
event ChangedEventHandler Changed;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to connect to the wireless network with the given ID.
|
/// Fired when credentials are required to connect to a network.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ConnectToWirelessNetwork(Guid id);
|
event CredentialsRequiredEventHandler CredentialsRequired;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to connect to the wireless network with the given name.
|
||||||
|
/// </summary>
|
||||||
|
void ConnectToWirelessNetwork(string name);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves all currently available wireless networks.
|
/// Retrieves all currently available wireless networks.
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.SystemComponents.Contracts.Network
|
namespace SafeExamBrowser.SystemComponents.Contracts.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -15,11 +13,6 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Network
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IWirelessNetwork
|
public interface IWirelessNetwork
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The unique identifier of the network.
|
|
||||||
/// </summary>
|
|
||||||
Guid Id { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The network name.
|
/// The network name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -58,6 +58,8 @@
|
||||||
<Compile Include="Audio\Events\VolumeChangedEventHandler.cs" />
|
<Compile Include="Audio\Events\VolumeChangedEventHandler.cs" />
|
||||||
<Compile Include="Audio\IAudio.cs" />
|
<Compile Include="Audio\IAudio.cs" />
|
||||||
<Compile Include="IFileSystem.cs" />
|
<Compile Include="IFileSystem.cs" />
|
||||||
|
<Compile Include="Network\Events\CredentialsRequiredEventArgs.cs" />
|
||||||
|
<Compile Include="Network\Events\CredentialsRequiredEventHandler.cs" />
|
||||||
<Compile Include="Registry\Events\RegistryValueChangedEventHandler.cs" />
|
<Compile Include="Registry\Events\RegistryValueChangedEventHandler.cs" />
|
||||||
<Compile Include="Registry\IRegistry.cs" />
|
<Compile Include="Registry\IRegistry.cs" />
|
||||||
<Compile Include="IRemoteSessionDetector.cs" />
|
<Compile Include="IRemoteSessionDetector.cs" />
|
||||||
|
|
|
@ -10,7 +10,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Timers;
|
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
|
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
|
||||||
|
@ -18,12 +17,22 @@ using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
using SimpleWifi;
|
using SimpleWifi;
|
||||||
using SimpleWifi.Win32;
|
using SimpleWifi.Win32;
|
||||||
using SimpleWifi.Win32.Interop;
|
using SimpleWifi.Win32.Interop;
|
||||||
|
using Timer = System.Timers.Timer;
|
||||||
|
|
||||||
namespace SafeExamBrowser.SystemComponents.Network
|
namespace SafeExamBrowser.SystemComponents.Network
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Switch to the following WiFi library:
|
||||||
|
/// https://github.com/emoacht/ManagedNativeWifi
|
||||||
|
/// https://www.nuget.org/packages/ManagedNativeWifi
|
||||||
|
///
|
||||||
|
/// Potentially useful:
|
||||||
|
/// https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.networkinterface?view=netframework-4.8
|
||||||
|
/// </summary>
|
||||||
public class NetworkAdapter : INetworkAdapter
|
public class NetworkAdapter : INetworkAdapter
|
||||||
{
|
{
|
||||||
private readonly object @lock = new object();
|
private readonly object @lock = new object();
|
||||||
|
|
||||||
private readonly ILogger logger;
|
private readonly ILogger logger;
|
||||||
private readonly INativeMethods nativeMethods;
|
private readonly INativeMethods nativeMethods;
|
||||||
private readonly List<WirelessNetwork> wirelessNetworks;
|
private readonly List<WirelessNetwork> wirelessNetworks;
|
||||||
|
@ -35,6 +44,7 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
public ConnectionType Type { get; private set; }
|
public ConnectionType Type { get; private set; }
|
||||||
|
|
||||||
public event ChangedEventHandler Changed;
|
public event ChangedEventHandler Changed;
|
||||||
|
public event CredentialsRequiredEventHandler CredentialsRequired;
|
||||||
|
|
||||||
public NetworkAdapter(ILogger logger, INativeMethods nativeMethods)
|
public NetworkAdapter(ILogger logger, INativeMethods nativeMethods)
|
||||||
{
|
{
|
||||||
|
@ -43,22 +53,27 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
this.wirelessNetworks = new List<WirelessNetwork>();
|
this.wirelessNetworks = new List<WirelessNetwork>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConnectToWirelessNetwork(Guid id)
|
public void ConnectToWirelessNetwork(string name)
|
||||||
{
|
{
|
||||||
lock (@lock)
|
lock (@lock)
|
||||||
{
|
{
|
||||||
var network = wirelessNetworks.FirstOrDefault(n => n.Id == id);
|
var network = wirelessNetworks.FirstOrDefault(n => n.Name == name);
|
||||||
|
|
||||||
if (network != default)
|
if (network != default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var request = new AuthRequest(network.AccessPoint);
|
var accessPoint = network.AccessPoint;
|
||||||
|
var request = new AuthRequest(accessPoint);
|
||||||
|
|
||||||
logger.Info($"Attempting to connect to '{network.Name}'...");
|
if (accessPoint.HasProfile || accessPoint.IsConnected || TryGetCredentials(request))
|
||||||
|
{
|
||||||
|
logger.Info($"Attempting to connect to wireless network '{network.Name}' with{(request.Password == default ? "out" : "")} credentials...");
|
||||||
|
|
||||||
network.AccessPoint.ConnectAsync(request, false, (success) => AccessPoint_OnConnectCompleted(network.Name, success));
|
// TODO: Retry resp. alert of password error on failure and then ignore profile?!
|
||||||
Status = ConnectionStatus.Connecting;
|
accessPoint.ConnectAsync(request, false, (success) => ConnectionAttemptCompleted(network.Name, success));
|
||||||
|
Status = ConnectionStatus.Connecting;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -67,7 +82,7 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.Warn($"Could not find network with id '{id}'!");
|
logger.Warn($"Could not find wireless network '{name}'!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +126,7 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AccessPoint_OnConnectCompleted(string name, bool success)
|
private void ConnectionAttemptCompleted(string name, bool success)
|
||||||
{
|
{
|
||||||
lock (@lock)
|
lock (@lock)
|
||||||
{
|
{
|
||||||
|
@ -129,12 +144,28 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool TryGetCredentials(AuthRequest request)
|
||||||
|
{
|
||||||
|
var args = new CredentialsRequiredEventArgs();
|
||||||
|
|
||||||
|
CredentialsRequired?.Invoke(args);
|
||||||
|
|
||||||
|
if (args.Success)
|
||||||
|
{
|
||||||
|
request.Password = args.Password;
|
||||||
|
request.Username = args.Username;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args.Success;
|
||||||
|
}
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
lock (@lock)
|
lock (@lock)
|
||||||
{
|
{
|
||||||
|
var current = default(WirelessNetwork);
|
||||||
var hasInternet = nativeMethods.HasInternetConnection();
|
var hasInternet = nativeMethods.HasInternetConnection();
|
||||||
var hasWireless = !wifi.NoWifiAvailable && !IsTurnedOff();
|
var hasWireless = !wifi.NoWifiAvailable && !IsTurnedOff();
|
||||||
var isConnecting = Status == ConnectionStatus.Connecting;
|
var isConnecting = Status == ConnectionStatus.Connecting;
|
||||||
|
@ -144,12 +175,13 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
|
|
||||||
if (hasWireless)
|
if (hasWireless)
|
||||||
{
|
{
|
||||||
foreach (var accessPoint in wifi.GetAccessPoints())
|
foreach (var wirelessNetwork in wifi.GetAccessPoints().Select(a => ToWirelessNetwork(a)))
|
||||||
{
|
{
|
||||||
// The user may only connect to an already configured or connected wireless network!
|
wirelessNetworks.Add(wirelessNetwork);
|
||||||
if (accessPoint.HasProfile || accessPoint.IsConnected)
|
|
||||||
|
if (wirelessNetwork.Status == ConnectionStatus.Connected)
|
||||||
{
|
{
|
||||||
wirelessNetworks.Add(ToWirelessNetwork(accessPoint));
|
current = wirelessNetwork;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +191,7 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
|
|
||||||
if (previousStatus != ConnectionStatus.Connected && Status == ConnectionStatus.Connected)
|
if (previousStatus != ConnectionStatus.Connected && Status == ConnectionStatus.Connected)
|
||||||
{
|
{
|
||||||
logger.Info("Connection established.");
|
logger.Info($"Connection established ({Type}{(current != default ? $", {current.Name}" : "")}).");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousStatus != ConnectionStatus.Disconnected && Status == ConnectionStatus.Disconnected)
|
if (previousStatus != ConnectionStatus.Disconnected && Status == ConnectionStatus.Disconnected)
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||||
using SimpleWifi;
|
using SimpleWifi;
|
||||||
|
|
||||||
|
@ -16,14 +15,8 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
{
|
{
|
||||||
internal AccessPoint AccessPoint { get; set; }
|
internal AccessPoint AccessPoint { get; set; }
|
||||||
|
|
||||||
public Guid Id { get; }
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public int SignalStrength { get; set; }
|
public int SignalStrength { get; set; }
|
||||||
public ConnectionStatus Status { get; set; }
|
public ConnectionStatus Status { get; set; }
|
||||||
|
|
||||||
public WirelessNetwork()
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,11 @@ namespace SafeExamBrowser.UserInterface.Contracts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ISystemControl CreateNetworkControl(INetworkAdapter adapter, Location location);
|
ISystemControl CreateNetworkControl(INetworkAdapter adapter, Location location);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a network dialog with the given message and title.
|
||||||
|
/// </summary>
|
||||||
|
INetworkDialog CreateNetworkDialog(string message, string title);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a notification control for the given notification, initialized for the specified location.
|
/// Creates a notification control for the given notification, initialized for the specified location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -96,11 +96,13 @@
|
||||||
<Compile Include="Windows\Data\ExamSelectionDialogResult.cs" />
|
<Compile Include="Windows\Data\ExamSelectionDialogResult.cs" />
|
||||||
<Compile Include="Windows\Data\LockScreenOption.cs" />
|
<Compile Include="Windows\Data\LockScreenOption.cs" />
|
||||||
<Compile Include="Windows\Data\LockScreenResult.cs" />
|
<Compile Include="Windows\Data\LockScreenResult.cs" />
|
||||||
|
<Compile Include="Windows\Data\NetworkDialogResult.cs" />
|
||||||
<Compile Include="Windows\Data\ServerFailureDialogResult.cs" />
|
<Compile Include="Windows\Data\ServerFailureDialogResult.cs" />
|
||||||
<Compile Include="Windows\Events\WindowClosedEventHandler.cs" />
|
<Compile Include="Windows\Events\WindowClosedEventHandler.cs" />
|
||||||
<Compile Include="Windows\Events\WindowClosingEventHandler.cs" />
|
<Compile Include="Windows\Events\WindowClosingEventHandler.cs" />
|
||||||
<Compile Include="Windows\IExamSelectionDialog.cs" />
|
<Compile Include="Windows\IExamSelectionDialog.cs" />
|
||||||
<Compile Include="Windows\ILockScreen.cs" />
|
<Compile Include="Windows\ILockScreen.cs" />
|
||||||
|
<Compile Include="Windows\INetworkDialog.cs" />
|
||||||
<Compile Include="Windows\IPasswordDialog.cs" />
|
<Compile Include="Windows\IPasswordDialog.cs" />
|
||||||
<Compile Include="Windows\Data\PasswordDialogResult.cs" />
|
<Compile Include="Windows\Data\PasswordDialogResult.cs" />
|
||||||
<Compile Include="Proctoring\IProctoringFinalizationDialog.cs" />
|
<Compile Include="Proctoring\IProctoringFinalizationDialog.cs" />
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.UserInterface.Contracts.Windows.Data
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the user interaction result of an <see cref="INetworkDialog"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class NetworkDialogResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The password entered by the user, or <c>default(string)</c> if the interaction was unsuccessful.
|
||||||
|
/// </summary>
|
||||||
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the user confirmed the dialog or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool Success { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The username entered by the user, or <c>default(string)</c> if no username is required or the interaction was unsuccessful.
|
||||||
|
/// </summary>
|
||||||
|
public string Username { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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.UserInterface.Contracts.Windows.Data;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the functionality of a network dialog.
|
||||||
|
/// </summary>
|
||||||
|
public interface INetworkDialog : IWindow
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the dialog as topmost window. If a parent window is specified, the dialog is rendered modally for the given parent.
|
||||||
|
/// </summary>
|
||||||
|
NetworkDialogResult Show(IWindow parent = null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -100,7 +100,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||||
{
|
{
|
||||||
var button = new NetworkButton(network);
|
var button = new NetworkButton(network);
|
||||||
|
|
||||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id);
|
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||||
|
|
||||||
if (network.Status == ConnectionStatus.Connected)
|
if (network.Status == ConnectionStatus.Connected)
|
||||||
{
|
{
|
||||||
|
|
|
@ -112,7 +112,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||||
{
|
{
|
||||||
var button = new NetworkButton(network);
|
var button = new NetworkButton(network);
|
||||||
|
|
||||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id);
|
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||||
|
|
||||||
if (network.Status == ConnectionStatus.Connected)
|
if (network.Status == ConnectionStatus.Connected)
|
||||||
{
|
{
|
||||||
|
|
|
@ -168,6 +168,9 @@
|
||||||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="MessageBoxFactory.cs" />
|
<Compile Include="MessageBoxFactory.cs" />
|
||||||
|
<Compile Include="Windows\NetworkDialog.xaml.cs">
|
||||||
|
<DependentUpon>NetworkDialog.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Windows\PasswordDialog.xaml.cs">
|
<Compile Include="Windows\PasswordDialog.xaml.cs">
|
||||||
<DependentUpon>PasswordDialog.xaml</DependentUpon>
|
<DependentUpon>PasswordDialog.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -394,6 +397,10 @@
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Windows\NetworkDialog.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Windows\ProctoringFinalizationDialog.xaml">
|
<Page Include="Windows\ProctoringFinalizationDialog.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|
|
@ -143,6 +143,11 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public INetworkDialog CreateNetworkDialog(string message, string title)
|
||||||
|
{
|
||||||
|
return Application.Current.Dispatcher.Invoke(() => new NetworkDialog(message, title, text));
|
||||||
|
}
|
||||||
|
|
||||||
public INotificationControl CreateNotificationControl(INotification notification, Location location)
|
public INotificationControl CreateNotificationControl(INotification notification, Location location)
|
||||||
{
|
{
|
||||||
if (location == Location.ActionCenter)
|
if (location == Location.ActionCenter)
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
<Window x:Class="SafeExamBrowser.UserInterface.Desktop.Windows.NetworkDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Windows"
|
||||||
|
mc:Ignorable="d" Height="350" Width="450" ResizeMode="NoResize" Topmost="True">
|
||||||
|
<Window.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="../Templates/Colors.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Window.Resources>
|
||||||
|
<Grid FocusManager.FocusedElement="{Binding ElementName=Password}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="2*" />
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid Grid.Row="0">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<fa:ImageAwesome Grid.Column="0" Foreground="LightGray" Icon="Wifi" Margin="25" Width="50" />
|
||||||
|
<Grid Grid.Column="1" Margin="0,0,25,25">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock Grid.Row="0" Name="Message" Margin="0,0,0,5" TextWrapping="WrapWithOverflow" VerticalAlignment="Bottom" />
|
||||||
|
<StackPanel Grid.Row="1" Orientation="Vertical">
|
||||||
|
<Label Name="UsernameLabel" Target="{Binding ElementName=Username}" />
|
||||||
|
<TextBox Name="Username" Height="25" Margin="0,0,0,5" VerticalContentAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Row="2" Orientation="Vertical">
|
||||||
|
<Label Name="PasswordLabel" Target="{Binding ElementName=Password}" />
|
||||||
|
<PasswordBox Grid.Row="2" Name="Password" Height="25" VerticalContentAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="1" Background="{StaticResource BackgroundBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
|
<WrapPanel Orientation="Horizontal" Margin="25,0" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||||
|
<Button Name="ConfirmButton" Cursor="Hand" Margin="10,0" Padding="10,5" MinWidth="75" />
|
||||||
|
<Button Name="CancelButton" Cursor="Hand" Padding="10,5" MinWidth="75" />
|
||||||
|
</WrapPanel>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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 System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
||||||
|
{
|
||||||
|
public partial class NetworkDialog : Window, INetworkDialog
|
||||||
|
{
|
||||||
|
private readonly IText text;
|
||||||
|
|
||||||
|
private WindowClosedEventHandler closed;
|
||||||
|
private WindowClosingEventHandler closing;
|
||||||
|
|
||||||
|
event WindowClosedEventHandler IWindow.Closed
|
||||||
|
{
|
||||||
|
add { closed += value; }
|
||||||
|
remove { closed -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
event WindowClosingEventHandler IWindow.Closing
|
||||||
|
{
|
||||||
|
add { closing += value; }
|
||||||
|
remove { closing -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal NetworkDialog(string message, string title, IText text)
|
||||||
|
{
|
||||||
|
this.text = text;
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
InitializeNetworkDialog(message, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BringToForeground()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(Activate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkDialogResult Show(IWindow parent = null)
|
||||||
|
{
|
||||||
|
return Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
var result = new NetworkDialogResult { Success = false };
|
||||||
|
|
||||||
|
if (parent is Window)
|
||||||
|
{
|
||||||
|
Owner = parent as Window;
|
||||||
|
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShowDialog() is true)
|
||||||
|
{
|
||||||
|
result.Password = Password.Password;
|
||||||
|
result.Success = true;
|
||||||
|
result.Username = Username.Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeNetworkDialog(string message, string title)
|
||||||
|
{
|
||||||
|
Message.Text = message;
|
||||||
|
// TODO
|
||||||
|
PasswordLabel.Content = "Password";
|
||||||
|
Title = title;
|
||||||
|
// TODO
|
||||||
|
UsernameLabel.Content = "Username";
|
||||||
|
WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||||
|
|
||||||
|
Closed += (o, args) => closed?.Invoke();
|
||||||
|
Closing += (o, args) => closing?.Invoke();
|
||||||
|
Loaded += (o, args) => Activate();
|
||||||
|
|
||||||
|
CancelButton.Content = text.Get(TextKey.PasswordDialog_Cancel);
|
||||||
|
CancelButton.Click += CancelButton_Click;
|
||||||
|
|
||||||
|
ConfirmButton.Content = text.Get(TextKey.PasswordDialog_Confirm);
|
||||||
|
ConfirmButton.Click += ConfirmButton_Click;
|
||||||
|
|
||||||
|
Password.KeyDown += Password_KeyDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CancelButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DialogResult = false;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfirmButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DialogResult = true;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Password_KeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.Enter)
|
||||||
|
{
|
||||||
|
DialogResult = true;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -100,7 +100,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
|
||||||
{
|
{
|
||||||
var button = new NetworkButton(network);
|
var button = new NetworkButton(network);
|
||||||
|
|
||||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id);
|
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||||
|
|
||||||
if (network.Status == ConnectionStatus.Connected)
|
if (network.Status == ConnectionStatus.Connected)
|
||||||
{
|
{
|
||||||
|
|
|
@ -112,7 +112,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
|
||||||
{
|
{
|
||||||
var button = new NetworkButton(network);
|
var button = new NetworkButton(network);
|
||||||
|
|
||||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id);
|
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||||
|
|
||||||
if (network.Status == ConnectionStatus.Connected)
|
if (network.Status == ConnectionStatus.Connected)
|
||||||
{
|
{
|
||||||
|
|
|
@ -143,6 +143,12 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public INetworkDialog CreateNetworkDialog(string message, string title)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public INotificationControl CreateNotificationControl(INotification notification, Location location)
|
public INotificationControl CreateNotificationControl(INotification notification, Location location)
|
||||||
{
|
{
|
||||||
if (location == Location.ActionCenter)
|
if (location == Location.ActionCenter)
|
||||||
|
|
Loading…
Reference in a new issue