diff --git a/SafeExamBrowser.Browser.Contracts/Events/SessionIdentifierDetectedEventHandler.cs b/SafeExamBrowser.Browser.Contracts/Events/SessionIdentifierDetectedEventHandler.cs
new file mode 100644
index 00000000..f56674fb
--- /dev/null
+++ b/SafeExamBrowser.Browser.Contracts/Events/SessionIdentifierDetectedEventHandler.cs
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2020 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.Browser.Contracts.Events
+{
+ ///
+ /// Event handler used to indicate that the browser has detected a session identifier of a LMS.
+ ///
+ public delegate void SessionIdentifierDetectedEventHandler(string identifier);
+}
diff --git a/SafeExamBrowser.Browser.Contracts/IBrowserApplication.cs b/SafeExamBrowser.Browser.Contracts/IBrowserApplication.cs
index 6b8965e9..dbce4df4 100644
--- a/SafeExamBrowser.Browser.Contracts/IBrowserApplication.cs
+++ b/SafeExamBrowser.Browser.Contracts/IBrowserApplication.cs
@@ -21,6 +21,11 @@ namespace SafeExamBrowser.Browser.Contracts
///
event DownloadRequestedEventHandler ConfigurationDownloadRequested;
+ ///
+ /// Event fired when the browser application detects a session identifier of an LMS.
+ ///
+ event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
+
///
/// Event fired when the browser application detects a request to terminate SEB.
///
diff --git a/SafeExamBrowser.Browser.Contracts/SafeExamBrowser.Browser.Contracts.csproj b/SafeExamBrowser.Browser.Contracts/SafeExamBrowser.Browser.Contracts.csproj
index 9702d106..542024a9 100644
--- a/SafeExamBrowser.Browser.Contracts/SafeExamBrowser.Browser.Contracts.csproj
+++ b/SafeExamBrowser.Browser.Contracts/SafeExamBrowser.Browser.Contracts.csproj
@@ -57,6 +57,7 @@
+
diff --git a/SafeExamBrowser.Browser/BrowserApplication.cs b/SafeExamBrowser.Browser/BrowserApplication.cs
index c3b7869e..cc08a4c8 100644
--- a/SafeExamBrowser.Browser/BrowserApplication.cs
+++ b/SafeExamBrowser.Browser/BrowserApplication.cs
@@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Timers;
using CefSharp;
using CefSharp.WinForms;
using SafeExamBrowser.Applications.Contracts;
@@ -39,8 +40,10 @@ namespace SafeExamBrowser.Browser
private IFileSystemDialog fileSystemDialog;
private IMessageBox messageBox;
private IModuleLogger logger;
+ private List sessionCookies;
private BrowserSettings settings;
private IText text;
+ private Timer timer;
private IUserInterfaceFactory uiFactory;
public bool AutoStart { get; private set; }
@@ -50,8 +53,9 @@ namespace SafeExamBrowser.Browser
public string Tooltip { get; private set; }
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
- public event WindowsChangedEventHandler WindowsChanged;
+ public event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
public event TerminationRequestedEventHandler TerminationRequested;
+ public event WindowsChangedEventHandler WindowsChanged;
public BrowserApplication(
AppConfig appConfig,
@@ -67,8 +71,10 @@ namespace SafeExamBrowser.Browser
this.instances = new List();
this.logger = logger;
this.messageBox = messageBox;
+ this.sessionCookies = new List();
this.settings = settings;
this.text = text;
+ this.timer = new Timer();
this.uiFactory = uiFactory;
}
@@ -104,12 +110,15 @@ namespace SafeExamBrowser.Browser
public void Start()
{
CreateNewInstance();
+ StartMonitoringCookies();
}
public void Terminate()
{
logger.Info("Initiating termination...");
+ StopMonitoringCookies();
+
foreach (var instance in instances)
{
instance.Terminated -= Instance_Terminated;
@@ -294,6 +303,19 @@ namespace SafeExamBrowser.Browser
return userAgent;
}
+ private void StartMonitoringCookies()
+ {
+ timer.AutoReset = false;
+ timer.Interval = 1000;
+ timer.Elapsed += Timer_Elapsed;
+ timer.Start();
+ }
+
+ private void StopMonitoringCookies()
+ {
+ timer.Stop();
+ }
+
private string ToScheme(ProxyProtocol protocol)
{
switch (protocol)
@@ -322,5 +344,35 @@ namespace SafeExamBrowser.Browser
instances.Remove(instances.First(i => i.Id == id));
WindowsChanged?.Invoke();
}
+
+ private void Timer_Elapsed(object sender, ElapsedEventArgs args)
+ {
+ try
+ {
+ var manager = Cef.GetGlobalCookieManager();
+ var task = manager.VisitAllCookiesAsync();
+ var cookies = task.GetAwaiter().GetResult();
+ var edxLogin = cookies.FirstOrDefault(c => c.Name == "edxloggedin");
+
+ // TODO: MoodleSession
+
+ if (edxLogin != default(Cookie))
+ {
+ var edxSession = cookies.FirstOrDefault(c => c.Domain == edxLogin.Domain && c.Name == "sessionid");
+
+ if (edxSession != default(Cookie) && !sessionCookies.Contains(edxSession.Domain))
+ {
+ sessionCookies.Add(edxSession.Domain);
+ SessionIdentifierDetected?.Invoke(edxSession.Value);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ logger.Error("Failed to read cookies!", e);
+ }
+
+ timer.Start();
+ }
}
}
diff --git a/SafeExamBrowser.Client/ClientContext.cs b/SafeExamBrowser.Client/ClientContext.cs
index 901bf1e7..c38865d6 100644
--- a/SafeExamBrowser.Client/ClientContext.cs
+++ b/SafeExamBrowser.Client/ClientContext.cs
@@ -49,7 +49,7 @@ namespace SafeExamBrowser.Client
internal IClientHost ClientHost { get; set; }
///
- /// The server proxy, if the current session mode is .
+ /// The server proxy (if the current session mode is ).
///
internal IServerProxy Server { get; set; }
diff --git a/SafeExamBrowser.Client/ClientController.cs b/SafeExamBrowser.Client/ClientController.cs
index 86ca9047..70777f35 100644
--- a/SafeExamBrowser.Client/ClientController.cs
+++ b/SafeExamBrowser.Client/ClientController.cs
@@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Threading;
using SafeExamBrowser.Applications.Contracts;
using SafeExamBrowser.Browser.Contracts;
using SafeExamBrowser.Browser.Contracts.Events;
@@ -183,6 +184,7 @@ namespace SafeExamBrowser.Client
applicationMonitor.ExplorerStarted += ApplicationMonitor_ExplorerStarted;
applicationMonitor.TerminationFailed += ApplicationMonitor_TerminationFailed;
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
+ Browser.SessionIdentifierDetected += Browser_SessionIdentifierDetected;
Browser.TerminationRequested += Browser_TerminationRequested;
ClientHost.MessageBoxRequested += ClientHost_MessageBoxRequested;
ClientHost.PasswordRequested += ClientHost_PasswordRequested;
@@ -218,6 +220,8 @@ namespace SafeExamBrowser.Client
if (Browser != null)
{
Browser.ConfigurationDownloadRequested -= Browser_ConfigurationDownloadRequested;
+ Browser.SessionIdentifierDetected -= Browser_SessionIdentifierDetected;
+ Browser.TerminationRequested -= Browser_TerminationRequested;
}
if (ClientHost != null)
@@ -341,6 +345,24 @@ namespace SafeExamBrowser.Client
}
}
+ private void Browser_SessionIdentifierDetected(string identifier)
+ {
+ if (Settings.SessionMode == SessionMode.Server)
+ {
+ var response = Server.SendSessionIdentifier(identifier);
+
+ while (!response.Success)
+ {
+ logger.Error($"Failed to communicate session identifier with server! {response.Message}");
+ // TODO: Check that is running in separat thread (not UI thread!!) or use different mechanism to wait!
+ Thread.Sleep(Settings.Server.RequestAttemptInterval);
+ response = Server.SendSessionIdentifier(identifier);
+ }
+
+ Server.StartConnectivity();
+ }
+ }
+
private void Browser_TerminationRequested()
{
logger.Info("Attempting to shutdown as requested by the browser...");
diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs
index 34936310..4b0f0e0f 100644
--- a/SafeExamBrowser.Client/CompositionRoot.cs
+++ b/SafeExamBrowser.Client/CompositionRoot.cs
@@ -244,6 +244,8 @@ namespace SafeExamBrowser.Client
var server = new ServerProxy(context.AppConfig, logger);
var operation = new ServerOperation(actionCenter, context, logger, server, taskbar);
+ context.Server = server;
+
return operation;
}
diff --git a/SafeExamBrowser.Client/Operations/ServerOperation.cs b/SafeExamBrowser.Client/Operations/ServerOperation.cs
index 189930d3..dd232f71 100644
--- a/SafeExamBrowser.Client/Operations/ServerOperation.cs
+++ b/SafeExamBrowser.Client/Operations/ServerOperation.cs
@@ -48,7 +48,12 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Initializing server...");
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeServer);
- server.Initialize(Context.AppConfig.ServerApi, Context.AppConfig.ServerConnectionToken, Context.AppConfig.ServerOauth2Token, Context.Settings.Server);
+ server.Initialize(
+ Context.AppConfig.ServerApi,
+ Context.AppConfig.ServerConnectionToken,
+ Context.AppConfig.ServerExamId,
+ Context.AppConfig.ServerOauth2Token,
+ Context.Settings.Server);
// TODO: Add action center and taskbar notifications
}
@@ -66,6 +71,7 @@ namespace SafeExamBrowser.Client.Operations
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServer);
// TODO: Stop sending pings and logs (or in controller?)
+ server.StopConnectivity();
// TODO: Stop action center and taskbar notifications
}
diff --git a/SafeExamBrowser.Configuration.Contracts/AppConfig.cs b/SafeExamBrowser.Configuration.Contracts/AppConfig.cs
index 245f4608..e5479d02 100644
--- a/SafeExamBrowser.Configuration.Contracts/AppConfig.cs
+++ b/SafeExamBrowser.Configuration.Contracts/AppConfig.cs
@@ -161,6 +161,11 @@ namespace SafeExamBrowser.Configuration.Contracts
///
public string ServerConnectionToken { get; set; }
+ ///
+ /// The identifier of the selected server exam.
+ ///
+ public string ServerExamId { get; set; }
+
///
/// The OAuth2 token for a server.
///
diff --git a/SafeExamBrowser.Runtime/Operations/ServerOperation.cs b/SafeExamBrowser.Runtime/Operations/ServerOperation.cs
index cdac4bda..dcf56c69 100644
--- a/SafeExamBrowser.Runtime/Operations/ServerOperation.cs
+++ b/SafeExamBrowser.Runtime/Operations/ServerOperation.cs
@@ -77,11 +77,18 @@ namespace SafeExamBrowser.Runtime.Operations
if (status == LoadStatus.Success)
{
+ var serverSettings = Context.Next.Settings.Server;
+
Context.Next.AppConfig.ServerApi = info.Api;
Context.Next.AppConfig.ServerConnectionToken = info.ConnectionToken;
+ Context.Next.AppConfig.ServerExamId = exam.Id;
Context.Next.AppConfig.ServerOauth2Token = info.Oauth2Token;
+
Context.Next.Settings = settings;
Context.Next.Settings.Browser.StartUrl = exam.Url;
+ Context.Next.Settings.Server = serverSettings;
+ Context.Next.Settings.SessionMode = SessionMode.Server;
+
result = OperationResult.Success;
}
else
@@ -105,6 +112,7 @@ namespace SafeExamBrowser.Runtime.Operations
if (fallback)
{
+ Context.Next.Settings.SessionMode = SessionMode.Normal;
result = OperationResult.Success;
}
}
diff --git a/SafeExamBrowser.Server.Contracts/IServerProxy.cs b/SafeExamBrowser.Server.Contracts/IServerProxy.cs
index eb779e1f..8fc5b4bd 100644
--- a/SafeExamBrowser.Server.Contracts/IServerProxy.cs
+++ b/SafeExamBrowser.Server.Contracts/IServerProxy.cs
@@ -51,11 +51,21 @@ namespace SafeExamBrowser.Server.Contracts
///
/// Initializes the configuration and server settings to be used for communication.
///
- void Initialize(string api, string connectionToken, string oauth2Token, ServerSettings settings);
+ void Initialize(string api, string connectionToken, string examId, string oauth2Token, ServerSettings settings);
///
/// TODO
///
- ServerResponse SendSessionInfo(string sessionId);
+ ServerResponse SendSessionIdentifier(string identifier);
+
+ ///
+ /// TODO
+ ///
+ void StartConnectivity();
+
+ ///
+ /// TODO
+ ///
+ void StopConnectivity();
}
}
diff --git a/SafeExamBrowser.Server/ServerProxy.cs b/SafeExamBrowser.Server/ServerProxy.cs
index 9e2c24a0..3418a8f8 100644
--- a/SafeExamBrowser.Server/ServerProxy.cs
+++ b/SafeExamBrowser.Server/ServerProxy.cs
@@ -29,6 +29,7 @@ namespace SafeExamBrowser.Server
{
private ApiVersion1 api;
private string connectionToken;
+ private string examId;
private HttpClient httpClient;
private readonly AppConfig appConfig;
private ILogger logger;
@@ -173,20 +174,31 @@ namespace SafeExamBrowser.Server
}
}
- public void Initialize(string api, string connectionToken, string oauth2Token, ServerSettings settings)
+ public void Initialize(string api, string connectionToken, string examId, string oauth2Token, ServerSettings settings)
{
this.api = JsonConvert.DeserializeObject(api);
this.connectionToken = connectionToken;
+ this.examId = examId;
this.oauth2Token = oauth2Token;
Initialize(settings);
}
- public ServerResponse SendSessionInfo(string sessionId)
+ public ServerResponse SendSessionIdentifier(string identifier)
{
return new ServerResponse(false, "TODO!");
}
+ public void StartConnectivity()
+ {
+ // TODO: Start sending logs and pings
+ }
+
+ public void StopConnectivity()
+ {
+ // TODO: Stop sending logs and pings
+ }
+
private bool TryParseApi(HttpContent content)
{
var success = false;