SEBWIN-219: Found acceptable solution for interception of configuration requests.

This commit is contained in:
dbuechel 2018-03-08 07:35:58 +01:00
parent a9306754d0
commit 5bd1d9dea4
15 changed files with 131 additions and 108 deletions

View file

@ -8,6 +8,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using CefSharp;
using SafeExamBrowser.Browser.Handlers;
@ -76,13 +77,13 @@ namespace SafeExamBrowser.Browser
button.RegisterInstance(instance);
instances.Add(instance);
instance.ConfigurationDetected += Instance_ConfigurationDetected;
instance.Terminated += Instance_Terminated;
instance.Window.Show();
}
private CefSettings InitializeCefSettings()
{
var schemeFactory = new SebSchemeHandlerFactory();
var cefSettings = new CefSettings
{
CachePath = runtimeInfo.BrowserCachePath,
@ -91,25 +92,12 @@ namespace SafeExamBrowser.Browser
LogSeverity = LogSeverity.Verbose
};
schemeFactory.ConfigurationDetected += OnConfigurationDetected;
cefSettings.RegisterScheme(new CefCustomScheme { SchemeName = "seb", SchemeHandlerFactory = schemeFactory });
cefSettings.RegisterScheme(new CefCustomScheme { SchemeName = "sebs", SchemeHandlerFactory = schemeFactory });
cefSettings.RegisterScheme(new CefCustomScheme { SchemeName = "seb", SchemeHandlerFactory = new SchemeHandlerFactory() });
cefSettings.RegisterScheme(new CefCustomScheme { SchemeName = "sebs", SchemeHandlerFactory = new SchemeHandlerFactory() });
return cefSettings;
}
private void OnConfigurationDetected(string url)
{
// TODO:
// 1. Ask whether reconfiguration should be attempted
// 2. Contact runtime and ask whether configuration valid and reconfiguration allowed
// - If yes, do nothing and wait for shutdown command
// - If no, show message box and NAVIGATE TO PREVIOUS PAGE -> but how?
uiFactory.Show("Detected re-configuration request for " + url, "Info");
}
private void Button_OnClick(Guid? instanceId = null)
{
if (instanceId.HasValue)
@ -122,6 +110,19 @@ namespace SafeExamBrowser.Browser
}
}
private void Instance_ConfigurationDetected(string url, CancelEventArgs args)
{
// TODO:
// 1. Ask whether reconfiguration should be attempted
// 2. Contact runtime and ask whether configuration valid and reconfiguration allowed
// - If yes, do nothing and wait for shutdown command
// - If no, show message box and NAVIGATE TO PREVIOUS PAGE -> but how?
var result = uiFactory.Show(TextKey.MessageBox_ReconfigureQuestion, TextKey.MessageBox_ReconfigureQuestionTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question);
args.Cancel = result == MessageBoxResult.No;
}
private void Instance_Terminated(Guid id)
{
instances.Remove(instances.FirstOrDefault(i => i.Id == id));

View file

@ -7,6 +7,7 @@
*/
using System;
using SafeExamBrowser.Browser.Handlers;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
@ -14,7 +15,7 @@ using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Browser
{
public class BrowserApplicationInstance : IApplicationInstance
internal class BrowserApplicationInstance : IApplicationInstance
{
private IBrowserControl control;
private IBrowserWindow window;
@ -23,6 +24,7 @@ namespace SafeExamBrowser.Browser
public string Name { get; private set; }
public IWindow Window { get { return window; } }
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
public event TerminatedEventHandler Terminated;
public event NameChangedEventHandler NameChanged;
@ -30,8 +32,10 @@ namespace SafeExamBrowser.Browser
{
Id = Guid.NewGuid();
// TODO: Move to initialize method!
control = new BrowserControl(settings, text);
control.AddressChanged += Control_AddressChanged;
(control as BrowserControl).ConfigurationDetected += (url, args) => ConfigurationDetected?.Invoke(url, args);
control.LoadingStateChanged += Control_LoadingStateChanged;
control.TitleChanged += Control_TitleChanged;

View file

@ -24,6 +24,8 @@ namespace SafeExamBrowser.Browser
private LoadingStateChangedEventHandler loadingStateChanged;
private TitleChangedEventHandler titleChanged;
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
event AddressChangedEventHandler IBrowserControl.AddressChanged
{
add { addressChanged += value; }
@ -75,12 +77,16 @@ namespace SafeExamBrowser.Browser
private void Initialize()
{
var requestHandler = new RequestHandler();
AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading);
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
requestHandler.ConfigurationDetected += (url, args) => ConfigurationDetected?.Invoke(url, args);
MenuHandler = new BrowserContextMenuHandler(settings, text);
KeyboardHandler = new BrowserKeyboardHandler(settings);
KeyboardHandler = new KeyboardHandler(settings);
MenuHandler = new ContextMenuHandler(settings, text);
RequestHandler = requestHandler;
}
}
}

View file

@ -13,16 +13,16 @@ using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.Browser
namespace SafeExamBrowser.Browser.Handlers
{
/// <remarks>
/// See https://cefsharp.github.io/api/57.0.0/html/T_CefSharp_IContextMenuHandler.htm.
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_IContextMenuHandler.htm.
/// </remarks>
internal class BrowserContextMenuHandler : IContextMenuHandler
internal class ContextMenuHandler : IContextMenuHandler
{
private const int DEV_CONSOLE_COMMAND = (int) CefMenuCommand.UserFirst + 1;
private BrowserSettings settings;
private IText text;
public BrowserContextMenuHandler(BrowserSettings settings, IText text)
public ContextMenuHandler(BrowserSettings settings, IText text)
{
this.settings = settings;
this.text = text;

View file

@ -13,13 +13,13 @@ using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.Browser
namespace SafeExamBrowser.Browser.Handlers
{
/// <remarks>
/// See https://cefsharp.github.io/api/57.0.0/html/T_CefSharp_IKeyboardHandler.htm.
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_IKeyboardHandler.htm.
/// </remarks>
internal class BrowserKeyboardHandler : IKeyboardHandler
internal class KeyboardHandler : IKeyboardHandler
{
private BrowserSettings settings;
public BrowserKeyboardHandler(BrowserSettings settings)
public KeyboardHandler(BrowserSettings settings)
{
this.settings = settings;
}

View file

@ -0,0 +1,50 @@
/*
* 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.ComponentModel;
using System.Threading.Tasks;
using CefSharp;
using CefSharp.Handler;
namespace SafeExamBrowser.Browser.Handlers
{
internal delegate void ConfigurationDetectedEventHandler(string url, CancelEventArgs args);
/// <remarks>
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_Handler_DefaultRequestHandler.htm.
/// </remarks>
internal class RequestHandler : DefaultRequestHandler
{
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
{
Task.Run(() =>
{
var allow = true;
// TODO: Check if the requested resource is a configuration file, even if the URL does not indicate so!
if (request.Url.StartsWith("seb") || request.Url.StartsWith("sebs") || request.Url.EndsWith(".seb"))
{
var args = new CancelEventArgs();
ConfigurationDetected?.Invoke(request.Url, args);
allow = !args.Cancel;
}
using (callback)
{
callback.Continue(allow);
}
});
return CefReturnValue.ContinueAsync;
}
}
}

View file

@ -11,17 +11,14 @@ using CefSharp;
namespace SafeExamBrowser.Browser.Handlers
{
/// <remarks>
/// See https://cefsharp.github.io/api/57.0.0/html/T_CefSharp_ISchemeHandlerFactory.htm.
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_ISchemeHandlerFactory.htm.
/// </remarks>
internal class SebSchemeHandlerFactory : ISchemeHandlerFactory
internal class SchemeHandlerFactory : ISchemeHandlerFactory
{
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
var handler = new SebSchemeHandler();
handler.ConfigurationDetected += (url) => ConfigurationDetected?.Invoke(url);
var page = "<html><body style=\"height: 90%; display: flex; align-items: center; justify-content: center\"><progress /></body></html>";
var handler = ResourceHandler.FromString(page);
return handler;
}

View file

@ -1,47 +0,0 @@
/*
* 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.Net;
using System.Text;
using System.Threading.Tasks;
using CefSharp;
namespace SafeExamBrowser.Browser.Handlers
{
internal delegate void ConfigurationDetectedEventHandler(string url);
/// <remarks>
/// See https://cefsharp.github.io/api/57.0.0/html/T_CefSharp_ResourceHandler.htm.
/// </remarks>
internal class SebSchemeHandler : ResourceHandler
{
internal event ConfigurationDetectedEventHandler ConfigurationDetected;
public override bool ProcessRequestAsync(IRequest request, ICallback callback)
{
Task.Run(() =>
{
using (callback)
{
var page = "<html><body style=\"height: 90%; display: flex; align-items: center; justify-content: center\"><progress /></body></html>";
var stream = GetMemoryStream(page, Encoding.UTF8);
ResponseLength = stream.Length;
MimeType = "text/html";
StatusCode = (int) HttpStatusCode.OK;
Stream = stream;
callback.Continue();
ConfigurationDetected?.Invoke(request.Url);
}
});
return true;
}
}
}

View file

@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\CefSharp.WinForms.57.0.0\build\CefSharp.WinForms.props" Condition="Exists('..\packages\CefSharp.WinForms.57.0.0\build\CefSharp.WinForms.props')" />
<Import Project="..\packages\CefSharp.Common.57.0.0\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.57.0.0\build\CefSharp.Common.props')" />
<Import Project="..\packages\CefSharp.WinForms.63.0.1\build\CefSharp.WinForms.props" Condition="Exists('..\packages\CefSharp.WinForms.63.0.1\build\CefSharp.WinForms.props')" />
<Import Project="..\packages\CefSharp.Common.63.0.1\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.63.0.1\build\CefSharp.Common.props')" />
<Import Project="..\packages\cef.redist.x86.3.3239.1723\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.3.3239.1723\build\cef.redist.x86.props')" />
<Import Project="..\packages\cef.redist.x64.3.3239.1723\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.3.3239.1723\build\cef.redist.x64.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -60,14 +62,14 @@
<Compile Include="BrowserApplicationController.cs" />
<Compile Include="BrowserApplicationInfo.cs" />
<Compile Include="BrowserApplicationInstance.cs" />
<Compile Include="Handlers\BrowserContextMenuHandler.cs" />
<Compile Include="Handlers\ContextMenuHandler.cs" />
<Compile Include="BrowserControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="BrowserIconResource.cs" />
<Compile Include="Handlers\BrowserKeyboardHandler.cs" />
<Compile Include="Handlers\SebSchemeHandler.cs" />
<Compile Include="Handlers\SebSchemeHandlerFactory.cs" />
<Compile Include="Handlers\KeyboardHandler.cs" />
<Compile Include="Handlers\RequestHandler.cs" />
<Compile Include="Handlers\SchemeHandlerFactory.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
@ -82,23 +84,21 @@
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\cef.redist.x64.3.2987.1601\build\cef.redist.x64.targets" Condition="Exists('..\packages\cef.redist.x64.3.2987.1601\build\cef.redist.x64.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\cef.redist.x64.3.2987.1601\build\cef.redist.x64.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.3.2987.1601\build\cef.redist.x64.targets'))" />
<Error Condition="!Exists('..\packages\cef.redist.x86.3.2987.1601\build\cef.redist.x86.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.3.2987.1601\build\cef.redist.x86.targets'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.57.0.0\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.57.0.0\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.57.0.0\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.57.0.0\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('..\packages\CefSharp.WinForms.57.0.0\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.WinForms.57.0.0\build\CefSharp.WinForms.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.WinForms.57.0.0\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.WinForms.57.0.0\build\CefSharp.WinForms.targets'))" />
</Target>
<Import Project="..\packages\cef.redist.x86.3.2987.1601\build\cef.redist.x86.targets" Condition="Exists('..\packages\cef.redist.x86.3.2987.1601\build\cef.redist.x86.targets')" />
<Import Project="..\packages\CefSharp.Common.57.0.0\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.57.0.0\build\CefSharp.Common.targets')" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<Import Project="..\packages\CefSharp.WinForms.57.0.0\build\CefSharp.WinForms.targets" Condition="Exists('..\packages\CefSharp.WinForms.57.0.0\build\CefSharp.WinForms.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\cef.redist.x64.3.3239.1723\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.3.3239.1723\build\cef.redist.x64.props'))" />
<Error Condition="!Exists('..\packages\cef.redist.x86.3.3239.1723\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.3.3239.1723\build\cef.redist.x86.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.63.0.1\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.63.0.1\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.63.0.1\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.63.0.1\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('..\packages\CefSharp.WinForms.63.0.1\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.WinForms.63.0.1\build\CefSharp.WinForms.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.WinForms.63.0.1\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.WinForms.63.0.1\build\CefSharp.WinForms.targets'))" />
</Target>
<Import Project="..\packages\CefSharp.Common.63.0.1\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.63.0.1\build\CefSharp.Common.targets')" />
<Import Project="..\packages\CefSharp.WinForms.63.0.1\build\CefSharp.WinForms.targets" Condition="Exists('..\packages\CefSharp.WinForms.63.0.1\build\CefSharp.WinForms.targets')" />
</Project>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="cef.redist.x64" version="3.2987.1601" targetFramework="net452" />
<package id="cef.redist.x86" version="3.2987.1601" targetFramework="net452" />
<package id="CefSharp.Common" version="57.0.0" targetFramework="net452" />
<package id="CefSharp.WinForms" version="57.0.0" targetFramework="net452" />
<package id="cef.redist.x64" version="3.3239.1723" targetFramework="net452" />
<package id="cef.redist.x86" version="3.3239.1723" targetFramework="net452" />
<package id="CefSharp.Common" version="63.0.1" targetFramework="net452" />
<package id="CefSharp.WinForms" version="63.0.1" targetFramework="net452" />
</packages>

View file

@ -6,6 +6,10 @@
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View file

@ -72,7 +72,7 @@ namespace SafeExamBrowser.Configuration
ServicePolicy = ServicePolicy.Optional
};
settings.Browser.StartUrl = "https://www.duckduckgo.com";
settings.Browser.StartUrl = "https://www.safeexambrowser.org/testing";
settings.Browser.AllowAddressBar = true;
settings.Browser.AllowBackwardNavigation = true;
settings.Browser.AllowDeveloperConsole = true;

View file

@ -24,6 +24,8 @@ namespace SafeExamBrowser.Contracts.I18n
MessageBox_QuitTitle,
MessageBox_QuitError,
MessageBox_QuitErrorTitle,
MessageBox_ReconfigureQuestion,
MessageBox_ReconfigureQuestionTitle,
MessageBox_SessionStartError,
MessageBox_SessionStartErrorTitle,
MessageBox_SessionStopError,

View file

@ -186,18 +186,18 @@ namespace SafeExamBrowser.Core.Communication
if (IsAcknowledged(response))
{
Logger.Info("Pinged proxy, connection is alive.");
Logger.Info("Pinged host, connection is alive.");
}
else
{
Logger.Error($"Proxy did not acknowledge ping message! Received: {ToString(response)}.");
Logger.Error($"Host did not acknowledge ping message! Received: {ToString(response)}.");
timer.Stop();
ConnectionLost?.Invoke();
}
}
catch (Exception e)
{
Logger.Error("Failed to ping proxy!", e);
Logger.Error("Failed to ping host!", e);
timer.Stop();
ConnectionLost?.Invoke();
}

View file

@ -30,6 +30,12 @@
<Entry key="MessageBox_QuitErrorTitle">
Quit Error
</Entry>
<Entry key="MessageBox_ReconfigureQuestion">
Would you like to reconfigure the application?
</Entry>
<Entry key="MessageBox_ReconfigureQuestionTitle">
Configuration Detected
</Entry>
<Entry key="MessageBox_SessionStartError">
The application failed to start a new session. Please consult the application log for more information...
</Entry>