SEBWIN-788: Finished implementation of new (wireless) network adapter and authentication functionality.
This commit is contained in:
parent
4015e9a574
commit
473edc7a2e
41 changed files with 818 additions and 310 deletions
Binary file not shown.
|
@ -698,7 +698,9 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
private void NetworkAdapter_CredentialsRequired(CredentialsRequiredEventArgs args)
|
||||
{
|
||||
var dialog = uiFactory.CreateNetworkDialog("TODO", "TODO");
|
||||
var message = text.Get(TextKey.CredentialsDialog_WirelessNetworkMessage).Replace("%%_NAME_%%", args.NetworkName);
|
||||
var title = text.Get(TextKey.CredentialsDialog_WirelessNetworkTitle);
|
||||
var dialog = uiFactory.CreateCredentialsDialog(CredentialsDialogPurpose.WirelessNetwork, message, title);
|
||||
var result = dialog.Show();
|
||||
|
||||
args.Password = result.Password;
|
||||
|
|
|
@ -26,26 +26,6 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
|||
InitializeClipboardSettings(settings);
|
||||
InitializeProctoringSettings(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)
|
||||
|
|
|
@ -47,6 +47,11 @@ namespace SafeExamBrowser.I18n.Contracts
|
|||
BrowserWindow_ZoomMenuMinus,
|
||||
BrowserWindow_ZoomMenuPlus,
|
||||
Build,
|
||||
CredentialsDialog_PasswordLabel,
|
||||
CredentialsDialog_UsernameLabel,
|
||||
CredentialsDialog_UsernameOptionalLabel,
|
||||
CredentialsDialog_WirelessNetworkMessage,
|
||||
CredentialsDialog_WirelessNetworkTitle,
|
||||
ExamSelectionDialog_Cancel,
|
||||
ExamSelectionDialog_Message,
|
||||
ExamSelectionDialog_Select,
|
||||
|
|
|
@ -99,6 +99,21 @@
|
|||
<Entry key="Build">
|
||||
Build
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_PasswordLabel">
|
||||
Passwort:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameLabel">
|
||||
Benutzername:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameOptionalLabel">
|
||||
Benutzername (optional):
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkMessage">
|
||||
Bitte geben Sie die erforderlichen Anmeldeinformationen ein, um eine Verbindung mit dem drahtlosen Netzwerk "%%_NAME_%%" herzustellen.
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkTitle">
|
||||
Netzwerk-Authentifizierung erforderlich
|
||||
</Entry>
|
||||
<Entry key="ExamSelectionDialog_Cancel">
|
||||
Abbrechen
|
||||
</Entry>
|
||||
|
|
|
@ -99,6 +99,21 @@
|
|||
<Entry key="Build">
|
||||
Build
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_PasswordLabel">
|
||||
Password:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameLabel">
|
||||
Username:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameOptionalLabel">
|
||||
Username (optional):
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkMessage">
|
||||
Please enter the required credentials to establish a connection to the wireless network "%%_NAME_%%".
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkTitle">
|
||||
Network Authentication Required
|
||||
</Entry>
|
||||
<Entry key="ExamSelectionDialog_Cancel">
|
||||
Cancel
|
||||
</Entry>
|
||||
|
|
|
@ -99,6 +99,21 @@
|
|||
<Entry key="Build">
|
||||
Build
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_PasswordLabel">
|
||||
Contraseña:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameLabel">
|
||||
Nombre de usuario:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameOptionalLabel">
|
||||
Nombre de usuario (opcional):
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkMessage">
|
||||
Por favor, introduzca las credenciales necesarias para establecer una conexión con la red inalámbrica "%%_NAME_%%".
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkTitle">
|
||||
Autenticación de red necesaria
|
||||
</Entry>
|
||||
<Entry key="ExamSelectionDialog_Cancel">
|
||||
Cancel
|
||||
</Entry>
|
||||
|
|
|
@ -99,6 +99,21 @@
|
|||
<Entry key="Build">
|
||||
Koosta
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_PasswordLabel">
|
||||
Parool:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameLabel">
|
||||
Kasutajanimi:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameOptionalLabel">
|
||||
Kasutajanimi (vabatahtlik):
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkMessage">
|
||||
Palun sisestage vajalikud volitused, et luua ühendus traadita võrguga "%%_NAME_%%".
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkTitle">
|
||||
Võrguautentimine nõutav
|
||||
</Entry>
|
||||
<Entry key="ExamSelectionDialog_Cancel">
|
||||
Tühista
|
||||
</Entry>
|
||||
|
|
|
@ -99,6 +99,21 @@
|
|||
<Entry key="Build">
|
||||
Build
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_PasswordLabel">
|
||||
Mot de passe:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameLabel">
|
||||
Nom d'utilisateur:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameOptionalLabel">
|
||||
Nom d'utilisateur (facultatif):
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkMessage">
|
||||
Veuillez saisir les informations d'identification requises pour établir une connexion au réseau sans fil "%%_NAME_%%".
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkTitle">
|
||||
Authentification réseau requise
|
||||
</Entry>
|
||||
<Entry key="ExamSelectionDialog_Cancel">
|
||||
Annuler
|
||||
</Entry>
|
||||
|
|
|
@ -99,6 +99,21 @@
|
|||
<Entry key="Build">
|
||||
Bangun
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_PasswordLabel">
|
||||
Kata sandi:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameLabel">
|
||||
Nama pengguna:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameOptionalLabel">
|
||||
Nama pengguna (opsional):
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkMessage">
|
||||
Masukkan kredensial yang diperlukan untuk membuat sambungan ke jaringan nirkabel "%%_NAMA_%%".
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkTitle">
|
||||
Diperlukan Otentikasi Jaringan
|
||||
</Entry>
|
||||
<Entry key="ExamSelectionDialog_Cancel">
|
||||
Batal
|
||||
</Entry>
|
||||
|
|
|
@ -99,6 +99,21 @@
|
|||
<Entry key="Build">
|
||||
Build
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_PasswordLabel">
|
||||
Password:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameLabel">
|
||||
Nome utente:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameOptionalLabel">
|
||||
Nome utente (facoltativo):
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkMessage">
|
||||
Inserire le credenziali richieste per stabilire una connessione alla rete wireless "%%_NAME_%%".
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkTitle">
|
||||
È richiesta l'autenticazione di rete
|
||||
</Entry>
|
||||
<Entry key="ExamSelectionDialog_Cancel">
|
||||
Annulla
|
||||
</Entry>
|
||||
|
|
|
@ -99,6 +99,21 @@
|
|||
<Entry key="Build">
|
||||
Build
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_PasswordLabel">
|
||||
Wachtwoord:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameLabel">
|
||||
Gebruikersnaam:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameOptionalLabel">
|
||||
Gebruikersnaam (optioneel):
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkMessage">
|
||||
Voer de vereiste gegevens in om verbinding te maken met het draadloze netwerk “%%_NAME_%%”.
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkTitle">
|
||||
Netwerkverificatie vereist
|
||||
</Entry>
|
||||
<Entry key="ExamSelectionDialog_Cancel">
|
||||
Annuleren
|
||||
</Entry>
|
||||
|
|
|
@ -99,6 +99,21 @@
|
|||
<Entry key="Build">
|
||||
Строить
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_PasswordLabel">
|
||||
Пароль:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameLabel">
|
||||
Имя пользователя:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameOptionalLabel">
|
||||
Имя пользователя (необязательно):
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkMessage">
|
||||
Введите необходимые учетные данные для установления соединения с беспроводной сетью "%%_NAME_%%".
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkTitle">
|
||||
Требуется сетевая аутентификация
|
||||
</Entry>
|
||||
<Entry key="ExamSelectionDialog_Cancel">
|
||||
Отмена
|
||||
</Entry>
|
||||
|
|
|
@ -99,6 +99,21 @@
|
|||
<Entry key="Build">
|
||||
生成
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_PasswordLabel">
|
||||
密码:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameLabel">
|
||||
用户名:
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_UsernameOptionalLabel">
|
||||
用户名(可选):
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkMessage">
|
||||
请输入与无线网络 "%%_NAME_%%" 建立连接所需的凭证。
|
||||
</Entry>
|
||||
<Entry key="CredentialsDialog_WirelessNetworkTitle">
|
||||
需要网络验证
|
||||
</Entry>
|
||||
<Entry key="ExamSelectionDialog_Cancel">
|
||||
取消
|
||||
</Entry>
|
||||
|
|
|
@ -9,22 +9,27 @@
|
|||
namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// The event arguments for the <see cref="CredentialsRequiredEventHandler"/>.
|
||||
/// </summary>
|
||||
public class CredentialsRequiredEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// The name of the network which requires credentials.
|
||||
/// </summary>
|
||||
public string NetworkName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The password as specified by the user.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Indicates whether the credentials could be successfully retrieved or not.
|
||||
/// </summary>
|
||||
public bool Success { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// The username as specified by the user.
|
||||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// Indicates that credentials are required to connect to a network.
|
||||
/// </summary>
|
||||
public delegate void CredentialsRequiredEventHandler(CredentialsRequiredEventArgs args);
|
||||
}
|
||||
|
|
|
@ -45,5 +45,15 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Network
|
|||
/// Retrieves all currently available wireless networks.
|
||||
/// </summary>
|
||||
IEnumerable<IWirelessNetwork> GetWirelessNetworks();
|
||||
|
||||
/// <summary>
|
||||
/// Starts periodically scanning the available wireless networks.
|
||||
/// </summary>
|
||||
void StartWirelessNetworkScanning();
|
||||
|
||||
/// <summary>
|
||||
/// Stops the periodical scanning of wireless networks.
|
||||
/// </summary>
|
||||
void StopWirelessNetworkScanning();
|
||||
}
|
||||
}
|
||||
|
|
35
SafeExamBrowser.SystemComponents/Network/Extensions.cs
Normal file
35
SafeExamBrowser.SystemComponents/Network/Extensions.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||
using Windows.Devices.WiFi;
|
||||
|
||||
namespace SafeExamBrowser.SystemComponents.Network
|
||||
{
|
||||
internal static class Extensions
|
||||
{
|
||||
internal static IOrderedEnumerable<WiFiAvailableNetwork> FilterAndOrder(this IReadOnlyList<WiFiAvailableNetwork> networks)
|
||||
{
|
||||
return networks.Where(n => !string.IsNullOrEmpty(n.Ssid)).GroupBy(n => n.Ssid).Select(g => g.First()).OrderBy(n => n.Ssid);
|
||||
}
|
||||
|
||||
internal static WirelessNetwork ToWirelessNetwork(this WiFiAvailableNetwork network)
|
||||
{
|
||||
return new WirelessNetwork
|
||||
{
|
||||
Name = network.Ssid,
|
||||
Network = network,
|
||||
SignalStrength = Convert.ToInt32(Math.Max(0, Math.Min(100, (network.NetworkRssiInDecibelMilliwatts + 100) * 2))),
|
||||
Status = ConnectionStatus.Disconnected
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,21 +14,15 @@ using SafeExamBrowser.Logging.Contracts;
|
|||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
using SimpleWifi;
|
||||
using SimpleWifi.Win32;
|
||||
using SimpleWifi.Win32.Interop;
|
||||
using Windows.Devices.Enumeration;
|
||||
using Windows.Devices.WiFi;
|
||||
using Windows.Foundation;
|
||||
using Windows.Networking.Connectivity;
|
||||
using Windows.Security.Credentials;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
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
|
||||
{
|
||||
private readonly object @lock = new object();
|
||||
|
@ -38,7 +32,9 @@ namespace SafeExamBrowser.SystemComponents.Network
|
|||
private readonly List<WirelessNetwork> wirelessNetworks;
|
||||
|
||||
private Timer timer;
|
||||
private Wifi wifi;
|
||||
private WiFiAdapter adapter;
|
||||
|
||||
private bool HasWirelessAdapter => adapter != default;
|
||||
|
||||
public ConnectionStatus Status { get; private set; }
|
||||
public ConnectionType Type { get; private set; }
|
||||
|
@ -55,36 +51,36 @@ namespace SafeExamBrowser.SystemComponents.Network
|
|||
|
||||
public void ConnectToWirelessNetwork(string name)
|
||||
{
|
||||
var network = default(WiFiAvailableNetwork);
|
||||
|
||||
lock (@lock)
|
||||
{
|
||||
var network = wirelessNetworks.FirstOrDefault(n => n.Name == name);
|
||||
network = wirelessNetworks.FirstOrDefault(n => n.Name == name)?.Network;
|
||||
}
|
||||
|
||||
if (network != default)
|
||||
if (network != default)
|
||||
{
|
||||
var isOpen = network.SecuritySettings.NetworkAuthenticationType == NetworkAuthenticationType.Open80211 && network.SecuritySettings.NetworkEncryptionType == NetworkEncryptionType.None;
|
||||
|
||||
if (isOpen)
|
||||
{
|
||||
try
|
||||
{
|
||||
var accessPoint = network.AccessPoint;
|
||||
var request = new AuthRequest(accessPoint);
|
||||
logger.Info($"Attempting to connect to open wireless 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...");
|
||||
|
||||
// TODO: Retry resp. alert of password error on failure and then ignore profile?!
|
||||
accessPoint.ConnectAsync(request, false, (success) => ConnectionAttemptCompleted(network.Name, success));
|
||||
Status = ConnectionStatus.Connecting;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to connect to wireless network '{network.Name}!'", e);
|
||||
}
|
||||
adapter.ConnectAsync(network, WiFiReconnectionKind.Automatic).Completed = (o, s) => Adapter_ConnectCompleted(name, o, s);
|
||||
Status = ConnectionStatus.Connecting;
|
||||
}
|
||||
else
|
||||
else if (TryGetCredentials(name, out var credentials))
|
||||
{
|
||||
logger.Warn($"Could not find wireless network '{name}'!");
|
||||
logger.Info($"Attempting to connect to wireless network '{name}' with credentials...");
|
||||
|
||||
adapter.ConnectAsync(network, WiFiReconnectionKind.Automatic, credentials).Completed = (o, s) => Adapter_ConnectCompleted(name, o, s);
|
||||
Status = ConnectionStatus.Connecting;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Could not find wireless network '{name}'!");
|
||||
}
|
||||
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
@ -101,103 +97,233 @@ namespace SafeExamBrowser.SystemComponents.Network
|
|||
{
|
||||
const int FIVE_SECONDS = 5000;
|
||||
|
||||
NetworkChange.NetworkAddressChanged += (o, args) => Update();
|
||||
NetworkChange.NetworkAvailabilityChanged += (o, args) => Update();
|
||||
|
||||
wifi = new Wifi();
|
||||
wifi.ConnectionStatusChanged += (o, args) => Update();
|
||||
|
||||
timer = new Timer(FIVE_SECONDS);
|
||||
timer.Elapsed += (o, args) => Update();
|
||||
timer.AutoReset = true;
|
||||
timer.Start();
|
||||
|
||||
InitializeAdapter();
|
||||
|
||||
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
|
||||
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
|
||||
NetworkInformation.NetworkStatusChanged += NetworkInformation_NetworkStatusChanged;
|
||||
|
||||
Update();
|
||||
|
||||
logger.Info("Started monitoring the network adapter.");
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
public void StartWirelessNetworkScanning()
|
||||
{
|
||||
if (timer != null)
|
||||
timer?.Start();
|
||||
|
||||
if (HasWirelessAdapter)
|
||||
{
|
||||
timer.Stop();
|
||||
logger.Info("Stopped monitoring the network adapter.");
|
||||
_ = adapter.ScanAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectionAttemptCompleted(string name, bool success)
|
||||
public void StopWirelessNetworkScanning()
|
||||
{
|
||||
lock (@lock)
|
||||
timer?.Stop();
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
|
||||
NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
|
||||
NetworkInformation.NetworkStatusChanged -= NetworkInformation_NetworkStatusChanged;
|
||||
|
||||
if (HasWirelessAdapter)
|
||||
{
|
||||
// This handler seems to be called before the connection has been fully established, thus we don't yet set the status to connected...
|
||||
Status = success ? ConnectionStatus.Connecting : ConnectionStatus.Disconnected;
|
||||
adapter.AvailableNetworksChanged -= Adapter_AvailableNetworksChanged;
|
||||
}
|
||||
|
||||
if (success)
|
||||
if (timer != default)
|
||||
{
|
||||
timer.Stop();
|
||||
}
|
||||
|
||||
logger.Info("Stopped monitoring the network adapter.");
|
||||
}
|
||||
|
||||
private void InitializeAdapter()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Requesting access is required as of fall 2024 and must be granted manually by the user, otherwise all wireless functionality will
|
||||
// be denied by the system (see also https://learn.microsoft.com/en-us/windows/win32/nativewifi/wi-fi-access-location-changes).
|
||||
var task = WiFiAdapter.RequestAccessAsync().AsTask();
|
||||
var status = task.GetAwaiter().GetResult();
|
||||
|
||||
if (status == WiFiAccessStatus.Allowed)
|
||||
{
|
||||
var findAll = DeviceInformation.FindAllAsync(WiFiAdapter.GetDeviceSelector()).AsTask();
|
||||
var devices = findAll.GetAwaiter().GetResult();
|
||||
|
||||
if (devices.Any())
|
||||
{
|
||||
var id = devices.First().Id;
|
||||
var getById = WiFiAdapter.FromIdAsync(id).AsTask();
|
||||
|
||||
logger.Debug($"Found {devices.Count()} wireless network adapter(s).");
|
||||
|
||||
adapter = getById.GetAwaiter().GetResult();
|
||||
adapter.AvailableNetworksChanged += Adapter_AvailableNetworksChanged;
|
||||
|
||||
logger.Debug($"Successfully initialized wireless network adapter '{id}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("Could not find a wireless network adapter.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"Access to the wireless network adapter has been denied ({status})!");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to initialize wireless network adapter!", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void Adapter_AvailableNetworksChanged(WiFiAdapter sender, object args)
|
||||
{
|
||||
Update(false);
|
||||
}
|
||||
|
||||
private void Adapter_ConnectCompleted(string name, IAsyncOperation<WiFiConnectionResult> operation, AsyncStatus status)
|
||||
{
|
||||
var connectionStatus = default(WiFiConnectionStatus?);
|
||||
|
||||
if (status == AsyncStatus.Completed)
|
||||
{
|
||||
connectionStatus = operation.GetResults()?.ConnectionStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"Failed to complete connection operation! Status: {status}.");
|
||||
}
|
||||
|
||||
if (connectionStatus == WiFiConnectionStatus.Success)
|
||||
{
|
||||
Status = ConnectionStatus.Connected;
|
||||
logger.Info($"Successfully connected to wireless network '{name}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"Failed to connect to wireless network '{name}!'");
|
||||
Status = ConnectionStatus.Disconnected;
|
||||
logger.Error($"Failed to connect to wireless network '{name}'! Reason: {connectionStatus}.");
|
||||
}
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private bool TryGetCredentials(AuthRequest request)
|
||||
private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
|
||||
{
|
||||
var args = new CredentialsRequiredEventArgs();
|
||||
logger.Debug("Network address changed.");
|
||||
Update();
|
||||
}
|
||||
|
||||
private void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
|
||||
{
|
||||
logger.Debug($"Network availability changed ({(e.IsAvailable ? "available" : "unavailable")}.");
|
||||
Update();
|
||||
}
|
||||
|
||||
private void NetworkInformation_NetworkStatusChanged(object sender)
|
||||
{
|
||||
logger.Debug("Network status changed.");
|
||||
Update();
|
||||
}
|
||||
|
||||
private bool TryGetCredentials(string network, out PasswordCredential credentials)
|
||||
{
|
||||
var args = new CredentialsRequiredEventArgs { NetworkName = network };
|
||||
|
||||
credentials = new PasswordCredential();
|
||||
|
||||
CredentialsRequired?.Invoke(args);
|
||||
|
||||
if (args.Success)
|
||||
{
|
||||
request.Password = args.Password;
|
||||
request.Username = args.Username;
|
||||
if (!string.IsNullOrEmpty(args.Password))
|
||||
{
|
||||
credentials.Password = args.Password;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(args.Username))
|
||||
{
|
||||
credentials.UserName = args.Username;
|
||||
}
|
||||
}
|
||||
|
||||
return args.Success;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
private bool TryGetCurrentWirelessNetwork(out string name)
|
||||
{
|
||||
name = default;
|
||||
|
||||
if (HasWirelessAdapter)
|
||||
{
|
||||
try
|
||||
{
|
||||
var getProfile = adapter.NetworkAdapter.GetConnectedProfileAsync().AsTask();
|
||||
var profile = getProfile.GetAwaiter().GetResult();
|
||||
|
||||
if (profile?.IsWlanConnectionProfile == true)
|
||||
{
|
||||
name = profile.WlanConnectionProfileDetails.GetConnectedSsid();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return name != default;
|
||||
}
|
||||
|
||||
private void Update(bool rescan = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
var current = default(WirelessNetwork);
|
||||
var hasInternet = nativeMethods.HasInternetConnection();
|
||||
var hasWireless = !wifi.NoWifiAvailable && !IsTurnedOff();
|
||||
var isConnecting = Status == ConnectionStatus.Connecting;
|
||||
var previousStatus = Status;
|
||||
|
||||
wirelessNetworks.Clear();
|
||||
|
||||
if (hasWireless)
|
||||
if (HasWirelessAdapter)
|
||||
{
|
||||
foreach (var wirelessNetwork in wifi.GetAccessPoints().Select(a => ToWirelessNetwork(a)))
|
||||
{
|
||||
wirelessNetworks.Add(wirelessNetwork);
|
||||
TryGetCurrentWirelessNetwork(out var currentNetwork);
|
||||
|
||||
if (wirelessNetwork.Status == ConnectionStatus.Connected)
|
||||
foreach (var network in adapter.NetworkReport.AvailableNetworks.FilterAndOrder())
|
||||
{
|
||||
var wirelessNetwork = network.ToWirelessNetwork();
|
||||
|
||||
if (network.Ssid == currentNetwork)
|
||||
{
|
||||
current = wirelessNetwork;
|
||||
wirelessNetwork.Status = ConnectionStatus.Connected;
|
||||
}
|
||||
|
||||
wirelessNetworks.Add(wirelessNetwork);
|
||||
}
|
||||
|
||||
if (rescan)
|
||||
{
|
||||
_ = adapter.ScanAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Type = hasWireless ? ConnectionType.Wireless : (hasInternet ? ConnectionType.Wired : ConnectionType.Undefined);
|
||||
Status = hasInternet ? ConnectionStatus.Connected : (hasWireless && isConnecting ? ConnectionStatus.Connecting : ConnectionStatus.Disconnected);
|
||||
Type = HasWirelessAdapter ? ConnectionType.Wireless : (hasInternet ? ConnectionType.Wired : ConnectionType.Undefined);
|
||||
Status = hasInternet ? ConnectionStatus.Connected : (HasWirelessAdapter && isConnecting ? ConnectionStatus.Connecting : ConnectionStatus.Disconnected);
|
||||
|
||||
if (previousStatus != ConnectionStatus.Connected && Status == ConnectionStatus.Connected)
|
||||
{
|
||||
logger.Info($"Connection established ({Type}{(current != default ? $", {current.Name}" : "")}).");
|
||||
}
|
||||
|
||||
if (previousStatus != ConnectionStatus.Disconnected && Status == ConnectionStatus.Disconnected)
|
||||
{
|
||||
logger.Info("Connection lost.");
|
||||
}
|
||||
LogNetworkChanges(previousStatus, wirelessNetworks.FirstOrDefault(n => n.Status == ConnectionStatus.Connected));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -208,40 +334,17 @@ namespace SafeExamBrowser.SystemComponents.Network
|
|||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
private bool IsTurnedOff()
|
||||
private void LogNetworkChanges(ConnectionStatus previousStatus, WirelessNetwork currentNetwork)
|
||||
{
|
||||
try
|
||||
if (previousStatus != ConnectionStatus.Connected && Status == ConnectionStatus.Connected)
|
||||
{
|
||||
var client = new WlanClient();
|
||||
|
||||
foreach (var @interface in client.Interfaces)
|
||||
{
|
||||
foreach (var state in @interface.RadioState.PhyRadioState)
|
||||
{
|
||||
if (state.dot11SoftwareRadioState == Dot11RadioState.On && state.dot11HardwareRadioState == Dot11RadioState.On)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to determine the radio state of the wireless adapter(s)! Assuming it is (all are) turned off...", e);
|
||||
logger.Info($"Connection established ({Type}{(currentNetwork != default ? $", {currentNetwork.Name}" : "")}).");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private WirelessNetwork ToWirelessNetwork(AccessPoint accessPoint)
|
||||
{
|
||||
return new WirelessNetwork
|
||||
if (previousStatus != ConnectionStatus.Disconnected && Status == ConnectionStatus.Disconnected)
|
||||
{
|
||||
AccessPoint = accessPoint,
|
||||
Name = accessPoint.Name,
|
||||
SignalStrength = Convert.ToInt32(accessPoint.SignalStrength),
|
||||
Status = accessPoint.IsConnected ? ConnectionStatus.Connected : ConnectionStatus.Disconnected
|
||||
};
|
||||
logger.Info("Connection lost.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||
using SimpleWifi;
|
||||
using Windows.Devices.WiFi;
|
||||
|
||||
namespace SafeExamBrowser.SystemComponents.Network
|
||||
{
|
||||
internal class WirelessNetwork : IWirelessNetwork
|
||||
{
|
||||
internal AccessPoint AccessPoint { get; set; }
|
||||
internal WiFiAvailableNetwork Network { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public int SignalStrength { get; set; }
|
||||
|
|
|
@ -58,12 +58,12 @@ namespace SafeExamBrowser.SystemComponents.PowerSupply
|
|||
|
||||
public void Initialize()
|
||||
{
|
||||
const int TWO_SECONDS = 2000;
|
||||
const int FIVE_SECONDS = 5000;
|
||||
|
||||
critical = SanitizeThreshold(settings.ChargeThresholdCritical);
|
||||
low = SanitizeThreshold(settings.ChargeThresholdLow);
|
||||
|
||||
timer = new Timer(TWO_SECONDS);
|
||||
timer = new Timer(FIVE_SECONDS);
|
||||
timer.Elapsed += Timer_Elapsed;
|
||||
timer.AutoReset = true;
|
||||
timer.Start();
|
||||
|
|
|
@ -49,44 +49,10 @@
|
|||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Win32.Registry, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NAudio, Version=2.2.1.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NAudio.2.2.1\lib\net472\NAudio.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NAudio.Asio, Version=2.2.1.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NAudio.Asio.2.2.1\lib\netstandard2.0\NAudio.Asio.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NAudio.Core, Version=2.2.1.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NAudio.Core.2.2.1\lib\netstandard2.0\NAudio.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NAudio.Midi, Version=2.2.1.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NAudio.Midi.2.2.1\lib\netstandard2.0\NAudio.Midi.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NAudio.Wasapi, Version=2.2.1.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NAudio.Wasapi.2.2.1\lib\netstandard2.0\NAudio.Wasapi.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NAudio.WinForms, Version=2.2.1.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NAudio.WinForms.2.2.1\lib\net472\NAudio.WinForms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NAudio.WinMM, Version=2.2.1.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NAudio.WinMM.2.2.1\lib\netstandard2.0\NAudio.WinMM.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="SimpleWifi, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Libraries\SimpleWifi.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Security.AccessControl, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.AccessControl.6.0.0\lib\net461\System.Security.AccessControl.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Principal.Windows, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -94,6 +60,7 @@
|
|||
<Compile Include="FileSystem.cs" />
|
||||
<Compile Include="Keyboard\KeyboardLayout.cs" />
|
||||
<Compile Include="Keyboard\Keyboard.cs" />
|
||||
<Compile Include="Network\Extensions.cs" />
|
||||
<Compile Include="PowerSupply\PowerSupply.cs" />
|
||||
<Compile Include="PowerSupply\PowerSupplyStatus.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
@ -125,7 +92,20 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Win32.Registry">
|
||||
<Version>5.0.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.Contracts">
|
||||
<Version>10.0.17134.1000</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NAudio">
|
||||
<Version>2.2.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Security.AccessControl">
|
||||
<Version>6.0.1</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Win32.Registry" version="5.0.0" targetFramework="net48" />
|
||||
<package id="NAudio" version="2.2.1" targetFramework="net48" />
|
||||
<package id="NAudio.Asio" version="2.2.1" targetFramework="net48" />
|
||||
<package id="NAudio.Core" version="2.2.1" targetFramework="net48" />
|
||||
<package id="NAudio.Midi" version="2.2.1" targetFramework="net48" />
|
||||
<package id="NAudio.Wasapi" version="2.2.1" targetFramework="net48" />
|
||||
<package id="NAudio.WinForms" version="2.2.1" targetFramework="net48" />
|
||||
<package id="NAudio.WinMM" version="2.2.1" targetFramework="net48" />
|
||||
<package id="System.Security.AccessControl" version="6.0.0" targetFramework="net48" />
|
||||
<package id="System.Security.Principal.Windows" version="5.0.0" targetFramework="net48" />
|
||||
</packages>
|
|
@ -58,6 +58,11 @@ namespace SafeExamBrowser.UserInterface.Contracts
|
|||
/// </summary>
|
||||
IBrowserWindow CreateBrowserWindow(IBrowserControl control, BrowserSettings settings, bool isMainWindow, ILogger logger);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a credentials dialog for the given purpose and with the specified message and title.
|
||||
/// </summary>
|
||||
ICredentialsDialog CreateCredentialsDialog(CredentialsDialogPurpose purpose, string message, string title);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an exam selection dialog for the given exams.
|
||||
/// </summary>
|
||||
|
@ -83,11 +88,6 @@ namespace SafeExamBrowser.UserInterface.Contracts
|
|||
/// </summary>
|
||||
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>
|
||||
/// Creates a notification control for the given notification, initialized for the specified location.
|
||||
/// </summary>
|
||||
|
|
|
@ -93,16 +93,17 @@
|
|||
<Compile Include="Shell\ITaskviewActivator.cs" />
|
||||
<Compile Include="Shell\ITerminationActivator.cs" />
|
||||
<Compile Include="Shell\Location.cs" />
|
||||
<Compile Include="Windows\Data\CredentialsDialogPurpose.cs" />
|
||||
<Compile Include="Windows\Data\ExamSelectionDialogResult.cs" />
|
||||
<Compile Include="Windows\Data\LockScreenOption.cs" />
|
||||
<Compile Include="Windows\Data\LockScreenResult.cs" />
|
||||
<Compile Include="Windows\Data\NetworkDialogResult.cs" />
|
||||
<Compile Include="Windows\Data\CredentialsDialogResult.cs" />
|
||||
<Compile Include="Windows\Data\ServerFailureDialogResult.cs" />
|
||||
<Compile Include="Windows\Events\WindowClosedEventHandler.cs" />
|
||||
<Compile Include="Windows\Events\WindowClosingEventHandler.cs" />
|
||||
<Compile Include="Windows\IExamSelectionDialog.cs" />
|
||||
<Compile Include="Windows\ILockScreen.cs" />
|
||||
<Compile Include="Windows\INetworkDialog.cs" />
|
||||
<Compile Include="Windows\ICredentialsDialog.cs" />
|
||||
<Compile Include="Windows\IPasswordDialog.cs" />
|
||||
<Compile Include="Windows\Data\PasswordDialogResult.cs" />
|
||||
<Compile Include="Proctoring\IProctoringFinalizationDialog.cs" />
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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 purpose of a <see cref="ICredentialsDialog"/>.
|
||||
/// </summary>
|
||||
public enum CredentialsDialogPurpose
|
||||
{
|
||||
/// <summary>
|
||||
/// Credentials for generic purposes.
|
||||
/// </summary>
|
||||
Generic,
|
||||
|
||||
/// <summary>
|
||||
/// Credentials for wireless network authentication.
|
||||
/// </summary>
|
||||
WirelessNetwork
|
||||
}
|
||||
}
|
|
@ -9,9 +9,9 @@
|
|||
namespace SafeExamBrowser.UserInterface.Contracts.Windows.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the user interaction result of an <see cref="INetworkDialog"/>.
|
||||
/// Defines the user interaction result of an <see cref="ICredentialsDialog"/>.
|
||||
/// </summary>
|
||||
public class NetworkDialogResult
|
||||
public class CredentialsDialogResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The password entered by the user, or <c>default(string)</c> if the interaction was unsuccessful.
|
|
@ -11,13 +11,13 @@ using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
|||
namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the functionality of a network dialog.
|
||||
/// Defines the functionality of a dialog to retrieve user credentials.
|
||||
/// </summary>
|
||||
public interface INetworkDialog : IWindow
|
||||
public interface ICredentialsDialog : 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);
|
||||
CredentialsDialogResult Show(IWindow parent = null);
|
||||
}
|
||||
}
|
|
@ -63,6 +63,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
|||
}
|
||||
Popup.IsOpen = Popup.IsMouseOver;
|
||||
}));
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
adapter.StopWirelessNetworkScanning();
|
||||
Grid.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
|
@ -73,6 +79,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
|||
}));
|
||||
Popup.Opened += (o, args) =>
|
||||
{
|
||||
adapter.StartWirelessNetworkScanning();
|
||||
Grid.Background = Brushes.Gray;
|
||||
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
||||
{
|
||||
|
@ -82,11 +89,6 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
|||
}
|
||||
}));
|
||||
};
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
Grid.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
WirelessIcon.Child = GetWirelessIcon(0);
|
||||
|
||||
Update();
|
||||
|
@ -94,23 +96,6 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
|||
|
||||
private void Update()
|
||||
{
|
||||
WirelessNetworksStackPanel.Children.Clear();
|
||||
|
||||
foreach (var network in adapter.GetWirelessNetworks())
|
||||
{
|
||||
var button = new NetworkButton(network);
|
||||
|
||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||
|
||||
if (network.Status == ConnectionStatus.Connected)
|
||||
{
|
||||
WirelessIcon.Child = GetWirelessIcon(network.SignalStrength);
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name));
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Add(button);
|
||||
}
|
||||
|
||||
switch (adapter.Type)
|
||||
{
|
||||
case ConnectionType.Wired:
|
||||
|
@ -154,6 +139,23 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
|||
WirelessIcon.Child = GetWirelessIcon(0);
|
||||
break;
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Clear();
|
||||
|
||||
foreach (var network in adapter.GetWirelessNetworks())
|
||||
{
|
||||
var button = new NetworkButton(network);
|
||||
|
||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||
|
||||
if (network.Status == ConnectionStatus.Connected)
|
||||
{
|
||||
WirelessIcon.Child = GetWirelessIcon(network.SignalStrength);
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name));
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateText(string text)
|
||||
|
|
|
@ -66,6 +66,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
|||
}));
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
adapter.StopWirelessNetworkScanning();
|
||||
Background = originalBrush;
|
||||
Button.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
|
@ -81,6 +82,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
|||
}));
|
||||
Popup.Opened += (o, args) =>
|
||||
{
|
||||
adapter.StartWirelessNetworkScanning();
|
||||
Background = Brushes.LightGray;
|
||||
Button.Background = Brushes.LightGray;
|
||||
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
||||
|
@ -106,23 +108,6 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
|||
|
||||
private void Update()
|
||||
{
|
||||
WirelessNetworksStackPanel.Children.Clear();
|
||||
|
||||
foreach (var network in adapter.GetWirelessNetworks())
|
||||
{
|
||||
var button = new NetworkButton(network);
|
||||
|
||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||
|
||||
if (network.Status == ConnectionStatus.Connected)
|
||||
{
|
||||
WirelessIcon.Child = GetWirelessIcon(network.SignalStrength);
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name));
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Add(button);
|
||||
}
|
||||
|
||||
switch (adapter.Type)
|
||||
{
|
||||
case ConnectionType.Wired:
|
||||
|
@ -166,6 +151,23 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
|||
WirelessIcon.Child = GetWirelessIcon(0);
|
||||
break;
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Clear();
|
||||
|
||||
foreach (var network in adapter.GetWirelessNetworks())
|
||||
{
|
||||
var button = new NetworkButton(network);
|
||||
|
||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||
|
||||
if (network.Status == ConnectionStatus.Connected)
|
||||
{
|
||||
WirelessIcon.Child = GetWirelessIcon(network.SignalStrength);
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name));
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateText(string text)
|
||||
|
|
|
@ -168,8 +168,8 @@
|
|||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="MessageBoxFactory.cs" />
|
||||
<Compile Include="Windows\NetworkDialog.xaml.cs">
|
||||
<DependentUpon>NetworkDialog.xaml</DependentUpon>
|
||||
<Compile Include="Windows\CredentialsDialog.xaml.cs">
|
||||
<DependentUpon>CredentialsDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\PasswordDialog.xaml.cs">
|
||||
<DependentUpon>PasswordDialog.xaml</DependentUpon>
|
||||
|
@ -397,7 +397,7 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\NetworkDialog.xaml">
|
||||
<Page Include="Windows\CredentialsDialog.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
|
|
|
@ -85,6 +85,11 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
|||
return Application.Current.Dispatcher.Invoke(() => new BrowserWindow(control, settings, isMainWindow, text, logger));
|
||||
}
|
||||
|
||||
public ICredentialsDialog CreateCredentialsDialog(CredentialsDialogPurpose purpose, string message, string title)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new CredentialsDialog(purpose, message, title, text));
|
||||
}
|
||||
|
||||
public IExamSelectionDialog CreateExamSelectionDialog(IEnumerable<Exam> exams)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new ExamSelectionDialog(exams, text));
|
||||
|
@ -143,11 +148,6 @@ 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)
|
||||
{
|
||||
if (location == Location.ActionCenter)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<Window x:Class="SafeExamBrowser.UserInterface.Desktop.Windows.NetworkDialog"
|
||||
<Window x:Class="SafeExamBrowser.UserInterface.Desktop.Windows.CredentialsDialog"
|
||||
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">
|
||||
mc:Ignorable="d" Height="325" Width="450" ResizeMode="NoResize" Topmost="True">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
|
@ -15,17 +15,17 @@
|
|||
</Window.Resources>
|
||||
<Grid FocusManager.FocusedElement="{Binding ElementName=Password}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid Grid.Row="0" VerticalAlignment="Center">
|
||||
<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">
|
||||
<fa:ImageAwesome Grid.Column="0" Name="PurposeIcon" Foreground="LightGray" Icon="Key" Margin="25" Rotation="90" Width="50" />
|
||||
<Grid Grid.Column="1" Margin="0,25,25,25">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
|
@ -33,18 +33,18 @@
|
|||
</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}" />
|
||||
<Label Name="UsernameLabel" Padding="0,5" 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}" />
|
||||
<Label Name="PasswordLabel" Padding="0,5" 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">
|
||||
<WrapPanel Orientation="Horizontal" Margin="25" 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>
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using FontAwesome.WPF;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
|
@ -15,7 +16,7 @@ using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
|||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
||||
{
|
||||
public partial class NetworkDialog : Window, INetworkDialog
|
||||
public partial class CredentialsDialog : Window, ICredentialsDialog
|
||||
{
|
||||
private readonly IText text;
|
||||
|
||||
|
@ -34,12 +35,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
remove { closing -= value; }
|
||||
}
|
||||
|
||||
internal NetworkDialog(string message, string title, IText text)
|
||||
internal CredentialsDialog(CredentialsDialogPurpose purpose, string message, string title, IText text)
|
||||
{
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeNetworkDialog(message, title);
|
||||
InitializeCredentialsDialog(purpose, message, title);
|
||||
}
|
||||
|
||||
public void BringToForeground()
|
||||
|
@ -47,11 +48,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
Dispatcher.Invoke(Activate);
|
||||
}
|
||||
|
||||
public NetworkDialogResult Show(IWindow parent = null)
|
||||
public CredentialsDialogResult Show(IWindow parent = null)
|
||||
{
|
||||
return Dispatcher.Invoke(() =>
|
||||
{
|
||||
var result = new NetworkDialogResult { Success = false };
|
||||
var result = new CredentialsDialogResult { Success = false };
|
||||
|
||||
if (parent is Window)
|
||||
{
|
||||
|
@ -70,14 +71,24 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
});
|
||||
}
|
||||
|
||||
private void InitializeNetworkDialog(string message, string title)
|
||||
private void InitializeCredentialsDialog(CredentialsDialogPurpose purpose, string message, string title)
|
||||
{
|
||||
if (purpose == CredentialsDialogPurpose.WirelessNetwork)
|
||||
{
|
||||
PurposeIcon.Icon = FontAwesomeIcon.Wifi;
|
||||
PurposeIcon.Rotation = 0;
|
||||
UsernameLabel.Content = text.Get(TextKey.CredentialsDialog_UsernameOptionalLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
PurposeIcon.Icon = FontAwesomeIcon.Key;
|
||||
PurposeIcon.Rotation = 90;
|
||||
UsernameLabel.Content = text.Get(TextKey.CredentialsDialog_UsernameLabel);
|
||||
}
|
||||
|
||||
PasswordLabel.Content = text.Get(TextKey.CredentialsDialog_PasswordLabel);
|
||||
Message.Text = message;
|
||||
// TODO
|
||||
PasswordLabel.Content = "Password";
|
||||
Title = title;
|
||||
// TODO
|
||||
UsernameLabel.Content = "Username";
|
||||
WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||
|
||||
Closed += (o, args) => closed?.Invoke();
|
|
@ -63,6 +63,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
|
|||
}
|
||||
Popup.IsOpen = Popup.IsMouseOver;
|
||||
}));
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
adapter.StopWirelessNetworkScanning();
|
||||
Grid.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
|
@ -73,6 +79,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
|
|||
}));
|
||||
Popup.Opened += (o, args) =>
|
||||
{
|
||||
adapter.StartWirelessNetworkScanning();
|
||||
Grid.Background = Brushes.Gray;
|
||||
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
||||
{
|
||||
|
@ -82,11 +89,6 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
|
|||
}
|
||||
}));
|
||||
};
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
Grid.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
WirelessIcon.Child = GetWirelessIcon(0);
|
||||
|
||||
Update();
|
||||
|
@ -94,23 +96,6 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
|
|||
|
||||
private void Update()
|
||||
{
|
||||
WirelessNetworksStackPanel.Children.Clear();
|
||||
|
||||
foreach (var network in adapter.GetWirelessNetworks())
|
||||
{
|
||||
var button = new NetworkButton(network);
|
||||
|
||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||
|
||||
if (network.Status == ConnectionStatus.Connected)
|
||||
{
|
||||
WirelessIcon.Child = GetWirelessIcon(network.SignalStrength);
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name));
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Add(button);
|
||||
}
|
||||
|
||||
switch (adapter.Type)
|
||||
{
|
||||
case ConnectionType.Wired:
|
||||
|
@ -154,6 +139,23 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
|
|||
WirelessIcon.Child = GetWirelessIcon(0);
|
||||
break;
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Clear();
|
||||
|
||||
foreach (var network in adapter.GetWirelessNetworks())
|
||||
{
|
||||
var button = new NetworkButton(network);
|
||||
|
||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||
|
||||
if (network.Status == ConnectionStatus.Connected)
|
||||
{
|
||||
WirelessIcon.Child = GetWirelessIcon(network.SignalStrength);
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name));
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateText(string text)
|
||||
|
|
|
@ -66,6 +66,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
|
|||
}));
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
adapter.StopWirelessNetworkScanning();
|
||||
Background = originalBrush;
|
||||
Button.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
|
@ -81,6 +82,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
|
|||
}));
|
||||
Popup.Opened += (o, args) =>
|
||||
{
|
||||
adapter.StartWirelessNetworkScanning();
|
||||
Background = Brushes.LightGray;
|
||||
Button.Background = Brushes.LightGray;
|
||||
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
||||
|
@ -106,23 +108,6 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
|
|||
|
||||
private void Update()
|
||||
{
|
||||
WirelessNetworksStackPanel.Children.Clear();
|
||||
|
||||
foreach (var network in adapter.GetWirelessNetworks())
|
||||
{
|
||||
var button = new NetworkButton(network);
|
||||
|
||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||
|
||||
if (network.Status == ConnectionStatus.Connected)
|
||||
{
|
||||
WirelessIcon.Child = GetWirelessIcon(network.SignalStrength);
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name));
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Add(button);
|
||||
}
|
||||
|
||||
switch (adapter.Type)
|
||||
{
|
||||
case ConnectionType.Wired:
|
||||
|
@ -166,6 +151,23 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
|
|||
WirelessIcon.Child = GetWirelessIcon(0);
|
||||
break;
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Clear();
|
||||
|
||||
foreach (var network in adapter.GetWirelessNetworks())
|
||||
{
|
||||
var button = new NetworkButton(network);
|
||||
|
||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||
|
||||
if (network.Status == ConnectionStatus.Connected)
|
||||
{
|
||||
WirelessIcon.Child = GetWirelessIcon(network.SignalStrength);
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name));
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateText(string text)
|
||||
|
|
|
@ -173,6 +173,9 @@
|
|||
<Compile Include="Windows\MessageBoxDialog.xaml.cs">
|
||||
<DependentUpon>MessageBoxDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\CredentialsDialog.xaml.cs">
|
||||
<DependentUpon>CredentialsDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\PasswordDialog.xaml.cs">
|
||||
<DependentUpon>PasswordDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -521,6 +524,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\CredentialsDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\PasswordDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
|
|
@ -85,6 +85,11 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
|||
return Application.Current.Dispatcher.Invoke(() => new BrowserWindow(control, settings, isMainWindow, text, logger));
|
||||
}
|
||||
|
||||
public ICredentialsDialog CreateCredentialsDialog(CredentialsDialogPurpose purpose, string message, string title)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new CredentialsDialog(purpose, message, title, text));
|
||||
}
|
||||
|
||||
public IExamSelectionDialog CreateExamSelectionDialog(IEnumerable<Exam> exams)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new ExamSelectionDialog(exams, text));
|
||||
|
@ -143,12 +148,6 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
|||
}
|
||||
}
|
||||
|
||||
public INetworkDialog CreateNetworkDialog(string message, string title)
|
||||
{
|
||||
// TODO
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public INotificationControl CreateNotificationControl(INotification notification, Location location)
|
||||
{
|
||||
if (location == Location.ActionCenter)
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<Window x:Class="SafeExamBrowser.UserInterface.Mobile.Windows.CredentialsDialog" x:ClassModifier="internal"
|
||||
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.Mobile"
|
||||
mc:Ignorable="d" Background="Transparent" Height="750" Width="1000" FontSize="16" ResizeMode="NoResize" Topmost="True" AllowsTransparency="True" WindowStyle="None">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<Grid Background="#66000000" FocusManager.FocusedElement="{Binding ElementName=Password}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" />
|
||||
<Grid Grid.Row="1" Background="White">
|
||||
<Grid Margin="25">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<fa:ImageAwesome Grid.Column="0" Name="PurposeIcon" Foreground="LightGray" Icon="Key" Margin="25" Rotation="90" Width="75" />
|
||||
<Grid Grid.Column="1" Margin="25,0,25,25">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" x:Name="Message" Margin="0,20" TextWrapping="WrapWithOverflow" VerticalAlignment="Bottom" />
|
||||
<StackPanel Grid.Row="1" Orientation="Vertical">
|
||||
<Label Name="UsernameLabel" Padding="0,5" Target="{Binding ElementName=Username}" />
|
||||
<TextBox Name="Username" Padding="12" VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="2" Orientation="Vertical">
|
||||
<Label Name="PasswordLabel" Padding="0,5" Target="{Binding ElementName=Password}" />
|
||||
<PasswordBox x:Name="Password" Padding="12" VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid Grid.Row="2" Background="{StaticResource BackgroundBrush}">
|
||||
<WrapPanel Orientation="Horizontal" Margin="50,25" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button x:Name="ConfirmButton" Cursor="Hand" Margin="20,0" Padding="20,10" MinWidth="100" />
|
||||
<Button x:Name="CancelButton" Cursor="Hand" Padding="20,10" MinWidth="100" />
|
||||
</WrapPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* 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 FontAwesome.WPF;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
||||
{
|
||||
internal partial class CredentialsDialog : Window, ICredentialsDialog
|
||||
{
|
||||
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 CredentialsDialog(CredentialsDialogPurpose purpose, string message, string title, IText text)
|
||||
{
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeCredentialsDialog(purpose, message, title);
|
||||
}
|
||||
|
||||
public void BringToForeground()
|
||||
{
|
||||
Dispatcher.Invoke(Activate);
|
||||
}
|
||||
|
||||
public CredentialsDialogResult Show(IWindow parent = null)
|
||||
{
|
||||
return Dispatcher.Invoke(() =>
|
||||
{
|
||||
var result = new CredentialsDialogResult { Success = false };
|
||||
|
||||
if (parent is Window)
|
||||
{
|
||||
Owner = parent as Window;
|
||||
}
|
||||
|
||||
InitializeBounds();
|
||||
|
||||
if (ShowDialog() is true)
|
||||
{
|
||||
result.Password = Password.Password;
|
||||
result.Success = true;
|
||||
result.Username = Username.Text;
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
private void InitializeBounds()
|
||||
{
|
||||
Left = 0;
|
||||
Top = 0;
|
||||
Height = SystemParameters.PrimaryScreenHeight;
|
||||
Width = SystemParameters.PrimaryScreenWidth;
|
||||
}
|
||||
|
||||
private void InitializeCredentialsDialog(CredentialsDialogPurpose purpose, string message, string title)
|
||||
{
|
||||
InitializeBounds();
|
||||
|
||||
if (purpose == CredentialsDialogPurpose.WirelessNetwork)
|
||||
{
|
||||
PurposeIcon.Icon = FontAwesomeIcon.Wifi;
|
||||
PurposeIcon.Rotation = 0;
|
||||
UsernameLabel.Content = text.Get(TextKey.CredentialsDialog_UsernameOptionalLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
PurposeIcon.Icon = FontAwesomeIcon.Key;
|
||||
PurposeIcon.Rotation = 90;
|
||||
UsernameLabel.Content = text.Get(TextKey.CredentialsDialog_UsernameLabel);
|
||||
}
|
||||
|
||||
PasswordLabel.Content = text.Get(TextKey.CredentialsDialog_PasswordLabel);
|
||||
Message.Text = message;
|
||||
Title = title;
|
||||
|
||||
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;
|
||||
|
||||
SystemParameters.StaticPropertyChanged += SystemParameters_StaticPropertyChanged;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private void SystemParameters_StaticPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(SystemParameters.WorkArea))
|
||||
{
|
||||
Dispatcher.InvokeAsync(InitializeBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,11 +27,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.SystemCompo
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.UserInterface.Desktop", "SafeExamBrowser.UserInterface.Desktop\SafeExamBrowser.UserInterface.Desktop.csproj", "{A502DF54-7169-4647-94BD-18B192924866}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{E03B19EC-8E4D-481C-9C1B-5C6C060D3D6B}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Libraries\SimpleWifi.dll = Libraries\SimpleWifi.dll
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Client", "SafeExamBrowser.Client\SafeExamBrowser.Client.csproj", "{7CC5A895-E0D3-4E43-9B39-CCEC05A5A6A7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Client.UnitTests", "SafeExamBrowser.Client.UnitTests\SafeExamBrowser.Client.UnitTests.csproj", "{15684416-FADF-4C51-85DE-4F343BFAB752}"
|
||||
|
|
Loading…
Reference in a new issue