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.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Browser;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
@ -37,6 +39,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
private Action shutdown;
|
||||
private ISplashScreen splashScreen;
|
||||
private ITaskbar taskbar;
|
||||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
private IWindowMonitor windowMonitor;
|
||||
private AppConfig appConfig;
|
||||
|
@ -68,6 +71,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
IRuntimeProxy runtime,
|
||||
Action shutdown,
|
||||
ITaskbar taskbar,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory,
|
||||
IWindowMonitor windowMonitor)
|
||||
{
|
||||
|
@ -79,6 +83,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
this.runtime = runtime;
|
||||
this.shutdown = shutdown;
|
||||
this.taskbar = taskbar;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
this.windowMonitor = windowMonitor;
|
||||
}
|
||||
|
@ -150,6 +155,8 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
private void RegisterEvents()
|
||||
{
|
||||
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
|
||||
ClientHost.PasswordRequested += ClientHost_PasswordRequested;
|
||||
ClientHost.ReconfigurationDenied += ClientHost_ReconfigurationDenied;
|
||||
ClientHost.Shutdown += ClientHost_Shutdown;
|
||||
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
||||
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
|
||||
|
@ -161,6 +168,8 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
private void DeregisterEvents()
|
||||
{
|
||||
Browser.ConfigurationDownloadRequested -= Browser_ConfigurationDownloadRequested;
|
||||
ClientHost.PasswordRequested -= ClientHost_PasswordRequested;
|
||||
ClientHost.ReconfigurationDenied -= ClientHost_ReconfigurationDenied;
|
||||
ClientHost.Shutdown -= ClientHost_Shutdown;
|
||||
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
||||
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()
|
||||
{
|
||||
taskbar.Close();
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace SafeExamBrowser.Client.Communication
|
|||
|
||||
public Guid StartupToken { private get; set; }
|
||||
|
||||
public event CommunicationEventHandler<PasswordRequestEventArgs> PasswordRequested;
|
||||
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationDenied;
|
||||
public event CommunicationEventHandler Shutdown;
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
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()
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>SafeExamBrowser.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
|
@ -147,6 +150,9 @@
|
|||
<Name>SafeExamBrowser.WindowsApi</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="SafeExamBrowser.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<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>
|
||||
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;
|
||||
RequestId = requestId;
|
||||
|
|
|
@ -11,14 +11,19 @@ using System;
|
|||
namespace SafeExamBrowser.Contracts.Communication.Data
|
||||
{
|
||||
/// <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>
|
||||
[Serializable]
|
||||
public class ReconfigurationResponse : Response
|
||||
public class ReconfigurationDeniedMessage : Message
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the reconfiguration request has been accepted.
|
||||
/// The full path to the configuration file for which a reconfiguration was denied.
|
||||
/// </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>
|
||||
/// The event arguments used for the password input event fired by the <see cref="Hosts.IRuntimeHost"/>.
|
||||
/// </summary>
|
||||
public class PasswordEventArgs : CommunicationEventArgs
|
||||
public class PasswordReplyEventArgs : CommunicationEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 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>
|
||||
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>
|
||||
/// Event fired when the runtime commands the client to shutdown.
|
||||
/// </summary>
|
||||
|
|
|
@ -32,9 +32,9 @@ namespace SafeExamBrowser.Contracts.Communication.Hosts
|
|||
event CommunicationEventHandler ClientReady;
|
||||
|
||||
/// <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>
|
||||
event CommunicationEventHandler<PasswordEventArgs> PasswordReceived;
|
||||
event CommunicationEventHandler<PasswordReplyEventArgs> PasswordReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the client requested a reconfiguration of the application.
|
||||
|
|
|
@ -20,8 +20,10 @@ namespace SafeExamBrowser.Contracts.Communication
|
|||
[ServiceKnownType(typeof(AuthenticationResponse))]
|
||||
[ServiceKnownType(typeof(ClientConfiguration))]
|
||||
[ServiceKnownType(typeof(ConfigurationResponse))]
|
||||
[ServiceKnownType(typeof(PasswordReplyMessage))]
|
||||
[ServiceKnownType(typeof(PasswordRequestMessage))]
|
||||
[ServiceKnownType(typeof(ReconfigurationMessage))]
|
||||
[ServiceKnownType(typeof(ReconfigurationResponse))]
|
||||
[ServiceKnownType(typeof(ReconfigurationDeniedMessage))]
|
||||
[ServiceKnownType(typeof(SimpleMessage))]
|
||||
[ServiceKnownType(typeof(SimpleResponse))]
|
||||
public interface ICommunication
|
||||
|
|
|
@ -16,6 +16,11 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies
|
|||
/// </summary>
|
||||
public interface IClientProxy : ICommunicationProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Informs the client that the reconfiguration request for the specified file was denied.
|
||||
/// </summary>
|
||||
void InformReconfigurationDenied(string filePath);
|
||||
|
||||
/// <summary>
|
||||
/// Instructs the client to initiate its shutdown procedure.
|
||||
/// </summary>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Proxies
|
||||
|
@ -38,5 +39,12 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies
|
|||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
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,
|
||||
PasswordDialog_AdminPasswordRequired,
|
||||
PasswordDialog_AdminPasswordRequiredTitle,
|
||||
PasswordDialog_Cancel,
|
||||
PasswordDialog_Confirm,
|
||||
PasswordDialog_SettingsPasswordRequired,
|
||||
PasswordDialog_SettingsPasswordRequiredTitle,
|
||||
ProgressIndicator_CloseRuntimeConnection,
|
||||
|
|
|
@ -63,9 +63,11 @@
|
|||
<Compile Include="Communication\Data\PasswordRequestMessage.cs" />
|
||||
<Compile Include="Communication\Data\PasswordRequestPurpose.cs" />
|
||||
<Compile Include="Communication\Data\PasswordReplyMessage.cs" />
|
||||
<Compile Include="Communication\Data\ReconfigurationDeniedMessage.cs" />
|
||||
<Compile Include="Communication\Events\CommunicationEventArgs.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\Hosts\IClientHost.cs" />
|
||||
<Compile Include="Communication\Hosts\IHostObject.cs" />
|
||||
|
@ -89,7 +91,6 @@
|
|||
<Compile Include="Communication\Data\ConfigurationResponse.cs" />
|
||||
<Compile Include="Communication\Data\ConnectionResponse.cs" />
|
||||
<Compile Include="Communication\Data\DisconnectionResponse.cs" />
|
||||
<Compile Include="Communication\Data\ReconfigurationResponse.cs" />
|
||||
<Compile Include="Communication\Data\Response.cs" />
|
||||
<Compile Include="Communication\Data\SimpleResponsePurport.cs" />
|
||||
<Compile Include="Communication\Data\SimpleResponse.cs" />
|
||||
|
|
|
@ -257,9 +257,9 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Hosts
|
|||
var received = false;
|
||||
var simpleReceived = false;
|
||||
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.OnConnectStub = (t) => { return true; };
|
||||
sut.Connect();
|
||||
|
@ -270,8 +270,8 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Hosts
|
|||
|
||||
Assert.IsTrue(received);
|
||||
Assert.IsFalse(simpleReceived);
|
||||
Assert.IsInstanceOfType(response, typeof(ReconfigurationResponse));
|
||||
Assert.AreSame(reconfigurationResponse, response);
|
||||
Assert.IsInstanceOfType(response, typeof(ConfigurationResponse));
|
||||
Assert.AreSame(configurationResponse, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ using System;
|
|||
using System.ServiceModel;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
@ -96,56 +95,24 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
[TestMethod]
|
||||
public void MustCorrectlyRequestReconfiguration()
|
||||
{
|
||||
//var url = "sebs://some/url.seb";
|
||||
//var response = new ReconfigurationResponse
|
||||
//{
|
||||
// Accepted = true
|
||||
//};
|
||||
var url = "file:///C:/Some/file/url.seb";
|
||||
|
||||
//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);
|
||||
|
||||
//Assert.IsTrue(accepted);
|
||||
|
||||
// TODO
|
||||
Assert.Fail();
|
||||
proxy.Verify(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationPath == url)), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustCorrectlyHandleDeniedReconfigurationRequest()
|
||||
[ExpectedException(typeof(CommunicationException))]
|
||||
public void MustFailIfReconfigurationRequestNotAcknowledged()
|
||||
{
|
||||
//var url = "sebs://some/url.seb";
|
||||
//var response = new ReconfigurationResponse
|
||||
//{
|
||||
// Accepted = false
|
||||
//};
|
||||
var url = "file:///C:/Some/file/url.seb";
|
||||
|
||||
//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);
|
||||
|
||||
//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();
|
||||
sut.RequestReconfiguration(url);
|
||||
}
|
||||
|
||||
[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()
|
||||
{
|
||||
var response = Send(SimpleMessagePurport.Shutdown);
|
||||
|
||||
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)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
var response = Send(new PasswordRequestMessage(purpose, requestId));
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
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)}.");
|
||||
}
|
||||
}
|
||||
|
||||
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">
|
||||
Administrator Password Required
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_Cancel">
|
||||
Cancel
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_Confirm">
|
||||
Confirm
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_SettingsPasswordRequired">
|
||||
Please enter the settings password for the application configuration:
|
||||
</Entry>
|
||||
|
|
|
@ -75,9 +75,9 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
}
|
||||
|
||||
[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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -337,7 +337,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
var clientProxy = new Mock<IClientProxy>();
|
||||
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 url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
@ -363,7 +363,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
var clientProxy = new Mock<IClientProxy>();
|
||||
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 url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
|
|
@ -188,9 +188,9 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
private bool TryGetPasswordViaClient(PasswordRequestPurpose purpose, out string password)
|
||||
{
|
||||
var requestId = Guid.NewGuid();
|
||||
var response = default(PasswordEventArgs);
|
||||
var response = default(PasswordReplyEventArgs);
|
||||
var responseEvent = new AutoResetEvent(false);
|
||||
var responseEventHandler = new CommunicationEventHandler<PasswordEventArgs>((args) =>
|
||||
var responseEventHandler = new CommunicationEventHandler<PasswordReplyEventArgs>((args) =>
|
||||
{
|
||||
if (args.RequestId == requestId)
|
||||
{
|
||||
|
|
|
@ -261,7 +261,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
else
|
||||
{
|
||||
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 ClientReady;
|
||||
public event CommunicationEventHandler<PasswordEventArgs> PasswordReceived;
|
||||
public event CommunicationEventHandler<PasswordReplyEventArgs> PasswordReceived;
|
||||
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
||||
public event CommunicationEventHandler ShutdownRequested;
|
||||
|
||||
|
@ -64,7 +64,7 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
switch (message)
|
||||
{
|
||||
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);
|
||||
case ReconfigurationMessage r:
|
||||
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>
|
||||
</Compile>
|
||||
<Compile Include="MessageBox.cs" />
|
||||
<Compile Include="PasswordDialog.xaml.cs">
|
||||
<DependentUpon>PasswordDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="RuntimeWindow.xaml.cs">
|
||||
<DependentUpon>RuntimeWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -224,6 +227,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="PasswordDialog.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="RuntimeWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
|
@ -81,7 +82,7 @@ namespace SafeExamBrowser.UserInterface.Classic
|
|||
|
||||
public IPasswordDialog CreatePasswordDialog(string message, string title)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
return Application.Current.Dispatcher.Invoke(() => new PasswordDialog(message, title, text));
|
||||
}
|
||||
|
||||
public ISystemPowerSupplyControl CreatePowerSupplyControl()
|
||||
|
|
Loading…
Add table
Reference in a new issue