SEBWIN-219: Finished scaffolding for application startup sequence.
This commit is contained in:
parent
10202a807f
commit
dda1b78ec5
69 changed files with 999 additions and 252 deletions
|
@ -25,7 +25,7 @@ namespace SafeExamBrowser.Client.UnitTests
|
||||||
private Mock<ITaskbar> taskbarMock;
|
private Mock<ITaskbar> taskbarMock;
|
||||||
private Mock<IWindowMonitor> windowMonitorMock;
|
private Mock<IWindowMonitor> windowMonitorMock;
|
||||||
|
|
||||||
private IClientController sut;
|
//private IClientController sut;
|
||||||
|
|
||||||
[TestInitialize]
|
[TestInitialize]
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
using System;
|
using System;
|
||||||
using SafeExamBrowser.Contracts.Behaviour;
|
using SafeExamBrowser.Contracts.Behaviour;
|
||||||
using SafeExamBrowser.Contracts.Behaviour.Operations;
|
using SafeExamBrowser.Contracts.Behaviour.Operations;
|
||||||
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Contracts.Monitoring;
|
using SafeExamBrowser.Contracts.Monitoring;
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
||||||
|
@ -21,6 +22,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private IOperationSequence operations;
|
private IOperationSequence operations;
|
||||||
private IProcessMonitor processMonitor;
|
private IProcessMonitor processMonitor;
|
||||||
|
private IRuntimeProxy runtime;
|
||||||
private ITaskbar taskbar;
|
private ITaskbar taskbar;
|
||||||
private IWindowMonitor windowMonitor;
|
private IWindowMonitor windowMonitor;
|
||||||
|
|
||||||
|
@ -29,6 +31,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IOperationSequence operations,
|
IOperationSequence operations,
|
||||||
IProcessMonitor processMonitor,
|
IProcessMonitor processMonitor,
|
||||||
|
IRuntimeProxy runtime,
|
||||||
ITaskbar taskbar,
|
ITaskbar taskbar,
|
||||||
IWindowMonitor windowMonitor)
|
IWindowMonitor windowMonitor)
|
||||||
{
|
{
|
||||||
|
@ -36,6 +39,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.operations = operations;
|
this.operations = operations;
|
||||||
this.processMonitor = processMonitor;
|
this.processMonitor = processMonitor;
|
||||||
|
this.runtime = runtime;
|
||||||
this.taskbar = taskbar;
|
this.taskbar = taskbar;
|
||||||
this.windowMonitor = windowMonitor;
|
this.windowMonitor = windowMonitor;
|
||||||
}
|
}
|
||||||
|
@ -45,15 +49,29 @@ namespace SafeExamBrowser.Client.Behaviour
|
||||||
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
||||||
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
|
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
|
||||||
windowMonitor.WindowChanged -= WindowMonitor_WindowChanged;
|
windowMonitor.WindowChanged -= WindowMonitor_WindowChanged;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
operations.TryRevert();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryStart()
|
public bool TryStart()
|
||||||
{
|
{
|
||||||
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
|
||||||
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
|
|
||||||
windowMonitor.WindowChanged += WindowMonitor_WindowChanged;
|
|
||||||
|
|
||||||
return true;
|
// TODO
|
||||||
|
|
||||||
|
var success = operations.TryPerform();
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
||||||
|
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
|
||||||
|
windowMonitor.WindowChanged += WindowMonitor_WindowChanged;
|
||||||
|
|
||||||
|
runtime.InformClientReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisplayMonitor_DisplaySettingsChanged()
|
private void DisplayMonitor_DisplaySettingsChanged()
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
|
||||||
var config = runtime.GetConfiguration();
|
var config = runtime.GetConfiguration();
|
||||||
|
|
||||||
configuration.RuntimeInfo = config.RuntimeInfo;
|
configuration.RuntimeInfo = config.RuntimeInfo;
|
||||||
configuration.SessionData = config.SessionData;
|
configuration.SessionId = config.SessionId;
|
||||||
configuration.Settings = config.Settings;
|
configuration.Settings = config.Settings;
|
||||||
|
|
||||||
logger.Info("Successfully retrieved the application configuration from the runtime.");
|
logger.Info("Successfully retrieved the application configuration from the runtime.");
|
||||||
|
|
|
@ -40,18 +40,20 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
connected = runtime.Connect(token);
|
connected = runtime.Connect(token);
|
||||||
|
|
||||||
logger.Info("Successfully connected to the runtime host.");
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger.Error("An unexpected error occurred while trying to connect to the runtime host!", e);
|
logger.Error("An unexpected error occurred while trying to connect to the runtime!", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connected)
|
if (connected)
|
||||||
|
{
|
||||||
|
logger.Info("Successfully connected to the runtime.");
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Abort = true;
|
Abort = true;
|
||||||
logger.Info("Failed to connect to the runtime. Aborting startup...");
|
logger.Error("Failed to connect to the runtime. Aborting startup...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,26 +17,32 @@ namespace SafeExamBrowser.Client.Communication
|
||||||
{
|
{
|
||||||
internal class ClientHost : BaseHost, IClientHost
|
internal class ClientHost : BaseHost, IClientHost
|
||||||
{
|
{
|
||||||
|
public Guid StartupToken { private get; set; }
|
||||||
|
|
||||||
public ClientHost(string address, ILogger logger) : base(address, logger)
|
public ClientHost(string address, ILogger logger) : base(address, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IConnectResponse OnConnect(Guid? token)
|
protected override bool OnConnect(Guid? token)
|
||||||
{
|
{
|
||||||
// TODO
|
return StartupToken == token;
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisconnect(IMessage message)
|
protected override void OnDisconnect()
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IResponse OnReceive(IMessage message)
|
protected override IResponse OnReceive(IMessage message)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
throw new NotImplementedException();
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IResponse OnReceive(Message message)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
var sequence = new OperationSequence(logger, operations);
|
var sequence = new OperationSequence(logger, operations);
|
||||||
|
|
||||||
ClientController = new ClientController(displayMonitor, logger, sequence, processMonitor, Taskbar, windowMonitor);
|
ClientController = new ClientController(displayMonitor, logger, sequence, processMonitor, runtimeProxy, Taskbar, windowMonitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Validate(string[] args)
|
private void Validate(string[] args)
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace SafeExamBrowser.Configuration
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ClientConfiguration : IClientConfiguration
|
public class ClientConfiguration : IClientConfiguration
|
||||||
{
|
{
|
||||||
public ISessionData SessionData { get; set; }
|
public Guid SessionId { get; set; }
|
||||||
public ISettings Settings { get; set; }
|
public ISettings Settings { get; set; }
|
||||||
public IRuntimeInfo RuntimeInfo { get; set; }
|
public IRuntimeInfo RuntimeInfo { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace SafeExamBrowser.Configuration
|
||||||
{
|
{
|
||||||
private RuntimeInfo runtimeInfo;
|
private RuntimeInfo runtimeInfo;
|
||||||
|
|
||||||
public ISessionData CurrentSessionData { get; private set; }
|
public ISession CurrentSession { get; private set; }
|
||||||
public ISettings CurrentSettings { get; private set; }
|
public ISettings CurrentSettings { get; private set; }
|
||||||
|
|
||||||
public IRuntimeInfo RuntimeInfo
|
public IRuntimeInfo RuntimeInfo
|
||||||
|
@ -34,15 +34,17 @@ namespace SafeExamBrowser.Configuration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISessionData InitializeSessionData()
|
public ISession InitializeSession()
|
||||||
{
|
{
|
||||||
var sessionData = new SessionData();
|
var session = new Session
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
StartupToken = Guid.NewGuid()
|
||||||
|
};
|
||||||
|
|
||||||
sessionData.Id = Guid.NewGuid();
|
CurrentSession = session;
|
||||||
|
|
||||||
CurrentSessionData = sessionData;
|
return session;
|
||||||
|
|
||||||
return sessionData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IClientConfiguration BuildClientConfiguration()
|
public IClientConfiguration BuildClientConfiguration()
|
||||||
|
@ -50,7 +52,7 @@ namespace SafeExamBrowser.Configuration
|
||||||
return new ClientConfiguration
|
return new ClientConfiguration
|
||||||
{
|
{
|
||||||
RuntimeInfo = RuntimeInfo,
|
RuntimeInfo = RuntimeInfo,
|
||||||
SessionData = CurrentSessionData,
|
SessionId = CurrentSession.Id,
|
||||||
Settings = CurrentSettings
|
Settings = CurrentSettings
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -64,10 +66,11 @@ namespace SafeExamBrowser.Configuration
|
||||||
|
|
||||||
public ISettings LoadDefaultSettings()
|
public ISettings LoadDefaultSettings()
|
||||||
{
|
{
|
||||||
var settings = new Settings.Settings();
|
var settings = new Settings.Settings
|
||||||
|
{
|
||||||
// TODO
|
// TODO
|
||||||
settings.ServicePolicy = ServicePolicy.Optional;
|
ServicePolicy = ServicePolicy.Optional
|
||||||
|
};
|
||||||
|
|
||||||
CurrentSettings = settings;
|
CurrentSettings = settings;
|
||||||
|
|
||||||
|
@ -93,6 +96,7 @@ namespace SafeExamBrowser.Configuration
|
||||||
BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt"),
|
BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt"),
|
||||||
ClientId = Guid.NewGuid(),
|
ClientId = Guid.NewGuid(),
|
||||||
ClientAddress = $"{baseAddress}/client/{clientId}",
|
ClientAddress = $"{baseAddress}/client/{clientId}",
|
||||||
|
ClientExecutablePath = Path.Combine(Path.GetDirectoryName(executable.Location), $"{nameof(SafeExamBrowser)}.Client.exe"),
|
||||||
ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt"),
|
ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt"),
|
||||||
DefaultSettingsFileName = "SebClientSettings.seb",
|
DefaultSettingsFileName = "SebClientSettings.seb",
|
||||||
ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright,
|
ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright,
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace SafeExamBrowser.Configuration
|
||||||
public string BrowserCachePath { get; set; }
|
public string BrowserCachePath { get; set; }
|
||||||
public string BrowserLogFile { get; set; }
|
public string BrowserLogFile { get; set; }
|
||||||
public string ClientAddress { get; set; }
|
public string ClientAddress { get; set; }
|
||||||
|
public string ClientExecutablePath { get; set; }
|
||||||
public Guid ClientId { get; set; }
|
public Guid ClientId { get; set; }
|
||||||
public string ClientLogFile { get; set; }
|
public string ClientLogFile { get; set; }
|
||||||
public string DefaultSettingsFileName { get; set; }
|
public string DefaultSettingsFileName { get; set; }
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ClientConfiguration.cs" />
|
<Compile Include="ClientConfiguration.cs" />
|
||||||
<Compile Include="RuntimeInfo.cs" />
|
<Compile Include="RuntimeInfo.cs" />
|
||||||
<Compile Include="SessionData.cs" />
|
<Compile Include="Session.cs" />
|
||||||
<Compile Include="Settings\BrowserSettings.cs" />
|
<Compile Include="Settings\BrowserSettings.cs" />
|
||||||
<Compile Include="Settings\KeyboardSettings.cs" />
|
<Compile Include="Settings\KeyboardSettings.cs" />
|
||||||
<Compile Include="Settings\MouseSettings.cs" />
|
<Compile Include="Settings\MouseSettings.cs" />
|
||||||
|
|
|
@ -8,12 +8,14 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Configuration
|
namespace SafeExamBrowser.Configuration
|
||||||
{
|
{
|
||||||
[Serializable]
|
public class Session : ISession
|
||||||
public class SessionData : ISessionData
|
|
||||||
{
|
{
|
||||||
|
public IProcess ClientProcess { get; set; }
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
public Guid StartupToken { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using SafeExamBrowser.Contracts.UserInterface;
|
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Behaviour
|
namespace SafeExamBrowser.Contracts.Behaviour
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Behaviour
|
namespace SafeExamBrowser.Contracts.Behaviour
|
||||||
{
|
{
|
||||||
// TODO: Interface really needed?!
|
// TODO: Interface really needed?!
|
||||||
|
|
|
@ -6,10 +6,15 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication
|
namespace SafeExamBrowser.Contracts.Communication
|
||||||
{
|
{
|
||||||
public interface IClientHost : ICommunicationHost
|
public interface IClientHost : ICommunicationHost
|
||||||
{
|
{
|
||||||
// TODO: Necessary?
|
/// <summary>
|
||||||
|
/// The startup token used for initial authentication.
|
||||||
|
/// </summary>
|
||||||
|
Guid StartupToken { set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,20 +6,15 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication
|
namespace SafeExamBrowser.Contracts.Communication
|
||||||
{
|
{
|
||||||
public interface IClientProxy
|
public interface IClientProxy : ICommunicationProxy
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to connect to the client host.
|
/// Instructs the client to submit its authentication data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool Connect(Guid token);
|
IAuthenticationResponse RequestAuthentication();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disconnects from the client host.
|
|
||||||
/// </summary>
|
|
||||||
void Disconnect();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,21 +17,20 @@ namespace SafeExamBrowser.Contracts.Communication
|
||||||
public interface ICommunication
|
public interface ICommunication
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initiates a connection to the host and must thus be called before any other opertion. To authenticate itself to the host, the
|
/// Initiates a connection and must thus be called before any other opertion. Where applicable, an authentication token should be
|
||||||
/// client can specify a security token. If the connection request was successful, a new session will be created by the host and
|
/// specified. Returns a response indicating whether the connection request was successful or not.
|
||||||
/// the client will subsequently be allowed to start communicating with the host.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[OperationContract(IsInitiating = true)]
|
[OperationContract(IsInitiating = true)]
|
||||||
IConnectResponse Connect(Guid? token = null);
|
IConnectionResponse Connect(Guid? token = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Closes the connection to the host and instructs it to terminate the communication session.
|
/// Closes a connection. Returns a response indicating whether the disconnection request was successful or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[OperationContract(IsInitiating = false, IsTerminating = true)]
|
[OperationContract(IsInitiating = false, IsTerminating = true)]
|
||||||
void Disconnect(IMessage message);
|
IDisconnectionResponse Disconnect(IDisconnectionMessage message);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a message to the host, optionally returning a response. If no response is expected, <c>null</c> will be returned.
|
/// Sends a message, optionally returning a response. If no response is expected, <c>null</c> will be returned.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[OperationContract(IsInitiating = false)]
|
[OperationContract(IsInitiating = false)]
|
||||||
IResponse Send(IMessage message);
|
IResponse Send(IMessage message);
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication
|
namespace SafeExamBrowser.Contracts.Communication
|
||||||
{
|
{
|
||||||
|
public delegate void CommunicationEventHandler();
|
||||||
|
|
||||||
public interface ICommunicationHost
|
public interface ICommunicationHost
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
public interface ICommunicationProxy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to establish a connection. Returns <c>true</c> if successful, otherwise <c>false</c>.
|
||||||
|
/// </summary>
|
||||||
|
bool Connect(Guid? token = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Terminates an open connection. Returns <c>true</c> if successful, otherwise <c>false</c>.
|
||||||
|
/// </summary>
|
||||||
|
bool Disconnect();
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,10 +6,20 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication
|
namespace SafeExamBrowser.Contracts.Communication
|
||||||
{
|
{
|
||||||
public interface IRuntimeHost : ICommunicationHost
|
public interface IRuntimeHost : ICommunicationHost
|
||||||
{
|
{
|
||||||
// TODO: Necessary?
|
/// <summary>
|
||||||
|
/// The startup token used for initial authentication.
|
||||||
|
/// </summary>
|
||||||
|
Guid StartupToken { set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event fired once the client has signaled that it is ready to operate.
|
||||||
|
/// </summary>
|
||||||
|
event CommunicationEventHandler ClientReady;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,26 +6,20 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication
|
namespace SafeExamBrowser.Contracts.Communication
|
||||||
{
|
{
|
||||||
public interface IRuntimeProxy
|
public interface IRuntimeProxy : ICommunicationProxy
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to establish a connection with the runtime host, utilizing the specified authentication token.
|
/// Retrieves the application configuration from the runtime.
|
||||||
/// </summary>
|
|
||||||
bool Connect(Guid token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disconnects from the runtime host.
|
|
||||||
/// </summary>
|
|
||||||
void Disconnect();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the application configuration from the runtime host.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IClientConfiguration GetConfiguration();
|
IClientConfiguration GetConfiguration();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Informs the runtime that the client is ready.
|
||||||
|
/// </summary>
|
||||||
|
void InformClientReady();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication
|
namespace SafeExamBrowser.Contracts.Communication
|
||||||
{
|
{
|
||||||
public interface IServiceProxy
|
public interface IServiceProxy : ICommunicationProxy
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instructs the proxy to ignore all operations or simulate a connection, where applicable. To be set e.g. when the service
|
/// Instructs the proxy to ignore all operations or simulate a connection, where applicable. To be set e.g. when the service
|
||||||
|
@ -19,16 +19,6 @@ namespace SafeExamBrowser.Contracts.Communication
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool Ignore { set; }
|
bool Ignore { set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tries to connect to the service host.
|
|
||||||
/// </summary>
|
|
||||||
bool Connect();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disconnects from the service host.
|
|
||||||
/// </summary>
|
|
||||||
void Disconnect();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instructs the service to start a new session according to the given parameters.
|
/// Instructs the service to start a new session according to the given parameters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* 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.Messages
|
||||||
|
{
|
||||||
|
public interface IDisconnectionMessage : IMessage
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,8 +13,8 @@ namespace SafeExamBrowser.Contracts.Communication.Messages
|
||||||
public interface IMessage
|
public interface IMessage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The communication token needed for authentication with the host.
|
/// The communication token needed for authentication.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Guid CommunicationToken { get; }
|
Guid CommunicationToken { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication.Messages
|
||||||
|
{
|
||||||
|
public interface ISimpleMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The purport of the message.
|
||||||
|
/// </summary>
|
||||||
|
Message Purport { get; }
|
||||||
|
}
|
||||||
|
}
|
28
SafeExamBrowser.Contracts/Communication/Messages/Message.cs
Normal file
28
SafeExamBrowser.Contracts/Communication/Messages/Message.cs
Normal file
|
@ -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.Messages
|
||||||
|
{
|
||||||
|
public enum Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Requests an interlocutor to submit data for authentication.
|
||||||
|
/// </summary>
|
||||||
|
Authenticate = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sent from the client to the runtime to indicate that the client is ready to operate.
|
||||||
|
/// </summary>
|
||||||
|
ClientIsReady,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sent from the client to the runtime to ask for the client configuration.
|
||||||
|
/// </summary>
|
||||||
|
ConfigurationNeeded,
|
||||||
|
}
|
||||||
|
}
|
|
@ -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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication.Responses
|
||||||
|
{
|
||||||
|
public interface IAuthenticationResponse : IResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The process identifier used for authentication.
|
||||||
|
/// </summary>
|
||||||
|
int ProcessId { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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.Configuration;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication.Responses
|
||||||
|
{
|
||||||
|
public interface IConfigurationResponse : IResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The configuration to be used by the client.
|
||||||
|
/// </summary>
|
||||||
|
IClientConfiguration Configuration { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,15 +10,15 @@ using System;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Communication.Responses
|
namespace SafeExamBrowser.Contracts.Communication.Responses
|
||||||
{
|
{
|
||||||
public interface IConnectResponse : IResponse
|
public interface IConnectionResponse : IResponse
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The communication token needed for authentication with the host. Is <c>null</c> if a connection was refused.
|
/// The communication token needed for authentication. Is <c>null</c> if a connection was refused.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Guid? CommunicationToken { get; }
|
Guid? CommunicationToken { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates whether the host has accepted the connection request.
|
/// Indicates whether the connection request has been accepted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool ConnectionEstablished { get; }
|
bool ConnectionEstablished { get; }
|
||||||
}
|
}
|
|
@ -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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication.Responses
|
||||||
|
{
|
||||||
|
public interface IDisconnectionResponse : IResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the connection has been terminated.
|
||||||
|
/// </summary>
|
||||||
|
bool ConnectionTerminated { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Configuration
|
namespace SafeExamBrowser.Contracts.Configuration
|
||||||
|
@ -13,9 +14,9 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
public interface IClientConfiguration
|
public interface IClientConfiguration
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The session data to be used by the client.
|
/// The unique identifier for the current session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ISessionData SessionData { get; set; }
|
Guid SessionId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The application settings to be used by the client.
|
/// The application settings to be used by the client.
|
||||||
|
|
|
@ -14,10 +14,10 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
public interface IConfigurationRepository
|
public interface IConfigurationRepository
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the current session data, i.e. the last ones which were initialized. If no session has been initialized yet, this
|
/// Retrieves the current session, i.e. the last one which was initialized. If no session has been initialized yet, this
|
||||||
/// property will be <c>null</c>!
|
/// property will be <c>null</c>!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ISessionData CurrentSessionData { get; }
|
ISession CurrentSession { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the current settings, i.e. the last ones which were loaded. If no settings have been loaded yet, this property will
|
/// Retrieves the current settings, i.e. the last ones which were loaded. If no settings have been loaded yet, this property will
|
||||||
|
@ -31,14 +31,14 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
IRuntimeInfo RuntimeInfo { get; }
|
IRuntimeInfo RuntimeInfo { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builds a configuration for the client component, given the currently loaded settings, session data and runtime information.
|
/// Builds a configuration for the client component, given the currently loaded settings, session and runtime information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IClientConfiguration BuildClientConfiguration();
|
IClientConfiguration BuildClientConfiguration();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes all relevant data for a new session.
|
/// Initializes all relevant data for a new session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ISessionData InitializeSessionData();
|
ISession InitializeSession();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to load settings from the specified path.
|
/// Attempts to load settings from the specified path.
|
||||||
|
|
|
@ -40,10 +40,15 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string ClientAddress { get; }
|
string ClientAddress { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The executable path of the client compontent.
|
||||||
|
/// </summary>
|
||||||
|
string ClientExecutablePath { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The unique identifier for the currently running client instance.
|
/// The unique identifier for the currently running client instance.
|
||||||
///
|
///
|
||||||
/// TODO: Will need to be updated for each new client instance!
|
/// TODO: Will need to be updated for each new client instance! -> Remove if unused!
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Guid ClientId { get; }
|
Guid ClientId { get; }
|
||||||
|
@ -85,6 +90,9 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The unique identifier for the currently running runtime instance.
|
/// The unique identifier for the currently running runtime instance.
|
||||||
|
///
|
||||||
|
/// TODO: Remove if unused!
|
||||||
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Guid RuntimeId { get; }
|
Guid RuntimeId { get; }
|
||||||
|
|
||||||
|
|
31
SafeExamBrowser.Contracts/Configuration/ISession.cs
Normal file
31
SafeExamBrowser.Contracts/Configuration/ISession.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* 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.WindowsApi;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Configuration
|
||||||
|
{
|
||||||
|
public interface ISession
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The process information of the client instance associated to this session.
|
||||||
|
/// </summary>
|
||||||
|
IProcess ClientProcess { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The unique session identifier.
|
||||||
|
/// </summary>
|
||||||
|
Guid Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The startup token used by the client and runtime components for initial authentication.
|
||||||
|
/// </summary>
|
||||||
|
Guid StartupToken { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,15 +60,22 @@
|
||||||
<Compile Include="Communication\ICommunication.cs" />
|
<Compile Include="Communication\ICommunication.cs" />
|
||||||
<Compile Include="Communication\IClientProxy.cs" />
|
<Compile Include="Communication\IClientProxy.cs" />
|
||||||
<Compile Include="Communication\ICommunicationHost.cs" />
|
<Compile Include="Communication\ICommunicationHost.cs" />
|
||||||
|
<Compile Include="Communication\ICommunicationProxy.cs" />
|
||||||
<Compile Include="Communication\IRuntimeHost.cs" />
|
<Compile Include="Communication\IRuntimeHost.cs" />
|
||||||
<Compile Include="Communication\IRuntimeProxy.cs" />
|
<Compile Include="Communication\IRuntimeProxy.cs" />
|
||||||
<Compile Include="Communication\IServiceProxy.cs" />
|
<Compile Include="Communication\IServiceProxy.cs" />
|
||||||
|
<Compile Include="Communication\Messages\IDisconnectionMessage.cs" />
|
||||||
<Compile Include="Communication\Messages\IMessage.cs" />
|
<Compile Include="Communication\Messages\IMessage.cs" />
|
||||||
|
<Compile Include="Communication\Messages\ISimpleMessage.cs" />
|
||||||
|
<Compile Include="Communication\Messages\Message.cs" />
|
||||||
|
<Compile Include="Communication\Responses\IAuthenticationResponse.cs" />
|
||||||
|
<Compile Include="Communication\Responses\IConfigurationResponse.cs" />
|
||||||
|
<Compile Include="Communication\Responses\IDisconnectionResponse.cs" />
|
||||||
<Compile Include="Communication\Responses\IResponse.cs" />
|
<Compile Include="Communication\Responses\IResponse.cs" />
|
||||||
<Compile Include="Communication\Responses\IConnectResponse.cs" />
|
<Compile Include="Communication\Responses\IConnectionResponse.cs" />
|
||||||
<Compile Include="Configuration\IClientConfiguration.cs" />
|
<Compile Include="Configuration\IClientConfiguration.cs" />
|
||||||
<Compile Include="Configuration\IRuntimeInfo.cs" />
|
<Compile Include="Configuration\IRuntimeInfo.cs" />
|
||||||
<Compile Include="Configuration\ISessionData.cs" />
|
<Compile Include="Configuration\ISession.cs" />
|
||||||
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
|
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
|
||||||
<Compile Include="Behaviour\INotificationController.cs" />
|
<Compile Include="Behaviour\INotificationController.cs" />
|
||||||
<Compile Include="Behaviour\Operations\IOperation.cs" />
|
<Compile Include="Behaviour\Operations\IOperation.cs" />
|
||||||
|
@ -131,10 +138,11 @@
|
||||||
<Compile Include="UserInterface\MessageBoxAction.cs" />
|
<Compile Include="UserInterface\MessageBoxAction.cs" />
|
||||||
<Compile Include="UserInterface\MessageBoxIcon.cs" />
|
<Compile Include="UserInterface\MessageBoxIcon.cs" />
|
||||||
<Compile Include="WindowsApi\IBounds.cs" />
|
<Compile Include="WindowsApi\IBounds.cs" />
|
||||||
|
<Compile Include="WindowsApi\IDesktop.cs" />
|
||||||
<Compile Include="WindowsApi\INativeMethods.cs" />
|
<Compile Include="WindowsApi\INativeMethods.cs" />
|
||||||
|
<Compile Include="WindowsApi\IProcess.cs" />
|
||||||
|
<Compile Include="WindowsApi\IProcessFactory.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup />
|
||||||
<Folder Include="Client\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
18
SafeExamBrowser.Contracts/WindowsApi/IDesktop.cs
Normal file
18
SafeExamBrowser.Contracts/WindowsApi/IDesktop.cs
Normal file
|
@ -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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.WindowsApi
|
||||||
|
{
|
||||||
|
public interface IDesktop
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the name of the currently active desktop.
|
||||||
|
/// </summary>
|
||||||
|
string CurrentName { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,15 +6,13 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
namespace SafeExamBrowser.Contracts.WindowsApi
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Configuration
|
|
||||||
{
|
{
|
||||||
public interface ISessionData
|
public interface IProcess
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The unique session identifier.
|
/// The process identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Guid Id { get; }
|
int Id { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
19
SafeExamBrowser.Contracts/WindowsApi/IProcessFactory.cs
Normal file
19
SafeExamBrowser.Contracts/WindowsApi/IProcessFactory.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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.WindowsApi
|
||||||
|
{
|
||||||
|
public interface IProcessFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Starts a new process on the currently active desktop.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="System.ComponentModel.Win32Exception">If the process could not be started.</exception>
|
||||||
|
IProcess StartNew(string path, params string[] args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ using SafeExamBrowser.Contracts.Communication;
|
||||||
using SafeExamBrowser.Contracts.Communication.Messages;
|
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
using SafeExamBrowser.Core.Communication.Responses;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Core.Communication
|
namespace SafeExamBrowser.Core.Communication
|
||||||
{
|
{
|
||||||
|
@ -22,6 +23,9 @@ namespace SafeExamBrowser.Core.Communication
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private ServiceHost host;
|
private ServiceHost host;
|
||||||
|
|
||||||
|
protected Guid? CommunicationToken { get; private set; }
|
||||||
|
protected ILogger Logger { get; private set; }
|
||||||
|
|
||||||
public bool IsRunning
|
public bool IsRunning
|
||||||
{
|
{
|
||||||
get { return host?.State == CommunicationState.Opened; }
|
get { return host?.State == CommunicationState.Opened; }
|
||||||
|
@ -33,33 +37,64 @@ namespace SafeExamBrowser.Core.Communication
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract IConnectResponse OnConnect(Guid? token);
|
protected abstract bool OnConnect(Guid? token);
|
||||||
protected abstract void OnDisconnect(IMessage message);
|
protected abstract void OnDisconnect();
|
||||||
protected abstract IResponse OnReceive(IMessage message);
|
protected abstract IResponse OnReceive(IMessage message);
|
||||||
|
protected abstract IResponse OnReceive(Message message);
|
||||||
|
|
||||||
public IConnectResponse Connect(Guid? token = null)
|
public IConnectionResponse Connect(Guid? token = null)
|
||||||
{
|
{
|
||||||
logger.Debug($"Received connection request with token '{token}'.");
|
logger.Debug($"Received connection request with authentication token '{token}'.");
|
||||||
|
|
||||||
var response = OnConnect(token);
|
var response = new ConnectionResponse();
|
||||||
|
var connected = OnConnect(token);
|
||||||
|
|
||||||
logger.Debug($"{(response.ConnectionEstablished ? "Accepted" : "Denied")} connection request.");
|
if (connected)
|
||||||
|
{
|
||||||
|
response.CommunicationToken = CommunicationToken = Guid.NewGuid();
|
||||||
|
response.ConnectionEstablished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug($"{(connected ? "Accepted" : "Denied")} connection request.");
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect(IMessage message)
|
public IDisconnectionResponse Disconnect(IDisconnectionMessage message)
|
||||||
{
|
{
|
||||||
|
var response = new DisconnectionResponse();
|
||||||
|
|
||||||
|
// TODO: Compare with ToString in BaseProxy - needed?
|
||||||
logger.Debug($"Received disconnection request with message '{message}'.");
|
logger.Debug($"Received disconnection request with message '{message}'.");
|
||||||
|
|
||||||
OnDisconnect(message);
|
if (IsAuthorized(message?.CommunicationToken))
|
||||||
|
{
|
||||||
|
OnDisconnect();
|
||||||
|
|
||||||
|
CommunicationToken = null;
|
||||||
|
response.ConnectionTerminated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IResponse Send(IMessage message)
|
public IResponse Send(IMessage message)
|
||||||
{
|
{
|
||||||
|
IResponse response = null;
|
||||||
|
|
||||||
logger.Debug($"Received message '{message}'.");
|
logger.Debug($"Received message '{message}'.");
|
||||||
|
|
||||||
var response = OnReceive(message);
|
if (IsAuthorized(message?.CommunicationToken))
|
||||||
|
{
|
||||||
|
if (message is ISimpleMessage)
|
||||||
|
{
|
||||||
|
response = OnReceive((message as ISimpleMessage).Purport);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response = OnReceive(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logger.Debug($"Sending response '{response}'.");
|
logger.Debug($"Sending response '{response}'.");
|
||||||
|
|
||||||
|
@ -87,6 +122,11 @@ namespace SafeExamBrowser.Core.Communication
|
||||||
logger.Debug($"Terminated communication host for endpoint '{address}'.");
|
logger.Debug($"Terminated communication host for endpoint '{address}'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsAuthorized(Guid? token)
|
||||||
|
{
|
||||||
|
return CommunicationToken == token;
|
||||||
|
}
|
||||||
|
|
||||||
private void Host_Closed(object sender, EventArgs e)
|
private void Host_Closed(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
logger.Debug("Communication host has been closed.");
|
logger.Debug("Communication host has been closed.");
|
||||||
|
|
|
@ -12,15 +12,16 @@ using SafeExamBrowser.Contracts.Communication;
|
||||||
using SafeExamBrowser.Contracts.Communication.Messages;
|
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
using SafeExamBrowser.Core.Communication.Messages;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Core.Communication
|
namespace SafeExamBrowser.Core.Communication
|
||||||
{
|
{
|
||||||
public abstract class BaseProxy : ICommunication
|
public abstract class BaseProxy : ICommunicationProxy
|
||||||
{
|
{
|
||||||
private string address;
|
private string address;
|
||||||
private ICommunication channel;
|
private ICommunication channel;
|
||||||
|
private Guid? communicationToken;
|
||||||
|
|
||||||
protected Guid? CommunicationToken { get; private set; }
|
|
||||||
protected ILogger Logger { get; private set; }
|
protected ILogger Logger { get; private set; }
|
||||||
|
|
||||||
public BaseProxy(string address, ILogger logger)
|
public BaseProxy(string address, ILogger logger)
|
||||||
|
@ -29,7 +30,7 @@ namespace SafeExamBrowser.Core.Communication
|
||||||
this.Logger = logger;
|
this.Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConnectResponse Connect(Guid? token = null)
|
public virtual bool Connect(Guid? token = null)
|
||||||
{
|
{
|
||||||
var endpoint = new EndpointAddress(address);
|
var endpoint = new EndpointAddress(address);
|
||||||
|
|
||||||
|
@ -42,48 +43,47 @@ namespace SafeExamBrowser.Core.Communication
|
||||||
|
|
||||||
var response = channel.Connect(token);
|
var response = channel.Connect(token);
|
||||||
|
|
||||||
CommunicationToken = response.CommunicationToken;
|
communicationToken = response.CommunicationToken;
|
||||||
Logger.Debug($"Tried to connect to {address}, connection was {(response.ConnectionEstablished ? "established" : "refused")}.");
|
Logger.Debug($"Tried to connect to {address}, connection was {(response.ConnectionEstablished ? "established" : "refused")}.");
|
||||||
|
|
||||||
|
return response.ConnectionEstablished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool Disconnect()
|
||||||
|
{
|
||||||
|
FailIfNotConnected(nameof(Disconnect));
|
||||||
|
|
||||||
|
var message = new DisconnectionMessage { CommunicationToken = communicationToken.Value };
|
||||||
|
var response = channel.Disconnect(message);
|
||||||
|
|
||||||
|
Logger.Debug($"{(response.ConnectionTerminated ? "Disconnected" : "Failed to disconnect")} from {address}.");
|
||||||
|
|
||||||
|
return response.ConnectionTerminated;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IResponse Send(IMessage message)
|
||||||
|
{
|
||||||
|
FailIfNotConnected(nameof(Send));
|
||||||
|
|
||||||
|
message.CommunicationToken = communicationToken.Value;
|
||||||
|
|
||||||
|
var response = channel.Send(message);
|
||||||
|
|
||||||
|
Logger.Debug($"Sent {ToString(message)}, got {ToString(response)}.");
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect(IMessage message)
|
protected IResponse Send(Message purport)
|
||||||
{
|
{
|
||||||
if (ChannelIsReady())
|
FailIfNotConnected(nameof(Send));
|
||||||
{
|
|
||||||
channel.Disconnect(message);
|
|
||||||
Logger.Debug($"Disconnected from {address}, transmitting {ToString(message)}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new CommunicationException($"Tried to disconnect from host, but channel was {GetChannelState()}!");
|
var message = new SimpleMessage { Purport = purport };
|
||||||
}
|
var response = channel.Send(message);
|
||||||
|
|
||||||
public IResponse Send(IMessage message)
|
Logger.Debug($"Sent {ToString(message)}, got {ToString(response)}.");
|
||||||
{
|
|
||||||
if (ChannelIsReady())
|
|
||||||
{
|
|
||||||
var response = channel.Send(message);
|
|
||||||
|
|
||||||
Logger.Debug($"Sent {ToString(message)}, got {ToString(response)}.");
|
return response;
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new CommunicationException($"Tried to send {ToString(message)}, but channel was {GetChannelState()}!");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void FailIfNotConnected(string operationName)
|
|
||||||
{
|
|
||||||
if (!CommunicationToken.HasValue)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Cannot perform '{operationName}' before being connected to endpoint!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ChannelIsReady()
|
|
||||||
{
|
|
||||||
return channel != null && (channel as ICommunicationObject).State == CommunicationState.Opened;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BaseProxy_Closed(object sender, EventArgs e)
|
private void BaseProxy_Closed(object sender, EventArgs e)
|
||||||
|
@ -111,6 +111,19 @@ namespace SafeExamBrowser.Core.Communication
|
||||||
Logger.Debug("Communication channel is opening...");
|
Logger.Debug("Communication channel is opening...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void FailIfNotConnected(string operationName)
|
||||||
|
{
|
||||||
|
if (!communicationToken.HasValue)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Cannot perform '{operationName}' before being connected to endpoint!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel == null || (channel as ICommunicationObject).State != CommunicationState.Opened)
|
||||||
|
{
|
||||||
|
throw new CommunicationException($"Tried to perform {operationName}, but channel was {GetChannelState()}!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string GetChannelState()
|
private string GetChannelState()
|
||||||
{
|
{
|
||||||
return channel == null ? "null" : $"in state '{(channel as ICommunicationObject).State}'";
|
return channel == null ? "null" : $"in state '{(channel as ICommunicationObject).State}'";
|
||||||
|
|
27
SafeExamBrowser.Core/Communication/ClientProxy.cs
Normal file
27
SafeExamBrowser.Core/Communication/ClientProxy.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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.Communication;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.Communication
|
||||||
|
{
|
||||||
|
public class ClientProxy : BaseProxy, IClientProxy
|
||||||
|
{
|
||||||
|
public ClientProxy(string address, ILogger logger) : base(address, logger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAuthenticationResponse RequestAuthentication()
|
||||||
|
{
|
||||||
|
return (IAuthenticationResponse) Send(Message.ClientIsReady);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ using SafeExamBrowser.Contracts.Communication.Messages;
|
||||||
namespace SafeExamBrowser.Core.Communication.Messages
|
namespace SafeExamBrowser.Core.Communication.Messages
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class Message : IMessage
|
internal class BaseMessage : IMessage
|
||||||
{
|
{
|
||||||
public Guid CommunicationToken { get; set; }
|
public Guid CommunicationToken { get; set; }
|
||||||
}
|
}
|
|
@ -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 System;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.Communication.Messages
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
internal class DisconnectionMessage : BaseMessage, IDisconnectionMessage
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
19
SafeExamBrowser.Core/Communication/Messages/SimpleMessage.cs
Normal file
19
SafeExamBrowser.Core/Communication/Messages/SimpleMessage.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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.Messages;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.Communication.Messages
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
internal class SimpleMessage : BaseMessage, ISimpleMessage
|
||||||
|
{
|
||||||
|
public Message Purport { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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.Responses;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.Communication.Responses
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
internal class ConnectionResponse : IConnectionResponse
|
||||||
|
{
|
||||||
|
public Guid? CommunicationToken { get; set; }
|
||||||
|
public bool ConnectionEstablished { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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.Responses;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.Communication.Responses
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
internal class DisconnectionResponse : IDisconnectionResponse
|
||||||
|
{
|
||||||
|
public bool ConnectionTerminated { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,11 +6,11 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Core.Communication.Messages;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Core.Communication
|
namespace SafeExamBrowser.Core.Communication
|
||||||
{
|
{
|
||||||
|
@ -20,22 +20,14 @@ namespace SafeExamBrowser.Core.Communication
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Connect(Guid token)
|
|
||||||
{
|
|
||||||
return base.Connect(token).ConnectionEstablished;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Disconnect()
|
|
||||||
{
|
|
||||||
FailIfNotConnected(nameof(Disconnect));
|
|
||||||
|
|
||||||
base.Disconnect(new Message { CommunicationToken = CommunicationToken.Value });
|
|
||||||
}
|
|
||||||
|
|
||||||
public IClientConfiguration GetConfiguration()
|
public IClientConfiguration GetConfiguration()
|
||||||
{
|
{
|
||||||
// TODO
|
return ((IConfigurationResponse) Send(Message.ConfigurationNeeded)).Configuration;
|
||||||
throw new NotImplementedException();
|
}
|
||||||
|
|
||||||
|
public void InformClientReady()
|
||||||
|
{
|
||||||
|
Send(Message.ClientIsReady);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ using System;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Core.Communication.Messages;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Core.Communication
|
namespace SafeExamBrowser.Core.Communication
|
||||||
{
|
{
|
||||||
|
@ -22,26 +21,24 @@ namespace SafeExamBrowser.Core.Communication
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Connect()
|
public override bool Connect(Guid? token)
|
||||||
{
|
{
|
||||||
if (IgnoreOperation(nameof(Connect)))
|
if (IgnoreOperation(nameof(Connect)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.Connect().ConnectionEstablished;
|
return base.Connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect()
|
public override bool Disconnect()
|
||||||
{
|
{
|
||||||
if (IgnoreOperation(nameof(Disconnect)))
|
if (IgnoreOperation(nameof(Disconnect)))
|
||||||
{
|
{
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FailIfNotConnected(nameof(Disconnect));
|
return base.Disconnect();
|
||||||
|
|
||||||
Disconnect(new Message { CommunicationToken = CommunicationToken.Value });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartSession(Guid sessionId, ISettings settings)
|
public void StartSession(Guid sessionId, ISettings settings)
|
||||||
|
@ -51,8 +48,6 @@ namespace SafeExamBrowser.Core.Communication
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FailIfNotConnected(nameof(StartSession));
|
|
||||||
|
|
||||||
// TODO: Send(new StartSessionMessage { Id = sessionId, Settings = settings });
|
// TODO: Send(new StartSessionMessage { Id = sessionId, Settings = settings });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,8 +58,6 @@ namespace SafeExamBrowser.Core.Communication
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FailIfNotConnected(nameof(StopSession));
|
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,12 @@
|
||||||
<Compile Include="Behaviour\Operations\OperationSequence.cs" />
|
<Compile Include="Behaviour\Operations\OperationSequence.cs" />
|
||||||
<Compile Include="Communication\BaseProxy.cs" />
|
<Compile Include="Communication\BaseProxy.cs" />
|
||||||
<Compile Include="Communication\BaseHost.cs" />
|
<Compile Include="Communication\BaseHost.cs" />
|
||||||
<Compile Include="Communication\Messages\Message.cs" />
|
<Compile Include="Communication\ClientProxy.cs" />
|
||||||
|
<Compile Include="Communication\Messages\DisconnectionMessage.cs" />
|
||||||
|
<Compile Include="Communication\Messages\BaseMessage.cs" />
|
||||||
|
<Compile Include="Communication\Messages\SimpleMessage.cs" />
|
||||||
|
<Compile Include="Communication\Responses\ConnectionResponse.cs" />
|
||||||
|
<Compile Include="Communication\Responses\DisconnectionResponse.cs" />
|
||||||
<Compile Include="Communication\RuntimeProxy.cs" />
|
<Compile Include="Communication\RuntimeProxy.cs" />
|
||||||
<Compile Include="Communication\ServiceProxy.cs" />
|
<Compile Include="Communication\ServiceProxy.cs" />
|
||||||
<Compile Include="Logging\DefaultLogFormatter.cs" />
|
<Compile Include="Logging\DefaultLogFormatter.cs" />
|
||||||
|
@ -87,8 +92,6 @@
|
||||||
<Name>SafeExamBrowser.Contracts</Name>
|
<Name>SafeExamBrowser.Contracts</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup />
|
||||||
<Folder Include="Communication\Responses\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -44,38 +44,38 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustConnectToService()
|
public void MustConnectToService()
|
||||||
{
|
{
|
||||||
service.Setup(s => s.Connect()).Returns(true);
|
service.Setup(s => s.Connect(null)).Returns(true);
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
service.Setup(s => s.Connect()).Returns(true);
|
service.Setup(s => s.Connect(null)).Returns(true);
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
service.Verify(s => s.Connect(), Times.Exactly(2));
|
service.Verify(s => s.Connect(null), Times.Exactly(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustNotFailIfServiceNotAvailable()
|
public void MustNotFailIfServiceNotAvailable()
|
||||||
{
|
{
|
||||||
service.Setup(s => s.Connect()).Returns(false);
|
service.Setup(s => s.Connect(null)).Returns(false);
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
service.Setup(s => s.Connect()).Returns(false);
|
service.Setup(s => s.Connect(null)).Returns(false);
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
service.Setup(s => s.Connect(null)).Throws<Exception>();
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
service.Setup(s => s.Connect(null)).Throws<Exception>();
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
@ -84,7 +84,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustAbortIfServiceMandatoryAndNotAvailable()
|
public void MustAbortIfServiceMandatoryAndNotAvailable()
|
||||||
{
|
{
|
||||||
service.Setup(s => s.Connect()).Returns(false);
|
service.Setup(s => s.Connect(null)).Returns(false);
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
@ -95,7 +95,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustNotAbortIfServiceOptionalAndNotAvailable()
|
public void MustNotAbortIfServiceOptionalAndNotAvailable()
|
||||||
{
|
{
|
||||||
service.Setup(s => s.Connect()).Returns(false);
|
service.Setup(s => s.Connect(null)).Returns(false);
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
@ -107,13 +107,13 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustDisconnectWhenReverting()
|
public void MustDisconnectWhenReverting()
|
||||||
{
|
{
|
||||||
service.Setup(s => s.Connect()).Returns(true);
|
service.Setup(s => s.Connect(null)).Returns(true);
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
|
|
||||||
service.Setup(s => s.Connect()).Returns(true);
|
service.Setup(s => s.Connect(null)).Returns(true);
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
@ -125,7 +125,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustNotFailWhenDisconnecting()
|
public void MustNotFailWhenDisconnecting()
|
||||||
{
|
{
|
||||||
service.Setup(s => s.Connect()).Returns(true);
|
service.Setup(s => s.Connect(null)).Returns(true);
|
||||||
service.Setup(s => s.Disconnect()).Throws<Exception>();
|
service.Setup(s => s.Disconnect()).Throws<Exception>();
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||||
|
|
||||||
|
@ -138,25 +138,25 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustNotDisconnnectIfNotAvailable()
|
public void MustNotDisconnnectIfNotAvailable()
|
||||||
{
|
{
|
||||||
service.Setup(s => s.Connect()).Returns(false);
|
service.Setup(s => s.Connect(null)).Returns(false);
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
|
|
||||||
service.Setup(s => s.Connect()).Returns(false);
|
service.Setup(s => s.Connect(null)).Returns(false);
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
|
|
||||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
service.Setup(s => s.Connect(null)).Throws<Exception>();
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
|
|
||||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
service.Setup(s => s.Connect(null)).Throws<Exception>();
|
||||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
|
@ -37,13 +37,14 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
logger.Info($"Initializing kiosk mode '{kioskMode}'...");
|
logger.Info($"Initializing kiosk mode '{kioskMode}'...");
|
||||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeKioskMode);
|
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeKioskMode);
|
||||||
|
|
||||||
if (kioskMode == KioskMode.CreateNewDesktop)
|
switch (kioskMode)
|
||||||
{
|
{
|
||||||
CreateNewDesktop();
|
case KioskMode.CreateNewDesktop:
|
||||||
}
|
CreateNewDesktop();
|
||||||
else
|
break;
|
||||||
{
|
case KioskMode.DisableExplorerShell:
|
||||||
DisableExplorerShell();
|
DisableExplorerShell();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,13 +58,14 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
logger.Info($"Reverting kiosk mode '{kioskMode}'...");
|
logger.Info($"Reverting kiosk mode '{kioskMode}'...");
|
||||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_RevertKioskMode);
|
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_RevertKioskMode);
|
||||||
|
|
||||||
if (kioskMode == KioskMode.CreateNewDesktop)
|
switch (kioskMode)
|
||||||
{
|
{
|
||||||
CloseNewDesktop();
|
case KioskMode.CreateNewDesktop:
|
||||||
}
|
CloseNewDesktop();
|
||||||
else
|
break;
|
||||||
{
|
case KioskMode.DisableExplorerShell:
|
||||||
RestartExplorerShell();
|
RestartExplorerShell();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
if (mandatory && !connected)
|
if (mandatory && !connected)
|
||||||
{
|
{
|
||||||
Abort = true;
|
Abort = true;
|
||||||
logger.Info("Aborting startup because the service is mandatory but not available!");
|
logger.Error("Aborting startup because the service is mandatory but not available!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -81,7 +81,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger.Error("Failed to disconnect from service host!", e);
|
logger.Error("Failed to disconnect from the service!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,19 @@
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
{
|
{
|
||||||
internal class SessionSequenceEndOperation : SessionSequenceOperation
|
internal class SessionSequenceEndOperation : SessionSequenceOperation
|
||||||
{
|
{
|
||||||
public SessionSequenceEndOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy) : base(configuration, logger, serviceProxy)
|
public SessionSequenceEndOperation(
|
||||||
|
IClientProxy client,
|
||||||
|
IConfigurationRepository configuration,
|
||||||
|
ILogger logger,
|
||||||
|
IProcessFactory processFactory,
|
||||||
|
IRuntimeHost runtimeHost,
|
||||||
|
IServiceProxy service) : base(client, configuration, logger, processFactory, runtimeHost, service)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,31 +6,46 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using SafeExamBrowser.Contracts.Behaviour.Operations;
|
using SafeExamBrowser.Contracts.Behaviour.Operations;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Contracts.UserInterface;
|
using SafeExamBrowser.Contracts.UserInterface;
|
||||||
|
using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
{
|
{
|
||||||
internal abstract class SessionSequenceOperation : IOperation
|
internal abstract class SessionSequenceOperation : IOperation
|
||||||
{
|
{
|
||||||
private bool sessionRunning;
|
private bool sessionRunning;
|
||||||
|
private IClientProxy client;
|
||||||
private IConfigurationRepository configuration;
|
private IConfigurationRepository configuration;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private IServiceProxy serviceProxy;
|
private IProcessFactory processFactory;
|
||||||
private ISessionData sessionData;
|
private IRuntimeHost runtimeHost;
|
||||||
|
private IServiceProxy service;
|
||||||
|
private ISession session;
|
||||||
|
|
||||||
public bool Abort { get; private set; }
|
public bool Abort { get; private set; }
|
||||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||||
|
|
||||||
public SessionSequenceOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy)
|
public SessionSequenceOperation(
|
||||||
|
IClientProxy client,
|
||||||
|
IConfigurationRepository configuration,
|
||||||
|
ILogger logger,
|
||||||
|
IProcessFactory processFactory,
|
||||||
|
IRuntimeHost runtimeHost,
|
||||||
|
IServiceProxy service)
|
||||||
{
|
{
|
||||||
|
this.client = client;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.serviceProxy = serviceProxy;
|
this.processFactory = processFactory;
|
||||||
|
this.runtimeHost = runtimeHost;
|
||||||
|
this.service = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void Perform();
|
public abstract void Perform();
|
||||||
|
@ -42,34 +57,80 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
logger.Info("Starting new session...");
|
logger.Info("Starting new session...");
|
||||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartSession, true);
|
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartSession, true);
|
||||||
|
|
||||||
sessionData = configuration.InitializeSessionData();
|
session = configuration.InitializeSession();
|
||||||
serviceProxy.StartSession(sessionData.Id, configuration.CurrentSettings);
|
runtimeHost.StartupToken = session.StartupToken;
|
||||||
|
|
||||||
// TODO:
|
service.StartSession(session.Id, configuration.CurrentSettings);
|
||||||
// - Create and connect to client
|
|
||||||
// - Verify session integrity and start event handling -> in runtime controller?
|
|
||||||
System.Threading.Thread.Sleep(5000);
|
|
||||||
|
|
||||||
sessionRunning = true;
|
try
|
||||||
logger.Info($"Successfully started new session with identifier '{sessionData.Id}'.");
|
{
|
||||||
|
StartClient();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
service.StopSession(session.Id);
|
||||||
|
logger.Error("Failed to start client!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sessionRunning)
|
||||||
|
{
|
||||||
|
logger.Info($"Successfully started new session with identifier '{session.Id}'.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Abort = true;
|
||||||
|
logger.Info($"Failed to start new session! Aborting...");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void StopSession()
|
protected void StopSession()
|
||||||
{
|
{
|
||||||
if (sessionRunning)
|
if (sessionRunning)
|
||||||
{
|
{
|
||||||
logger.Info($"Stopping session with identifier '{sessionData.Id}'...");
|
logger.Info($"Stopping session with identifier '{session.Id}'...");
|
||||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopSession, true);
|
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopSession, true);
|
||||||
|
|
||||||
serviceProxy.StopSession(sessionData.Id);
|
service.StopSession(session.Id);
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - Terminate client (or does it terminate itself?)
|
// - Terminate client (or does it terminate itself?)
|
||||||
// - Stop event handling and verify session termination -> in runtime controller?
|
|
||||||
System.Threading.Thread.Sleep(5000);
|
|
||||||
|
|
||||||
sessionRunning = false;
|
sessionRunning = false;
|
||||||
logger.Info($"Successfully stopped session with identifier '{sessionData.Id}'.");
|
logger.Info($"Successfully stopped session with identifier '{session.Id}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartClient()
|
||||||
|
{
|
||||||
|
var clientReady = new AutoResetEvent(false);
|
||||||
|
var clientReadyHandler = new CommunicationEventHandler(() => clientReady.Set());
|
||||||
|
var clientExecutable = configuration.RuntimeInfo.ClientExecutablePath;
|
||||||
|
var hostUri = configuration.RuntimeInfo.RuntimeAddress;
|
||||||
|
var token = session.StartupToken.ToString("D");
|
||||||
|
|
||||||
|
runtimeHost.ClientReady += clientReadyHandler;
|
||||||
|
session.ClientProcess = processFactory.StartNew(clientExecutable, hostUri, token);
|
||||||
|
|
||||||
|
clientReady.WaitOne();
|
||||||
|
runtimeHost.ClientReady -= clientReadyHandler;
|
||||||
|
|
||||||
|
if (client.Connect(session.StartupToken))
|
||||||
|
{
|
||||||
|
var response = client.RequestAuthentication();
|
||||||
|
|
||||||
|
// TODO: Further integrity checks necessary?
|
||||||
|
if (session.ClientProcess.Id == response.ProcessId)
|
||||||
|
{
|
||||||
|
sessionRunning = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Error("Failed to verify client integrity!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Error("Failed to connect to client!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,19 @@
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
{
|
{
|
||||||
internal class SessionSequenceStartOperation : SessionSequenceOperation
|
internal class SessionSequenceStartOperation : SessionSequenceOperation
|
||||||
{
|
{
|
||||||
public SessionSequenceStartOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy) : base(configuration, logger, serviceProxy)
|
public SessionSequenceStartOperation(
|
||||||
|
IClientProxy client,
|
||||||
|
IConfigurationRepository configuration,
|
||||||
|
ILogger logger,
|
||||||
|
IProcessFactory processFactory,
|
||||||
|
IRuntimeHost runtimeHost,
|
||||||
|
IServiceProxy service) : base(client, configuration, logger, processFactory, runtimeHost, service)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
||||||
{
|
{
|
||||||
private bool sessionRunning;
|
private bool sessionRunning;
|
||||||
|
|
||||||
|
private IClientProxy client;
|
||||||
private IConfigurationRepository configuration;
|
private IConfigurationRepository configuration;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private IOperationSequence bootstrapSequence;
|
private IOperationSequence bootstrapSequence;
|
||||||
|
@ -29,29 +30,31 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
||||||
private IRuntimeHost runtimeHost;
|
private IRuntimeHost runtimeHost;
|
||||||
private IRuntimeInfo runtimeInfo;
|
private IRuntimeInfo runtimeInfo;
|
||||||
private IRuntimeWindow runtimeWindow;
|
private IRuntimeWindow runtimeWindow;
|
||||||
private IServiceProxy serviceProxy;
|
private IServiceProxy service;
|
||||||
private ISplashScreen splashScreen;
|
private ISplashScreen splashScreen;
|
||||||
private Action shutdown;
|
private Action shutdown;
|
||||||
private IUserInterfaceFactory uiFactory;
|
private IUserInterfaceFactory uiFactory;
|
||||||
|
|
||||||
public RuntimeController(
|
public RuntimeController(
|
||||||
|
IClientProxy client,
|
||||||
IConfigurationRepository configuration,
|
IConfigurationRepository configuration,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IOperationSequence bootstrapSequence,
|
IOperationSequence bootstrapSequence,
|
||||||
IOperationSequence sessionSequence,
|
IOperationSequence sessionSequence,
|
||||||
IRuntimeHost runtimeHost,
|
IRuntimeHost runtimeHost,
|
||||||
IRuntimeInfo runtimeInfo,
|
IRuntimeInfo runtimeInfo,
|
||||||
IServiceProxy serviceProxy,
|
IServiceProxy service,
|
||||||
Action shutdown,
|
Action shutdown,
|
||||||
IUserInterfaceFactory uiFactory)
|
IUserInterfaceFactory uiFactory)
|
||||||
{
|
{
|
||||||
|
this.client = client;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.bootstrapSequence = bootstrapSequence;
|
this.bootstrapSequence = bootstrapSequence;
|
||||||
this.sessionSequence = sessionSequence;
|
this.sessionSequence = sessionSequence;
|
||||||
this.runtimeHost = runtimeHost;
|
this.runtimeHost = runtimeHost;
|
||||||
this.runtimeInfo = runtimeInfo;
|
this.runtimeInfo = runtimeInfo;
|
||||||
this.serviceProxy = serviceProxy;
|
this.service = service;
|
||||||
this.shutdown = shutdown;
|
this.shutdown = shutdown;
|
||||||
this.uiFactory = uiFactory;
|
this.uiFactory = uiFactory;
|
||||||
}
|
}
|
||||||
|
@ -103,10 +106,6 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
||||||
logger.Log(string.Empty);
|
logger.Log(string.Empty);
|
||||||
logger.Info("--- Initiating shutdown procedure ---");
|
logger.Info("--- Initiating shutdown procedure ---");
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// - Disconnect from service
|
|
||||||
// - Terminate runtime communication host
|
|
||||||
// - Revert kiosk mode (or do that when stopping session?)
|
|
||||||
var success = bootstrapSequence.TryRevert();
|
var success = bootstrapSequence.TryRevert();
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
|
@ -142,7 +141,6 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uiFactory.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error);
|
uiFactory.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error);
|
||||||
logger.Info($"Failed to start new session. Terminating application...");
|
|
||||||
|
|
||||||
if (!initial)
|
if (!initial)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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.Responses;
|
||||||
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Runtime.Communication.Responses
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
internal class ConfigurationResponse : IConfigurationResponse
|
||||||
|
{
|
||||||
|
public IClientConfiguration Configuration { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,33 +10,54 @@ using System;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
using SafeExamBrowser.Contracts.Communication.Messages;
|
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||||
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Core.Communication;
|
using SafeExamBrowser.Core.Communication;
|
||||||
|
using SafeExamBrowser.Runtime.Communication.Responses;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Communication
|
namespace SafeExamBrowser.Runtime.Communication
|
||||||
{
|
{
|
||||||
internal class RuntimeHost : BaseHost, IRuntimeHost
|
internal class RuntimeHost : BaseHost, IRuntimeHost
|
||||||
{
|
{
|
||||||
public RuntimeHost(string address, ILogger logger) : base(address, logger)
|
private IConfigurationRepository configuration;
|
||||||
|
|
||||||
|
public Guid StartupToken { private get; set; }
|
||||||
|
|
||||||
|
public event CommunicationEventHandler ClientReady;
|
||||||
|
|
||||||
|
public RuntimeHost(string address, IConfigurationRepository configuration, ILogger logger) : base(address, logger)
|
||||||
{
|
{
|
||||||
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IConnectResponse OnConnect(Guid? token = null)
|
protected override bool OnConnect(Guid? token = null)
|
||||||
{
|
{
|
||||||
// TODO
|
return StartupToken == token;
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisconnect(IMessage message)
|
protected override void OnDisconnect()
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IResponse OnReceive(IMessage message)
|
protected override IResponse OnReceive(IMessage message)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
throw new NotImplementedException();
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IResponse OnReceive(Message message)
|
||||||
|
{
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case Message.ClientIsReady:
|
||||||
|
ClientReady?.Invoke();
|
||||||
|
break;
|
||||||
|
case Message.ConfigurationNeeded:
|
||||||
|
return new ConfigurationResponse { Configuration = configuration.BuildClientConfiguration() };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
var args = Environment.GetCommandLineArgs();
|
var args = Environment.GetCommandLineArgs();
|
||||||
var configuration = new ConfigurationRepository();
|
var configuration = new ConfigurationRepository();
|
||||||
var nativeMethods = new NativeMethods();
|
var nativeMethods = new NativeMethods();
|
||||||
|
Action shutdown = Application.Current.Shutdown;
|
||||||
|
|
||||||
logger = new Logger();
|
logger = new Logger();
|
||||||
runtimeInfo = configuration.RuntimeInfo;
|
runtimeInfo = configuration.RuntimeInfo;
|
||||||
|
@ -48,7 +49,10 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
var text = new Text(logger);
|
var text = new Text(logger);
|
||||||
var uiFactory = new UserInterfaceFactory(text);
|
var uiFactory = new UserInterfaceFactory(text);
|
||||||
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, new ModuleLogger(logger, typeof(RuntimeHost)));
|
var desktop = new Desktop(new ModuleLogger(logger, typeof(Desktop)));
|
||||||
|
var processFactory = new ProcessFactory(desktop, new ModuleLogger(logger, typeof(ProcessFactory)));
|
||||||
|
var clientProxy = new ClientProxy(runtimeInfo.ClientAddress, new ModuleLogger(logger, typeof(ClientProxy)));
|
||||||
|
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, configuration, new ModuleLogger(logger, typeof(RuntimeHost)));
|
||||||
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ModuleLogger(logger, typeof(ServiceProxy)));
|
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ModuleLogger(logger, typeof(ServiceProxy)));
|
||||||
|
|
||||||
var bootstrapOperations = new Queue<IOperation>();
|
var bootstrapOperations = new Queue<IOperation>();
|
||||||
|
@ -57,16 +61,16 @@ namespace SafeExamBrowser.Runtime
|
||||||
bootstrapOperations.Enqueue(new I18nOperation(logger, text));
|
bootstrapOperations.Enqueue(new I18nOperation(logger, text));
|
||||||
bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger));
|
bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger));
|
||||||
|
|
||||||
sessionOperations.Enqueue(new SessionSequenceStartOperation(configuration, logger, serviceProxy));
|
sessionOperations.Enqueue(new SessionSequenceStartOperation(clientProxy, configuration, logger, processFactory, runtimeHost, serviceProxy));
|
||||||
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeInfo, text, uiFactory, args));
|
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeInfo, text, uiFactory, args));
|
||||||
sessionOperations.Enqueue(new ServiceConnectionOperation(configuration, logger, serviceProxy, text));
|
sessionOperations.Enqueue(new ServiceConnectionOperation(configuration, logger, serviceProxy, text));
|
||||||
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
|
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
|
||||||
sessionOperations.Enqueue(new SessionSequenceEndOperation(configuration, logger, serviceProxy));
|
sessionOperations.Enqueue(new SessionSequenceEndOperation(clientProxy, configuration, logger, processFactory, runtimeHost, serviceProxy));
|
||||||
|
|
||||||
var boostrapSequence = new OperationSequence(logger, bootstrapOperations);
|
var boostrapSequence = new OperationSequence(logger, bootstrapOperations);
|
||||||
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
||||||
|
|
||||||
RuntimeController = new RuntimeController(configuration, logger, boostrapSequence, sessionSequence, runtimeHost, runtimeInfo, serviceProxy, Application.Current.Shutdown, uiFactory);
|
RuntimeController = new RuntimeController(clientProxy, configuration, logger, boostrapSequence, sessionSequence, runtimeHost, runtimeInfo, serviceProxy, shutdown, uiFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void LogStartupInformation()
|
internal void LogStartupInformation()
|
||||||
|
|
|
@ -93,6 +93,7 @@
|
||||||
<Compile Include="Behaviour\Operations\SessionSequenceEndOperation.cs" />
|
<Compile Include="Behaviour\Operations\SessionSequenceEndOperation.cs" />
|
||||||
<Compile Include="Behaviour\Operations\SessionSequenceOperation.cs" />
|
<Compile Include="Behaviour\Operations\SessionSequenceOperation.cs" />
|
||||||
<Compile Include="Behaviour\Operations\SessionSequenceStartOperation.cs" />
|
<Compile Include="Behaviour\Operations\SessionSequenceStartOperation.cs" />
|
||||||
|
<Compile Include="Communication\Responses\ConfigurationResponse.cs" />
|
||||||
<Compile Include="Communication\RuntimeHost.cs" />
|
<Compile Include="Communication\RuntimeHost.cs" />
|
||||||
<Compile Include="CompositionRoot.cs" />
|
<Compile Include="CompositionRoot.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs">
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
|
@ -162,4 +163,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<PostBuildEvent>xcopy /E /Y "$(SolutionDir)SafeExamBrowser.Client\bin\$(PlatformName)\$(ConfigurationName)" "$(ProjectDir)bin\$(PlatformName)\$(ConfigurationName)"</PostBuildEvent>
|
||||||
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -32,6 +32,13 @@ namespace SafeExamBrowser.WindowsApi.Constants
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal const int MIN_ALL = 419;
|
internal const int MIN_ALL = 419;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the default priority class for processes, i.e. a process with no special scheduling needs.
|
||||||
|
///
|
||||||
|
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686219(v=vs.85).aspx.
|
||||||
|
/// </summary>
|
||||||
|
internal const int NORMAL_PRIORITY_CLASS = 0x20;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The callback function is not mapped into the address space of the process that generates the event. Because the hook function
|
/// The callback function is not mapped into the address space of the process that generates the event. Because the hook function
|
||||||
/// is called across process boundaries, the system must queue events. Although this method is asynchronous, events are guaranteed
|
/// is called across process boundaries, the system must queue events. Although this method is asynchronous, events are guaranteed
|
||||||
|
|
26
SafeExamBrowser.WindowsApi/Desktop.cs
Normal file
26
SafeExamBrowser.WindowsApi/Desktop.cs
Normal file
|
@ -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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.WindowsApi
|
||||||
|
{
|
||||||
|
public class Desktop : IDesktop
|
||||||
|
{
|
||||||
|
private ILogger logger;
|
||||||
|
|
||||||
|
// TODO!
|
||||||
|
public string CurrentName => "Default";
|
||||||
|
|
||||||
|
public Desktop(ILogger logger)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,19 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class Kernel32
|
internal class Kernel32
|
||||||
{
|
{
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||||
|
internal static extern bool CreateProcess(
|
||||||
|
string lpApplicationName,
|
||||||
|
string lpCommandLine,
|
||||||
|
ref SECURITY_ATTRIBUTES lpProcessAttributes,
|
||||||
|
ref SECURITY_ATTRIBUTES lpThreadAttributes,
|
||||||
|
bool bInheritHandles,
|
||||||
|
uint dwCreationFlags,
|
||||||
|
IntPtr lpEnvironment,
|
||||||
|
string lpCurrentDirectory,
|
||||||
|
[In] ref STARTUPINFO lpStartupInfo,
|
||||||
|
out PROCESS_INFORMATION lpProcessInformation);
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||||
internal static extern IntPtr GetModuleHandle(string lpModuleName);
|
internal static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
{
|
{
|
||||||
var handle = GetShellWindowHandle();
|
var handle = GetShellWindowHandle();
|
||||||
|
|
||||||
User32.SendMessage(handle, Constant.WM_COMMAND, (IntPtr)Constant.MIN_ALL, IntPtr.Zero);
|
User32.SendMessage(handle, Constant.WM_COMMAND, (IntPtr) Constant.MIN_ALL, IntPtr.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PostCloseMessageToShell()
|
public void PostCloseMessageToShell()
|
||||||
|
@ -245,10 +245,10 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
|
|
||||||
public IntPtr RegisterSystemForegroundEvent(Action<IntPtr> callback)
|
public IntPtr RegisterSystemForegroundEvent(Action<IntPtr> callback)
|
||||||
{
|
{
|
||||||
EventProc eventProc = (IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) =>
|
void eventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||||
{
|
{
|
||||||
callback(hwnd);
|
callback(hwnd);
|
||||||
};
|
}
|
||||||
|
|
||||||
var handle = User32.SetWinEventHook(Constant.EVENT_SYSTEM_FOREGROUND, Constant.EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, eventProc, 0, 0, Constant.WINEVENT_OUTOFCONTEXT);
|
var handle = User32.SetWinEventHook(Constant.EVENT_SYSTEM_FOREGROUND, Constant.EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, eventProc, 0, 0, Constant.WINEVENT_OUTOFCONTEXT);
|
||||||
|
|
||||||
|
@ -262,10 +262,10 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
|
|
||||||
public IntPtr RegisterSystemCaptureStartEvent(Action<IntPtr> callback)
|
public IntPtr RegisterSystemCaptureStartEvent(Action<IntPtr> callback)
|
||||||
{
|
{
|
||||||
EventProc eventProc = (IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) =>
|
void eventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||||
{
|
{
|
||||||
callback(hwnd);
|
callback(hwnd);
|
||||||
};
|
}
|
||||||
|
|
||||||
var handle = User32.SetWinEventHook(Constant.EVENT_SYSTEM_CAPTURESTART, Constant.EVENT_SYSTEM_CAPTURESTART, IntPtr.Zero, eventProc, 0, 0, Constant.WINEVENT_OUTOFCONTEXT);
|
var handle = User32.SetWinEventHook(Constant.EVENT_SYSTEM_CAPTURESTART, Constant.EVENT_SYSTEM_CAPTURESTART, IntPtr.Zero, eventProc, 0, 0, Constant.WINEVENT_OUTOFCONTEXT);
|
||||||
|
|
||||||
|
|
27
SafeExamBrowser.WindowsApi/Process.cs
Normal file
27
SafeExamBrowser.WindowsApi/Process.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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.WindowsApi;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.WindowsApi
|
||||||
|
{
|
||||||
|
internal class Process : IProcess
|
||||||
|
{
|
||||||
|
private System.Diagnostics.Process process;
|
||||||
|
|
||||||
|
public int Id
|
||||||
|
{
|
||||||
|
get { return process.Id; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Process(int id)
|
||||||
|
{
|
||||||
|
process = System.Diagnostics.Process.GetProcessById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
SafeExamBrowser.WindowsApi/ProcessFactory.cs
Normal file
60
SafeExamBrowser.WindowsApi/ProcessFactory.cs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* 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 System.ComponentModel;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
|
using SafeExamBrowser.WindowsApi.Constants;
|
||||||
|
using SafeExamBrowser.WindowsApi.Types;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.WindowsApi
|
||||||
|
{
|
||||||
|
public class ProcessFactory : IProcessFactory
|
||||||
|
{
|
||||||
|
private IDesktop desktop;
|
||||||
|
private ILogger logger;
|
||||||
|
|
||||||
|
public ProcessFactory(IDesktop desktop, ILogger logger)
|
||||||
|
{
|
||||||
|
this.desktop = desktop;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IProcess StartNew(string path, params string[] args)
|
||||||
|
{
|
||||||
|
var processInfo = new PROCESS_INFORMATION();
|
||||||
|
var processAttributes = new SECURITY_ATTRIBUTES();
|
||||||
|
var threadAttributes = new SECURITY_ATTRIBUTES();
|
||||||
|
var startupInfo = new STARTUPINFO();
|
||||||
|
|
||||||
|
startupInfo.cb = Marshal.SizeOf(startupInfo);
|
||||||
|
startupInfo.lpDesktop = desktop.CurrentName;
|
||||||
|
|
||||||
|
var success = Kernel32.CreateProcess(
|
||||||
|
null,
|
||||||
|
path,
|
||||||
|
ref processAttributes,
|
||||||
|
ref threadAttributes,
|
||||||
|
true,
|
||||||
|
Constant.NORMAL_PRIORITY_CLASS,
|
||||||
|
IntPtr.Zero,
|
||||||
|
null,
|
||||||
|
ref startupInfo,
|
||||||
|
out processInfo);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Process(processInfo.dwProcessId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,7 +54,10 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Constants\Constant.cs" />
|
<Compile Include="Constants\Constant.cs" />
|
||||||
<Compile Include="Constants\HookType.cs" />
|
<Compile Include="Constants\HookType.cs" />
|
||||||
|
<Compile Include="Desktop.cs" />
|
||||||
<Compile Include="Monitoring\MouseHook.cs" />
|
<Compile Include="Monitoring\MouseHook.cs" />
|
||||||
|
<Compile Include="Process.cs" />
|
||||||
|
<Compile Include="ProcessFactory.cs" />
|
||||||
<Compile Include="Types\Bounds.cs" />
|
<Compile Include="Types\Bounds.cs" />
|
||||||
<Compile Include="Types\EXECUTION_STATE.cs" />
|
<Compile Include="Types\EXECUTION_STATE.cs" />
|
||||||
<Compile Include="Types\KBDLLHOOKSTRUCT.cs" />
|
<Compile Include="Types\KBDLLHOOKSTRUCT.cs" />
|
||||||
|
@ -69,7 +72,10 @@
|
||||||
<Compile Include="Constants\SPIF.cs" />
|
<Compile Include="Constants\SPIF.cs" />
|
||||||
<Compile Include="Types\MSLLHOOKSTRUCT.cs" />
|
<Compile Include="Types\MSLLHOOKSTRUCT.cs" />
|
||||||
<Compile Include="Types\POINT.cs" />
|
<Compile Include="Types\POINT.cs" />
|
||||||
|
<Compile Include="Types\PROCESS_INFORMATION.cs" />
|
||||||
<Compile Include="Types\RECT.cs" />
|
<Compile Include="Types\RECT.cs" />
|
||||||
|
<Compile Include="Types\SECURITY_ATTRIBUTES.cs" />
|
||||||
|
<Compile Include="Types\STARTUPINFO.cs" />
|
||||||
<Compile Include="User32.cs" />
|
<Compile Include="User32.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
26
SafeExamBrowser.WindowsApi/Types/PROCESS_INFORMATION.cs
Normal file
26
SafeExamBrowser.WindowsApi/Types/PROCESS_INFORMATION.cs
Normal file
|
@ -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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.WindowsApi.Types
|
||||||
|
{
|
||||||
|
/// <remarks>
|
||||||
|
/// See http://pinvoke.net/default.aspx/Structures/PROCESS_INFORMATION.html.
|
||||||
|
/// See https://msdn.microsoft.com/en-us/library/ms684873(VS.85).aspx.
|
||||||
|
/// </remarks>
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct PROCESS_INFORMATION
|
||||||
|
{
|
||||||
|
public IntPtr hProcess;
|
||||||
|
public IntPtr hThread;
|
||||||
|
public int dwProcessId;
|
||||||
|
public int dwThreadId;
|
||||||
|
}
|
||||||
|
}
|
25
SafeExamBrowser.WindowsApi/Types/SECURITY_ATTRIBUTES.cs
Normal file
25
SafeExamBrowser.WindowsApi/Types/SECURITY_ATTRIBUTES.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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 System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.WindowsApi.Types
|
||||||
|
{
|
||||||
|
/// <remarks>
|
||||||
|
/// See http://pinvoke.net/default.aspx/Structures/SECURITY_ATTRIBUTES.html.
|
||||||
|
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560(v=vs.85).aspx.
|
||||||
|
/// </remarks>
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct SECURITY_ATTRIBUTES
|
||||||
|
{
|
||||||
|
public int nLength;
|
||||||
|
public IntPtr lpSecurityDescriptor;
|
||||||
|
public int bInheritHandle;
|
||||||
|
}
|
||||||
|
}
|
39
SafeExamBrowser.WindowsApi/Types/STARTUPINFO.cs
Normal file
39
SafeExamBrowser.WindowsApi/Types/STARTUPINFO.cs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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 System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.WindowsApi.Types
|
||||||
|
{
|
||||||
|
/// <remarks>
|
||||||
|
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspx.
|
||||||
|
/// </remarks>
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct STARTUPINFO
|
||||||
|
{
|
||||||
|
public int cb;
|
||||||
|
public string lpReserved;
|
||||||
|
public string lpDesktop;
|
||||||
|
public string lpTitle;
|
||||||
|
public int dwX;
|
||||||
|
public int dwY;
|
||||||
|
public int dwXSize;
|
||||||
|
public int dwYSize;
|
||||||
|
public int dwXCountChars;
|
||||||
|
public int dwYCountChars;
|
||||||
|
public int dwFillAttribute;
|
||||||
|
public int dwFlags;
|
||||||
|
public short wShowWindow;
|
||||||
|
public short cbReserved2;
|
||||||
|
public IntPtr lpReserved2;
|
||||||
|
public IntPtr hStdInput;
|
||||||
|
public IntPtr hStdOutput;
|
||||||
|
public IntPtr hStdError;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue