SEBWIN-220: Implemented password input mechanism and dialog.
This commit is contained in:
parent
9a12bbdb7d
commit
f8e5a4bedf
30 changed files with 316 additions and 71 deletions
|
@ -12,6 +12,8 @@ using System.IO;
|
||||||
using SafeExamBrowser.Contracts.Behaviour;
|
using SafeExamBrowser.Contracts.Behaviour;
|
||||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Browser;
|
using SafeExamBrowser.Contracts.Browser;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Data;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
@ -37,6 +39,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
private Action shutdown;
|
private Action shutdown;
|
||||||
private ISplashScreen splashScreen;
|
private ISplashScreen splashScreen;
|
||||||
private ITaskbar taskbar;
|
private ITaskbar taskbar;
|
||||||
|
private IText text;
|
||||||
private IUserInterfaceFactory uiFactory;
|
private IUserInterfaceFactory uiFactory;
|
||||||
private IWindowMonitor windowMonitor;
|
private IWindowMonitor windowMonitor;
|
||||||
private AppConfig appConfig;
|
private AppConfig appConfig;
|
||||||
|
@ -68,6 +71,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
IRuntimeProxy runtime,
|
IRuntimeProxy runtime,
|
||||||
Action shutdown,
|
Action shutdown,
|
||||||
ITaskbar taskbar,
|
ITaskbar taskbar,
|
||||||
|
IText text,
|
||||||
IUserInterfaceFactory uiFactory,
|
IUserInterfaceFactory uiFactory,
|
||||||
IWindowMonitor windowMonitor)
|
IWindowMonitor windowMonitor)
|
||||||
{
|
{
|
||||||
|
@ -79,6 +83,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
this.runtime = runtime;
|
this.runtime = runtime;
|
||||||
this.shutdown = shutdown;
|
this.shutdown = shutdown;
|
||||||
this.taskbar = taskbar;
|
this.taskbar = taskbar;
|
||||||
|
this.text = text;
|
||||||
this.uiFactory = uiFactory;
|
this.uiFactory = uiFactory;
|
||||||
this.windowMonitor = windowMonitor;
|
this.windowMonitor = windowMonitor;
|
||||||
}
|
}
|
||||||
|
@ -150,6 +155,8 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
private void RegisterEvents()
|
private void RegisterEvents()
|
||||||
{
|
{
|
||||||
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
|
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
|
||||||
|
ClientHost.PasswordRequested += ClientHost_PasswordRequested;
|
||||||
|
ClientHost.ReconfigurationDenied += ClientHost_ReconfigurationDenied;
|
||||||
ClientHost.Shutdown += ClientHost_Shutdown;
|
ClientHost.Shutdown += ClientHost_Shutdown;
|
||||||
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
||||||
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
|
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
|
||||||
|
@ -161,6 +168,8 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
private void DeregisterEvents()
|
private void DeregisterEvents()
|
||||||
{
|
{
|
||||||
Browser.ConfigurationDownloadRequested -= Browser_ConfigurationDownloadRequested;
|
Browser.ConfigurationDownloadRequested -= Browser_ConfigurationDownloadRequested;
|
||||||
|
ClientHost.PasswordRequested -= ClientHost_PasswordRequested;
|
||||||
|
ClientHost.ReconfigurationDenied -= ClientHost_ReconfigurationDenied;
|
||||||
ClientHost.Shutdown -= ClientHost_Shutdown;
|
ClientHost.Shutdown -= ClientHost_Shutdown;
|
||||||
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
||||||
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
|
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
|
||||||
|
@ -236,6 +245,27 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ClientHost_PasswordRequested(PasswordRequestEventArgs args)
|
||||||
|
{
|
||||||
|
var isAdmin = args.Purpose == PasswordRequestPurpose.Administrator;
|
||||||
|
var message = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequired : TextKey.PasswordDialog_SettingsPasswordRequired;
|
||||||
|
var title = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequiredTitle : TextKey.PasswordDialog_SettingsPasswordRequiredTitle;
|
||||||
|
var dialog = uiFactory.CreatePasswordDialog(text.Get(message), text.Get(title));
|
||||||
|
|
||||||
|
logger.Info($"Received input request with id '{args.RequestId}' for the {args.Purpose.ToString().ToLower()} password.");
|
||||||
|
|
||||||
|
var result = dialog.Show();
|
||||||
|
|
||||||
|
runtime.SubmitPassword(args.RequestId, result.Success, result.Password);
|
||||||
|
logger.Info($"Password request with id '{args.RequestId}' was {(result.Success ? "successful" : "aborted by the user")}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClientHost_ReconfigurationDenied(ReconfigurationEventArgs args)
|
||||||
|
{
|
||||||
|
logger.Info($"The reconfiguration request for '{args.ConfigurationPath}' was denied by the runtime!");
|
||||||
|
messageBox.Show(TextKey.MessageBox_ReconfigurationDenied, TextKey.MessageBox_ReconfigurationDeniedTitle);
|
||||||
|
}
|
||||||
|
|
||||||
private void ClientHost_Shutdown()
|
private void ClientHost_Shutdown()
|
||||||
{
|
{
|
||||||
taskbar.Close();
|
taskbar.Close();
|
||||||
|
|
|
@ -22,6 +22,8 @@ namespace SafeExamBrowser.Client.Communication
|
||||||
|
|
||||||
public Guid StartupToken { private get; set; }
|
public Guid StartupToken { private get; set; }
|
||||||
|
|
||||||
|
public event CommunicationEventHandler<PasswordRequestEventArgs> PasswordRequested;
|
||||||
|
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationDenied;
|
||||||
public event CommunicationEventHandler Shutdown;
|
public event CommunicationEventHandler Shutdown;
|
||||||
|
|
||||||
public ClientHost(string address, IHostObjectFactory factory, ILogger logger, int processId) : base(address, factory, logger)
|
public ClientHost(string address, IHostObjectFactory factory, ILogger logger, int processId) : base(address, factory, logger)
|
||||||
|
@ -49,6 +51,16 @@ namespace SafeExamBrowser.Client.Communication
|
||||||
|
|
||||||
protected override Response OnReceive(Message message)
|
protected override Response OnReceive(Message message)
|
||||||
{
|
{
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case PasswordRequestMessage p:
|
||||||
|
PasswordRequested?.InvokeAsync(new PasswordRequestEventArgs { Purpose = p.Purpose, RequestId = p.RequestId });
|
||||||
|
return new SimpleResponse(SimpleResponsePurport.Acknowledged);
|
||||||
|
case ReconfigurationDeniedMessage r:
|
||||||
|
ReconfigurationDenied?.InvokeAsync(new ReconfigurationEventArgs { ConfigurationPath = r.FilePath });
|
||||||
|
return new SimpleResponse(SimpleResponsePurport.Acknowledged);
|
||||||
|
}
|
||||||
|
|
||||||
return new SimpleResponse(SimpleResponsePurport.UnknownMessage);
|
return new SimpleResponse(SimpleResponsePurport.UnknownMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
var sequence = new OperationSequence(logger, operations);
|
var sequence = new OperationSequence(logger, operations);
|
||||||
|
|
||||||
ClientController = new ClientController(displayMonitor, logger, messageBox, sequence, processMonitor, runtimeProxy, shutdown, Taskbar, uiFactory, windowMonitor);
|
ClientController = new ClientController(displayMonitor, logger, messageBox, sequence, processMonitor, runtimeProxy, shutdown, Taskbar, text, uiFactory, windowMonitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void LogStartupInformation()
|
internal void LogStartupInformation()
|
||||||
|
|
|
@ -56,6 +56,9 @@
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationIcon>SafeExamBrowser.ico</ApplicationIcon>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
@ -147,6 +150,9 @@
|
||||||
<Name>SafeExamBrowser.WindowsApi</Name>
|
<Name>SafeExamBrowser.WindowsApi</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="SafeExamBrowser.ico" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>robocopy "$(SolutionDir)SafeExamBrowser.Browser\bin\$(PlatformName)\$(ConfigurationName)" "$(ProjectDir)bin\$(PlatformName)\$(ConfigurationName)" /e /np
|
<PostBuildEvent>robocopy "$(SolutionDir)SafeExamBrowser.Browser\bin\$(PlatformName)\$(ConfigurationName)" "$(ProjectDir)bin\$(PlatformName)\$(ConfigurationName)" /e /np
|
||||||
|
|
BIN
SafeExamBrowser.Client/SafeExamBrowser.ico
Normal file
BIN
SafeExamBrowser.Client/SafeExamBrowser.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 361 KiB |
|
@ -31,7 +31,7 @@ namespace SafeExamBrowser.Contracts.Communication.Data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Success { get; private set; }
|
public bool Success { get; private set; }
|
||||||
|
|
||||||
public PasswordReplyMessage(string password, Guid requestId, bool success)
|
public PasswordReplyMessage(Guid requestId, bool success, string password = null)
|
||||||
{
|
{
|
||||||
Password = password;
|
Password = password;
|
||||||
RequestId = requestId;
|
RequestId = requestId;
|
||||||
|
|
|
@ -11,14 +11,19 @@ using System;
|
||||||
namespace SafeExamBrowser.Contracts.Communication.Data
|
namespace SafeExamBrowser.Contracts.Communication.Data
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The response to a <see cref="ReconfigurationMessage"/>.
|
/// This message is transmitted from the runtime to the client in order to inform the latter that a reconfiguration request was denied.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ReconfigurationResponse : Response
|
public class ReconfigurationDeniedMessage : Message
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates whether the reconfiguration request has been accepted.
|
/// The full path to the configuration file for which a reconfiguration was denied.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Accepted { get; set; }
|
public string FilePath { get; private set; }
|
||||||
|
|
||||||
|
public ReconfigurationDeniedMessage(string filePath)
|
||||||
|
{
|
||||||
|
FilePath = filePath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@ namespace SafeExamBrowser.Contracts.Communication.Events
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The event arguments used for the password input event fired by the <see cref="Hosts.IRuntimeHost"/>.
|
/// The event arguments used for the password input event fired by the <see cref="Hosts.IRuntimeHost"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PasswordEventArgs : CommunicationEventArgs
|
public class PasswordReplyEventArgs : CommunicationEventArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The password entered by the user, or <c>null</c> if not available.
|
/// The password entered by the user, or <c>null</c> if not available.
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* 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 SafeExamBrowser.Contracts.Communication.Data;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The event arguments used for the password request event fired by the <see cref="Hosts.IClientHost"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class PasswordRequestEventArgs : CommunicationEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The purpose for which a password is requested.
|
||||||
|
/// </summary>
|
||||||
|
public PasswordRequestPurpose Purpose { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the password request.
|
||||||
|
/// </summary>
|
||||||
|
public Guid RequestId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,16 @@ namespace SafeExamBrowser.Contracts.Communication.Hosts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Guid StartupToken { set; }
|
Guid StartupToken { set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event fired when the runtime requests a password input from the user.
|
||||||
|
/// </summary>
|
||||||
|
event CommunicationEventHandler<PasswordRequestEventArgs> PasswordRequested;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event fired when the runtime denied a reconfiguration request.
|
||||||
|
/// </summary>
|
||||||
|
event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationDenied;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event fired when the runtime commands the client to shutdown.
|
/// Event fired when the runtime commands the client to shutdown.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -32,9 +32,9 @@ namespace SafeExamBrowser.Contracts.Communication.Hosts
|
||||||
event CommunicationEventHandler ClientReady;
|
event CommunicationEventHandler ClientReady;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event fired when the client transmitted a password entered by the user.
|
/// Event fired when the client submitted a password entered by the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event CommunicationEventHandler<PasswordEventArgs> PasswordReceived;
|
event CommunicationEventHandler<PasswordReplyEventArgs> PasswordReceived;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event fired when the client requested a reconfiguration of the application.
|
/// Event fired when the client requested a reconfiguration of the application.
|
||||||
|
|
|
@ -20,8 +20,10 @@ namespace SafeExamBrowser.Contracts.Communication
|
||||||
[ServiceKnownType(typeof(AuthenticationResponse))]
|
[ServiceKnownType(typeof(AuthenticationResponse))]
|
||||||
[ServiceKnownType(typeof(ClientConfiguration))]
|
[ServiceKnownType(typeof(ClientConfiguration))]
|
||||||
[ServiceKnownType(typeof(ConfigurationResponse))]
|
[ServiceKnownType(typeof(ConfigurationResponse))]
|
||||||
|
[ServiceKnownType(typeof(PasswordReplyMessage))]
|
||||||
|
[ServiceKnownType(typeof(PasswordRequestMessage))]
|
||||||
[ServiceKnownType(typeof(ReconfigurationMessage))]
|
[ServiceKnownType(typeof(ReconfigurationMessage))]
|
||||||
[ServiceKnownType(typeof(ReconfigurationResponse))]
|
[ServiceKnownType(typeof(ReconfigurationDeniedMessage))]
|
||||||
[ServiceKnownType(typeof(SimpleMessage))]
|
[ServiceKnownType(typeof(SimpleMessage))]
|
||||||
[ServiceKnownType(typeof(SimpleResponse))]
|
[ServiceKnownType(typeof(SimpleResponse))]
|
||||||
public interface ICommunication
|
public interface ICommunication
|
||||||
|
|
|
@ -16,6 +16,11 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IClientProxy : ICommunicationProxy
|
public interface IClientProxy : ICommunicationProxy
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Informs the client that the reconfiguration request for the specified file was denied.
|
||||||
|
/// </summary>
|
||||||
|
void InformReconfigurationDenied(string filePath);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instructs the client to initiate its shutdown procedure.
|
/// Instructs the client to initiate its shutdown procedure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication.Proxies
|
namespace SafeExamBrowser.Contracts.Communication.Proxies
|
||||||
|
@ -38,5 +39,12 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||||
void RequestReconfiguration(string filePath);
|
void RequestReconfiguration(string filePath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Submits the result of a password input previously requested by the runtime. If the procedure was aborted by the user,
|
||||||
|
/// the password parameter will be <c>null</c>!
|
||||||
|
/// </summary>
|
||||||
|
/// /// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||||
|
void SubmitPassword(Guid requestId, bool success, string password = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,8 @@ namespace SafeExamBrowser.Contracts.I18n
|
||||||
Notification_LogTooltip,
|
Notification_LogTooltip,
|
||||||
PasswordDialog_AdminPasswordRequired,
|
PasswordDialog_AdminPasswordRequired,
|
||||||
PasswordDialog_AdminPasswordRequiredTitle,
|
PasswordDialog_AdminPasswordRequiredTitle,
|
||||||
|
PasswordDialog_Cancel,
|
||||||
|
PasswordDialog_Confirm,
|
||||||
PasswordDialog_SettingsPasswordRequired,
|
PasswordDialog_SettingsPasswordRequired,
|
||||||
PasswordDialog_SettingsPasswordRequiredTitle,
|
PasswordDialog_SettingsPasswordRequiredTitle,
|
||||||
ProgressIndicator_CloseRuntimeConnection,
|
ProgressIndicator_CloseRuntimeConnection,
|
||||||
|
|
|
@ -63,9 +63,11 @@
|
||||||
<Compile Include="Communication\Data\PasswordRequestMessage.cs" />
|
<Compile Include="Communication\Data\PasswordRequestMessage.cs" />
|
||||||
<Compile Include="Communication\Data\PasswordRequestPurpose.cs" />
|
<Compile Include="Communication\Data\PasswordRequestPurpose.cs" />
|
||||||
<Compile Include="Communication\Data\PasswordReplyMessage.cs" />
|
<Compile Include="Communication\Data\PasswordReplyMessage.cs" />
|
||||||
|
<Compile Include="Communication\Data\ReconfigurationDeniedMessage.cs" />
|
||||||
<Compile Include="Communication\Events\CommunicationEventArgs.cs" />
|
<Compile Include="Communication\Events\CommunicationEventArgs.cs" />
|
||||||
<Compile Include="Communication\Events\CommunicationEventHandler.cs" />
|
<Compile Include="Communication\Events\CommunicationEventHandler.cs" />
|
||||||
<Compile Include="Communication\Events\PasswordEventArgs.cs" />
|
<Compile Include="Communication\Events\PasswordReplyEventArgs.cs" />
|
||||||
|
<Compile Include="Communication\Events\PasswordRequestEventArgs.cs" />
|
||||||
<Compile Include="Communication\Events\ReconfigurationEventArgs.cs" />
|
<Compile Include="Communication\Events\ReconfigurationEventArgs.cs" />
|
||||||
<Compile Include="Communication\Hosts\IClientHost.cs" />
|
<Compile Include="Communication\Hosts\IClientHost.cs" />
|
||||||
<Compile Include="Communication\Hosts\IHostObject.cs" />
|
<Compile Include="Communication\Hosts\IHostObject.cs" />
|
||||||
|
@ -89,7 +91,6 @@
|
||||||
<Compile Include="Communication\Data\ConfigurationResponse.cs" />
|
<Compile Include="Communication\Data\ConfigurationResponse.cs" />
|
||||||
<Compile Include="Communication\Data\ConnectionResponse.cs" />
|
<Compile Include="Communication\Data\ConnectionResponse.cs" />
|
||||||
<Compile Include="Communication\Data\DisconnectionResponse.cs" />
|
<Compile Include="Communication\Data\DisconnectionResponse.cs" />
|
||||||
<Compile Include="Communication\Data\ReconfigurationResponse.cs" />
|
|
||||||
<Compile Include="Communication\Data\Response.cs" />
|
<Compile Include="Communication\Data\Response.cs" />
|
||||||
<Compile Include="Communication\Data\SimpleResponsePurport.cs" />
|
<Compile Include="Communication\Data\SimpleResponsePurport.cs" />
|
||||||
<Compile Include="Communication\Data\SimpleResponse.cs" />
|
<Compile Include="Communication\Data\SimpleResponse.cs" />
|
||||||
|
|
|
@ -257,9 +257,9 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Hosts
|
||||||
var received = false;
|
var received = false;
|
||||||
var simpleReceived = false;
|
var simpleReceived = false;
|
||||||
var message = new ReconfigurationMessage(null);
|
var message = new ReconfigurationMessage(null);
|
||||||
var reconfigurationResponse = new ReconfigurationResponse();
|
var configurationResponse = new ConfigurationResponse();
|
||||||
|
|
||||||
sut.OnReceiveStub = (m) => { received = true; return reconfigurationResponse; };
|
sut.OnReceiveStub = (m) => { received = true; return configurationResponse; };
|
||||||
sut.OnReceiveSimpleMessageStub = (m) => { simpleReceived = true; return null; };
|
sut.OnReceiveSimpleMessageStub = (m) => { simpleReceived = true; return null; };
|
||||||
sut.OnConnectStub = (t) => { return true; };
|
sut.OnConnectStub = (t) => { return true; };
|
||||||
sut.Connect();
|
sut.Connect();
|
||||||
|
@ -270,8 +270,8 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Hosts
|
||||||
|
|
||||||
Assert.IsTrue(received);
|
Assert.IsTrue(received);
|
||||||
Assert.IsFalse(simpleReceived);
|
Assert.IsFalse(simpleReceived);
|
||||||
Assert.IsInstanceOfType(response, typeof(ReconfigurationResponse));
|
Assert.IsInstanceOfType(response, typeof(ConfigurationResponse));
|
||||||
Assert.AreSame(reconfigurationResponse, response);
|
Assert.AreSame(configurationResponse, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ using System;
|
||||||
using System.ServiceModel;
|
using System.ServiceModel;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
|
||||||
using SafeExamBrowser.Contracts.Communication.Data;
|
using SafeExamBrowser.Contracts.Communication.Data;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
@ -96,56 +95,24 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustCorrectlyRequestReconfiguration()
|
public void MustCorrectlyRequestReconfiguration()
|
||||||
{
|
{
|
||||||
//var url = "sebs://some/url.seb";
|
var url = "file:///C:/Some/file/url.seb";
|
||||||
//var response = new ReconfigurationResponse
|
|
||||||
//{
|
|
||||||
// Accepted = true
|
|
||||||
//};
|
|
||||||
|
|
||||||
//proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url))).Returns(response);
|
proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationPath == url))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged));
|
||||||
|
|
||||||
//var accepted = sut.RequestReconfiguration(url);
|
sut.RequestReconfiguration(url);
|
||||||
|
|
||||||
//proxy.Verify(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url)), Times.Once);
|
proxy.Verify(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationPath == url)), Times.Once);
|
||||||
|
|
||||||
//Assert.IsTrue(accepted);
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
Assert.Fail();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustCorrectlyHandleDeniedReconfigurationRequest()
|
[ExpectedException(typeof(CommunicationException))]
|
||||||
|
public void MustFailIfReconfigurationRequestNotAcknowledged()
|
||||||
{
|
{
|
||||||
//var url = "sebs://some/url.seb";
|
var url = "file:///C:/Some/file/url.seb";
|
||||||
//var response = new ReconfigurationResponse
|
|
||||||
//{
|
|
||||||
// Accepted = false
|
|
||||||
//};
|
|
||||||
|
|
||||||
//proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url))).Returns(response);
|
proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationPath == url))).Returns<Response>(null);
|
||||||
|
|
||||||
//var accepted = sut.RequestReconfiguration(url);
|
sut.RequestReconfiguration(url);
|
||||||
|
|
||||||
//Assert.IsFalse(accepted);
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
Assert.Fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustNotFailIfIncorrectResponseToReconfigurationRequest()
|
|
||||||
{
|
|
||||||
//var url = "sebs://some/url.seb";
|
|
||||||
|
|
||||||
//proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationUrl == url))).Returns<Response>(null);
|
|
||||||
|
|
||||||
//var accepted = sut.RequestReconfiguration(url);
|
|
||||||
|
|
||||||
//Assert.IsFalse(accepted);
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
Assert.Fail();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
|
@ -23,13 +23,23 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InformReconfigurationDenied(string filePath)
|
||||||
|
{
|
||||||
|
var response = Send(new ReconfigurationDeniedMessage(filePath));
|
||||||
|
|
||||||
|
if (!IsAcknowledged(response))
|
||||||
|
{
|
||||||
|
throw new CommunicationException($"Client did not acknowledge shutdown request! Received: {ToString(response)}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void InitiateShutdown()
|
public void InitiateShutdown()
|
||||||
{
|
{
|
||||||
var response = Send(SimpleMessagePurport.Shutdown);
|
var response = Send(SimpleMessagePurport.Shutdown);
|
||||||
|
|
||||||
if (!IsAcknowledged(response))
|
if (!IsAcknowledged(response))
|
||||||
{
|
{
|
||||||
throw new CommunicationException($"Runtime did not acknowledge shutdown request! Received: {ToString(response)}.");
|
throw new CommunicationException($"Client did not acknowledge shutdown request! Received: {ToString(response)}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +57,12 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
||||||
|
|
||||||
public void RequestPassword(PasswordRequestPurpose purpose, Guid requestId)
|
public void RequestPassword(PasswordRequestPurpose purpose, Guid requestId)
|
||||||
{
|
{
|
||||||
// TODO
|
var response = Send(new PasswordRequestMessage(purpose, requestId));
|
||||||
throw new NotImplementedException();
|
|
||||||
|
if (!IsAcknowledged(response))
|
||||||
|
{
|
||||||
|
throw new CommunicationException($"Client did not acknowledge shutdown request! Received: {ToString(response)}.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.ServiceModel;
|
using System.ServiceModel;
|
||||||
using SafeExamBrowser.Contracts.Communication.Data;
|
using SafeExamBrowser.Contracts.Communication.Data;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
|
@ -64,5 +65,15 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
||||||
throw new CommunicationException($"Runtime did not acknowledge shutdown request! Response: {ToString(response)}.");
|
throw new CommunicationException($"Runtime did not acknowledge shutdown request! Response: {ToString(response)}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SubmitPassword(Guid requestId, bool success, string password = null)
|
||||||
|
{
|
||||||
|
var response = Send(new PasswordReplyMessage(requestId, success, password));
|
||||||
|
|
||||||
|
if (!IsAcknowledged(response))
|
||||||
|
{
|
||||||
|
throw new CommunicationException($"Runtime did not acknowledge password submission! Response: {ToString(response)}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,12 @@
|
||||||
<Entry key="PasswordDialog_AdminPasswordRequiredTitle">
|
<Entry key="PasswordDialog_AdminPasswordRequiredTitle">
|
||||||
Administrator Password Required
|
Administrator Password Required
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="PasswordDialog_Cancel">
|
||||||
|
Cancel
|
||||||
|
</Entry>
|
||||||
|
<Entry key="PasswordDialog_Confirm">
|
||||||
|
Confirm
|
||||||
|
</Entry>
|
||||||
<Entry key="PasswordDialog_SettingsPasswordRequired">
|
<Entry key="PasswordDialog_SettingsPasswordRequired">
|
||||||
Please enter the settings password for the application configuration:
|
Please enter the settings password for the application configuration:
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -75,9 +75,9 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustStartClientOnRepeat()
|
public void TODO()
|
||||||
{
|
{
|
||||||
// TODO: Extract static fields from operation -> allows unit testing of this requirement etc.!
|
// TODO: MustStartClientOnRepeat -> Extract static fields from operation -> allows unit testing of this requirement etc.!
|
||||||
Assert.Fail();
|
Assert.Fail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,7 +337,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
var clientProxy = new Mock<IClientProxy>();
|
var clientProxy = new Mock<IClientProxy>();
|
||||||
var passwordReceived = new Action<PasswordRequestPurpose, Guid>((p, id) =>
|
var passwordReceived = new Action<PasswordRequestPurpose, Guid>((p, id) =>
|
||||||
{
|
{
|
||||||
runtimeHost.Raise(r => r.PasswordReceived += null, new PasswordEventArgs { RequestId = id, Success = true });
|
runtimeHost.Raise(r => r.PasswordReceived += null, new PasswordReplyEventArgs { RequestId = id, Success = true });
|
||||||
});
|
});
|
||||||
var session = new Mock<ISessionData>();
|
var session = new Mock<ISessionData>();
|
||||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||||
|
@ -363,7 +363,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
var clientProxy = new Mock<IClientProxy>();
|
var clientProxy = new Mock<IClientProxy>();
|
||||||
var passwordReceived = new Action<PasswordRequestPurpose, Guid>((p, id) =>
|
var passwordReceived = new Action<PasswordRequestPurpose, Guid>((p, id) =>
|
||||||
{
|
{
|
||||||
runtimeHost.Raise(r => r.PasswordReceived += null, new PasswordEventArgs { RequestId = id, Success = false });
|
runtimeHost.Raise(r => r.PasswordReceived += null, new PasswordReplyEventArgs { RequestId = id, Success = false });
|
||||||
});
|
});
|
||||||
var session = new Mock<ISessionData>();
|
var session = new Mock<ISessionData>();
|
||||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||||
|
|
|
@ -188,9 +188,9 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
private bool TryGetPasswordViaClient(PasswordRequestPurpose purpose, out string password)
|
private bool TryGetPasswordViaClient(PasswordRequestPurpose purpose, out string password)
|
||||||
{
|
{
|
||||||
var requestId = Guid.NewGuid();
|
var requestId = Guid.NewGuid();
|
||||||
var response = default(PasswordEventArgs);
|
var response = default(PasswordReplyEventArgs);
|
||||||
var responseEvent = new AutoResetEvent(false);
|
var responseEvent = new AutoResetEvent(false);
|
||||||
var responseEventHandler = new CommunicationEventHandler<PasswordEventArgs>((args) =>
|
var responseEventHandler = new CommunicationEventHandler<PasswordReplyEventArgs>((args) =>
|
||||||
{
|
{
|
||||||
if (args.RequestId == requestId)
|
if (args.RequestId == requestId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -261,7 +261,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.Info($"Denied request for reconfiguration with '{args.ConfigurationPath}' due to '{mode}' mode!");
|
logger.Info($"Denied request for reconfiguration with '{args.ConfigurationPath}' due to '{mode}' mode!");
|
||||||
// TODO: configuration.CurrentSession.ClientProxy.InformReconfigurationDenied();
|
configuration.CurrentSession.ClientProxy.InformReconfigurationDenied(args.ConfigurationPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace SafeExamBrowser.Runtime.Communication
|
||||||
|
|
||||||
public event CommunicationEventHandler ClientDisconnected;
|
public event CommunicationEventHandler ClientDisconnected;
|
||||||
public event CommunicationEventHandler ClientReady;
|
public event CommunicationEventHandler ClientReady;
|
||||||
public event CommunicationEventHandler<PasswordEventArgs> PasswordReceived;
|
public event CommunicationEventHandler<PasswordReplyEventArgs> PasswordReceived;
|
||||||
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
||||||
public event CommunicationEventHandler ShutdownRequested;
|
public event CommunicationEventHandler ShutdownRequested;
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ namespace SafeExamBrowser.Runtime.Communication
|
||||||
switch (message)
|
switch (message)
|
||||||
{
|
{
|
||||||
case PasswordReplyMessage r:
|
case PasswordReplyMessage r:
|
||||||
PasswordReceived?.InvokeAsync(new PasswordEventArgs { Password = r.Password, RequestId = r.RequestId, Success = r.Success });
|
PasswordReceived?.InvokeAsync(new PasswordReplyEventArgs { Password = r.Password, RequestId = r.RequestId, Success = r.Success });
|
||||||
return new SimpleResponse(SimpleResponsePurport.Acknowledged);
|
return new SimpleResponse(SimpleResponsePurport.Acknowledged);
|
||||||
case ReconfigurationMessage r:
|
case ReconfigurationMessage r:
|
||||||
ReconfigurationRequested?.InvokeAsync(new ReconfigurationEventArgs { ConfigurationPath = r.ConfigurationPath });
|
ReconfigurationRequested?.InvokeAsync(new ReconfigurationEventArgs { ConfigurationPath = r.ConfigurationPath });
|
||||||
|
|
35
SafeExamBrowser.UserInterface.Classic/PasswordDialog.xaml
Normal file
35
SafeExamBrowser.UserInterface.Classic/PasswordDialog.xaml
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<Window x:Class="SafeExamBrowser.UserInterface.Classic.PasswordDialog"
|
||||||
|
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Classic"
|
||||||
|
mc:Ignorable="d" Height="200" Width="450" ResizeMode="NoResize" Topmost="True">
|
||||||
|
<Window.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="./Templates/Colors.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Window.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="4*" />
|
||||||
|
<RowDefinition Height="2*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid Grid.Row="0" Margin="25,0,25,25">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock Grid.Row="0" x:Name="Message" Margin="0,0,0,10" TextWrapping="WrapWithOverflow" VerticalAlignment="Bottom" />
|
||||||
|
<PasswordBox Grid.Row="1" x:Name="Password" Height="25" VerticalContentAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="1" Background="{StaticResource BackgroundBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
|
<WrapPanel Orientation="Horizontal" Margin="25,0" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||||
|
<Button x:Name="ConfirmButton" Cursor="Hand" Margin="10,0" Padding="10,5" MinWidth="75" />
|
||||||
|
<Button x:Name="CancelButton" Cursor="Hand" Padding="10,5" MinWidth="75" />
|
||||||
|
</WrapPanel>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
94
SafeExamBrowser.UserInterface.Classic/PasswordDialog.xaml.cs
Normal file
94
SafeExamBrowser.UserInterface.Classic/PasswordDialog.xaml.cs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* 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 SafeExamBrowser.Contracts.I18n;
|
||||||
|
using SafeExamBrowser.Contracts.UserInterface.Windows;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.UserInterface.Classic
|
||||||
|
{
|
||||||
|
public partial class PasswordDialog : Window, IPasswordDialog
|
||||||
|
{
|
||||||
|
private IText text;
|
||||||
|
private WindowClosingEventHandler closing;
|
||||||
|
|
||||||
|
event WindowClosingEventHandler IWindow.Closing
|
||||||
|
{
|
||||||
|
add { closing += value; }
|
||||||
|
remove { closing -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public PasswordDialog(string message, string title, IText text)
|
||||||
|
{
|
||||||
|
this.text = text;
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
InitializePasswordDialog(message, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BringToForeground()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(Activate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPasswordDialogResult Show(IWindow parent = null)
|
||||||
|
{
|
||||||
|
return Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
var result = new PasswordDialogResult { Success = false };
|
||||||
|
|
||||||
|
if (parent is Window)
|
||||||
|
{
|
||||||
|
Owner = parent as Window;
|
||||||
|
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShowDialog() is true)
|
||||||
|
{
|
||||||
|
result.Password = Password.Password;
|
||||||
|
result.Success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializePasswordDialog(string message, string title)
|
||||||
|
{
|
||||||
|
Message.Text = message;
|
||||||
|
Title = title;
|
||||||
|
WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||||
|
|
||||||
|
CancelButton.Content = text.Get(TextKey.PasswordDialog_Cancel);
|
||||||
|
CancelButton.Click += CancelButton_Click;
|
||||||
|
|
||||||
|
ConfirmButton.Content = text.Get(TextKey.PasswordDialog_Confirm);
|
||||||
|
ConfirmButton.Click += ConfirmButton_Click;
|
||||||
|
|
||||||
|
Closing += (o, args) => closing?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CancelButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DialogResult = false;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfirmButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DialogResult = true;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PasswordDialogResult : IPasswordDialogResult
|
||||||
|
{
|
||||||
|
public string Password { get; set; }
|
||||||
|
public bool Success { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,6 +105,9 @@
|
||||||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="MessageBox.cs" />
|
<Compile Include="MessageBox.cs" />
|
||||||
|
<Compile Include="PasswordDialog.xaml.cs">
|
||||||
|
<DependentUpon>PasswordDialog.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="RuntimeWindow.xaml.cs">
|
<Compile Include="RuntimeWindow.xaml.cs">
|
||||||
<DependentUpon>RuntimeWindow.xaml</DependentUpon>
|
<DependentUpon>RuntimeWindow.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -224,6 +227,10 @@
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="PasswordDialog.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="RuntimeWindow.xaml">
|
<Page Include="RuntimeWindow.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Windows;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
|
@ -81,7 +82,7 @@ namespace SafeExamBrowser.UserInterface.Classic
|
||||||
|
|
||||||
public IPasswordDialog CreatePasswordDialog(string message, string title)
|
public IPasswordDialog CreatePasswordDialog(string message, string title)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
return Application.Current.Dispatcher.Invoke(() => new PasswordDialog(message, title, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISystemPowerSupplyControl CreatePowerSupplyControl()
|
public ISystemPowerSupplyControl CreatePowerSupplyControl()
|
||||||
|
|
Loading…
Add table
Reference in a new issue