diff --git a/SafeExamBrowser.Browser.UnitTests/Handlers/ResourceHandlerTests.cs b/SafeExamBrowser.Browser.UnitTests/Handlers/ResourceHandlerTests.cs index 4f088018..822e883c 100644 --- a/SafeExamBrowser.Browser.UnitTests/Handlers/ResourceHandlerTests.cs +++ b/SafeExamBrowser.Browser.UnitTests/Handlers/ResourceHandlerTests.cs @@ -60,8 +60,8 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers var request = new Mock(); browser.SetupGet(b => b.Address).Returns("http://www.host.org"); - keyGenerator.Setup(g => g.CalculateBrowserExamKeyHash(It.IsAny())).Returns(new Random().Next().ToString()); - keyGenerator.Setup(g => g.CalculateConfigurationKeyHash(It.IsAny())).Returns(new Random().Next().ToString()); + keyGenerator.Setup(g => g.CalculateBrowserExamKeyHash(It.IsAny(), It.IsAny(), It.IsAny())).Returns(new Random().Next().ToString()); + keyGenerator.Setup(g => g.CalculateConfigurationKeyHash(It.IsAny(), It.IsAny())).Returns(new Random().Next().ToString()); request.SetupGet(r => r.Headers).Returns(new NameValueCollection()); request.SetupGet(r => r.Url).Returns("http://www.host.org"); request.SetupSet(r => r.Headers = It.IsAny()).Callback((h) => headers = h); diff --git a/SafeExamBrowser.Browser/Handlers/RenderProcessMessageHandler.cs b/SafeExamBrowser.Browser/Handlers/RenderProcessMessageHandler.cs index 24e11acf..7c711747 100644 --- a/SafeExamBrowser.Browser/Handlers/RenderProcessMessageHandler.cs +++ b/SafeExamBrowser.Browser/Handlers/RenderProcessMessageHandler.cs @@ -34,8 +34,8 @@ namespace SafeExamBrowser.Browser.Handlers public void OnContextCreated(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame) { - var browserExamKey = keyGenerator.CalculateBrowserExamKeyHash(frame.Url); - var configurationKey = keyGenerator.CalculateConfigurationKeyHash(frame.Url); + var browserExamKey = keyGenerator.CalculateBrowserExamKeyHash(settings.ConfigurationKey, settings.BrowserExamKeySalt, frame.Url); + var configurationKey = keyGenerator.CalculateConfigurationKeyHash(settings.ConfigurationKey, frame.Url); var api = contentLoader.LoadApi(browserExamKey, configurationKey, appConfig.ProgramBuildVersion); frame.ExecuteJavaScriptAsync(api); diff --git a/SafeExamBrowser.Browser/Handlers/ResourceHandler.cs b/SafeExamBrowser.Browser/Handlers/ResourceHandler.cs index 7577be9b..35194051 100644 --- a/SafeExamBrowser.Browser/Handlers/ResourceHandler.cs +++ b/SafeExamBrowser.Browser/Handlers/ResourceHandler.cs @@ -124,12 +124,12 @@ namespace SafeExamBrowser.Browser.Handlers if (settings.SendConfigurationKey) { - headers["X-SafeExamBrowser-ConfigKeyHash"] = keyGenerator.CalculateConfigurationKeyHash(request.Url); + headers["X-SafeExamBrowser-ConfigKeyHash"] = keyGenerator.CalculateConfigurationKeyHash(settings.ConfigurationKey, request.Url); } if (settings.SendBrowserExamKey) { - headers["X-SafeExamBrowser-RequestHash"] = keyGenerator.CalculateBrowserExamKeyHash(request.Url); + headers["X-SafeExamBrowser-RequestHash"] = keyGenerator.CalculateBrowserExamKeyHash(settings.ConfigurationKey, settings.BrowserExamKeySalt, request.Url); } request.Headers = headers; diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index c4cc26ba..324baadc 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -223,7 +223,7 @@ namespace SafeExamBrowser.Client private IOperation BuildBrowserOperation() { var fileSystemDialog = BuildFileSystemDialog(); - var keyGenerator = new KeyGenerator(context.AppConfig, context.IntegrityModule, ModuleLogger(nameof(KeyGenerator)), context.Settings); + var keyGenerator = new KeyGenerator(context.AppConfig, context.IntegrityModule, ModuleLogger(nameof(KeyGenerator))); var moduleLogger = ModuleLogger(nameof(BrowserApplication)); var browser = new BrowserApplication( context.AppConfig, @@ -287,7 +287,8 @@ namespace SafeExamBrowser.Client private IOperation BuildServerOperation() { - var server = new ServerProxy(context.AppConfig, ModuleLogger(nameof(ServerProxy)), systemInfo, userInfo, powerSupply, networkAdapter); + var keyGenerator = new KeyGenerator(context.AppConfig, context.IntegrityModule, ModuleLogger(nameof(KeyGenerator))); + var server = new ServerProxy(context.AppConfig, keyGenerator, ModuleLogger(nameof(ServerProxy)), systemInfo, userInfo, powerSupply, networkAdapter); var operation = new ServerOperation(context, logger, server); context.Server = server; diff --git a/SafeExamBrowser.Configuration.Contracts/Cryptography/IKeyGenerator.cs b/SafeExamBrowser.Configuration.Contracts/Cryptography/IKeyGenerator.cs index d374263e..657ac731 100644 --- a/SafeExamBrowser.Configuration.Contracts/Cryptography/IKeyGenerator.cs +++ b/SafeExamBrowser.Configuration.Contracts/Cryptography/IKeyGenerator.cs @@ -13,14 +13,19 @@ namespace SafeExamBrowser.Configuration.Contracts.Cryptography /// public interface IKeyGenerator { + /// + /// Calculates the encrypted value of the app signature key. + /// + string CalculateAppSignatureKey(string connectionToken, string salt); + /// /// Calculates the hash value of the browser exam key (BEK) for the given URL. /// - string CalculateBrowserExamKeyHash(string url); + string CalculateBrowserExamKeyHash(string configurationKey, byte[] salt, string url); /// /// Calculates the hash value of the configuration key (CK) for the given URL. /// - string CalculateConfigurationKeyHash(string url); + string CalculateConfigurationKeyHash(string configurationKey, string url); } } diff --git a/SafeExamBrowser.Configuration.Contracts/Integrity/IIntegrityModule.cs b/SafeExamBrowser.Configuration.Contracts/Integrity/IIntegrityModule.cs index efdcd49d..6370c5c2 100644 --- a/SafeExamBrowser.Configuration.Contracts/Integrity/IIntegrityModule.cs +++ b/SafeExamBrowser.Configuration.Contracts/Integrity/IIntegrityModule.cs @@ -23,6 +23,11 @@ namespace SafeExamBrowser.Configuration.Contracts.Integrity /// void ClearSession(string configurationKey, string startUrl); + /// + /// Attempts to calculate the app signature key. + /// + bool TryCalculateAppSignatureKey(string connectionToken, string salt, out string appSignatureKey); + /// /// Attempts to calculate the browser exam key. /// diff --git a/SafeExamBrowser.Configuration/Cryptography/KeyGenerator.cs b/SafeExamBrowser.Configuration/Cryptography/KeyGenerator.cs index 34b4053c..03530c10 100644 --- a/SafeExamBrowser.Configuration/Cryptography/KeyGenerator.cs +++ b/SafeExamBrowser.Configuration/Cryptography/KeyGenerator.cs @@ -13,7 +13,6 @@ using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Configuration.Contracts.Cryptography; using SafeExamBrowser.Configuration.Contracts.Integrity; using SafeExamBrowser.Logging.Contracts; -using SafeExamBrowser.Settings; namespace SafeExamBrowser.Configuration.Cryptography { @@ -25,42 +24,51 @@ namespace SafeExamBrowser.Configuration.Cryptography private readonly AppConfig appConfig; private readonly IIntegrityModule integrityModule; private readonly ILogger logger; - private readonly AppSettings settings; private string browserExamKey; - public KeyGenerator(AppConfig appConfig, IIntegrityModule integrityModule, ILogger logger, AppSettings settings) + public KeyGenerator(AppConfig appConfig, IIntegrityModule integrityModule, ILogger logger) { this.algorithm = new SHA256Managed(); this.appConfig = appConfig; this.integrityModule = integrityModule; this.logger = logger; - this.settings = settings; } - public string CalculateBrowserExamKeyHash(string url) + public string CalculateAppSignatureKey(string connectionToken, string salt) + { + if (integrityModule.TryCalculateAppSignatureKey(connectionToken, salt, out var appSignatureKey)) + { + logger.Debug("Successfully calculated app signature key using integrity module."); + } + else + { + logger.Error("Failed to calculate app signature key using integrity module!"); + } + + return appSignatureKey; + } + + public string CalculateBrowserExamKeyHash(string configurationKey, byte[] salt, string url) { var urlWithoutFragment = url.Split('#')[0]; - var hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(urlWithoutFragment + (browserExamKey ?? ComputeBrowserExamKey()))); + var hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(urlWithoutFragment + (browserExamKey ?? ComputeBrowserExamKey(configurationKey, salt)))); var key = ToString(hash); return key; } - public string CalculateConfigurationKeyHash(string url) + public string CalculateConfigurationKeyHash(string configurationKey, string url) { var urlWithoutFragment = url.Split('#')[0]; - var hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(urlWithoutFragment + settings.Browser.ConfigurationKey)); + var hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(urlWithoutFragment + configurationKey)); var key = ToString(hash); return key; } - private string ComputeBrowserExamKey() + private string ComputeBrowserExamKey(string configurationKey, byte[] salt) { - var configurationKey = settings.Browser.ConfigurationKey; - var salt = settings.Browser.BrowserExamKeySalt; - lock (@lock) { if (browserExamKey == default) @@ -81,11 +89,11 @@ namespace SafeExamBrowser.Configuration.Cryptography if (integrityModule.TryCalculateBrowserExamKey(configurationKey, ToString(salt), out browserExamKey)) { - logger.Debug("Successfully calculated BEK using integrity module."); + logger.Debug("Successfully calculated browser exam key using integrity module."); } else { - logger.Warn("Failed to calculate BEK using integrity module! Falling back to simplified calculation..."); + logger.Warn("Failed to calculate browser exam key using integrity module! Falling back to simplified calculation..."); using (var algorithm = new HMACSHA256(salt)) { diff --git a/SafeExamBrowser.Configuration/Integrity/IntegrityModule.cs b/SafeExamBrowser.Configuration/Integrity/IntegrityModule.cs index adccc846..7eb25d1b 100644 --- a/SafeExamBrowser.Configuration/Integrity/IntegrityModule.cs +++ b/SafeExamBrowser.Configuration/Integrity/IntegrityModule.cs @@ -74,6 +74,26 @@ namespace SafeExamBrowser.Configuration.Integrity } } + public bool TryCalculateAppSignatureKey(string connectionToken, string salt, out string appSignatureKey) + { + appSignatureKey = default; + + try + { + appSignatureKey = CalculateAppSignatureKey(connectionToken, salt); + } + catch (DllNotFoundException) + { + logger.Warn("Integrity module is not available!"); + } + catch (Exception e) + { + logger.Error("Unexpected error while attempting to calculate app signature key!", e); + } + + return appSignatureKey != default; + } + public bool TryCalculateBrowserExamKey(string configurationKey, string salt, out string browserExamKey) { browserExamKey = default; @@ -214,6 +234,10 @@ namespace SafeExamBrowser.Configuration.Integrity return success; } + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.BStr)] + private static extern string CalculateAppSignatureKey(string connectionToken, string salt); + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.BStr)] private static extern string CalculateBrowserExamKey(string configurationKey, string salt); diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/ServerOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/ServerOperationTests.cs index dfc03ef1..12c7abfc 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Operations/ServerOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Operations/ServerOperationTests.cs @@ -80,6 +80,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations server.Setup(s => s.Connect()).Returns(new ServerResponse(true)).Callback(() => connect = ++counter); server.Setup(s => s.Initialize(It.IsAny())).Callback(() => initialize = ++counter); server.Setup(s => s.GetConnectionInfo()).Returns(connection).Callback(() => getConnection = ++counter); + server.Setup(s => s.SendSelectedExam(It.IsAny())).Returns(new ServerResponse(true)); server .Setup(s => s.GetAvailableExams(It.IsAny())) .Returns(new ServerResponse>(true, default(IEnumerable))) @@ -106,6 +107,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations server.Verify(s => s.GetAvailableExams(It.IsAny()), Times.Once); server.Verify(s => s.GetConfigurationFor(It.Is(e => e == exam)), Times.Once); server.Verify(s => s.GetConnectionInfo(), Times.Once); + server.Verify(s => s.SendSelectedExam(It.Is(e => e == exam)), Times.Once); Assert.AreEqual(1, initialize); Assert.AreEqual(2, connect); @@ -274,6 +276,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations server.Setup(s => s.GetConnectionInfo()).Returns(connection); server.Setup(s => s.GetAvailableExams(It.IsAny())).Returns(new ServerResponse>(true, new[] { exam })); server.Setup(s => s.GetConfigurationFor(It.IsAny())).Returns(new ServerResponse(true, new Uri("file:///configuration.seb"))); + server.Setup(s => s.SendSelectedExam(It.IsAny())).Returns(new ServerResponse(true)); sut.ActionRequired += (args) => Assert.Fail(); var result = sut.Perform(); @@ -284,6 +287,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations server.Verify(s => s.GetAvailableExams(It.IsAny()), Times.Once); server.Verify(s => s.GetConfigurationFor(It.Is(e => e == exam)), Times.Once); server.Verify(s => s.GetConnectionInfo(), Times.Once); + server.Verify(s => s.SendSelectedExam(It.Is(e => e == exam)), Times.Once); Assert.AreEqual(OperationResult.Success, result); } @@ -332,6 +336,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations server.Setup(s => s.Connect()).Returns(new ServerResponse(true)).Callback(() => connect = ++counter); server.Setup(s => s.Initialize(It.IsAny())).Callback(() => initialize = ++counter); server.Setup(s => s.GetConnectionInfo()).Returns(connection).Callback(() => getConnection = ++counter); + server.Setup(s => s.SendSelectedExam(It.IsAny())).Returns(new ServerResponse(true)); server .Setup(s => s.GetAvailableExams(It.IsAny())) .Returns(new ServerResponse>(true, default(IEnumerable))) @@ -358,6 +363,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations server.Verify(s => s.GetAvailableExams(It.IsAny()), Times.Once); server.Verify(s => s.GetConfigurationFor(It.Is(e => e == exam)), Times.Once); server.Verify(s => s.GetConnectionInfo(), Times.Once); + server.Verify(s => s.SendSelectedExam(It.Is(e => e == exam)), Times.Once); Assert.AreEqual(1, initialize); Assert.AreEqual(2, connect); @@ -526,6 +532,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations server.Setup(s => s.GetConnectionInfo()).Returns(connection); server.Setup(s => s.GetAvailableExams(It.IsAny())).Returns(new ServerResponse>(true, new[] { exam })); server.Setup(s => s.GetConfigurationFor(It.IsAny())).Returns(new ServerResponse(true, new Uri("file:///configuration.seb"))); + server.Setup(s => s.SendSelectedExam(It.IsAny())).Returns(new ServerResponse(true)); sut.ActionRequired += (args) => Assert.Fail(); var result = sut.Repeat(); @@ -536,6 +543,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations server.Verify(s => s.GetAvailableExams(It.IsAny()), Times.Once); server.Verify(s => s.GetConfigurationFor(It.Is(e => e == exam)), Times.Once); server.Verify(s => s.GetConnectionInfo(), Times.Once); + server.Verify(s => s.SendSelectedExam(It.Is(e => e == exam)), Times.Once); Assert.AreEqual(OperationResult.Success, result); } diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index dff10cd2..552e003f 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -71,6 +71,7 @@ namespace SafeExamBrowser.Runtime var displayMonitor = new DisplayMonitor(ModuleLogger(nameof(DisplayMonitor)), nativeMethods, systemInfo); var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods); var fileSystem = new FileSystem(); + var keyGenerator = new KeyGenerator(appConfig, integrityModule, ModuleLogger(nameof(KeyGenerator))); var messageBox = new MessageBoxFactory(text); var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory))); var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), ModuleLogger(nameof(ProxyFactory))); @@ -78,7 +79,7 @@ namespace SafeExamBrowser.Runtime var remoteSessionDetector = new RemoteSessionDetector(ModuleLogger(nameof(RemoteSessionDetector))); var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), ModuleLogger(nameof(RuntimeHost)), FIVE_SECONDS); var runtimeWindow = uiFactory.CreateRuntimeWindow(appConfig); - var server = new ServerProxy(appConfig, ModuleLogger(nameof(ServerProxy)), systemInfo, userInfo); + var server = new ServerProxy(appConfig, keyGenerator, ModuleLogger(nameof(ServerProxy)), systemInfo, userInfo); var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), ModuleLogger(nameof(ServiceProxy)), Interlocutor.Runtime); var sessionContext = new SessionContext(); var splashScreen = uiFactory.CreateSplashScreen(appConfig); diff --git a/SafeExamBrowser.Server/Requests/AppSignatureKeyRequest.cs b/SafeExamBrowser.Server/Requests/AppSignatureKeyRequest.cs index 773070e5..0ab371bf 100644 --- a/SafeExamBrowser.Server/Requests/AppSignatureKeyRequest.cs +++ b/SafeExamBrowser.Server/Requests/AppSignatureKeyRequest.cs @@ -24,9 +24,9 @@ namespace SafeExamBrowser.Server.Requests { } - internal bool TryExecute(out string message) + internal bool TryExecute(string appSignatureKey, out string message) { - var content = $"seb_signature_key={"WINDOWS-TEST-ASK-1234"}"; + var content = $"seb_signature_key={appSignatureKey}"; var success = TryExecute(new HttpMethod("PATCH"), api.HandshakeEndpoint, out var response, content, ContentType.URL_ENCODED, Authorization, Token); message = response.ToLogString(); diff --git a/SafeExamBrowser.Server/Requests/NetworkAdapterRequest.cs b/SafeExamBrowser.Server/Requests/NetworkAdapterRequest.cs index c5c025e9..b0a3ceba 100644 --- a/SafeExamBrowser.Server/Requests/NetworkAdapterRequest.cs +++ b/SafeExamBrowser.Server/Requests/NetworkAdapterRequest.cs @@ -13,6 +13,7 @@ using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Server.Data; using SafeExamBrowser.Settings.Logging; using SafeExamBrowser.Settings.Server; +using SafeExamBrowser.SystemComponents.Contracts.Network; namespace SafeExamBrowser.Server.Requests { @@ -27,22 +28,24 @@ namespace SafeExamBrowser.Server.Requests { } - internal bool TryExecute(string text, int? value = default) + internal bool TryExecute(IWirelessNetwork network, out string message) { var json = new JObject { - ["text"] = text, + ["text"] = network != default ? $" {network.Name}: {network.Status}, {network.SignalStrength}%" : " not connected", ["timestamp"] = DateTime.Now.ToUnixTimestamp(), ["type"] = LogLevel.Info.ToLogType() }; - if (value != default) + if (network != default) { - json["numericValue"] = value.Value; + json["numericValue"] = network.SignalStrength; } var success = TryExecute(HttpMethod.Post, api.LogEndpoint, out var response, json.ToString(), ContentType.JSON, Authorization, Token); + message = response.ToLogString(); + return success; } } diff --git a/SafeExamBrowser.Server/Requests/PowerSupplyRequest.cs b/SafeExamBrowser.Server/Requests/PowerSupplyRequest.cs index bcf4f48d..d9ab5b87 100644 --- a/SafeExamBrowser.Server/Requests/PowerSupplyRequest.cs +++ b/SafeExamBrowser.Server/Requests/PowerSupplyRequest.cs @@ -13,6 +13,7 @@ using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Server.Data; using SafeExamBrowser.Settings.Logging; using SafeExamBrowser.Settings.Server; +using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; namespace SafeExamBrowser.Server.Requests { @@ -27,8 +28,24 @@ namespace SafeExamBrowser.Server.Requests { } - internal bool TryExecute(string text, int value) + internal bool TryExecute(IPowerSupplyStatus status, bool previouslyConnected, int previousValue, out string message) { + var connected = status.IsOnline; + var text = default(string); + var value = Convert.ToInt32(status.BatteryCharge * 100); + + if (value != previousValue) + { + var chargeInfo = $"{status.BatteryChargeStatus} at {value}%"; + var gridInfo = $"{(connected ? "connected to" : "disconnected from")} the power grid"; + + text = $" {chargeInfo}, {status.BatteryTimeRemaining} remaining, {gridInfo}"; + } + else if (connected != previouslyConnected) + { + text = $" Device has been {(connected ? "connected to" : "disconnected from")} power grid"; + } + var json = new JObject { ["numericValue"] = value, @@ -37,7 +54,9 @@ namespace SafeExamBrowser.Server.Requests ["type"] = LogLevel.Info.ToLogType() }; - var success = TryExecute(HttpMethod.Post, api.LogEndpoint, out _, json.ToString(), ContentType.JSON, Authorization, Token); + var success = TryExecute(HttpMethod.Post, api.LogEndpoint, out var response, json.ToString(), ContentType.JSON, Authorization, Token); + + message = response.ToLogString(); return success; } diff --git a/SafeExamBrowser.Server/ServerProxy.cs b/SafeExamBrowser.Server/ServerProxy.cs index 2bfad729..a0c987bb 100644 --- a/SafeExamBrowser.Server/ServerProxy.cs +++ b/SafeExamBrowser.Server/ServerProxy.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using System.Timers; using Newtonsoft.Json; using SafeExamBrowser.Configuration.Contracts; +using SafeExamBrowser.Configuration.Contracts.Cryptography; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Server.Contracts; using SafeExamBrowser.Server.Contracts.Data; @@ -34,6 +35,7 @@ namespace SafeExamBrowser.Server private readonly AppConfig appConfig; private readonly FileSystem fileSystem; private readonly ConcurrentQueue instructionConfirmations; + private readonly IKeyGenerator keyGenerator; private readonly ILogger logger; private readonly ConcurrentQueue logContent; private readonly Timer logTimer; @@ -45,16 +47,16 @@ namespace SafeExamBrowser.Server private readonly INetworkAdapter networkAdapter; private ApiVersion1 api; - private bool connectedToPowergrid; private int currentHandId; private int currentLockScreenId; - private int currentPowerSupplyValue; - private int currentWlanValue; private string examId; private HttpClient httpClient; private int notificationId; private int pingNumber; + private bool powerSupplyConnected; + private int powerSupplyValue; private ServerSettings settings; + private int wirelessNetworkValue; public event ServerEventHandler HandConfirmed; public event ServerEventHandler LockScreenConfirmed; @@ -65,6 +67,7 @@ namespace SafeExamBrowser.Server public ServerProxy( AppConfig appConfig, + IKeyGenerator keyGenerator, ILogger logger, ISystemInfo systemInfo, IUserInfo userInfo, @@ -73,6 +76,7 @@ namespace SafeExamBrowser.Server { this.api = new ApiVersion1(); this.appConfig = appConfig; + this.keyGenerator = keyGenerator; this.fileSystem = new FileSystem(appConfig, logger); this.instructionConfirmations = new ConcurrentQueue(); this.logger = logger; @@ -291,7 +295,7 @@ namespace SafeExamBrowser.Server if (success && salt != default) { logger.Info("App signature key salt detected, performing key exchange..."); - success = TrySendAppSignatureKey(out message); + success = TrySendAppSignatureKey(salt, out message); } else { @@ -425,23 +429,22 @@ namespace SafeExamBrowser.Server { var connected = status.IsOnline; var value = Convert.ToInt32(status.BatteryCharge * 100); - var text = default(string); - if (value != currentPowerSupplyValue) + if (powerSupplyConnected != connected || powerSupplyValue != value) { - var chargeInfo = $"{status.BatteryChargeStatus} at {value}%"; - var gridInfo = $"{(status.IsOnline ? "connected to" : "disconnected from")} the power grid"; + var request = new PowerSupplyRequest(api, httpClient, logger, parser, settings); + var success = request.TryExecute(status, powerSupplyConnected, powerSupplyValue, out var message); - currentPowerSupplyValue = value; - text = $" {chargeInfo}, {status.BatteryTimeRemaining} remaining, {gridInfo}"; + if (success) + { + powerSupplyConnected = connected; + powerSupplyValue = value; + } + else + { + logger.Warn($"Failed to send power supply status! {message}"); + } } - else if (connected != connectedToPowergrid) - { - connectedToPowergrid = connected; - text = $" Device has been {(connected ? "connected to" : "disconnected from")} power grid"; - } - - new PowerSupplyRequest(api, httpClient, logger, parser, settings).TryExecute(text, value); } catch (Exception e) { @@ -457,23 +460,19 @@ namespace SafeExamBrowser.Server { var network = networkAdapter.GetWirelessNetworks().FirstOrDefault(n => n.Status == ConnectionStatus.Connected); - if (network?.SignalStrength != currentWlanValue) + if (network?.SignalStrength != wirelessNetworkValue) { - var text = default(string); - var value = default(int?); + var request = new NetworkAdapterRequest(api, httpClient, logger, parser, settings); + var success = request.TryExecute(network, out var message); - if (network != default(IWirelessNetwork)) + if (success) { - text = $" {network.Name}: {network.Status}, {network.SignalStrength}%"; - value = network.SignalStrength; + wirelessNetworkValue = network?.SignalStrength ?? NOT_CONNECTED; } else { - text = " not connected"; + logger.Warn($"Failed to send wireless status! {message}"); } - - new NetworkAdapterRequest(api, httpClient, logger, parser, settings).TryExecute(text, value); - currentWlanValue = network?.SignalStrength ?? NOT_CONNECTED; } } catch (Exception e) @@ -507,13 +506,11 @@ namespace SafeExamBrowser.Server } } - private bool TrySendAppSignatureKey(out string message) + private bool TrySendAppSignatureKey(string salt, out string message) { - // TODO: - // keyGenerator.CalculateAppSignatureKey(configurationKey, server.AppSignatureKeySalt) - + var appSignatureKey = keyGenerator.CalculateAppSignatureKey(BaseRequest.ConnectionToken, salt); var request = new AppSignatureKeyRequest(api, httpClient, logger, parser, settings); - var success = request.TryExecute(out message); + var success = request.TryExecute(appSignatureKey, out message); if (success) {