From ef13cfe9c579965f9a46089e1173e467fb12267b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20B=C3=BCchel?= Date: Mon, 27 Jul 2020 15:58:30 +0200 Subject: [PATCH] SEBWIN-405: Implemented loading of server exam configuration. --- SafeExamBrowser.Runtime/CompositionRoot.cs | 5 +- .../Operations/ServerOperation.cs | 6 ++ .../SafeExamBrowser.Server.csproj | 4 + SafeExamBrowser.Server/ServerProxy.cs | 101 ++++++++++++++---- 4 files changed, 96 insertions(+), 20 deletions(-) diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index 4ed0bade..6ca5f035 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -63,11 +63,12 @@ namespace SafeExamBrowser.Runtime var uiFactory = new UserInterfaceFactory(text); var desktopFactory = new DesktopFactory(ModuleLogger(nameof(DesktopFactory))); var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods); + var fileSystem = new FileSystem(); var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory))); var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), ModuleLogger(nameof(ProxyFactory))); var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), ModuleLogger(nameof(RuntimeHost)), FIVE_SECONDS); var runtimeWindow = uiFactory.CreateRuntimeWindow(appConfig); - var server = new ServerProxy(ModuleLogger(nameof(ServerProxy))); + var server = new ServerProxy(appConfig, ModuleLogger(nameof(ServerProxy))); var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), ModuleLogger(nameof(ServiceProxy)), Interlocutor.Runtime); var sessionContext = new SessionContext(); var splashScreen = uiFactory.CreateSplashScreen(appConfig); @@ -82,7 +83,7 @@ namespace SafeExamBrowser.Runtime sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost, sessionContext)); sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new FileSystem(), new HashAlgorithm(), logger, sessionContext)); - sessionOperations.Enqueue(new ServerOperation(args, configuration, logger, sessionContext, server)); + sessionOperations.Enqueue(new ServerOperation(args, configuration, fileSystem, logger, sessionContext, server)); sessionOperations.Enqueue(new VirtualMachineOperation(vmDetector, logger, sessionContext)); sessionOperations.Enqueue(new ServiceOperation(logger, runtimeHost, serviceProxy, sessionContext, THIRTY_SECONDS, userInfo)); sessionOperations.Enqueue(new ClientTerminationOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, THIRTY_SECONDS)); diff --git a/SafeExamBrowser.Runtime/Operations/ServerOperation.cs b/SafeExamBrowser.Runtime/Operations/ServerOperation.cs index 4e3de3cd..68eb0aed 100644 --- a/SafeExamBrowser.Runtime/Operations/ServerOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/ServerOperation.cs @@ -16,11 +16,13 @@ using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Runtime.Operations.Events; using SafeExamBrowser.Server.Contracts; using SafeExamBrowser.Settings; +using SafeExamBrowser.SystemComponents.Contracts; namespace SafeExamBrowser.Runtime.Operations { internal class ServerOperation : ConfigurationBaseOperation { + private readonly IFileSystem fileSystem; private readonly ILogger logger; private readonly IServerProxy server; @@ -30,10 +32,12 @@ namespace SafeExamBrowser.Runtime.Operations public ServerOperation( string[] commandLineArgs, IConfigurationRepository configuration, + IFileSystem fileSystem, ILogger logger, SessionContext context, IServerProxy server) : base(commandLineArgs, configuration, context) { + this.fileSystem = fileSystem; this.logger = logger; this.server = server; } @@ -67,6 +71,8 @@ namespace SafeExamBrowser.Runtime.Operations { var status = TryLoadSettings(uri, UriSource.Server, out _, out var settings); + fileSystem.Delete(uri.LocalPath); + if (status == LoadStatus.Success) { Context.Next.Settings = settings; diff --git a/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj b/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj index 16f24cf8..22fc33de 100644 --- a/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj +++ b/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj @@ -63,6 +63,10 @@ + + {7d74555e-63e1-4c46-bd0a-8580552368c8} + SafeExamBrowser.Configuration.Contracts + {64ea30fb-11d4-436a-9c2b-88566285363e} SafeExamBrowser.Logging.Contracts diff --git a/SafeExamBrowser.Server/ServerProxy.cs b/SafeExamBrowser.Server/ServerProxy.cs index e5909291..0bf55d62 100644 --- a/SafeExamBrowser.Server/ServerProxy.cs +++ b/SafeExamBrowser.Server/ServerProxy.cs @@ -16,6 +16,7 @@ using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Server.Contracts; using SafeExamBrowser.Server.Data; @@ -28,13 +29,15 @@ namespace SafeExamBrowser.Server private ApiVersion1 api; private string connectionToken; private HttpClient httpClient; + private readonly AppConfig appConfig; private ILogger logger; private string oauth2Token; private ServerSettings settings; - public ServerProxy(ILogger logger) + public ServerProxy(AppConfig appConfig, ILogger logger) { this.api = new ApiVersion1(); + this.appConfig = appConfig; this.httpClient = new HttpClient(); this.logger = logger; } @@ -75,7 +78,7 @@ namespace SafeExamBrowser.Server public ServerResponse Disconnect() { - return new ServerResponse(false, "Some error message here"); + return new ServerResponse(false, "TODO!"); } public ServerResponse> GetAvailableExams() @@ -83,37 +86,69 @@ namespace SafeExamBrowser.Server var authorization = ("Authorization", $"Bearer {oauth2Token}"); var content = $"institutionId={settings.Institution}"; var contentType = "application/x-www-form-urlencoded"; + var exams = default(IList); var success = TryExecute(HttpMethod.Post, api.HandshakeEndpoint, out var response, content, contentType, authorization); var message = ToString(response); - var hasToken = TryParseConnectionToken(response); - var hasExams = TryParseExams(response.Content, out var exams); - if (success && hasExams && hasToken) + if (success) { - logger.Info("Successfully retrieved connection token and available exams."); - } - else if (!hasExams) - { - logger.Error("Failed to retrieve available exams!"); - } - else if (!hasToken) - { - logger.Error("Failed to retrieve connection token!"); + var hasExams = TryParseExams(response.Content, out exams); + var hasToken = TryParseConnectionToken(response); + + success = hasExams && hasToken; + + if (success) + { + logger.Info("Successfully retrieved connection token and available exams."); + } + else if (!hasExams) + { + logger.Error("Failed to retrieve available exams!"); + } + else if (!hasToken) + { + logger.Error("Failed to retrieve connection token!"); + } } else { logger.Error("Failed to load connection token and available exams!"); } - return new ServerResponse>(hasExams && hasToken, exams, message); + return new ServerResponse>(success, exams, message); } public ServerResponse GetConfigurationFor(Exam exam) { - // 4. Send exam ID + var authorization = ("Authorization", $"Bearer {oauth2Token}"); + var token = ("SEBConnectionToken", connectionToken); + var uri = default(Uri); - return new ServerResponse(false, default(Uri), "Some error message here"); + var success = TryExecute(HttpMethod.Get, $"{api.ConfigurationEndpoint}?examId={exam.Id}", out var response, default(string), default(string), authorization, token); + var message = ToString(response); + + if (success) + { + logger.Info("Successfully retrieved exam configuration."); + + success = TrySaveFile(response.Content, out uri); + + if (success) + { + logger.Info($"Successfully saved exam configuration as '{uri}'."); + } + else + { + logger.Error("Failed to save exam configuration!"); + } + } + else + { + logger.Error("Failed to retrieve exam configuration!"); + } + + return new ServerResponse(success, uri, message); } public void Initialize(ServerSettings settings) @@ -129,7 +164,7 @@ namespace SafeExamBrowser.Server public ServerResponse SendSessionInfo(string sessionId) { - return new ServerResponse(false, "Some error message here"); + return new ServerResponse(false, "TODO!"); } private bool TryParseApi(HttpContent content) @@ -301,6 +336,36 @@ namespace SafeExamBrowser.Server return response != default(HttpResponseMessage) && response.IsSuccessStatusCode; } + private bool TrySaveFile(HttpContent content, out Uri uri) + { + uri = new Uri(Path.Combine(appConfig.TemporaryDirectory, $"ServerExam{appConfig.ConfigurationFileExtension}")); + + try + { + var task = Task.Run(async () => + { + return await content.ReadAsStreamAsync(); + }); + + using (var data = task.GetAwaiter().GetResult()) + using (var file = new FileStream(uri.LocalPath, FileMode.Create)) + { + data.Seek(0, SeekOrigin.Begin); + data.CopyTo(file); + data.Flush(); + file.Flush(); + } + + return true; + } + catch (Exception e) + { + logger.Error($"Failed to save file '{uri.LocalPath}'!", e); + } + + return false; + } + private string Extract(HttpContent content) { var task = Task.Run(async () =>