SEBWIN-220: Finished draft of (re-)configuration mechanism.
This commit is contained in:
parent
639bde7860
commit
eb47cb362b
30 changed files with 529 additions and 101 deletions
|
@ -11,7 +11,7 @@ using System;
|
|||
namespace SafeExamBrowser.Contracts.Communication.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// The response to be used to reply to an authentication request (see <see cref="Messages.SimpleMessagePurport.Authenticate"/>).
|
||||
/// The response to be used to reply to an authentication request (see <see cref="SimpleMessagePurport.Authenticate"/>).
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class AuthenticationResponse : Response
|
||||
|
|
|
@ -12,7 +12,7 @@ using SafeExamBrowser.Contracts.Configuration;
|
|||
namespace SafeExamBrowser.Contracts.Communication.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// The response to be used to reply to a configuration request (see <see cref="Messages.SimpleMessagePurport.ConfigurationNeeded"/>).
|
||||
/// The response to be used to reply to a configuration request (see <see cref="SimpleMessagePurport.ConfigurationNeeded"/>).
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ConfigurationResponse : Response
|
||||
|
|
|
@ -11,7 +11,7 @@ using System;
|
|||
namespace SafeExamBrowser.Contracts.Communication.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// The response transmitted to a <see cref="Messages.DisconnectionMessage"/>
|
||||
/// The response transmitted to a <see cref="DisconnectionMessage"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DisconnectionResponse : Response
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// The reply to a <see cref="PasswordRequestMessage"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PasswordReplyMessage : Message
|
||||
{
|
||||
/// <summary>
|
||||
/// The password entered by the user, or <c>null</c> if the user interaction was unsuccessful.
|
||||
/// </summary>
|
||||
public string Password { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier for the password request.
|
||||
/// </summary>
|
||||
public Guid RequestId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the user interaction was successful or not.
|
||||
/// </summary>
|
||||
public bool Success { get; private set; }
|
||||
|
||||
public PasswordReplyMessage(string password, Guid requestId, bool success)
|
||||
{
|
||||
Password = password;
|
||||
RequestId = requestId;
|
||||
Success = success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// This message is transmitted to the client to request a password input by the user.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PasswordRequestMessage : Message
|
||||
{
|
||||
/// <summary>
|
||||
/// The purpose of the password request.
|
||||
/// </summary>
|
||||
public PasswordRequestPurpose Purpose { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier for the password request.
|
||||
/// </summary>
|
||||
public Guid RequestId { get; private set; }
|
||||
|
||||
public PasswordRequestMessage(PasswordRequestPurpose purpose, Guid requestId)
|
||||
{
|
||||
Purpose = purpose;
|
||||
RequestId = requestId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines all possible reasons for a <see cref="PasswordRequestMessage"/>.
|
||||
/// </summary>
|
||||
public enum PasswordRequestPurpose
|
||||
{
|
||||
Undefined = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The password is to be used as administrator password for an application configuration.
|
||||
/// </summary>
|
||||
Administrator,
|
||||
|
||||
/// <summary>
|
||||
/// The password is to be used as settings password for an application configuration.
|
||||
/// </summary>
|
||||
Settings
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ using System;
|
|||
namespace SafeExamBrowser.Contracts.Communication.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// The response to a <see cref="Messages.ReconfigurationMessage"/>.
|
||||
/// The response to a <see cref="ReconfigurationMessage"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ReconfigurationResponse : Response
|
||||
|
|
|
@ -11,7 +11,7 @@ using System;
|
|||
namespace SafeExamBrowser.Contracts.Communication.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// The base class for respones, from which a response must inherit in order to be sent to an interlocutor as reply to <see cref="ICommunication.Send(Messages.Message)"/>.
|
||||
/// The base class for respones, from which a response must inherit in order to be sent to an interlocutor as reply to <see cref="ICommunication.Send(Message)"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class Response
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// The password entered by the user, or <c>null</c> if not available.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the password request.
|
||||
/// </summary>
|
||||
public Guid RequestId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the password has been successfully entered by the user.
|
||||
/// </summary>
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
|
@ -31,6 +31,11 @@ namespace SafeExamBrowser.Contracts.Communication.Hosts
|
|||
/// </summary>
|
||||
event CommunicationEventHandler ClientReady;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the client transmitted a password entered by the user.
|
||||
/// </summary>
|
||||
event CommunicationEventHandler<PasswordEventArgs> PasswordReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the client requested a reconfiguration of the application.
|
||||
/// </summary>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Proxies
|
||||
|
@ -26,5 +27,11 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies
|
|||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
AuthenticationResponse RequestAuthentication();
|
||||
|
||||
/// <summary>
|
||||
/// Requests the client to render a password dialog and subsequently return the interaction result as separate message.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
void RequestPassword(PasswordRequestPurpose purpose, Guid requestId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
/// Attempts to load settings from the specified resource, using the optional passwords. Returns a <see cref="LoadStatus"/>
|
||||
/// indicating the result of the operation.
|
||||
/// </summary>
|
||||
LoadStatus LoadSettings(Uri resource, string settingsPassword = null, string adminPassword = null);
|
||||
LoadStatus LoadSettings(Uri resource, string adminPassword = null, string settingsPassword = null);
|
||||
|
||||
/// <summary>
|
||||
/// Loads the default settings.
|
||||
|
|
|
@ -44,6 +44,10 @@ namespace SafeExamBrowser.Contracts.I18n
|
|||
MessageBox_StartupErrorTitle,
|
||||
Notification_AboutTooltip,
|
||||
Notification_LogTooltip,
|
||||
PasswordDialog_AdminPasswordRequired,
|
||||
PasswordDialog_AdminPasswordRequiredTitle,
|
||||
PasswordDialog_SettingsPasswordRequired,
|
||||
PasswordDialog_SettingsPasswordRequiredTitle,
|
||||
ProgressIndicator_CloseRuntimeConnection,
|
||||
ProgressIndicator_EmptyClipboard,
|
||||
ProgressIndicator_FinalizeServiceSession,
|
||||
|
|
|
@ -60,8 +60,12 @@
|
|||
<Compile Include="Browser\DownloadFinishedCallback.cs" />
|
||||
<Compile Include="Browser\DownloadRequestedEventHandler.cs" />
|
||||
<Compile Include="Browser\IBrowserApplicationController.cs" />
|
||||
<Compile Include="Communication\Data\PasswordRequestMessage.cs" />
|
||||
<Compile Include="Communication\Data\PasswordRequestPurpose.cs" />
|
||||
<Compile Include="Communication\Data\PasswordReplyMessage.cs" />
|
||||
<Compile Include="Communication\Events\CommunicationEventArgs.cs" />
|
||||
<Compile Include="Communication\Events\CommunicationEventHandler.cs" />
|
||||
<Compile Include="Communication\Events\PasswordEventArgs.cs" />
|
||||
<Compile Include="Communication\Events\ReconfigurationEventArgs.cs" />
|
||||
<Compile Include="Communication\Hosts\IClientHost.cs" />
|
||||
<Compile Include="Communication\Hosts\IHostObject.cs" />
|
||||
|
@ -139,6 +143,8 @@
|
|||
<Compile Include="UserInterface\MessageBox\IMessageBox.cs" />
|
||||
<Compile Include="UserInterface\IProgressIndicator.cs" />
|
||||
<Compile Include="UserInterface\Taskbar\QuitButtonClickedEventHandler.cs" />
|
||||
<Compile Include="UserInterface\Windows\IPasswordDialog.cs" />
|
||||
<Compile Include="UserInterface\Windows\IPasswordDialogResult.cs" />
|
||||
<Compile Include="UserInterface\Windows\IRuntimeWindow.cs" />
|
||||
<Compile Include="UserInterface\MessageBox\MessageBoxResult.cs" />
|
||||
<Compile Include="UserInterface\Taskbar\INotificationButton.cs" />
|
||||
|
|
|
@ -37,6 +37,11 @@ namespace SafeExamBrowser.Contracts.UserInterface
|
|||
/// </summary>
|
||||
IBrowserWindow CreateBrowserWindow(IBrowserControl control, BrowserSettings settings);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a system control which allows to change the keyboard layout of the computer.
|
||||
/// </summary>
|
||||
ISystemKeyboardLayoutControl CreateKeyboardLayoutControl();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new log window which runs on its own thread.
|
||||
/// </summary>
|
||||
|
@ -48,9 +53,9 @@ namespace SafeExamBrowser.Contracts.UserInterface
|
|||
INotificationButton CreateNotification(INotificationInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a system control which allows to change the keyboard layout of the computer.
|
||||
/// Creates a password dialog with the given message and title.
|
||||
/// </summary>
|
||||
ISystemKeyboardLayoutControl CreateKeyboardLayoutControl();
|
||||
IPasswordDialog CreatePasswordDialog(string message, string title);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a system control displaying the power supply status of the computer.
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.UserInterface.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the functionality of a password dialog.
|
||||
/// </summary>
|
||||
public interface IPasswordDialog : IWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows the dialog as topmost window. If a parent window is specified, the dialog is rendered modally for the given parent.
|
||||
/// </summary>
|
||||
IPasswordDialogResult Show(IWindow parent = null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.UserInterface.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the user interaction result of an <see cref="IPasswordDialog"/>.
|
||||
/// </summary>
|
||||
public interface IPasswordDialogResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The password entered by the user, or <c>null</c> if the interaction was unsuccessful.
|
||||
/// </summary>
|
||||
string Password { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the user confirmed the dialog or not.
|
||||
/// </summary>
|
||||
bool Success { get; }
|
||||
}
|
||||
}
|
|
@ -14,14 +14,14 @@ using SafeExamBrowser.Core.Communication.Hosts;
|
|||
|
||||
namespace SafeExamBrowser.Core.UnitTests.Communication.Hosts
|
||||
{
|
||||
internal class BaseHostImpl : BaseHost
|
||||
internal class BaseHostStub : BaseHost
|
||||
{
|
||||
public Func<Guid?, bool> OnConnectStub { get; set; }
|
||||
public Action OnDisconnectStub { get; set; }
|
||||
public Func<Message, Response> OnReceiveStub { get; set; }
|
||||
public Func<SimpleMessagePurport, Response> OnReceiveSimpleMessageStub { get; set; }
|
||||
|
||||
public BaseHostImpl(string address, IHostObjectFactory factory, ILogger logger) : base(address, factory, logger)
|
||||
public BaseHostStub(string address, IHostObjectFactory factory, ILogger logger) : base(address, factory, logger)
|
||||
{
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Hosts
|
|||
private Mock<IHostObject> hostObject;
|
||||
private Mock<IHostObjectFactory> hostObjectFactory;
|
||||
private Mock<ILogger> logger;
|
||||
private BaseHostImpl sut;
|
||||
private BaseHostStub sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
|
@ -35,7 +35,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Hosts
|
|||
|
||||
hostObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>(), It.IsAny<ICommunication>())).Returns(hostObject.Object);
|
||||
|
||||
sut = new BaseHostImpl("net.pipe://some/address/here", hostObjectFactory.Object, logger.Object);
|
||||
sut = new BaseHostStub("net.pipe://some/address/here", hostObjectFactory.Object, logger.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
<Compile Include="Behaviour\OperationModel\I18nOperationTests.cs" />
|
||||
<Compile Include="Behaviour\OperationModel\DelegateOperationTests.cs" />
|
||||
<Compile Include="Behaviour\OperationModel\OperationSequenceTests.cs" />
|
||||
<Compile Include="Communication\Hosts\BaseHostImpl.cs" />
|
||||
<Compile Include="Communication\Hosts\BaseHostStub.cs" />
|
||||
<Compile Include="Communication\Hosts\BaseHostTests.cs" />
|
||||
<Compile Include="Communication\Proxies\BaseProxyImpl.cs" />
|
||||
<Compile Include="Communication\Proxies\BaseProxyTests.cs" />
|
||||
|
|
|
@ -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;
|
||||
|
@ -43,5 +44,11 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
|||
|
||||
throw new CommunicationException($"Did not receive authentication response! Received: {ToString(response)}.");
|
||||
}
|
||||
|
||||
public void RequestPassword(PasswordRequestPurpose purpose, Guid requestId)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,18 @@
|
|||
<Entry key="Notification_LogTooltip">
|
||||
Application Log
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_AdminPasswordRequired">
|
||||
Please enter the administrator password for the application configuration:
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_AdminPasswordRequiredTitle">
|
||||
Administrator Password Required
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_SettingsPasswordRequired">
|
||||
Please enter the settings password for the application configuration:
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_SettingsPasswordRequiredTitle">
|
||||
Settings Password Required
|
||||
</Entry>
|
||||
<Entry key="ProgressIndicator_CloseRuntimeConnection">
|
||||
Closing runtime connection
|
||||
</Entry>
|
||||
|
|
|
@ -11,11 +11,14 @@ using System.IO;
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Windows;
|
||||
using SafeExamBrowser.Runtime.Behaviour.Operations;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||
|
@ -23,12 +26,15 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
[TestClass]
|
||||
public class ConfigurationOperationTests
|
||||
{
|
||||
private RuntimeInfo info;
|
||||
private Mock<ILogger> logger;
|
||||
private Mock<IMessageBox> messageBox;
|
||||
private RuntimeInfo info;
|
||||
private Mock<IPasswordDialog> passwordDialog;
|
||||
private Mock<IConfigurationRepository> repository;
|
||||
private Mock<IRuntimeHost> runtimeHost;
|
||||
private Settings settings;
|
||||
private Mock<IText> text;
|
||||
private Mock<IUserInterfaceFactory> uiFactory;
|
||||
private ConfigurationOperation sut;
|
||||
|
||||
[TestInitialize]
|
||||
|
@ -37,42 +43,24 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
info = new RuntimeInfo();
|
||||
logger = new Mock<ILogger>();
|
||||
messageBox = new Mock<IMessageBox>();
|
||||
passwordDialog = new Mock<IPasswordDialog>();
|
||||
repository = new Mock<IConfigurationRepository>();
|
||||
runtimeHost = new Mock<IRuntimeHost>();
|
||||
settings = new Settings();
|
||||
text = new Mock<IText>();
|
||||
uiFactory = new Mock<IUserInterfaceFactory>();
|
||||
|
||||
info.AppDataFolder = @"C:\Not\Really\AppData";
|
||||
info.DefaultSettingsFileName = "SettingsDummy.txt";
|
||||
info.ProgramDataFolder = @"C:\Not\Really\ProgramData";
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailWithoutCommandLineArgs()
|
||||
{
|
||||
repository.Setup(r => r.LoadDefaultSettings());
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, info, text.Object, null);
|
||||
sut.Perform();
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, info, text.Object, new string[] { });
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadDefaultSettings(), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailWithInvalidUri()
|
||||
{
|
||||
var path = @"an/invalid\path.'*%yolo/()";
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, info, text.Object, new[] { "blubb.exe", path });
|
||||
sut.Perform();
|
||||
uiFactory.Setup(f => f.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>())).Returns(passwordDialog.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustUseCommandLineArgumentAs1stPrio()
|
||||
{
|
||||
var path = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
var location = Path.GetDirectoryName(GetType().Assembly.Location);
|
||||
|
||||
info.ProgramDataFolder = location;
|
||||
|
@ -81,10 +69,10 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, info, text.Object, new[] { "blubb.exe", path });
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut.Perform();
|
||||
|
||||
var resource = new Uri(path);
|
||||
var resource = new Uri(url);
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(resource)), null, null), Times.Once);
|
||||
}
|
||||
|
@ -100,7 +88,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, info, text.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, null);
|
||||
sut.Perform();
|
||||
|
||||
var resource = new Uri(Path.Combine(location, "SettingsDummy.txt"));
|
||||
|
@ -118,7 +106,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, info, text.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, null);
|
||||
sut.Perform();
|
||||
|
||||
var resource = new Uri(Path.Combine(location, "SettingsDummy.txt"));
|
||||
|
@ -129,7 +117,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
[TestMethod]
|
||||
public void MustFallbackToDefaultsAsLastPrio()
|
||||
{
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, info, text.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, null);
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadDefaultSettings(), Times.Once);
|
||||
|
@ -139,11 +127,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
public void MustAbortIfWishedByUser()
|
||||
{
|
||||
info.ProgramDataFolder = Path.GetDirectoryName(GetType().Assembly.Location);
|
||||
messageBox.Setup(u => u.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.Yes);
|
||||
messageBox.Setup(m => m.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.Yes);
|
||||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, info, text.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, null);
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
|
@ -153,15 +141,121 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
[TestMethod]
|
||||
public void MustNotAbortIfNotWishedByUser()
|
||||
{
|
||||
messageBox.Setup(u => u.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.No);
|
||||
messageBox.Setup(m => m.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.No);
|
||||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, info, text.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, null);
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
Assert.AreEqual(OperationResult.Success, result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotAllowToAbortIfNotInConfigureClientMode()
|
||||
{
|
||||
settings.ConfigurationMode = ConfigurationMode.Exam;
|
||||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, null);
|
||||
sut.Perform();
|
||||
|
||||
messageBox.Verify(m => m.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>()), Times.Never);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailWithoutCommandLineArgs()
|
||||
{
|
||||
repository.Setup(r => r.LoadDefaultSettings());
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, null);
|
||||
sut.Perform();
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, new string[] { });
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadDefaultSettings(), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailWithInvalidUri()
|
||||
{
|
||||
var uri = @"an/invalid\uri.'*%yolo/()你好";
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, new[] { "blubb.exe", uri });
|
||||
sut.Perform();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustOnlyAllowToEnterAdminPasswordFiveTimes()
|
||||
{
|
||||
var result = new PasswordDialogResultStub { Success = true };
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(result);
|
||||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.AdminPasswordNeeded);
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), null, null), Times.Exactly(5));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustOnlyAllowToEnterSettingsPasswordFiveTimes()
|
||||
{
|
||||
var result = new PasswordDialogResultStub { Success = true };
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(result);
|
||||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), null, null), Times.Exactly(5));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustSucceedIfAdminPasswordCorrect()
|
||||
{
|
||||
var password = "test";
|
||||
var result = new PasswordDialogResultStub { Password = password, Success = true };
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(result);
|
||||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.AdminPasswordNeeded);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), password, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), null, null), Times.Exactly(1));
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), password, null), Times.Exactly(1));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustSucceedIfSettingsPasswordCorrect()
|
||||
{
|
||||
var password = "test";
|
||||
var result = new PasswordDialogResultStub { Password = password, Success = true };
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(result);
|
||||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, password)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, messageBox.Object, runtimeHost.Object, info, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), null, null), Times.Exactly(1));
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), null, password), Times.Exactly(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* 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 SafeExamBrowser.Contracts.UserInterface.Windows;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||
{
|
||||
internal class PasswordDialogResultStub : IPasswordDialogResult
|
||||
{
|
||||
public string Password { get; set; }
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
|
@ -81,6 +81,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Behaviour\Operations\ConfigurationOperationTests.cs" />
|
||||
<Compile Include="Behaviour\Operations\KioskModeOperationTests.cs" />
|
||||
<Compile Include="Behaviour\Operations\PasswordDialogResultStub.cs" />
|
||||
<Compile Include="Behaviour\Operations\ServiceOperationTests.cs" />
|
||||
<Compile Include="Behaviour\Operations\ClientOperationTests.cs" />
|
||||
<Compile Include="Behaviour\Operations\ClientTerminationOperationTests.cs" />
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
|
@ -23,8 +27,10 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
private IConfigurationRepository repository;
|
||||
private ILogger logger;
|
||||
private IMessageBox messageBox;
|
||||
private IText text;
|
||||
private IRuntimeHost runtimeHost;
|
||||
private RuntimeInfo runtimeInfo;
|
||||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
private string[] commandLineArgs;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
|
@ -33,16 +39,20 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
IConfigurationRepository repository,
|
||||
ILogger logger,
|
||||
IMessageBox messageBox,
|
||||
IRuntimeHost runtimeHost,
|
||||
RuntimeInfo runtimeInfo,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory,
|
||||
string[] commandLineArgs)
|
||||
{
|
||||
this.repository = repository;
|
||||
this.logger = logger;
|
||||
this.messageBox = messageBox;
|
||||
this.commandLineArgs = commandLineArgs;
|
||||
this.runtimeHost = runtimeHost;
|
||||
this.runtimeInfo = runtimeInfo;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
}
|
||||
|
||||
public OperationResult Perform()
|
||||
|
@ -54,22 +64,11 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
|
||||
if (isValidUri)
|
||||
{
|
||||
logger.Info($"Loading settings from '{uri.AbsolutePath}'...");
|
||||
logger.Info($"Attempting to load settings from '{uri.AbsolutePath}'...");
|
||||
|
||||
var result = LoadSettings(uri);
|
||||
|
||||
if (result == OperationResult.Success && repository.CurrentSettings.ConfigurationMode == ConfigurationMode.ConfigureClient)
|
||||
{
|
||||
var abort = IsConfigurationSufficient();
|
||||
|
||||
logger.Info($"The user chose to {(abort ? "abort" : "continue")} after successful client configuration.");
|
||||
|
||||
if (abort)
|
||||
{
|
||||
return OperationResult.Aborted;
|
||||
}
|
||||
}
|
||||
|
||||
HandleClientConfiguration(ref result);
|
||||
LogOperationResult(result);
|
||||
|
||||
return result;
|
||||
|
@ -90,7 +89,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
|
||||
if (isValidUri)
|
||||
{
|
||||
logger.Info($"Loading settings from '{uri.AbsolutePath}'...");
|
||||
logger.Info($"Attempting to load settings from '{uri.AbsolutePath}'...");
|
||||
|
||||
var result = LoadSettings(uri);
|
||||
|
||||
|
@ -117,19 +116,19 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
|
||||
for (int adminAttempts = 0, settingsAttempts = 0; adminAttempts < 5 && settingsAttempts < 5;)
|
||||
{
|
||||
status = repository.LoadSettings(uri, settingsPassword, adminPassword);
|
||||
status = repository.LoadSettings(uri, adminPassword, settingsPassword);
|
||||
|
||||
if (status == LoadStatus.AdminPasswordNeeded || status == LoadStatus.SettingsPasswordNeeded)
|
||||
{
|
||||
var isAdmin = status == LoadStatus.AdminPasswordNeeded;
|
||||
var success = isAdmin ? TryGetAdminPassword(out adminPassword) : TryGetSettingsPassword(out settingsPassword);
|
||||
var purpose = status == LoadStatus.AdminPasswordNeeded ? PasswordRequestPurpose.Administrator : PasswordRequestPurpose.Settings;
|
||||
var aborted = !TryGetPassword(purpose, out string password);
|
||||
|
||||
if (success)
|
||||
{
|
||||
adminAttempts += isAdmin ? 1 : 0;
|
||||
settingsAttempts += isAdmin ? 0 : 1;
|
||||
}
|
||||
else
|
||||
adminAttempts += purpose == PasswordRequestPurpose.Administrator ? 1 : 0;
|
||||
adminPassword = purpose == PasswordRequestPurpose.Administrator ? password : adminPassword;
|
||||
settingsAttempts += purpose == PasswordRequestPurpose.Settings ? 1 : 0;
|
||||
settingsPassword = purpose == PasswordRequestPurpose.Settings ? password : settingsPassword;
|
||||
|
||||
if (aborted)
|
||||
{
|
||||
return OperationResult.Aborted;
|
||||
}
|
||||
|
@ -142,45 +141,101 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
|
||||
if (status == LoadStatus.InvalidData)
|
||||
{
|
||||
if (IsHtmlPage(uri))
|
||||
{
|
||||
repository.LoadDefaultSettings();
|
||||
repository.CurrentSettings.Browser.StartUrl = uri.AbsoluteUri;
|
||||
logger.Info($"The specified URI '{uri.AbsoluteUri}' appears to point to a HTML page, setting it as startup URL.");
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
logger.Error($"The specified settings resource '{uri.AbsoluteUri}' is invalid!");
|
||||
HandleInvalidData(ref status, uri);
|
||||
}
|
||||
|
||||
return status == LoadStatus.Success ? OperationResult.Success : OperationResult.Failed;
|
||||
}
|
||||
|
||||
private bool TryGetPassword(PasswordRequestPurpose purpose, out string password)
|
||||
{
|
||||
var isStartup = repository.CurrentSession == null;
|
||||
var isRunningOnDefaultDesktop = repository.CurrentSettings?.KioskMode == KioskMode.DisableExplorerShell;
|
||||
|
||||
if (isStartup || isRunningOnDefaultDesktop)
|
||||
{
|
||||
return TryGetPasswordViaDialog(purpose, out password);
|
||||
}
|
||||
else
|
||||
{
|
||||
return TryGetPasswordViaClient(purpose, out password);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetPasswordViaDialog(PasswordRequestPurpose purpose, out string password)
|
||||
{
|
||||
var isAdmin = 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));
|
||||
var result = dialog.Show();
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
password = result.Password;
|
||||
}
|
||||
else
|
||||
{
|
||||
password = default(string);
|
||||
}
|
||||
|
||||
return result.Success;
|
||||
}
|
||||
|
||||
private bool TryGetPasswordViaClient(PasswordRequestPurpose purpose, out string password)
|
||||
{
|
||||
var requestId = Guid.NewGuid();
|
||||
var response = default(PasswordEventArgs);
|
||||
var responseEvent = new AutoResetEvent(false);
|
||||
var responseEventHandler = new CommunicationEventHandler<PasswordEventArgs>((args) =>
|
||||
{
|
||||
if (args.RequestId == requestId)
|
||||
{
|
||||
response = args;
|
||||
responseEvent.Set();
|
||||
}
|
||||
});
|
||||
|
||||
runtimeHost.PasswordReceived += responseEventHandler;
|
||||
repository.CurrentSession.ClientProxy.RequestPassword(purpose, requestId);
|
||||
responseEvent.WaitOne();
|
||||
runtimeHost.PasswordReceived -= responseEventHandler;
|
||||
|
||||
if (response.Success)
|
||||
{
|
||||
password = response.Password;
|
||||
}
|
||||
else
|
||||
{
|
||||
password = default(string);
|
||||
}
|
||||
|
||||
return response.Success;
|
||||
}
|
||||
|
||||
private void HandleInvalidData(ref LoadStatus status, Uri uri)
|
||||
{
|
||||
if (IsHtmlPage(uri))
|
||||
{
|
||||
repository.LoadDefaultSettings();
|
||||
repository.CurrentSettings.Browser.StartUrl = uri.AbsoluteUri;
|
||||
logger.Info($"The specified URI '{uri.AbsoluteUri}' appears to point to a HTML page, setting it as startup URL.");
|
||||
|
||||
status = LoadStatus.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"The specified settings resource '{uri.AbsoluteUri}' is invalid!");
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsHtmlPage(Uri uri)
|
||||
{
|
||||
// TODO
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetAdminPassword(out string password)
|
||||
{
|
||||
password = default(string);
|
||||
|
||||
// TODO
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryGetSettingsPassword(out string password)
|
||||
{
|
||||
password = default(string);
|
||||
|
||||
// TODO
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryInitializeSettingsUri(out Uri uri)
|
||||
{
|
||||
var path = string.Empty;
|
||||
|
@ -224,6 +279,21 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
return isValidUri;
|
||||
}
|
||||
|
||||
private void HandleClientConfiguration(ref OperationResult result)
|
||||
{
|
||||
if (result == OperationResult.Success && repository.CurrentSettings.ConfigurationMode == ConfigurationMode.ConfigureClient)
|
||||
{
|
||||
var abort = IsConfigurationSufficient();
|
||||
|
||||
logger.Info($"The user chose to {(abort ? "abort" : "continue")} after successful client configuration.");
|
||||
|
||||
if (abort)
|
||||
{
|
||||
result = OperationResult.Aborted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsConfigurationSufficient()
|
||||
{
|
||||
var message = text.Get(TextKey.MessageBox_ClientConfigurationQuestion);
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
|
||||
public event CommunicationEventHandler ClientDisconnected;
|
||||
public event CommunicationEventHandler ClientReady;
|
||||
public event CommunicationEventHandler<PasswordEventArgs> PasswordReceived;
|
||||
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
||||
public event CommunicationEventHandler ShutdownRequested;
|
||||
|
||||
|
@ -62,6 +63,9 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
{
|
||||
switch (message)
|
||||
{
|
||||
case PasswordReplyMessage r:
|
||||
PasswordReceived?.InvokeAsync(new PasswordEventArgs { Password = r.Password, RequestId = r.RequestId, Success = r.Success });
|
||||
return new SimpleResponse(SimpleResponsePurport.Acknowledged);
|
||||
case ReconfigurationMessage r:
|
||||
ReconfigurationRequested?.InvokeAsync(new ReconfigurationEventArgs { ConfigurationPath = r.ConfigurationPath });
|
||||
return new SimpleResponse(SimpleResponsePurport.Acknowledged);
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace SafeExamBrowser.Runtime
|
|||
bootstrapOperations.Enqueue(new I18nOperation(logger, text));
|
||||
bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger));
|
||||
|
||||
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, messageBox, runtimeInfo, text, args));
|
||||
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, messageBox, runtimeHost, runtimeInfo, text, uiFactory, args));
|
||||
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost));
|
||||
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text));
|
||||
sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, TEN_SECONDS));
|
||||
|
|
|
@ -44,6 +44,11 @@ namespace SafeExamBrowser.UserInterface.Classic
|
|||
return new BrowserWindow(control, settings);
|
||||
}
|
||||
|
||||
public ISystemKeyboardLayoutControl CreateKeyboardLayoutControl()
|
||||
{
|
||||
return new KeyboardLayoutControl();
|
||||
}
|
||||
|
||||
public IWindow CreateLogWindow(ILogger logger)
|
||||
{
|
||||
LogWindow logWindow = null;
|
||||
|
@ -74,9 +79,9 @@ namespace SafeExamBrowser.UserInterface.Classic
|
|||
return new NotificationButton(info);
|
||||
}
|
||||
|
||||
public ISystemKeyboardLayoutControl CreateKeyboardLayoutControl()
|
||||
public IPasswordDialog CreatePasswordDialog(string message, string title)
|
||||
{
|
||||
return new KeyboardLayoutControl();
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public ISystemPowerSupplyControl CreatePowerSupplyControl()
|
||||
|
|
|
@ -81,6 +81,12 @@ namespace SafeExamBrowser.UserInterface.Windows10
|
|||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public IPasswordDialog CreatePasswordDialog(string message, string title)
|
||||
{
|
||||
// TODO
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public ISystemPowerSupplyControl CreatePowerSupplyControl()
|
||||
{
|
||||
return new PowerSupplyControl();
|
||||
|
|
Loading…
Reference in a new issue