SEBWIN-314: Main requests are now entirely prevented (before any loading happens) and only content requests are intercepted with custom resource handling.

This commit is contained in:
dbuechel 2019-09-12 12:31:17 +02:00
parent ceba0e8a2f
commit d51422e188
10 changed files with 123 additions and 54 deletions

View file

@ -57,7 +57,6 @@
<Compile Include="Events\DownloadFinishedCallback.cs" />
<Compile Include="Events\DownloadRequestedEventHandler.cs" />
<Compile Include="IBrowserApplication.cs" />
<Compile Include="Events\ProgressChangedEventHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View file

@ -8,6 +8,7 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using SafeExamBrowser.Applications.Contracts;
using SafeExamBrowser.Applications.Contracts.Events;
using SafeExamBrowser.Browser.Contracts.Events;
@ -102,7 +103,7 @@ namespace SafeExamBrowser.Browser
var keyboardHandler = new KeyboardHandler();
var lifeSpanHandler = new LifeSpanHandler();
var requestLogger = logger.CloneFor($"{nameof(RequestHandler)} {Id}");
var requestHandler = new RequestHandler(appConfig, settings.Filter, logger, text);
var requestHandler = new RequestHandler(appConfig, settings.Filter, requestLogger, text);
displayHandler.FaviconChanged += DisplayHandler_FaviconChanged;
displayHandler.ProgressChanged += DisplayHandler_ProgressChanged;
@ -112,6 +113,7 @@ namespace SafeExamBrowser.Browser
keyboardHandler.ZoomOutRequested += ZoomOutRequested;
keyboardHandler.ZoomResetRequested += ZoomResetRequested;
lifeSpanHandler.PopupRequested += LifeSpanHandler_PopupRequested;
requestHandler.RequestBlocked += RequestHandler_RequestBlocked;
control = new BrowserControl(contextMenuHandler, displayHandler, downloadHandler, keyboardHandler, lifeSpanHandler, requestHandler, url);
control.AddressChanged += Control_AddressChanged;
@ -224,6 +226,17 @@ namespace SafeExamBrowser.Browser
}
}
private void RequestHandler_RequestBlocked(string url)
{
Task.Run(() =>
{
var message = text.Get(TextKey.MessageBox_BrowserNavigationBlocked).Replace("%%URL%%", url);
var title = text.Get(TextKey.MessageBox_BrowserNavigationBlockedTitle);
messageBox.Show(message, title, parent: window);
});
}
private void ReloadRequested()
{
if (WindowSettings.AllowReloading && WindowSettings.ShowReloadWarning)

View file

@ -6,10 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
namespace SafeExamBrowser.Browser.Contracts.Events
namespace SafeExamBrowser.Browser.Events
{
/// <summary>
/// Event handler used to indicate the current progress value of the page load process (from <c>0.0</c> to <c>1.0</c>).
/// </summary>
public delegate void ProgressChangedEventHandler(double value);
internal delegate void ProgressChangedEventHandler(double value);
}

View file

@ -0,0 +1,12 @@
/*
* Copyright (c) 2019 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.Events
{
internal delegate void RequestBlockedEventHandler(string url);
}

View file

@ -10,7 +10,6 @@ using System.Collections.Generic;
using System.Linq;
using CefSharp;
using CefSharp.Structs;
using SafeExamBrowser.Browser.Contracts.Events;
using SafeExamBrowser.Browser.Events;
namespace SafeExamBrowser.Browser.Handlers

View file

@ -7,6 +7,8 @@
*/
using CefSharp;
using SafeExamBrowser.Browser.Events;
using SafeExamBrowser.Browser.Filters;
using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
@ -16,15 +18,28 @@ namespace SafeExamBrowser.Browser.Handlers
{
internal class RequestHandler : CefSharp.Handler.RequestHandler
{
private RequestFilter filter;
private ILogger logger;
private ResourceHandler resourceHandler;
private BrowserFilterSettings settings;
internal event RequestBlockedEventHandler RequestBlocked;
internal RequestHandler(AppConfig appConfig, BrowserFilterSettings settings, ILogger logger, IText text)
{
this.resourceHandler = new ResourceHandler(appConfig, settings, logger, text);
this.filter = new RequestFilter();
this.logger = logger;
this.resourceHandler = new ResourceHandler(appConfig, settings, filter, logger, text);
this.settings = settings;
}
internal void Initiailize()
{
if (settings.FilterMainRequests || settings.FilterContentRequests)
{
InitializeFilter();
}
resourceHandler.Initialize();
}
@ -32,5 +47,45 @@ namespace SafeExamBrowser.Browser.Handlers
{
return resourceHandler;
}
protected override bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect)
{
if (Block(request))
{
RequestBlocked?.Invoke(request.Url);
return true;
}
return base.OnBeforeBrowse(chromiumWebBrowser, browser, frame, request, userGesture, isRedirect);
}
private bool Block(IRequest request)
{
if (settings.FilterMainRequests)
{
var result = filter.Process(request.Url);
var block = result == FilterResult.Block;
if (block)
{
logger.Info($"Blocked main request for '{request.Url}'.");
}
return block;
}
return false;
}
private void InitializeFilter()
{
foreach (var rule in settings.Rules)
{
filter.Load(rule);
}
logger.Debug($"Initialized request filter with {settings.Rules.Count} rules.");
}
}
}

View file

@ -25,14 +25,14 @@ namespace SafeExamBrowser.Browser.Handlers
private BrowserFilterSettings settings;
private ILogger logger;
private RequestFilter filter;
private IResourceHandler contentBlockedHandler;
private IResourceHandler pageBlockedHandler;
private IResourceHandler contentHandler;
private IResourceHandler pageHandler;
private IText text;
internal ResourceHandler(AppConfig appConfig, BrowserFilterSettings settings, ILogger logger, IText text)
internal ResourceHandler(AppConfig appConfig, BrowserFilterSettings settings, RequestFilter filter, ILogger logger, IText text)
{
this.appConfig = appConfig;
this.filter = new RequestFilter();
this.filter = filter;
this.logger = logger;
this.settings = settings;
this.text = text;
@ -40,22 +40,17 @@ namespace SafeExamBrowser.Browser.Handlers
internal void Initialize()
{
if (settings.FilterMainRequests || settings.FilterContentRequests)
if (settings.FilterContentRequests)
{
InitializeFilter();
InitializeResourceHandlers();
}
}
protected override IResourceHandler GetResourceHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request)
{
if (BlockMainRequest(request))
if (Block(request))
{
return pageBlockedHandler;
}
if (BlockContentRequest(request))
{
return contentBlockedHandler;
return ResourceHandlerFor(request.ResourceType);
}
return base.GetResourceHandler(chromiumWebBrowser, browser, frame, request);
@ -73,7 +68,7 @@ namespace SafeExamBrowser.Browser.Handlers
return CefReturnValue.Cancel;
}
ReplaceCustomScheme(request);
ReplaceSebScheme(request);
return base.OnBeforeResourceLoad(webBrowser, browser, frame, request, callback);
}
@ -87,9 +82,9 @@ namespace SafeExamBrowser.Browser.Handlers
request.Headers = headers;
}
private bool BlockContentRequest(IRequest request)
private bool Block(IRequest request)
{
if (settings.FilterContentRequests && request.ResourceType != ResourceType.MainFrame)
if (settings.FilterContentRequests)
{
var result = filter.Process(request.Url);
var block = result == FilterResult.Block;
@ -105,25 +100,7 @@ namespace SafeExamBrowser.Browser.Handlers
return false;
}
private bool BlockMainRequest(IRequest request)
{
if (settings.FilterMainRequests && request.ResourceType == ResourceType.MainFrame)
{
var result = filter.Process(request.Url);
var block = result == FilterResult.Block;
if (block)
{
logger.Info($"Blocked main request for '{request.Url}'.");
}
return block;
}
return false;
}
private void InitializeFilter()
private void InitializeResourceHandlers()
{
var assembly = Assembly.GetAssembly(typeof(RequestFilter));
var contentMessage = text.Get(TextKey.Browser_BlockedContentMessage);
@ -136,17 +113,12 @@ namespace SafeExamBrowser.Browser.Handlers
var pageHtml = new StreamReader(pageStream).ReadToEnd();
contentHtml = contentHtml.Replace("%%MESSAGE%%", contentMessage);
contentHandler = CefSharp.ResourceHandler.FromString(contentHtml);
pageHtml = pageHtml.Replace("%%MESSAGE%%", pageMessage).Replace("%%TITLE%%", pageTitle).Replace("%%BACK_BUTTON%%", pageButton);
pageHandler = CefSharp.ResourceHandler.FromString(pageHtml);
contentBlockedHandler = CefSharp.ResourceHandler.FromString(contentHtml);
pageBlockedHandler = CefSharp.ResourceHandler.FromString(pageHtml);
foreach (var rule in settings.Rules)
{
filter.Load(rule);
}
logger.Debug($"Initialized request filter with {settings.Rules.Count} rules.");
logger.Debug("Initialized resource handlers for blocked requests.");
}
private bool IsMailtoUrl(string url)
@ -154,7 +126,7 @@ namespace SafeExamBrowser.Browser.Handlers
return url.StartsWith(Uri.UriSchemeMailto);
}
private void ReplaceCustomScheme(IRequest request)
private void ReplaceSebScheme(IRequest request)
{
if (Uri.IsWellFormedUriString(request.Url, UriKind.RelativeOrAbsolute))
{
@ -170,5 +142,17 @@ namespace SafeExamBrowser.Browser.Handlers
}
}
}
private IResourceHandler ResourceHandlerFor(ResourceType resourceType)
{
switch (resourceType)
{
case ResourceType.MainFrame:
case ResourceType.SubFrame:
return pageHandler;
default:
return contentHandler;
}
}
}
}

View file

@ -72,6 +72,8 @@
<Compile Include="Events\FaviconChangedEventHandler.cs" />
<Compile Include="Events\PopupRequestedEventArgs.cs" />
<Compile Include="Events\PopupRequestedEventHandler.cs" />
<Compile Include="Events\ProgressChangedEventHandler.cs" />
<Compile Include="Events\RequestBlockedEventHandler.cs" />
<Compile Include="Filters\RequestFilter.cs" />
<Compile Include="Filters\Rules\Rule.cs" />
<Compile Include="Filters\Rules\RegexRule.cs" />

View file

@ -24,6 +24,8 @@ namespace SafeExamBrowser.I18n.Contracts
LogWindow_Title,
MessageBox_ApplicationError,
MessageBox_ApplicationErrorTitle,
MessageBox_BrowserNavigationBlocked,
MessageBox_BrowserNavigationBlockedTitle,
MessageBox_CancelButton,
MessageBox_ClientConfigurationError,
MessageBox_ClientConfigurationErrorTitle,

View file

@ -30,6 +30,12 @@
<Entry key="MessageBox_ApplicationErrorTitle">
Application Error
</Entry>
<Entry key="MessageBox_BrowserNavigationBlocked">
Access to "%%URL%%" is not allowed according to the application configuration.
</Entry>
<Entry key="MessageBox_BrowserNavigationBlockedTitle">
Page Blocked
</Entry>
<Entry key="MessageBox_CancelButton">
Cancel
</Entry>