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)
|
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();
|
var result = dialog.Show();
|
||||||
|
|
||||||
args.Password = result.Password;
|
args.Password = result.Password;
|
||||||
|
|
|
@ -26,26 +26,6 @@ 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)
|
||||||
|
|
|
@ -47,6 +47,11 @@ namespace SafeExamBrowser.I18n.Contracts
|
||||||
BrowserWindow_ZoomMenuMinus,
|
BrowserWindow_ZoomMenuMinus,
|
||||||
BrowserWindow_ZoomMenuPlus,
|
BrowserWindow_ZoomMenuPlus,
|
||||||
Build,
|
Build,
|
||||||
|
CredentialsDialog_PasswordLabel,
|
||||||
|
CredentialsDialog_UsernameLabel,
|
||||||
|
CredentialsDialog_UsernameOptionalLabel,
|
||||||
|
CredentialsDialog_WirelessNetworkMessage,
|
||||||
|
CredentialsDialog_WirelessNetworkTitle,
|
||||||
ExamSelectionDialog_Cancel,
|
ExamSelectionDialog_Cancel,
|
||||||
ExamSelectionDialog_Message,
|
ExamSelectionDialog_Message,
|
||||||
ExamSelectionDialog_Select,
|
ExamSelectionDialog_Select,
|
||||||
|
|
|
@ -99,6 +99,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
Build
|
Build
|
||||||
</Entry>
|
</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">
|
<Entry key="ExamSelectionDialog_Cancel">
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -99,6 +99,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
Build
|
Build
|
||||||
</Entry>
|
</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">
|
<Entry key="ExamSelectionDialog_Cancel">
|
||||||
Cancel
|
Cancel
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -99,6 +99,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
Build
|
Build
|
||||||
</Entry>
|
</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">
|
<Entry key="ExamSelectionDialog_Cancel">
|
||||||
Cancel
|
Cancel
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -99,6 +99,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
Koosta
|
Koosta
|
||||||
</Entry>
|
</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">
|
<Entry key="ExamSelectionDialog_Cancel">
|
||||||
Tühista
|
Tühista
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -99,6 +99,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
Build
|
Build
|
||||||
</Entry>
|
</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">
|
<Entry key="ExamSelectionDialog_Cancel">
|
||||||
Annuler
|
Annuler
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -99,6 +99,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
Bangun
|
Bangun
|
||||||
</Entry>
|
</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">
|
<Entry key="ExamSelectionDialog_Cancel">
|
||||||
Batal
|
Batal
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -99,6 +99,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
Build
|
Build
|
||||||
</Entry>
|
</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">
|
<Entry key="ExamSelectionDialog_Cancel">
|
||||||
Annulla
|
Annulla
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -99,6 +99,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
Build
|
Build
|
||||||
</Entry>
|
</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">
|
<Entry key="ExamSelectionDialog_Cancel">
|
||||||
Annuleren
|
Annuleren
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -99,6 +99,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
Строить
|
Строить
|
||||||
</Entry>
|
</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 key="ExamSelectionDialog_Cancel">
|
||||||
Отмена
|
Отмена
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -99,6 +99,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
生成
|
生成
|
||||||
</Entry>
|
</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 key="ExamSelectionDialog_Cancel">
|
||||||
取消
|
取消
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -9,22 +9,27 @@
|
||||||
namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events
|
namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// The event arguments for the <see cref="CredentialsRequiredEventHandler"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CredentialsRequiredEventArgs
|
public class CredentialsRequiredEventArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// The name of the network which requires credentials.
|
||||||
|
/// </summary>
|
||||||
|
public string NetworkName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The password as specified by the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Indicates whether the credentials could be successfully retrieved or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Success { get; set; }
|
public bool Success { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// The username as specified by the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events
|
namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Indicates that credentials are required to connect to a network.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public delegate void CredentialsRequiredEventHandler(CredentialsRequiredEventArgs args);
|
public delegate void CredentialsRequiredEventHandler(CredentialsRequiredEventArgs args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,5 +45,15 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Network
|
||||||
/// Retrieves all currently available wireless networks.
|
/// Retrieves all currently available wireless networks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IEnumerable<IWirelessNetwork> GetWirelessNetworks();
|
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;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
|
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
using SimpleWifi;
|
using Windows.Devices.Enumeration;
|
||||||
using SimpleWifi.Win32;
|
using Windows.Devices.WiFi;
|
||||||
using SimpleWifi.Win32.Interop;
|
using Windows.Foundation;
|
||||||
|
using Windows.Networking.Connectivity;
|
||||||
|
using Windows.Security.Credentials;
|
||||||
using Timer = System.Timers.Timer;
|
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();
|
||||||
|
@ -38,7 +32,9 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
private readonly List<WirelessNetwork> wirelessNetworks;
|
private readonly List<WirelessNetwork> wirelessNetworks;
|
||||||
|
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
private Wifi wifi;
|
private WiFiAdapter adapter;
|
||||||
|
|
||||||
|
private bool HasWirelessAdapter => adapter != default;
|
||||||
|
|
||||||
public ConnectionStatus Status { get; private set; }
|
public ConnectionStatus Status { get; private set; }
|
||||||
public ConnectionType Type { get; private set; }
|
public ConnectionType Type { get; private set; }
|
||||||
|
@ -55,36 +51,36 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
|
|
||||||
public void ConnectToWirelessNetwork(string name)
|
public void ConnectToWirelessNetwork(string name)
|
||||||
{
|
{
|
||||||
|
var network = default(WiFiAvailableNetwork);
|
||||||
|
|
||||||
lock (@lock)
|
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
|
logger.Info($"Attempting to connect to open wireless network '{name}'...");
|
||||||
{
|
|
||||||
var accessPoint = network.AccessPoint;
|
|
||||||
var request = new AuthRequest(accessPoint);
|
|
||||||
|
|
||||||
if (accessPoint.HasProfile || accessPoint.IsConnected || TryGetCredentials(request))
|
adapter.ConnectAsync(network, WiFiReconnectionKind.Automatic).Completed = (o, s) => Adapter_ConnectCompleted(name, o, s);
|
||||||
{
|
Status = ConnectionStatus.Connecting;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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();
|
Changed?.Invoke();
|
||||||
}
|
}
|
||||||
|
@ -101,103 +97,233 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
{
|
{
|
||||||
const int FIVE_SECONDS = 5000;
|
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 = new Timer(FIVE_SECONDS);
|
||||||
timer.Elapsed += (o, args) => Update();
|
timer.Elapsed += (o, args) => Update();
|
||||||
timer.AutoReset = true;
|
timer.AutoReset = true;
|
||||||
timer.Start();
|
|
||||||
|
InitializeAdapter();
|
||||||
|
|
||||||
|
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
|
||||||
|
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
|
||||||
|
NetworkInformation.NetworkStatusChanged += NetworkInformation_NetworkStatusChanged;
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
|
|
||||||
logger.Info("Started monitoring the network adapter.");
|
logger.Info("Started monitoring the network adapter.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Terminate()
|
public void StartWirelessNetworkScanning()
|
||||||
{
|
{
|
||||||
if (timer != null)
|
timer?.Start();
|
||||||
|
|
||||||
|
if (HasWirelessAdapter)
|
||||||
{
|
{
|
||||||
timer.Stop();
|
_ = adapter.ScanAsync();
|
||||||
logger.Info("Stopped monitoring the network adapter.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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...
|
adapter.AvailableNetworksChanged -= Adapter_AvailableNetworksChanged;
|
||||||
Status = success ? ConnectionStatus.Connecting : ConnectionStatus.Disconnected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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}'.");
|
logger.Info($"Successfully connected to wireless network '{name}'.");
|
||||||
}
|
}
|
||||||
else
|
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);
|
CredentialsRequired?.Invoke(args);
|
||||||
|
|
||||||
if (args.Success)
|
if (args.Success)
|
||||||
{
|
{
|
||||||
request.Password = args.Password;
|
if (!string.IsNullOrEmpty(args.Password))
|
||||||
request.Username = args.Username;
|
{
|
||||||
|
credentials.Password = args.Password;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(args.Username))
|
||||||
|
{
|
||||||
|
credentials.UserName = args.Username;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return args.Success;
|
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
|
try
|
||||||
{
|
{
|
||||||
lock (@lock)
|
lock (@lock)
|
||||||
{
|
{
|
||||||
var current = default(WirelessNetwork);
|
|
||||||
var hasInternet = nativeMethods.HasInternetConnection();
|
var hasInternet = nativeMethods.HasInternetConnection();
|
||||||
var hasWireless = !wifi.NoWifiAvailable && !IsTurnedOff();
|
|
||||||
var isConnecting = Status == ConnectionStatus.Connecting;
|
var isConnecting = Status == ConnectionStatus.Connecting;
|
||||||
var previousStatus = Status;
|
var previousStatus = Status;
|
||||||
|
|
||||||
wirelessNetworks.Clear();
|
wirelessNetworks.Clear();
|
||||||
|
|
||||||
if (hasWireless)
|
if (HasWirelessAdapter)
|
||||||
{
|
{
|
||||||
foreach (var wirelessNetwork in wifi.GetAccessPoints().Select(a => ToWirelessNetwork(a)))
|
TryGetCurrentWirelessNetwork(out var currentNetwork);
|
||||||
{
|
|
||||||
wirelessNetworks.Add(wirelessNetwork);
|
|
||||||
|
|
||||||
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);
|
Type = HasWirelessAdapter ? ConnectionType.Wireless : (hasInternet ? ConnectionType.Wired : ConnectionType.Undefined);
|
||||||
Status = hasInternet ? ConnectionStatus.Connected : (hasWireless && isConnecting ? ConnectionStatus.Connecting : ConnectionStatus.Disconnected);
|
Status = hasInternet ? ConnectionStatus.Connected : (HasWirelessAdapter && isConnecting ? ConnectionStatus.Connecting : ConnectionStatus.Disconnected);
|
||||||
|
|
||||||
if (previousStatus != ConnectionStatus.Connected && Status == ConnectionStatus.Connected)
|
LogNetworkChanges(previousStatus, wirelessNetworks.FirstOrDefault(n => n.Status == ConnectionStatus.Connected));
|
||||||
{
|
|
||||||
logger.Info($"Connection established ({Type}{(current != default ? $", {current.Name}" : "")}).");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previousStatus != ConnectionStatus.Disconnected && Status == ConnectionStatus.Disconnected)
|
|
||||||
{
|
|
||||||
logger.Info("Connection lost.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -208,40 +334,17 @@ namespace SafeExamBrowser.SystemComponents.Network
|
||||||
Changed?.Invoke();
|
Changed?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsTurnedOff()
|
private void LogNetworkChanges(ConnectionStatus previousStatus, WirelessNetwork currentNetwork)
|
||||||
{
|
{
|
||||||
try
|
if (previousStatus != ConnectionStatus.Connected && Status == ConnectionStatus.Connected)
|
||||||
{
|
{
|
||||||
var client = new WlanClient();
|
logger.Info($"Connection established ({Type}{(currentNetwork != default ? $", {currentNetwork.Name}" : "")}).");
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (previousStatus != ConnectionStatus.Disconnected && Status == ConnectionStatus.Disconnected)
|
||||||
}
|
|
||||||
|
|
||||||
private WirelessNetwork ToWirelessNetwork(AccessPoint accessPoint)
|
|
||||||
{
|
|
||||||
return new WirelessNetwork
|
|
||||||
{
|
{
|
||||||
AccessPoint = accessPoint,
|
logger.Info("Connection lost.");
|
||||||
Name = accessPoint.Name,
|
}
|
||||||
SignalStrength = Convert.ToInt32(accessPoint.SignalStrength),
|
|
||||||
Status = accessPoint.IsConnected ? ConnectionStatus.Connected : ConnectionStatus.Disconnected
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||||
using SimpleWifi;
|
using Windows.Devices.WiFi;
|
||||||
|
|
||||||
namespace SafeExamBrowser.SystemComponents.Network
|
namespace SafeExamBrowser.SystemComponents.Network
|
||||||
{
|
{
|
||||||
internal class WirelessNetwork : IWirelessNetwork
|
internal class WirelessNetwork : IWirelessNetwork
|
||||||
{
|
{
|
||||||
internal AccessPoint AccessPoint { get; set; }
|
internal WiFiAvailableNetwork Network { get; set; }
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public int SignalStrength { get; set; }
|
public int SignalStrength { get; set; }
|
||||||
|
|
|
@ -58,12 +58,12 @@ namespace SafeExamBrowser.SystemComponents.PowerSupply
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
const int TWO_SECONDS = 2000;
|
const int FIVE_SECONDS = 5000;
|
||||||
|
|
||||||
critical = SanitizeThreshold(settings.ChargeThresholdCritical);
|
critical = SanitizeThreshold(settings.ChargeThresholdCritical);
|
||||||
low = SanitizeThreshold(settings.ChargeThresholdLow);
|
low = SanitizeThreshold(settings.ChargeThresholdLow);
|
||||||
|
|
||||||
timer = new Timer(TWO_SECONDS);
|
timer = new Timer(FIVE_SECONDS);
|
||||||
timer.Elapsed += Timer_Elapsed;
|
timer.Elapsed += Timer_Elapsed;
|
||||||
timer.AutoReset = true;
|
timer.AutoReset = true;
|
||||||
timer.Start();
|
timer.Start();
|
||||||
|
|
|
@ -49,44 +49,10 @@
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<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="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="System" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System.Management" />
|
<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" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -94,6 +60,7 @@
|
||||||
<Compile Include="FileSystem.cs" />
|
<Compile Include="FileSystem.cs" />
|
||||||
<Compile Include="Keyboard\KeyboardLayout.cs" />
|
<Compile Include="Keyboard\KeyboardLayout.cs" />
|
||||||
<Compile Include="Keyboard\Keyboard.cs" />
|
<Compile Include="Keyboard\Keyboard.cs" />
|
||||||
|
<Compile Include="Network\Extensions.cs" />
|
||||||
<Compile Include="PowerSupply\PowerSupply.cs" />
|
<Compile Include="PowerSupply\PowerSupply.cs" />
|
||||||
<Compile Include="PowerSupply\PowerSupplyStatus.cs" />
|
<Compile Include="PowerSupply\PowerSupplyStatus.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
@ -125,7 +92,20 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="app.config" />
|
<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>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</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>
|
/// </summary>
|
||||||
IBrowserWindow CreateBrowserWindow(IBrowserControl control, BrowserSettings settings, bool isMainWindow, ILogger logger);
|
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>
|
/// <summary>
|
||||||
/// Creates an exam selection dialog for the given exams.
|
/// Creates an exam selection dialog for the given exams.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -83,11 +88,6 @@ 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>
|
||||||
|
|
|
@ -93,16 +93,17 @@
|
||||||
<Compile Include="Shell\ITaskviewActivator.cs" />
|
<Compile Include="Shell\ITaskviewActivator.cs" />
|
||||||
<Compile Include="Shell\ITerminationActivator.cs" />
|
<Compile Include="Shell\ITerminationActivator.cs" />
|
||||||
<Compile Include="Shell\Location.cs" />
|
<Compile Include="Shell\Location.cs" />
|
||||||
|
<Compile Include="Windows\Data\CredentialsDialogPurpose.cs" />
|
||||||
<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\CredentialsDialogResult.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\ICredentialsDialog.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,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
|
namespace SafeExamBrowser.UserInterface.Contracts.Windows.Data
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the user interaction result of an <see cref="INetworkDialog"/>.
|
/// Defines the user interaction result of an <see cref="ICredentialsDialog"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NetworkDialogResult
|
public class CredentialsDialogResult
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The password entered by the user, or <c>default(string)</c> if the interaction was unsuccessful.
|
/// 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
|
namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the functionality of a network dialog.
|
/// Defines the functionality of a dialog to retrieve user credentials.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface INetworkDialog : IWindow
|
public interface ICredentialsDialog : IWindow
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shows the dialog as topmost window. If a parent window is specified, the dialog is rendered modally for the given parent.
|
/// Shows the dialog as topmost window. If a parent window is specified, the dialog is rendered modally for the given parent.
|
||||||
/// </summary>
|
/// </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.IsOpen = Popup.IsMouseOver;
|
||||||
}));
|
}));
|
||||||
|
Popup.Closed += (o, args) =>
|
||||||
|
{
|
||||||
|
adapter.StopWirelessNetworkScanning();
|
||||||
|
Grid.Background = originalBrush;
|
||||||
|
lastOpenedBySpacePress = false;
|
||||||
|
};
|
||||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||||
|
@ -73,6 +79,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||||
}));
|
}));
|
||||||
Popup.Opened += (o, args) =>
|
Popup.Opened += (o, args) =>
|
||||||
{
|
{
|
||||||
|
adapter.StartWirelessNetworkScanning();
|
||||||
Grid.Background = Brushes.Gray;
|
Grid.Background = Brushes.Gray;
|
||||||
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
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);
|
WirelessIcon.Child = GetWirelessIcon(0);
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
|
@ -94,23 +96,6 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||||
|
|
||||||
private void Update()
|
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)
|
switch (adapter.Type)
|
||||||
{
|
{
|
||||||
case ConnectionType.Wired:
|
case ConnectionType.Wired:
|
||||||
|
@ -154,6 +139,23 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||||
WirelessIcon.Child = GetWirelessIcon(0);
|
WirelessIcon.Child = GetWirelessIcon(0);
|
||||||
break;
|
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)
|
private void UpdateText(string text)
|
||||||
|
|
|
@ -66,6 +66,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||||
}));
|
}));
|
||||||
Popup.Closed += (o, args) =>
|
Popup.Closed += (o, args) =>
|
||||||
{
|
{
|
||||||
|
adapter.StopWirelessNetworkScanning();
|
||||||
Background = originalBrush;
|
Background = originalBrush;
|
||||||
Button.Background = originalBrush;
|
Button.Background = originalBrush;
|
||||||
lastOpenedBySpacePress = false;
|
lastOpenedBySpacePress = false;
|
||||||
|
@ -81,6 +82,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||||
}));
|
}));
|
||||||
Popup.Opened += (o, args) =>
|
Popup.Opened += (o, args) =>
|
||||||
{
|
{
|
||||||
|
adapter.StartWirelessNetworkScanning();
|
||||||
Background = Brushes.LightGray;
|
Background = Brushes.LightGray;
|
||||||
Button.Background = Brushes.LightGray;
|
Button.Background = Brushes.LightGray;
|
||||||
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
||||||
|
@ -106,23 +108,6 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||||
|
|
||||||
private void Update()
|
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)
|
switch (adapter.Type)
|
||||||
{
|
{
|
||||||
case ConnectionType.Wired:
|
case ConnectionType.Wired:
|
||||||
|
@ -166,6 +151,23 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||||
WirelessIcon.Child = GetWirelessIcon(0);
|
WirelessIcon.Child = GetWirelessIcon(0);
|
||||||
break;
|
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)
|
private void UpdateText(string text)
|
||||||
|
|
|
@ -168,8 +168,8 @@
|
||||||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="MessageBoxFactory.cs" />
|
<Compile Include="MessageBoxFactory.cs" />
|
||||||
<Compile Include="Windows\NetworkDialog.xaml.cs">
|
<Compile Include="Windows\CredentialsDialog.xaml.cs">
|
||||||
<DependentUpon>NetworkDialog.xaml</DependentUpon>
|
<DependentUpon>CredentialsDialog.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Windows\PasswordDialog.xaml.cs">
|
<Compile Include="Windows\PasswordDialog.xaml.cs">
|
||||||
<DependentUpon>PasswordDialog.xaml</DependentUpon>
|
<DependentUpon>PasswordDialog.xaml</DependentUpon>
|
||||||
|
@ -397,7 +397,7 @@
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Windows\NetworkDialog.xaml">
|
<Page Include="Windows\CredentialsDialog.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
|
|
@ -85,6 +85,11 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
return Application.Current.Dispatcher.Invoke(() => new BrowserWindow(control, settings, isMainWindow, text, logger));
|
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)
|
public IExamSelectionDialog CreateExamSelectionDialog(IEnumerable<Exam> exams)
|
||||||
{
|
{
|
||||||
return Application.Current.Dispatcher.Invoke(() => new ExamSelectionDialog(exams, text));
|
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)
|
public INotificationControl CreateNotificationControl(INotification notification, Location location)
|
||||||
{
|
{
|
||||||
if (location == Location.ActionCenter)
|
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="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Windows"
|
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>
|
<Window.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
@ -15,17 +15,17 @@
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
<Grid FocusManager.FocusedElement="{Binding ElementName=Password}">
|
<Grid FocusManager.FocusedElement="{Binding ElementName=Password}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="2*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="1*" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Grid.Row="0">
|
<Grid Grid.Row="0" VerticalAlignment="Center">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<fa:ImageAwesome Grid.Column="0" Foreground="LightGray" Icon="Wifi" Margin="25" Width="50" />
|
<fa:ImageAwesome Grid.Column="0" Name="PurposeIcon" Foreground="LightGray" Icon="Key" Margin="25" Rotation="90" Width="50" />
|
||||||
<Grid Grid.Column="1" Margin="0,0,25,25">
|
<Grid Grid.Column="1" Margin="0,25,25,25">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
@ -33,18 +33,18 @@
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Grid.Row="0" Name="Message" Margin="0,0,0,5" TextWrapping="WrapWithOverflow" VerticalAlignment="Bottom" />
|
<TextBlock Grid.Row="0" Name="Message" Margin="0,0,0,5" TextWrapping="WrapWithOverflow" VerticalAlignment="Bottom" />
|
||||||
<StackPanel Grid.Row="1" Orientation="Vertical">
|
<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" />
|
<TextBox Name="Username" Height="25" Margin="0,0,0,5" VerticalContentAlignment="Center" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Grid.Row="2" Orientation="Vertical">
|
<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" />
|
<PasswordBox Grid.Row="2" Name="Password" Height="25" VerticalContentAlignment="Center" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid Grid.Row="1" Background="{StaticResource BackgroundBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
<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="ConfirmButton" Cursor="Hand" Margin="10,0" Padding="10,5" MinWidth="75" />
|
||||||
<Button Name="CancelButton" Cursor="Hand" Padding="10,5" MinWidth="75" />
|
<Button Name="CancelButton" Cursor="Hand" Padding="10,5" MinWidth="75" />
|
||||||
</WrapPanel>
|
</WrapPanel>
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using FontAwesome.WPF;
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
|
@ -15,7 +16,7 @@ using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
||||||
{
|
{
|
||||||
public partial class NetworkDialog : Window, INetworkDialog
|
public partial class CredentialsDialog : Window, ICredentialsDialog
|
||||||
{
|
{
|
||||||
private readonly IText text;
|
private readonly IText text;
|
||||||
|
|
||||||
|
@ -34,12 +35,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
||||||
remove { closing -= value; }
|
remove { closing -= value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal NetworkDialog(string message, string title, IText text)
|
internal CredentialsDialog(CredentialsDialogPurpose purpose, string message, string title, IText text)
|
||||||
{
|
{
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
InitializeNetworkDialog(message, title);
|
InitializeCredentialsDialog(purpose, message, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BringToForeground()
|
public void BringToForeground()
|
||||||
|
@ -47,11 +48,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
||||||
Dispatcher.Invoke(Activate);
|
Dispatcher.Invoke(Activate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NetworkDialogResult Show(IWindow parent = null)
|
public CredentialsDialogResult Show(IWindow parent = null)
|
||||||
{
|
{
|
||||||
return Dispatcher.Invoke(() =>
|
return Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
var result = new NetworkDialogResult { Success = false };
|
var result = new CredentialsDialogResult { Success = false };
|
||||||
|
|
||||||
if (parent is Window)
|
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;
|
Message.Text = message;
|
||||||
// TODO
|
|
||||||
PasswordLabel.Content = "Password";
|
|
||||||
Title = title;
|
Title = title;
|
||||||
// TODO
|
|
||||||
UsernameLabel.Content = "Username";
|
|
||||||
WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||||
|
|
||||||
Closed += (o, args) => closed?.Invoke();
|
Closed += (o, args) => closed?.Invoke();
|
|
@ -63,6 +63,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
|
||||||
}
|
}
|
||||||
Popup.IsOpen = Popup.IsMouseOver;
|
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(() =>
|
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||||
|
@ -73,6 +79,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
|
||||||
}));
|
}));
|
||||||
Popup.Opened += (o, args) =>
|
Popup.Opened += (o, args) =>
|
||||||
{
|
{
|
||||||
|
adapter.StartWirelessNetworkScanning();
|
||||||
Grid.Background = Brushes.Gray;
|
Grid.Background = Brushes.Gray;
|
||||||
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
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);
|
WirelessIcon.Child = GetWirelessIcon(0);
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
|
@ -94,23 +96,6 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
|
||||||
|
|
||||||
private void Update()
|
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)
|
switch (adapter.Type)
|
||||||
{
|
{
|
||||||
case ConnectionType.Wired:
|
case ConnectionType.Wired:
|
||||||
|
@ -154,6 +139,23 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
|
||||||
WirelessIcon.Child = GetWirelessIcon(0);
|
WirelessIcon.Child = GetWirelessIcon(0);
|
||||||
break;
|
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)
|
private void UpdateText(string text)
|
||||||
|
|
|
@ -66,6 +66,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
|
||||||
}));
|
}));
|
||||||
Popup.Closed += (o, args) =>
|
Popup.Closed += (o, args) =>
|
||||||
{
|
{
|
||||||
|
adapter.StopWirelessNetworkScanning();
|
||||||
Background = originalBrush;
|
Background = originalBrush;
|
||||||
Button.Background = originalBrush;
|
Button.Background = originalBrush;
|
||||||
lastOpenedBySpacePress = false;
|
lastOpenedBySpacePress = false;
|
||||||
|
@ -81,6 +82,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
|
||||||
}));
|
}));
|
||||||
Popup.Opened += (o, args) =>
|
Popup.Opened += (o, args) =>
|
||||||
{
|
{
|
||||||
|
adapter.StartWirelessNetworkScanning();
|
||||||
Background = Brushes.LightGray;
|
Background = Brushes.LightGray;
|
||||||
Button.Background = Brushes.LightGray;
|
Button.Background = Brushes.LightGray;
|
||||||
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
||||||
|
@ -106,23 +108,6 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
|
||||||
|
|
||||||
private void Update()
|
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)
|
switch (adapter.Type)
|
||||||
{
|
{
|
||||||
case ConnectionType.Wired:
|
case ConnectionType.Wired:
|
||||||
|
@ -166,6 +151,23 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
|
||||||
WirelessIcon.Child = GetWirelessIcon(0);
|
WirelessIcon.Child = GetWirelessIcon(0);
|
||||||
break;
|
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)
|
private void UpdateText(string text)
|
||||||
|
|
|
@ -173,6 +173,9 @@
|
||||||
<Compile Include="Windows\MessageBoxDialog.xaml.cs">
|
<Compile Include="Windows\MessageBoxDialog.xaml.cs">
|
||||||
<DependentUpon>MessageBoxDialog.xaml</DependentUpon>
|
<DependentUpon>MessageBoxDialog.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Windows\CredentialsDialog.xaml.cs">
|
||||||
|
<DependentUpon>CredentialsDialog.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>
|
||||||
|
@ -521,6 +524,10 @@
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Windows\CredentialsDialog.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
<Page Include="Windows\PasswordDialog.xaml">
|
<Page Include="Windows\PasswordDialog.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
|
|
@ -85,6 +85,11 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
||||||
return Application.Current.Dispatcher.Invoke(() => new BrowserWindow(control, settings, isMainWindow, text, logger));
|
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)
|
public IExamSelectionDialog CreateExamSelectionDialog(IEnumerable<Exam> exams)
|
||||||
{
|
{
|
||||||
return Application.Current.Dispatcher.Invoke(() => new ExamSelectionDialog(exams, text));
|
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)
|
public INotificationControl CreateNotificationControl(INotification notification, Location location)
|
||||||
{
|
{
|
||||||
if (location == Location.ActionCenter)
|
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
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.UserInterface.Desktop", "SafeExamBrowser.UserInterface.Desktop\SafeExamBrowser.UserInterface.Desktop.csproj", "{A502DF54-7169-4647-94BD-18B192924866}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.UserInterface.Desktop", "SafeExamBrowser.UserInterface.Desktop\SafeExamBrowser.UserInterface.Desktop.csproj", "{A502DF54-7169-4647-94BD-18B192924866}"
|
||||||
EndProject
|
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}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Client", "SafeExamBrowser.Client\SafeExamBrowser.Client.csproj", "{7CC5A895-E0D3-4E43-9B39-CCEC05A5A6A7}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Client.UnitTests", "SafeExamBrowser.Client.UnitTests\SafeExamBrowser.Client.UnitTests.csproj", "{15684416-FADF-4C51-85DE-4F343BFAB752}"
|
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