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:
parent
ceba0e8a2f
commit
d51422e188
10 changed files with 123 additions and 54 deletions
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
12
SafeExamBrowser.Browser/Events/RequestBlockedEventHandler.cs
Normal file
12
SafeExamBrowser.Browser/Events/RequestBlockedEventHandler.cs
Normal 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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace SafeExamBrowser.I18n.Contracts
|
|||
LogWindow_Title,
|
||||
MessageBox_ApplicationError,
|
||||
MessageBox_ApplicationErrorTitle,
|
||||
MessageBox_BrowserNavigationBlocked,
|
||||
MessageBox_BrowserNavigationBlockedTitle,
|
||||
MessageBox_CancelButton,
|
||||
MessageBox_ClientConfigurationError,
|
||||
MessageBox_ClientConfigurationErrorTitle,
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue