diff --git a/SafeExamBrowser.Client/Behaviour/ClientController.cs b/SafeExamBrowser.Client/Behaviour/ClientController.cs index 0e3bca5b..f5935e94 100644 --- a/SafeExamBrowser.Client/Behaviour/ClientController.cs +++ b/SafeExamBrowser.Client/Behaviour/ClientController.cs @@ -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(); diff --git a/SafeExamBrowser.Client/Communication/ClientHost.cs b/SafeExamBrowser.Client/Communication/ClientHost.cs index b9445f61..732edc39 100644 --- a/SafeExamBrowser.Client/Communication/ClientHost.cs +++ b/SafeExamBrowser.Client/Communication/ClientHost.cs @@ -22,6 +22,8 @@ namespace SafeExamBrowser.Client.Communication public Guid StartupToken { private get; set; } + public event CommunicationEventHandler PasswordRequested; + public event CommunicationEventHandler 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); } diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index a7a8e1f7..7a6c495f 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -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() diff --git a/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj b/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj index 86f6b40c..735142bd 100644 --- a/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj +++ b/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj @@ -56,6 +56,9 @@ prompt true + + SafeExamBrowser.ico + @@ -147,6 +150,9 @@ SafeExamBrowser.WindowsApi + + + robocopy "$(SolutionDir)SafeExamBrowser.Browser\bin\$(PlatformName)\$(ConfigurationName)" "$(ProjectDir)bin\$(PlatformName)\$(ConfigurationName)" /e /np diff --git a/SafeExamBrowser.Client/SafeExamBrowser.ico b/SafeExamBrowser.Client/SafeExamBrowser.ico new file mode 100644 index 00000000..abdc4635 Binary files /dev/null and b/SafeExamBrowser.Client/SafeExamBrowser.ico differ diff --git a/SafeExamBrowser.Contracts/Communication/Data/PasswordReplyMessage.cs b/SafeExamBrowser.Contracts/Communication/Data/PasswordReplyMessage.cs index 99aaf52c..c4f9e62e 100644 --- a/SafeExamBrowser.Contracts/Communication/Data/PasswordReplyMessage.cs +++ b/SafeExamBrowser.Contracts/Communication/Data/PasswordReplyMessage.cs @@ -31,7 +31,7 @@ namespace SafeExamBrowser.Contracts.Communication.Data /// 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; diff --git a/SafeExamBrowser.Contracts/Communication/Data/ReconfigurationResponse.cs b/SafeExamBrowser.Contracts/Communication/Data/ReconfigurationDeniedMessage.cs similarity index 52% rename from SafeExamBrowser.Contracts/Communication/Data/ReconfigurationResponse.cs rename to SafeExamBrowser.Contracts/Communication/Data/ReconfigurationDeniedMessage.cs index 65671f70..f8bbc4df 100644 --- a/SafeExamBrowser.Contracts/Communication/Data/ReconfigurationResponse.cs +++ b/SafeExamBrowser.Contracts/Communication/Data/ReconfigurationDeniedMessage.cs @@ -11,14 +11,19 @@ using System; namespace SafeExamBrowser.Contracts.Communication.Data { /// - /// The response to a . + /// This message is transmitted from the runtime to the client in order to inform the latter that a reconfiguration request was denied. /// [Serializable] - public class ReconfigurationResponse : Response + public class ReconfigurationDeniedMessage : Message { /// - /// Indicates whether the reconfiguration request has been accepted. + /// The full path to the configuration file for which a reconfiguration was denied. /// - public bool Accepted { get; set; } + public string FilePath { get; private set; } + + public ReconfigurationDeniedMessage(string filePath) + { + FilePath = filePath; + } } } diff --git a/SafeExamBrowser.Contracts/Communication/Events/PasswordEventArgs.cs b/SafeExamBrowser.Contracts/Communication/Events/PasswordReplyEventArgs.cs similarity index 93% rename from SafeExamBrowser.Contracts/Communication/Events/PasswordEventArgs.cs rename to SafeExamBrowser.Contracts/Communication/Events/PasswordReplyEventArgs.cs index 742c0520..6c99a2f2 100644 --- a/SafeExamBrowser.Contracts/Communication/Events/PasswordEventArgs.cs +++ b/SafeExamBrowser.Contracts/Communication/Events/PasswordReplyEventArgs.cs @@ -13,7 +13,7 @@ namespace SafeExamBrowser.Contracts.Communication.Events /// /// The event arguments used for the password input event fired by the . /// - public class PasswordEventArgs : CommunicationEventArgs + public class PasswordReplyEventArgs : CommunicationEventArgs { /// /// The password entered by the user, or null if not available. diff --git a/SafeExamBrowser.Contracts/Communication/Events/PasswordRequestEventArgs.cs b/SafeExamBrowser.Contracts/Communication/Events/PasswordRequestEventArgs.cs new file mode 100644 index 00000000..45f84d2f --- /dev/null +++ b/SafeExamBrowser.Contracts/Communication/Events/PasswordRequestEventArgs.cs @@ -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 +{ + /// + /// The event arguments used for the password request event fired by the . + /// + public class PasswordRequestEventArgs : CommunicationEventArgs + { + /// + /// The purpose for which a password is requested. + /// + public PasswordRequestPurpose Purpose { get; set; } + + /// + /// Identifies the password request. + /// + public Guid RequestId { get; set; } + } +} diff --git a/SafeExamBrowser.Contracts/Communication/Hosts/IClientHost.cs b/SafeExamBrowser.Contracts/Communication/Hosts/IClientHost.cs index 073bf146..87a6a3e0 100644 --- a/SafeExamBrowser.Contracts/Communication/Hosts/IClientHost.cs +++ b/SafeExamBrowser.Contracts/Communication/Hosts/IClientHost.cs @@ -21,6 +21,16 @@ namespace SafeExamBrowser.Contracts.Communication.Hosts /// Guid StartupToken { set; } + /// + /// Event fired when the runtime requests a password input from the user. + /// + event CommunicationEventHandler PasswordRequested; + + /// + /// Event fired when the runtime denied a reconfiguration request. + /// + event CommunicationEventHandler ReconfigurationDenied; + /// /// Event fired when the runtime commands the client to shutdown. /// diff --git a/SafeExamBrowser.Contracts/Communication/Hosts/IRuntimeHost.cs b/SafeExamBrowser.Contracts/Communication/Hosts/IRuntimeHost.cs index a2839f48..e9e8011d 100644 --- a/SafeExamBrowser.Contracts/Communication/Hosts/IRuntimeHost.cs +++ b/SafeExamBrowser.Contracts/Communication/Hosts/IRuntimeHost.cs @@ -32,9 +32,9 @@ namespace SafeExamBrowser.Contracts.Communication.Hosts event CommunicationEventHandler ClientReady; /// - /// Event fired when the client transmitted a password entered by the user. + /// Event fired when the client submitted a password entered by the user. /// - event CommunicationEventHandler PasswordReceived; + event CommunicationEventHandler PasswordReceived; /// /// Event fired when the client requested a reconfiguration of the application. diff --git a/SafeExamBrowser.Contracts/Communication/ICommunication.cs b/SafeExamBrowser.Contracts/Communication/ICommunication.cs index c0c0707d..0b984fb4 100644 --- a/SafeExamBrowser.Contracts/Communication/ICommunication.cs +++ b/SafeExamBrowser.Contracts/Communication/ICommunication.cs @@ -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 diff --git a/SafeExamBrowser.Contracts/Communication/Proxies/IClientProxy.cs b/SafeExamBrowser.Contracts/Communication/Proxies/IClientProxy.cs index d62abb93..13e0ed36 100644 --- a/SafeExamBrowser.Contracts/Communication/Proxies/IClientProxy.cs +++ b/SafeExamBrowser.Contracts/Communication/Proxies/IClientProxy.cs @@ -16,6 +16,11 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies /// public interface IClientProxy : ICommunicationProxy { + /// + /// Informs the client that the reconfiguration request for the specified file was denied. + /// + void InformReconfigurationDenied(string filePath); + /// /// Instructs the client to initiate its shutdown procedure. /// diff --git a/SafeExamBrowser.Contracts/Communication/Proxies/IRuntimeProxy.cs b/SafeExamBrowser.Contracts/Communication/Proxies/IRuntimeProxy.cs index 7d74e4c0..5a261088 100644 --- a/SafeExamBrowser.Contracts/Communication/Proxies/IRuntimeProxy.cs +++ b/SafeExamBrowser.Contracts/Communication/Proxies/IRuntimeProxy.cs @@ -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 /// /// If the communication failed. void RequestReconfiguration(string filePath); + + /// + /// 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 null! + /// + /// /// If the communication failed. + void SubmitPassword(Guid requestId, bool success, string password = null); } } diff --git a/SafeExamBrowser.Contracts/I18n/TextKey.cs b/SafeExamBrowser.Contracts/I18n/TextKey.cs index 1685a828..dd9dce29 100644 --- a/SafeExamBrowser.Contracts/I18n/TextKey.cs +++ b/SafeExamBrowser.Contracts/I18n/TextKey.cs @@ -46,6 +46,8 @@ namespace SafeExamBrowser.Contracts.I18n Notification_LogTooltip, PasswordDialog_AdminPasswordRequired, PasswordDialog_AdminPasswordRequiredTitle, + PasswordDialog_Cancel, + PasswordDialog_Confirm, PasswordDialog_SettingsPasswordRequired, PasswordDialog_SettingsPasswordRequiredTitle, ProgressIndicator_CloseRuntimeConnection, diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index c8a2a291..728a555d 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -63,9 +63,11 @@ + - + + @@ -89,7 +91,6 @@ - diff --git a/SafeExamBrowser.Core.UnitTests/Communication/Hosts/BaseHostTests.cs b/SafeExamBrowser.Core.UnitTests/Communication/Hosts/BaseHostTests.cs index 68d65007..508c265d 100644 --- a/SafeExamBrowser.Core.UnitTests/Communication/Hosts/BaseHostTests.cs +++ b/SafeExamBrowser.Core.UnitTests/Communication/Hosts/BaseHostTests.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); } } } diff --git a/SafeExamBrowser.Core.UnitTests/Communication/Proxies/RuntimeProxyTests.cs b/SafeExamBrowser.Core.UnitTests/Communication/Proxies/RuntimeProxyTests.cs index 7b5ae328..58de0025 100644 --- a/SafeExamBrowser.Core.UnitTests/Communication/Proxies/RuntimeProxyTests.cs +++ b/SafeExamBrowser.Core.UnitTests/Communication/Proxies/RuntimeProxyTests.cs @@ -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(m => m.ConfigurationUrl == url))).Returns(response); + proxy.Setup(p => p.Send(It.Is(m => m.ConfigurationPath == url))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged)); - //var accepted = sut.RequestReconfiguration(url); + sut.RequestReconfiguration(url); - //proxy.Verify(p => p.Send(It.Is(m => m.ConfigurationUrl == url)), Times.Once); - - //Assert.IsTrue(accepted); - - // TODO - Assert.Fail(); + proxy.Verify(p => p.Send(It.Is(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(m => m.ConfigurationUrl == url))).Returns(response); + proxy.Setup(p => p.Send(It.Is(m => m.ConfigurationPath == url))).Returns(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(m => m.ConfigurationUrl == url))).Returns(null); - - //var accepted = sut.RequestReconfiguration(url); - - //Assert.IsFalse(accepted); - - // TODO - Assert.Fail(); + sut.RequestReconfiguration(url); } [TestMethod] diff --git a/SafeExamBrowser.Core/Communication/Proxies/ClientProxy.cs b/SafeExamBrowser.Core/Communication/Proxies/ClientProxy.cs index 8d4fe460..81f6db3e 100644 --- a/SafeExamBrowser.Core/Communication/Proxies/ClientProxy.cs +++ b/SafeExamBrowser.Core/Communication/Proxies/ClientProxy.cs @@ -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)}."); + } } } } diff --git a/SafeExamBrowser.Core/Communication/Proxies/RuntimeProxy.cs b/SafeExamBrowser.Core/Communication/Proxies/RuntimeProxy.cs index 71ec8a68..6cb7e0bc 100644 --- a/SafeExamBrowser.Core/Communication/Proxies/RuntimeProxy.cs +++ b/SafeExamBrowser.Core/Communication/Proxies/RuntimeProxy.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; @@ -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)}."); + } + } } } diff --git a/SafeExamBrowser.Core/I18n/Text.xml b/SafeExamBrowser.Core/I18n/Text.xml index 5374a81e..14c1426e 100644 --- a/SafeExamBrowser.Core/I18n/Text.xml +++ b/SafeExamBrowser.Core/I18n/Text.xml @@ -90,6 +90,12 @@ Administrator Password Required + + Cancel + + + Confirm + Please enter the settings password for the application configuration: diff --git a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ClientTerminationOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ClientTerminationOperationTests.cs index 404f67b0..eeddfbb1 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ClientTerminationOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ClientTerminationOperationTests.cs @@ -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(); } } diff --git a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs index b0de0a62..04af1235 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs @@ -337,7 +337,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations var clientProxy = new Mock(); var passwordReceived = new Action((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(); var url = @"http://www.safeexambrowser.org/whatever.seb"; @@ -363,7 +363,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations var clientProxy = new Mock(); var passwordReceived = new Action((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(); var url = @"http://www.safeexambrowser.org/whatever.seb"; diff --git a/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs b/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs index cfcf0db5..a24c8dba 100644 --- a/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs +++ b/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs @@ -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((args) => + var responseEventHandler = new CommunicationEventHandler((args) => { if (args.RequestId == requestId) { diff --git a/SafeExamBrowser.Runtime/Behaviour/RuntimeController.cs b/SafeExamBrowser.Runtime/Behaviour/RuntimeController.cs index 8e1a01b3..cc30cbf5 100644 --- a/SafeExamBrowser.Runtime/Behaviour/RuntimeController.cs +++ b/SafeExamBrowser.Runtime/Behaviour/RuntimeController.cs @@ -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); } } diff --git a/SafeExamBrowser.Runtime/Communication/RuntimeHost.cs b/SafeExamBrowser.Runtime/Communication/RuntimeHost.cs index af14c254..2ca3b207 100644 --- a/SafeExamBrowser.Runtime/Communication/RuntimeHost.cs +++ b/SafeExamBrowser.Runtime/Communication/RuntimeHost.cs @@ -25,7 +25,7 @@ namespace SafeExamBrowser.Runtime.Communication public event CommunicationEventHandler ClientDisconnected; public event CommunicationEventHandler ClientReady; - public event CommunicationEventHandler PasswordReceived; + public event CommunicationEventHandler PasswordReceived; public event CommunicationEventHandler 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 }); diff --git a/SafeExamBrowser.UserInterface.Classic/PasswordDialog.xaml b/SafeExamBrowser.UserInterface.Classic/PasswordDialog.xaml new file mode 100644 index 00000000..76476a29 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Classic/PasswordDialog.xaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + +