SEBWIN-788: Implemented scaffolding for wireless network credentials.

This commit is contained in:
Damian Büchel 2024-05-02 10:30:26 +02:00
parent e4a82e2f63
commit 4015e9a574
24 changed files with 395 additions and 35 deletions

View file

@ -33,6 +33,7 @@ using SafeExamBrowser.Server.Contracts;
using SafeExamBrowser.Server.Contracts.Data;
using SafeExamBrowser.Settings;
using SafeExamBrowser.Settings.Monitoring;
using SafeExamBrowser.SystemComponents.Contracts.Network;
using SafeExamBrowser.SystemComponents.Contracts.Registry;
using SafeExamBrowser.UserInterface.Contracts;
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
@ -61,6 +62,7 @@ namespace SafeExamBrowser.Client.UnitTests
private Mock<IIntegrityModule> integrityModule;
private Mock<ILogger> logger;
private Mock<IMessageBox> messageBox;
private Mock<INetworkAdapter> networkAdapter;
private Mock<IOperationSequence> operationSequence;
private Mock<IRegistry> registry;
private Mock<IRuntimeProxy> runtimeProxy;
@ -94,6 +96,7 @@ namespace SafeExamBrowser.Client.UnitTests
integrityModule = new Mock<IIntegrityModule>();
logger = new Mock<ILogger>();
messageBox = new Mock<IMessageBox>();
networkAdapter = new Mock<INetworkAdapter>();
operationSequence = new Mock<IOperationSequence>();
registry = new Mock<IRegistry>();
runtimeProxy = new Mock<IRuntimeProxy>();
@ -122,6 +125,7 @@ namespace SafeExamBrowser.Client.UnitTests
hashAlgorithm.Object,
logger.Object,
messageBox.Object,
networkAdapter.Object,
operationSequence.Object,
registry.Object,
runtimeProxy.Object,

View file

@ -35,6 +35,8 @@ using SafeExamBrowser.Proctoring.Contracts.Events;
using SafeExamBrowser.Server.Contracts;
using SafeExamBrowser.Server.Contracts.Data;
using SafeExamBrowser.Settings;
using SafeExamBrowser.SystemComponents.Contracts.Network;
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
using SafeExamBrowser.SystemComponents.Contracts.Registry;
using SafeExamBrowser.UserInterface.Contracts;
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
@ -57,6 +59,7 @@ namespace SafeExamBrowser.Client
private readonly IHashAlgorithm hashAlgorithm;
private readonly ILogger logger;
private readonly IMessageBox messageBox;
private readonly INetworkAdapter networkAdapter;
private readonly IOperationSequence operations;
private readonly IRegistry registry;
private readonly IRuntimeProxy runtime;
@ -87,6 +90,7 @@ namespace SafeExamBrowser.Client
IHashAlgorithm hashAlgorithm,
ILogger logger,
IMessageBox messageBox,
INetworkAdapter networkAdapter,
IOperationSequence operations,
IRegistry registry,
IRuntimeProxy runtime,
@ -106,6 +110,7 @@ namespace SafeExamBrowser.Client
this.hashAlgorithm = hashAlgorithm;
this.logger = logger;
this.messageBox = messageBox;
this.networkAdapter = networkAdapter;
this.operations = operations;
this.registry = registry;
this.runtime = runtime;
@ -214,6 +219,7 @@ namespace SafeExamBrowser.Client
ClientHost.ServerFailureActionRequested += ClientHost_ServerFailureActionRequested;
ClientHost.Shutdown += ClientHost_Shutdown;
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
networkAdapter.CredentialsRequired += NetworkAdapter_CredentialsRequired;
registry.ValueChanged += Registry_ValueChanged;
runtime.ConnectionLost += Runtime_ConnectionLost;
systemMonitor.SessionChanged += SystemMonitor_SessionChanged;
@ -690,6 +696,16 @@ namespace SafeExamBrowser.Client
}
}
private void NetworkAdapter_CredentialsRequired(CredentialsRequiredEventArgs args)
{
var dialog = uiFactory.CreateNetworkDialog("TODO", "TODO");
var result = dialog.Show();
args.Password = result.Password;
args.Success = result.Success;
args.Username = result.Username;
}
private void Operations_ActionRequired(ActionRequiredEventArgs args)
{
switch (args)

View file

@ -154,6 +154,7 @@ namespace SafeExamBrowser.Client
hashAlgorithm,
logger,
messageBox,
networkAdapter,
sequence,
registry,
runtimeProxy,

View file

@ -26,6 +26,26 @@ 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)

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 ETH Zürich, IT Services
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events
{
/// <summary>
///
/// </summary>
public class CredentialsRequiredEventArgs
{
/// <summary>
///
/// </summary>
public string Password { get; set; }
/// <summary>
///
/// </summary>
public bool Success { get; set; }
/// <summary>
///
/// </summary>
public string Username { get; set; }
}
}

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2024 ETH Zürich, IT Services
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events
{
/// <summary>
///
/// </summary>
public delegate void CredentialsRequiredEventHandler(CredentialsRequiredEventArgs args);
}

View file

@ -6,7 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using System.Collections.Generic;
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
@ -33,9 +32,14 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Network
event ChangedEventHandler Changed;
/// <summary>
/// Attempts to connect to the wireless network with the given ID.
/// Fired when credentials are required to connect to a network.
/// </summary>
void ConnectToWirelessNetwork(Guid id);
event CredentialsRequiredEventHandler CredentialsRequired;
/// <summary>
/// Attempts to connect to the wireless network with the given name.
/// </summary>
void ConnectToWirelessNetwork(string name);
/// <summary>
/// Retrieves all currently available wireless networks.

View file

@ -6,8 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
namespace SafeExamBrowser.SystemComponents.Contracts.Network
{
/// <summary>
@ -15,11 +13,6 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Network
/// </summary>
public interface IWirelessNetwork
{
/// <summary>
/// The unique identifier of the network.
/// </summary>
Guid Id { get; }
/// <summary>
/// The network name.
/// </summary>

View file

@ -58,6 +58,8 @@
<Compile Include="Audio\Events\VolumeChangedEventHandler.cs" />
<Compile Include="Audio\IAudio.cs" />
<Compile Include="IFileSystem.cs" />
<Compile Include="Network\Events\CredentialsRequiredEventArgs.cs" />
<Compile Include="Network\Events\CredentialsRequiredEventHandler.cs" />
<Compile Include="Registry\Events\RegistryValueChangedEventHandler.cs" />
<Compile Include="Registry\IRegistry.cs" />
<Compile Include="IRemoteSessionDetector.cs" />

View file

@ -10,7 +10,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Timers;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.Network;
using SafeExamBrowser.SystemComponents.Contracts.Network.Events;
@ -18,12 +17,22 @@ using SafeExamBrowser.WindowsApi.Contracts;
using SimpleWifi;
using SimpleWifi.Win32;
using SimpleWifi.Win32.Interop;
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();
private readonly ILogger logger;
private readonly INativeMethods nativeMethods;
private readonly List<WirelessNetwork> wirelessNetworks;
@ -35,6 +44,7 @@ namespace SafeExamBrowser.SystemComponents.Network
public ConnectionType Type { get; private set; }
public event ChangedEventHandler Changed;
public event CredentialsRequiredEventHandler CredentialsRequired;
public NetworkAdapter(ILogger logger, INativeMethods nativeMethods)
{
@ -43,22 +53,27 @@ namespace SafeExamBrowser.SystemComponents.Network
this.wirelessNetworks = new List<WirelessNetwork>();
}
public void ConnectToWirelessNetwork(Guid id)
public void ConnectToWirelessNetwork(string name)
{
lock (@lock)
{
var network = wirelessNetworks.FirstOrDefault(n => n.Id == id);
var network = wirelessNetworks.FirstOrDefault(n => n.Name == name);
if (network != default)
{
try
{
var request = new AuthRequest(network.AccessPoint);
var accessPoint = network.AccessPoint;
var request = new AuthRequest(accessPoint);
logger.Info($"Attempting to connect to '{network.Name}'...");
if (accessPoint.HasProfile || accessPoint.IsConnected || TryGetCredentials(request))
{
logger.Info($"Attempting to connect to wireless network '{network.Name}' with{(request.Password == default ? "out" : "")} credentials...");
network.AccessPoint.ConnectAsync(request, false, (success) => AccessPoint_OnConnectCompleted(network.Name, success));
Status = ConnectionStatus.Connecting;
// 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)
{
@ -67,7 +82,7 @@ namespace SafeExamBrowser.SystemComponents.Network
}
else
{
logger.Warn($"Could not find network with id '{id}'!");
logger.Warn($"Could not find wireless network '{name}'!");
}
}
@ -111,7 +126,7 @@ namespace SafeExamBrowser.SystemComponents.Network
}
}
private void AccessPoint_OnConnectCompleted(string name, bool success)
private void ConnectionAttemptCompleted(string name, bool success)
{
lock (@lock)
{
@ -129,12 +144,28 @@ namespace SafeExamBrowser.SystemComponents.Network
}
}
private bool TryGetCredentials(AuthRequest request)
{
var args = new CredentialsRequiredEventArgs();
CredentialsRequired?.Invoke(args);
if (args.Success)
{
request.Password = args.Password;
request.Username = args.Username;
}
return args.Success;
}
private void Update()
{
try
{
lock (@lock)
{
var current = default(WirelessNetwork);
var hasInternet = nativeMethods.HasInternetConnection();
var hasWireless = !wifi.NoWifiAvailable && !IsTurnedOff();
var isConnecting = Status == ConnectionStatus.Connecting;
@ -144,12 +175,13 @@ namespace SafeExamBrowser.SystemComponents.Network
if (hasWireless)
{
foreach (var accessPoint in wifi.GetAccessPoints())
foreach (var wirelessNetwork in wifi.GetAccessPoints().Select(a => ToWirelessNetwork(a)))
{
// The user may only connect to an already configured or connected wireless network!
if (accessPoint.HasProfile || accessPoint.IsConnected)
wirelessNetworks.Add(wirelessNetwork);
if (wirelessNetwork.Status == ConnectionStatus.Connected)
{
wirelessNetworks.Add(ToWirelessNetwork(accessPoint));
current = wirelessNetwork;
}
}
}
@ -159,7 +191,7 @@ namespace SafeExamBrowser.SystemComponents.Network
if (previousStatus != ConnectionStatus.Connected && Status == ConnectionStatus.Connected)
{
logger.Info("Connection established.");
logger.Info($"Connection established ({Type}{(current != default ? $", {current.Name}" : "")}).");
}
if (previousStatus != ConnectionStatus.Disconnected && Status == ConnectionStatus.Disconnected)

View file

@ -6,7 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using SafeExamBrowser.SystemComponents.Contracts.Network;
using SimpleWifi;
@ -16,14 +15,8 @@ namespace SafeExamBrowser.SystemComponents.Network
{
internal AccessPoint AccessPoint { get; set; }
public Guid Id { get; }
public string Name { get; set; }
public int SignalStrength { get; set; }
public ConnectionStatus Status { get; set; }
public WirelessNetwork()
{
Id = Guid.NewGuid();
}
}
}

View file

@ -83,6 +83,11 @@ 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>

View file

@ -96,11 +96,13 @@
<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\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\IPasswordDialog.cs" />
<Compile Include="Windows\Data\PasswordDialogResult.cs" />
<Compile Include="Proctoring\IProctoringFinalizationDialog.cs" />

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 ETH Zürich, IT Services
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
namespace SafeExamBrowser.UserInterface.Contracts.Windows.Data
{
/// <summary>
/// Defines the user interaction result of an <see cref="INetworkDialog"/>.
/// </summary>
public class NetworkDialogResult
{
/// <summary>
/// The password entered by the user, or <c>default(string)</c> if the interaction was unsuccessful.
/// </summary>
public string Password { get; set; }
/// <summary>
/// Indicates whether the user confirmed the dialog or not.
/// </summary>
public bool Success { get; set; }
/// <summary>
/// The username entered by the user, or <c>default(string)</c> if no username is required or the interaction was unsuccessful.
/// </summary>
public string Username { get; set; }
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2024 ETH Zürich, IT Services
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
namespace SafeExamBrowser.UserInterface.Contracts.Windows
{
/// <summary>
/// Defines the functionality of a network dialog.
/// </summary>
public interface INetworkDialog : IWindow
{
/// <summary>
/// Shows the dialog as topmost window. If a parent window is specified, the dialog is rendered modally for the given parent.
/// </summary>
NetworkDialogResult Show(IWindow parent = null);
}
}

View file

@ -100,7 +100,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
{
var button = new NetworkButton(network);
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id);
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
if (network.Status == ConnectionStatus.Connected)
{

View file

@ -112,7 +112,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
{
var button = new NetworkButton(network);
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id);
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
if (network.Status == ConnectionStatus.Connected)
{

View file

@ -168,6 +168,9 @@
<DependentUpon>LogWindow.xaml</DependentUpon>
</Compile>
<Compile Include="MessageBoxFactory.cs" />
<Compile Include="Windows\NetworkDialog.xaml.cs">
<DependentUpon>NetworkDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\PasswordDialog.xaml.cs">
<DependentUpon>PasswordDialog.xaml</DependentUpon>
</Compile>
@ -394,6 +397,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Windows\NetworkDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Windows\ProctoringFinalizationDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View file

@ -143,6 +143,11 @@ namespace SafeExamBrowser.UserInterface.Desktop
}
}
public INetworkDialog CreateNetworkDialog(string message, string title)
{
return Application.Current.Dispatcher.Invoke(() => new NetworkDialog(message, title, text));
}
public INotificationControl CreateNotificationControl(INotification notification, Location location)
{
if (location == Location.ActionCenter)

View file

@ -0,0 +1,53 @@
<Window x:Class="SafeExamBrowser.UserInterface.Desktop.Windows.NetworkDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Windows"
mc:Ignorable="d" Height="350" Width="450" ResizeMode="NoResize" Topmost="True">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Templates/Colors.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid FocusManager.FocusedElement="{Binding ElementName=Password}">
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<fa:ImageAwesome Grid.Column="0" Foreground="LightGray" Icon="Wifi" Margin="25" Width="50" />
<Grid Grid.Column="1" Margin="0,0,25,25">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Name="Message" Margin="0,0,0,5" TextWrapping="WrapWithOverflow" VerticalAlignment="Bottom" />
<StackPanel Grid.Row="1" Orientation="Vertical">
<Label Name="UsernameLabel" Target="{Binding ElementName=Username}" />
<TextBox Name="Username" Height="25" Margin="0,0,0,5" VerticalContentAlignment="Center" />
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Vertical">
<Label Name="PasswordLabel" Target="{Binding ElementName=Password}" />
<PasswordBox Grid.Row="2" Name="Password" Height="25" VerticalContentAlignment="Center" />
</StackPanel>
</Grid>
</Grid>
</Grid>
<Grid Grid.Row="1" Background="{StaticResource BackgroundBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<WrapPanel Orientation="Horizontal" Margin="25,0" HorizontalAlignment="Right" VerticalAlignment="Center">
<Button Name="ConfirmButton" Cursor="Hand" Margin="10,0" Padding="10,5" MinWidth="75" />
<Button Name="CancelButton" Cursor="Hand" Padding="10,5" MinWidth="75" />
</WrapPanel>
</Grid>
</Grid>
</Window>

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2024 ETH Zürich, IT Services
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Windows;
using System.Windows.Input;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.UserInterface.Contracts.Windows;
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
public partial class NetworkDialog : Window, INetworkDialog
{
private readonly IText text;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
remove { closing -= value; }
}
internal NetworkDialog(string message, string title, IText text)
{
this.text = text;
InitializeComponent();
InitializeNetworkDialog(message, title);
}
public void BringToForeground()
{
Dispatcher.Invoke(Activate);
}
public NetworkDialogResult Show(IWindow parent = null)
{
return Dispatcher.Invoke(() =>
{
var result = new NetworkDialogResult { Success = false };
if (parent is Window)
{
Owner = parent as Window;
WindowStartupLocation = WindowStartupLocation.CenterOwner;
}
if (ShowDialog() is true)
{
result.Password = Password.Password;
result.Success = true;
result.Username = Username.Text;
}
return result;
});
}
private void InitializeNetworkDialog(string message, string title)
{
Message.Text = message;
// TODO
PasswordLabel.Content = "Password";
Title = title;
// TODO
UsernameLabel.Content = "Username";
WindowStartupLocation = WindowStartupLocation.CenterScreen;
Closed += (o, args) => closed?.Invoke();
Closing += (o, args) => closing?.Invoke();
Loaded += (o, args) => Activate();
CancelButton.Content = text.Get(TextKey.PasswordDialog_Cancel);
CancelButton.Click += CancelButton_Click;
ConfirmButton.Content = text.Get(TextKey.PasswordDialog_Confirm);
ConfirmButton.Click += ConfirmButton_Click;
Password.KeyDown += Password_KeyDown;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
private void ConfirmButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
Close();
}
private void Password_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
DialogResult = true;
Close();
}
}
}
}

View file

@ -100,7 +100,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
{
var button = new NetworkButton(network);
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id);
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
if (network.Status == ConnectionStatus.Connected)
{

View file

@ -112,7 +112,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
{
var button = new NetworkButton(network);
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id);
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
if (network.Status == ConnectionStatus.Connected)
{

View file

@ -143,6 +143,12 @@ namespace SafeExamBrowser.UserInterface.Mobile
}
}
public INetworkDialog CreateNetworkDialog(string message, string title)
{
// TODO
throw new System.NotImplementedException();
}
public INotificationControl CreateNotificationControl(INotification notification, Location location)
{
if (location == Location.ActionCenter)