SEBWIN-314: Completed infrastructure for request filter.
This commit is contained in:
parent
367ebf1329
commit
1dd65e1bda
25 changed files with 669 additions and 167 deletions
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using SafeExamBrowser.Browser.Filters;
|
||||||
|
using SafeExamBrowser.Settings.Browser;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Browser.UnitTests.Filters
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class RequestFilterTests
|
||||||
|
{
|
||||||
|
private RequestFilter sut;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
sut = new RequestFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustProcessBlockRulesFirst()
|
||||||
|
{
|
||||||
|
var allow = new FilterRuleSettings { Expression = "*", Type = FilterType.Simplified, Result = FilterResult.Allow };
|
||||||
|
var block = new FilterRuleSettings { Expression = "*", Type = FilterType.Simplified, Result = FilterResult.Block };
|
||||||
|
|
||||||
|
sut.Load(allow);
|
||||||
|
sut.Load(block);
|
||||||
|
|
||||||
|
var result = sut.Process("safeexambrowser.org");
|
||||||
|
|
||||||
|
Assert.AreEqual(FilterResult.Block, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustProcessAllowRulesSecond()
|
||||||
|
{
|
||||||
|
var allow = new FilterRuleSettings { Expression = "*", Type = FilterType.Simplified, Result = FilterResult.Allow };
|
||||||
|
var block = new FilterRuleSettings { Expression = "xyz", Type = FilterType.Simplified, Result = FilterResult.Block };
|
||||||
|
|
||||||
|
sut.Load(allow);
|
||||||
|
sut.Load(block);
|
||||||
|
|
||||||
|
var result = sut.Process("safeexambrowser.org");
|
||||||
|
|
||||||
|
Assert.AreEqual(FilterResult.Allow, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustReturnDefault()
|
||||||
|
{
|
||||||
|
var allow = new FilterRuleSettings { Expression = "xyz", Type = FilterType.Simplified, Result = FilterResult.Allow };
|
||||||
|
var block = new FilterRuleSettings { Expression = "xyz", Type = FilterType.Simplified, Result = FilterResult.Block };
|
||||||
|
|
||||||
|
sut.Default = (FilterResult) (-1);
|
||||||
|
sut.Load(allow);
|
||||||
|
sut.Load(block);
|
||||||
|
|
||||||
|
var result = sut.Process("safeexambrowser.org");
|
||||||
|
|
||||||
|
Assert.AreEqual((FilterResult) (-1), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustReturnDefaultWithoutRules()
|
||||||
|
{
|
||||||
|
sut.Default = FilterResult.Allow;
|
||||||
|
var result = sut.Process("safeexambrowser.org");
|
||||||
|
Assert.AreEqual(FilterResult.Allow, result);
|
||||||
|
|
||||||
|
sut.Default = FilterResult.Block;
|
||||||
|
result = sut.Process("safeexambrowser.org");
|
||||||
|
Assert.AreEqual(FilterResult.Block, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[ExpectedException(typeof(NotImplementedException))]
|
||||||
|
public void MustNotAllowUnsupportedResult()
|
||||||
|
{
|
||||||
|
sut.Load(new FilterRuleSettings { Result = (FilterResult) (-1) });
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[ExpectedException(typeof(NotImplementedException))]
|
||||||
|
public void MustNotAllowUnsupportedFilterType()
|
||||||
|
{
|
||||||
|
sut.Load(new FilterRuleSettings { Type = (FilterType) (-1) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
SafeExamBrowser.Browser.UnitTests/Properties/AssemblyInfo.cs
Normal file
17
SafeExamBrowser.Browser.UnitTests/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
[assembly: AssemblyTitle("SafeExamBrowser.Browser.UnitTests")]
|
||||||
|
[assembly: AssemblyDescription("Safe Exam Browser")]
|
||||||
|
[assembly: AssemblyCompany("ETH Zürich")]
|
||||||
|
[assembly: AssemblyProduct("SafeExamBrowser.Browser.UnitTests")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2019 ETH Zürich, Educational Development and Technology (LET)")]
|
||||||
|
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
[assembly: Guid("f54c4c0e-4c72-4f88-a389-7f6de3ccb745")]
|
||||||
|
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyInformationalVersion("1.0.0.0")]
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props')" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>SafeExamBrowser.Browser.UnitTests</RootNamespace>
|
||||||
|
<AssemblyName>SafeExamBrowser.Browser.UnitTests</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||||
|
<IsCodedUITest>False</IsCodedUITest>
|
||||||
|
<TestProjectType>UnitTest</TestProjectType>
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Filters\RequestFilterTests.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\SafeExamBrowser.Browser.Contracts\SafeExamBrowser.Browser.Contracts.csproj">
|
||||||
|
<Project>{5fb5273d-277c-41dd-8593-a25ce1aff2e9}</Project>
|
||||||
|
<Name>SafeExamBrowser.Browser.Contracts</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\SafeExamBrowser.Browser\SafeExamBrowser.Browser.csproj">
|
||||||
|
<Project>{04e653f1-98e6-4e34-9dd7-7f2bc1a8b767}</Project>
|
||||||
|
<Name>SafeExamBrowser.Browser</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj">
|
||||||
|
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
|
||||||
|
<Name>SafeExamBrowser.Settings</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.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\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props'))" />
|
||||||
|
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets'))" />
|
||||||
|
</Target>
|
||||||
|
<Import Project="..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets')" />
|
||||||
|
</Project>
|
5
SafeExamBrowser.Browser.UnitTests/packages.config
Normal file
5
SafeExamBrowser.Browser.UnitTests/packages.config
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="MSTest.TestAdapter" version="1.3.2" targetFramework="net472" />
|
||||||
|
<package id="MSTest.TestFramework" version="1.3.2" targetFramework="net472" />
|
||||||
|
</packages>
|
|
@ -14,9 +14,9 @@ using SafeExamBrowser.Browser.Contracts.Events;
|
||||||
using SafeExamBrowser.Browser.Events;
|
using SafeExamBrowser.Browser.Events;
|
||||||
using SafeExamBrowser.Browser.Handlers;
|
using SafeExamBrowser.Browser.Handlers;
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
using SafeExamBrowser.Settings.Browser;
|
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.Settings.Browser;
|
||||||
using SafeExamBrowser.UserInterface.Contracts;
|
using SafeExamBrowser.UserInterface.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||||
|
@ -102,7 +102,7 @@ namespace SafeExamBrowser.Browser
|
||||||
var keyboardHandler = new KeyboardHandler();
|
var keyboardHandler = new KeyboardHandler();
|
||||||
var lifeSpanHandler = new LifeSpanHandler();
|
var lifeSpanHandler = new LifeSpanHandler();
|
||||||
var requestLogger = logger.CloneFor($"{nameof(RequestHandler)} {Id}");
|
var requestLogger = logger.CloneFor($"{nameof(RequestHandler)} {Id}");
|
||||||
var requestHandler = new RequestHandler(appConfig, settings, logger);
|
var requestHandler = new RequestHandler(appConfig, settings.Filter, logger, text);
|
||||||
|
|
||||||
displayHandler.FaviconChanged += DisplayHandler_FaviconChanged;
|
displayHandler.FaviconChanged += DisplayHandler_FaviconChanged;
|
||||||
displayHandler.ProgressChanged += DisplayHandler_ProgressChanged;
|
displayHandler.ProgressChanged += DisplayHandler_ProgressChanged;
|
||||||
|
@ -117,6 +117,8 @@ namespace SafeExamBrowser.Browser
|
||||||
control.AddressChanged += Control_AddressChanged;
|
control.AddressChanged += Control_AddressChanged;
|
||||||
control.LoadingStateChanged += Control_LoadingStateChanged;
|
control.LoadingStateChanged += Control_LoadingStateChanged;
|
||||||
control.TitleChanged += Control_TitleChanged;
|
control.TitleChanged += Control_TitleChanged;
|
||||||
|
|
||||||
|
requestHandler.Initiailize();
|
||||||
control.Initialize();
|
control.Initialize();
|
||||||
|
|
||||||
logger.Debug("Initialized browser control.");
|
logger.Debug("Initialized browser control.");
|
||||||
|
|
3
SafeExamBrowser.Browser/Filters/BlockedContent.html
Normal file
3
SafeExamBrowser.Browser/Filters/BlockedContent.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<div style="background-color: lightgray; display: table; font-family: 'Segoe UI'; height: 100%; text-align: center; width: 100%">
|
||||||
|
<p style="display: table-cell; font-weight: bold; vertical-align: middle">%%MESSAGE%%</p>
|
||||||
|
</div>
|
13
SafeExamBrowser.Browser/Filters/BlockedPage.html
Normal file
13
SafeExamBrowser.Browser/Filters/BlockedPage.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html style="height: 100%; width: 100%">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>%%TITLE%%</title>
|
||||||
|
</head>
|
||||||
|
<body style="background-color: lightgray; display: table; font-family: 'Segoe UI'; height: 98%; text-align: center; width: 99%">
|
||||||
|
<div style="display: table-cell; vertical-align: middle">
|
||||||
|
<p style="font-weight: bold">%%MESSAGE%%</p>
|
||||||
|
<button onclick="window.history.back()" style="cursor: pointer">⭠ %%BACK_BUTTON%%</button>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -7,20 +7,74 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using SafeExamBrowser.Browser.Filters.Rules;
|
||||||
using SafeExamBrowser.Settings.Browser;
|
using SafeExamBrowser.Settings.Browser;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Browser.Filters
|
namespace SafeExamBrowser.Browser.Filters
|
||||||
{
|
{
|
||||||
internal class RequestFilter
|
internal class RequestFilter
|
||||||
{
|
{
|
||||||
internal void Load(FilterRule rule)
|
private IList<Rule> allowRules;
|
||||||
{
|
private IList<Rule> blockRules;
|
||||||
|
|
||||||
|
internal FilterResult Default { get; set; }
|
||||||
|
|
||||||
|
internal RequestFilter()
|
||||||
|
{
|
||||||
|
allowRules = new List<Rule>();
|
||||||
|
blockRules = new List<Rule>();
|
||||||
|
Default = FilterResult.Block;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal FilterResult Process(Uri request)
|
internal void Load(FilterRuleSettings settings)
|
||||||
{
|
{
|
||||||
return FilterResult.Allow;
|
var rule = default(Rule);
|
||||||
|
|
||||||
|
switch (settings.Type)
|
||||||
|
{
|
||||||
|
case FilterType.Regex:
|
||||||
|
rule = new RegexRule(settings.Expression);
|
||||||
|
break;
|
||||||
|
case FilterType.Simplified:
|
||||||
|
rule = new SimpleRule(settings.Expression);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Filter rule of type '{settings.Type}' is not yet implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (settings.Result)
|
||||||
|
{
|
||||||
|
case FilterResult.Allow:
|
||||||
|
allowRules.Add(rule);
|
||||||
|
break;
|
||||||
|
case FilterResult.Block:
|
||||||
|
blockRules.Add(rule);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Filter result '{settings.Result}' is not yet implemented!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal FilterResult Process(string url)
|
||||||
|
{
|
||||||
|
foreach (var rule in blockRules)
|
||||||
|
{
|
||||||
|
if (rule.IsMatch(url))
|
||||||
|
{
|
||||||
|
return FilterResult.Block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var rule in allowRules)
|
||||||
|
{
|
||||||
|
if (rule.IsMatch(url))
|
||||||
|
{
|
||||||
|
return FilterResult.Allow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
31
SafeExamBrowser.Browser/Filters/Rules/RegexRule.cs
Normal file
31
SafeExamBrowser.Browser/Filters/Rules/RegexRule.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Browser.Filters.Rules
|
||||||
|
{
|
||||||
|
internal class RegexRule : Rule
|
||||||
|
{
|
||||||
|
private string expression;
|
||||||
|
|
||||||
|
public RegexRule(string expression) : base(expression)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Initialize(string expression)
|
||||||
|
{
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override bool IsMatch(string url)
|
||||||
|
{
|
||||||
|
return Regex.IsMatch(url, expression, RegexOptions.IgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
SafeExamBrowser.Browser/Filters/Rules/Rule.cs
Normal file
21
SafeExamBrowser.Browser/Filters/Rules/Rule.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* 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.Filters.Rules
|
||||||
|
{
|
||||||
|
internal abstract class Rule
|
||||||
|
{
|
||||||
|
internal Rule(string expression)
|
||||||
|
{
|
||||||
|
Initialize(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract bool IsMatch(string url);
|
||||||
|
protected abstract void Initialize(string expression);
|
||||||
|
}
|
||||||
|
}
|
31
SafeExamBrowser.Browser/Filters/Rules/SimpleRule.cs
Normal file
31
SafeExamBrowser.Browser/Filters/Rules/SimpleRule.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Browser.Filters.Rules
|
||||||
|
{
|
||||||
|
internal class SimpleRule : Rule
|
||||||
|
{
|
||||||
|
private string expression;
|
||||||
|
|
||||||
|
public SimpleRule(string expression) : base(expression)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Initialize(string expression)
|
||||||
|
{
|
||||||
|
this.expression = expression.Replace("*", @".*");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override bool IsMatch(string url)
|
||||||
|
{
|
||||||
|
return Regex.IsMatch(url, expression, RegexOptions.IgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,46 +7,30 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using SafeExamBrowser.Browser.Filters;
|
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings;
|
using SafeExamBrowser.Settings.Browser;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Browser.Handlers
|
namespace SafeExamBrowser.Browser.Handlers
|
||||||
{
|
{
|
||||||
internal class RequestHandler : CefSharp.Handler.RequestHandler
|
internal class RequestHandler : CefSharp.Handler.RequestHandler
|
||||||
{
|
{
|
||||||
private AppConfig appConfig;
|
private ResourceHandler resourceHandler;
|
||||||
private BrowserSettings settings;
|
|
||||||
private RequestFilter filter;
|
|
||||||
private ILogger logger;
|
|
||||||
private ResourceRequestHandler resourceRequestHandler;
|
|
||||||
|
|
||||||
internal RequestHandler(AppConfig appConfig, BrowserSettings settings, ILogger logger)
|
internal RequestHandler(AppConfig appConfig, BrowserFilterSettings settings, ILogger logger, IText text)
|
||||||
{
|
{
|
||||||
this.appConfig = appConfig;
|
this.resourceHandler = new ResourceHandler(appConfig, settings, logger, text);
|
||||||
this.settings = settings;
|
|
||||||
this.filter = new RequestFilter();
|
|
||||||
this.logger = logger;
|
|
||||||
this.resourceRequestHandler = new ResourceRequestHandler(appConfig, settings, logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Initiailize()
|
internal void Initiailize()
|
||||||
{
|
{
|
||||||
if (settings.FilterMainRequests || settings.FilterContentRequests)
|
resourceHandler.Initialize();
|
||||||
{
|
|
||||||
foreach (var rule in settings.FilterRules)
|
|
||||||
{
|
|
||||||
filter.Load(rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Debug("Initialized request filter.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
|
protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
|
||||||
{
|
{
|
||||||
return resourceRequestHandler;
|
return resourceHandler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
174
SafeExamBrowser.Browser/Handlers/ResourceHandler.cs
Normal file
174
SafeExamBrowser.Browser/Handlers/ResourceHandler.cs
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using CefSharp;
|
||||||
|
using SafeExamBrowser.Browser.Filters;
|
||||||
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.Settings.Browser;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Browser.Handlers
|
||||||
|
{
|
||||||
|
internal class ResourceHandler : CefSharp.Handler.ResourceRequestHandler
|
||||||
|
{
|
||||||
|
private AppConfig appConfig;
|
||||||
|
private BrowserFilterSettings settings;
|
||||||
|
private ILogger logger;
|
||||||
|
private RequestFilter filter;
|
||||||
|
private IResourceHandler contentBlockedHandler;
|
||||||
|
private IResourceHandler pageBlockedHandler;
|
||||||
|
private IText text;
|
||||||
|
|
||||||
|
internal ResourceHandler(AppConfig appConfig, BrowserFilterSettings settings, ILogger logger, IText text)
|
||||||
|
{
|
||||||
|
this.appConfig = appConfig;
|
||||||
|
this.filter = new RequestFilter();
|
||||||
|
this.logger = logger;
|
||||||
|
this.settings = settings;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Initialize()
|
||||||
|
{
|
||||||
|
if (settings.FilterMainRequests || settings.FilterContentRequests)
|
||||||
|
{
|
||||||
|
InitializeFilter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IResourceHandler GetResourceHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request)
|
||||||
|
{
|
||||||
|
if (BlockMainRequest(request))
|
||||||
|
{
|
||||||
|
return pageBlockedHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BlockContentRequest(request))
|
||||||
|
{
|
||||||
|
return contentBlockedHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.GetResourceHandler(chromiumWebBrowser, browser, frame, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override CefReturnValue OnBeforeResourceLoad(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
|
||||||
|
{
|
||||||
|
// TODO: CEF does not yet support intercepting requests from service workers, thus the user agent must be statically set at browser
|
||||||
|
// startup for now. Once CEF has full support of service workers, the static user agent should be removed and the method below
|
||||||
|
// reactivated. See https://bitbucket.org/chromiumembedded/cef/issues/2622 for the current status of development.
|
||||||
|
// AppendCustomUserAgent(request);
|
||||||
|
|
||||||
|
if (IsMailtoUrl(request.Url))
|
||||||
|
{
|
||||||
|
return CefReturnValue.Cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplaceCustomScheme(request);
|
||||||
|
|
||||||
|
return base.OnBeforeResourceLoad(webBrowser, browser, frame, request, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppendCustomUserAgent(IRequest request)
|
||||||
|
{
|
||||||
|
var headers = new NameValueCollection(request.Headers);
|
||||||
|
var userAgent = request.Headers["User-Agent"];
|
||||||
|
|
||||||
|
headers["User-Agent"] = $"{userAgent} SEB/{appConfig.ProgramInformationalVersion}";
|
||||||
|
request.Headers = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool BlockContentRequest(IRequest request)
|
||||||
|
{
|
||||||
|
if (settings.FilterContentRequests && request.ResourceType != ResourceType.MainFrame)
|
||||||
|
{
|
||||||
|
var result = filter.Process(request.Url);
|
||||||
|
var block = result == FilterResult.Block;
|
||||||
|
|
||||||
|
if (block)
|
||||||
|
{
|
||||||
|
logger.Info($"Blocked content request for '{request.Url}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
var assembly = Assembly.GetAssembly(typeof(RequestFilter));
|
||||||
|
var contentMessage = text.Get(TextKey.Browser_BlockedContentMessage);
|
||||||
|
var contentStream = assembly.GetManifestResourceStream($"{typeof(RequestFilter).Namespace}.BlockedContent.html");
|
||||||
|
var pageButton = text.Get(TextKey.Browser_BlockedPageButton);
|
||||||
|
var pageMessage = text.Get(TextKey.Browser_BlockedPageMessage);
|
||||||
|
var pageTitle = text.Get(TextKey.Browser_BlockedPageTitle);
|
||||||
|
var pageStream = assembly.GetManifestResourceStream($"{typeof(RequestFilter).Namespace}.BlockedPage.html");
|
||||||
|
var contentHtml = new StreamReader(contentStream).ReadToEnd();
|
||||||
|
var pageHtml = new StreamReader(pageStream).ReadToEnd();
|
||||||
|
|
||||||
|
contentHtml = contentHtml.Replace("%%MESSAGE%%", contentMessage);
|
||||||
|
pageHtml = pageHtml.Replace("%%MESSAGE%%", pageMessage).Replace("%%TITLE%%", pageTitle).Replace("%%BACK_BUTTON%%", pageButton);
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsMailtoUrl(string url)
|
||||||
|
{
|
||||||
|
return url.StartsWith(Uri.UriSchemeMailto);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReplaceCustomScheme(IRequest request)
|
||||||
|
{
|
||||||
|
if (Uri.IsWellFormedUriString(request.Url, UriKind.RelativeOrAbsolute))
|
||||||
|
{
|
||||||
|
var uri = new Uri(request.Url);
|
||||||
|
|
||||||
|
if (uri.Scheme == appConfig.SebUriScheme)
|
||||||
|
{
|
||||||
|
request.Url = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri.AbsoluteUri;
|
||||||
|
}
|
||||||
|
else if (uri.Scheme == appConfig.SebUriSchemeSecure)
|
||||||
|
{
|
||||||
|
request.Url = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttps }.Uri.AbsoluteUri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using CefSharp;
|
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
|
||||||
using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Browser.Handlers
|
|
||||||
{
|
|
||||||
internal class ResourceRequestHandler : CefSharp.Handler.ResourceRequestHandler
|
|
||||||
{
|
|
||||||
private AppConfig appConfig;
|
|
||||||
private BrowserSettings settings;
|
|
||||||
private ILogger logger;
|
|
||||||
|
|
||||||
internal ResourceRequestHandler(AppConfig appConfig, BrowserSettings settings, ILogger logger)
|
|
||||||
{
|
|
||||||
this.appConfig = appConfig;
|
|
||||||
this.settings = settings;
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IResourceHandler GetResourceHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request)
|
|
||||||
{
|
|
||||||
if (FilterMainRequest(request) || FilterContentRequest(request))
|
|
||||||
{
|
|
||||||
return ResourceHandler.FromString("<html><body>Blocked!</body></html>");
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.GetResourceHandler(webBrowser, browser, frame, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override CefReturnValue OnBeforeResourceLoad(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
|
|
||||||
{
|
|
||||||
// TODO: CEF does not yet support intercepting requests from service workers, thus the user agent must be statically set at browser
|
|
||||||
// startup for now. Once CEF has full support of service workers, the static user agent should be removed and the method below
|
|
||||||
// reactivated. See https://bitbucket.org/chromiumembedded/cef/issues/2622 for the current status of development.
|
|
||||||
// AppendCustomUserAgent(request);
|
|
||||||
|
|
||||||
if (IsMailtoUrl(request.Url))
|
|
||||||
{
|
|
||||||
return CefReturnValue.Cancel;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReplaceCustomScheme(request);
|
|
||||||
|
|
||||||
return base.OnBeforeResourceLoad(webBrowser, browser, frame, request, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AppendCustomUserAgent(IRequest request)
|
|
||||||
{
|
|
||||||
var headers = new NameValueCollection(request.Headers);
|
|
||||||
var userAgent = request.Headers["User-Agent"];
|
|
||||||
|
|
||||||
headers["User-Agent"] = $"{userAgent} SEB/{appConfig.ProgramInformationalVersion}";
|
|
||||||
request.Headers = headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool FilterContentRequest(IRequest request)
|
|
||||||
{
|
|
||||||
return settings.FilterContentRequests && request.ResourceType != ResourceType.MainFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool FilterMainRequest(IRequest request)
|
|
||||||
{
|
|
||||||
return settings.FilterMainRequests && request.ResourceType == ResourceType.MainFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsMailtoUrl(string url)
|
|
||||||
{
|
|
||||||
return url.StartsWith(Uri.UriSchemeMailto);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReplaceCustomScheme(IRequest request)
|
|
||||||
{
|
|
||||||
if (Uri.IsWellFormedUriString(request.Url, UriKind.RelativeOrAbsolute))
|
|
||||||
{
|
|
||||||
var uri = new Uri(request.Url);
|
|
||||||
|
|
||||||
if (uri.Scheme == appConfig.SebUriScheme)
|
|
||||||
{
|
|
||||||
request.Url = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri.AbsoluteUri;
|
|
||||||
}
|
|
||||||
else if (uri.Scheme == appConfig.SebUriSchemeSecure)
|
|
||||||
{
|
|
||||||
request.Url = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttps }.Uri.AbsoluteUri;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
|
@ -14,6 +15,7 @@ using System.Runtime.InteropServices;
|
||||||
// to COM components. If you need to access a type in this assembly from
|
// to COM components. If you need to access a type in this assembly from
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
[assembly: InternalsVisibleTo("SafeExamBrowser.Browser.UnitTests")]
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
[assembly: Guid("04e653f1-98e6-4e34-9dd7-7f2bc1a8b767")]
|
[assembly: Guid("04e653f1-98e6-4e34-9dd7-7f2bc1a8b767")]
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
@ -72,6 +73,9 @@
|
||||||
<Compile Include="Events\PopupRequestedEventArgs.cs" />
|
<Compile Include="Events\PopupRequestedEventArgs.cs" />
|
||||||
<Compile Include="Events\PopupRequestedEventHandler.cs" />
|
<Compile Include="Events\PopupRequestedEventHandler.cs" />
|
||||||
<Compile Include="Filters\RequestFilter.cs" />
|
<Compile Include="Filters\RequestFilter.cs" />
|
||||||
|
<Compile Include="Filters\Rules\Rule.cs" />
|
||||||
|
<Compile Include="Filters\Rules\RegexRule.cs" />
|
||||||
|
<Compile Include="Filters\Rules\SimpleRule.cs" />
|
||||||
<Compile Include="Handlers\ContextMenuHandler.cs" />
|
<Compile Include="Handlers\ContextMenuHandler.cs" />
|
||||||
<Compile Include="BrowserControl.cs">
|
<Compile Include="BrowserControl.cs">
|
||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
|
@ -82,7 +86,7 @@
|
||||||
<Compile Include="Handlers\KeyboardHandler.cs" />
|
<Compile Include="Handlers\KeyboardHandler.cs" />
|
||||||
<Compile Include="Handlers\LifeSpanHandler.cs" />
|
<Compile Include="Handlers\LifeSpanHandler.cs" />
|
||||||
<Compile Include="Handlers\RequestHandler.cs" />
|
<Compile Include="Handlers\RequestHandler.cs" />
|
||||||
<Compile Include="Handlers\ResourceRequestHandler.cs" />
|
<Compile Include="Handlers\ResourceHandler.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -124,6 +128,10 @@
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Filters\BlockedContent.html" />
|
||||||
|
<EmbeddedResource Include="Filters\BlockedPage.html" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
|
|
|
@ -110,7 +110,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
{
|
{
|
||||||
if (value is bool filter)
|
if (value is bool filter)
|
||||||
{
|
{
|
||||||
settings.Browser.FilterContentRequests = filter;
|
settings.Browser.Filter.FilterContentRequests = filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
{
|
{
|
||||||
if (value is bool filter)
|
if (value is bool filter)
|
||||||
{
|
{
|
||||||
settings.Browser.FilterMainRequests = filter;
|
settings.Browser.Filter.FilterMainRequests = filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,30 +126,33 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
{
|
{
|
||||||
const int ALLOW = 1;
|
const int ALLOW = 1;
|
||||||
|
|
||||||
if (value is IEnumerable<IDictionary<string, object>> ruleDataList)
|
if (value is IList<object> ruleDataList)
|
||||||
{
|
{
|
||||||
foreach (var ruleData in ruleDataList)
|
foreach (var item in ruleDataList)
|
||||||
{
|
{
|
||||||
if (ruleData.TryGetValue(Keys.Browser.Filter.RuleIsActive, out var v) && v is bool active && active)
|
if (item is IDictionary<string, object> ruleData)
|
||||||
{
|
{
|
||||||
var rule = new FilterRule();
|
if (ruleData.TryGetValue(Keys.Browser.Filter.RuleIsActive, out var v) && v is bool active && active)
|
||||||
|
|
||||||
if (ruleData.TryGetValue(Keys.Browser.Filter.RuleExpression, out v) && v is string expression)
|
|
||||||
{
|
{
|
||||||
rule.Expression = expression;
|
var rule = new FilterRuleSettings();
|
||||||
}
|
|
||||||
|
|
||||||
if (ruleData.TryGetValue(Keys.Browser.Filter.RuleAction, out v) && v is int action)
|
if (ruleData.TryGetValue(Keys.Browser.Filter.RuleExpression, out v) && v is string expression)
|
||||||
{
|
{
|
||||||
rule.Result = action == ALLOW ? FilterResult.Allow : FilterResult.Block;
|
rule.Expression = expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ruleData.TryGetValue(Keys.Browser.Filter.RuleExpressionIsRegex, out v) && v is bool regex)
|
if (ruleData.TryGetValue(Keys.Browser.Filter.RuleAction, out v) && v is int action)
|
||||||
{
|
{
|
||||||
rule.Type = regex ? FilterType.Regex : FilterType.Simplified;
|
rule.Result = action == ALLOW ? FilterResult.Allow : FilterResult.Block;
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.Browser.FilterRules.Add(rule);
|
if (ruleData.TryGetValue(Keys.Browser.Filter.RuleExpressionIsRegex, out v) && v is bool regex)
|
||||||
|
{
|
||||||
|
rule.Type = regex ? FilterType.Regex : FilterType.Simplified;
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Browser.Filter.Rules.Add(rule);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,10 @@ namespace SafeExamBrowser.I18n.Contracts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum TextKey
|
public enum TextKey
|
||||||
{
|
{
|
||||||
|
Browser_BlockedContentMessage,
|
||||||
|
Browser_BlockedPageButton,
|
||||||
|
Browser_BlockedPageMessage,
|
||||||
|
Browser_BlockedPageTitle,
|
||||||
BrowserWindow_DeveloperConsoleMenuItem,
|
BrowserWindow_DeveloperConsoleMenuItem,
|
||||||
BrowserWindow_ZoomMenuItem,
|
BrowserWindow_ZoomMenuItem,
|
||||||
Build,
|
Build,
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<Text>
|
<Text>
|
||||||
|
<Entry key="Browser_BlockedContentMessage">
|
||||||
|
Content blocked
|
||||||
|
</Entry>
|
||||||
|
<Entry key="Browser_BlockedPageButton">
|
||||||
|
Back to previous page
|
||||||
|
</Entry>
|
||||||
|
<Entry key="Browser_BlockedPageMessage">
|
||||||
|
Access to this page is not allowed according to the application configuration.
|
||||||
|
</Entry>
|
||||||
|
<Entry key="Browser_BlockedPageTitle">
|
||||||
|
Page Blocked
|
||||||
|
</Entry>
|
||||||
<Entry key="BrowserWindow_DeveloperConsoleMenuItem">
|
<Entry key="BrowserWindow_DeveloperConsoleMenuItem">
|
||||||
Developer Console
|
Developer Console
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
40
SafeExamBrowser.Settings/Browser/BrowserFilterSettings.cs
Normal file
40
SafeExamBrowser.Settings/Browser/BrowserFilterSettings.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Settings.Browser
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines all configuration options for the request filter of the browser.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class BrowserFilterSettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines whether all content requests for a web page should be filtered according to the defined <see cref="Rules"/>.
|
||||||
|
/// </summary>
|
||||||
|
public bool FilterContentRequests { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines whether the main request for a web page should be filtered according to the defined <see cref="Rules"/>.
|
||||||
|
/// </summary>
|
||||||
|
public bool FilterMainRequests { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines all rules to be used to filter web requests.
|
||||||
|
/// </summary>
|
||||||
|
public IList<FilterRuleSettings> Rules { get; set; }
|
||||||
|
|
||||||
|
public BrowserFilterSettings()
|
||||||
|
{
|
||||||
|
Rules = new List<FilterRuleSettings>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Settings.Browser
|
namespace SafeExamBrowser.Settings.Browser
|
||||||
{
|
{
|
||||||
|
@ -48,19 +47,9 @@ namespace SafeExamBrowser.Settings.Browser
|
||||||
public string CustomUserAgent { get; set; }
|
public string CustomUserAgent { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines whether all content requests for a web page should be filtered according to the defined <see cref="FilterRules"/>.
|
/// The settings to be used for the browser request filter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool FilterContentRequests { get; set; }
|
public BrowserFilterSettings Filter { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines whether the main request for a web page should be filtered according to the defined <see cref="FilterRules"/>.
|
|
||||||
/// </summary>
|
|
||||||
public bool FilterMainRequests { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines all rules to be used to filter web requests.
|
|
||||||
/// </summary>
|
|
||||||
public IList<FilterRule> FilterRules { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The configuration to be used for the main browser window.
|
/// The configuration to be used for the main browser window.
|
||||||
|
@ -80,7 +69,7 @@ namespace SafeExamBrowser.Settings.Browser
|
||||||
public BrowserSettings()
|
public BrowserSettings()
|
||||||
{
|
{
|
||||||
AdditionalWindowSettings = new BrowserWindowSettings();
|
AdditionalWindowSettings = new BrowserWindowSettings();
|
||||||
FilterRules = new List<FilterRule>();
|
Filter = new BrowserFilterSettings();
|
||||||
MainWindowSettings = new BrowserWindowSettings();
|
MainWindowSettings = new BrowserWindowSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,10 @@ using System;
|
||||||
namespace SafeExamBrowser.Settings.Browser
|
namespace SafeExamBrowser.Settings.Browser
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines a request filter rule.
|
/// Defines the settings for a request filter rule.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class FilterRule
|
public class FilterRuleSettings
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The expression according to which requests should be filtered.
|
/// The expression according to which requests should be filtered.
|
|
@ -53,10 +53,11 @@
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Browser\BrowserFilterSettings.cs" />
|
||||||
<Compile Include="Browser\BrowserSettings.cs" />
|
<Compile Include="Browser\BrowserSettings.cs" />
|
||||||
<Compile Include="Browser\BrowserWindowSettings.cs" />
|
<Compile Include="Browser\BrowserWindowSettings.cs" />
|
||||||
<Compile Include="Browser\FilterResult.cs" />
|
<Compile Include="Browser\FilterResult.cs" />
|
||||||
<Compile Include="Browser\FilterRule.cs" />
|
<Compile Include="Browser\FilterRuleSettings.cs" />
|
||||||
<Compile Include="Browser\FilterType.cs" />
|
<Compile Include="Browser\FilterType.cs" />
|
||||||
<Compile Include="ConfigurationMode.cs" />
|
<Compile Include="ConfigurationMode.cs" />
|
||||||
<Compile Include="KioskMode.cs" />
|
<Compile Include="KioskMode.cs" />
|
||||||
|
|
|
@ -104,6 +104,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.WindowsApi.
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Settings", "SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj", "{30B2D907-5861-4F39-ABAD-C4ABF1B3470E}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Settings", "SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj", "{30B2D907-5861-4F39-ABAD-C4ABF1B3470E}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Browser.UnitTests", "SafeExamBrowser.Browser.UnitTests\SafeExamBrowser.Browser.UnitTests.csproj", "{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -466,6 +468,14 @@ Global
|
||||||
{30B2D907-5861-4F39-ABAD-C4ABF1B3470E}.Release|Any CPU.Build.0 = Release|Any CPU
|
{30B2D907-5861-4F39-ABAD-C4ABF1B3470E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{30B2D907-5861-4F39-ABAD-C4ABF1B3470E}.Release|x86.ActiveCfg = Release|x86
|
{30B2D907-5861-4F39-ABAD-C4ABF1B3470E}.Release|x86.ActiveCfg = Release|x86
|
||||||
{30B2D907-5861-4F39-ABAD-C4ABF1B3470E}.Release|x86.Build.0 = Release|x86
|
{30B2D907-5861-4F39-ABAD-C4ABF1B3470E}.Release|x86.Build.0 = Release|x86
|
||||||
|
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Release|x86.Build.0 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -7,7 +7,8 @@ before_build:
|
||||||
build_script:
|
build_script:
|
||||||
- msbuild /verbosity:minimal "SafeExamBrowser.sln"
|
- msbuild /verbosity:minimal "SafeExamBrowser.sln"
|
||||||
test_script:
|
test_script:
|
||||||
- .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register -target:"vstest.console.exe" -targetargs:"/logger:Appveyor .\SafeExamBrowser.Client.UnitTests\bin\%PLATFORM%\%CONFIGURATION%\SafeExamBrowser.Client.UnitTests.dll" -filter:"+[*]* -[*.UnitTests]* -[*Moq*]*" -mergebyhash -output:"coverage.xml"
|
- .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register -target:"vstest.console.exe" -targetargs:"/logger:Appveyor .\SafeExamBrowser.Browser.UnitTests\bin\%PLATFORM%\%CONFIGURATION%\SafeExamBrowser.Browser.UnitTests.dll" -filter:"+[*]* -[*.UnitTests]* -[*Moq*]*" -mergebyhash -output:"coverage.xml"
|
||||||
|
- .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register -target:"vstest.console.exe" -targetargs:"/logger:Appveyor .\SafeExamBrowser.Client.UnitTests\bin\%PLATFORM%\%CONFIGURATION%\SafeExamBrowser.Client.UnitTests.dll" -filter:"+[*]* -[*.UnitTests]* -[*Moq*]*" -mergebyhash -mergeoutput -output:"coverage.xml"
|
||||||
- .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register -target:"vstest.console.exe" -targetargs:"/logger:Appveyor .\SafeExamBrowser.Communication.UnitTests\bin\%PLATFORM%\%CONFIGURATION%\SafeExamBrowser.Communication.UnitTests.dll" -filter:"+[*]* -[*.UnitTests]* -[*Moq*]*" -mergebyhash -mergeoutput -output:"coverage.xml"
|
- .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register -target:"vstest.console.exe" -targetargs:"/logger:Appveyor .\SafeExamBrowser.Communication.UnitTests\bin\%PLATFORM%\%CONFIGURATION%\SafeExamBrowser.Communication.UnitTests.dll" -filter:"+[*]* -[*.UnitTests]* -[*Moq*]*" -mergebyhash -mergeoutput -output:"coverage.xml"
|
||||||
- .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register -target:"vstest.console.exe" -targetargs:"/logger:Appveyor .\SafeExamBrowser.Configuration.UnitTests\bin\%PLATFORM%\%CONFIGURATION%\SafeExamBrowser.Configuration.UnitTests.dll" -filter:"+[*]* -[*.UnitTests]* -[*Moq*]*" -mergebyhash -mergeoutput -output:"coverage.xml"
|
- .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register -target:"vstest.console.exe" -targetargs:"/logger:Appveyor .\SafeExamBrowser.Configuration.UnitTests\bin\%PLATFORM%\%CONFIGURATION%\SafeExamBrowser.Configuration.UnitTests.dll" -filter:"+[*]* -[*.UnitTests]* -[*Moq*]*" -mergebyhash -mergeoutput -output:"coverage.xml"
|
||||||
- .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register -target:"vstest.console.exe" -targetargs:"/logger:Appveyor .\SafeExamBrowser.Core.UnitTests\bin\%PLATFORM%\%CONFIGURATION%\SafeExamBrowser.Core.UnitTests.dll" -filter:"+[*]* -[*.UnitTests]* -[*Moq*]*" -mergebyhash -mergeoutput -output:"coverage.xml"
|
- .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register -target:"vstest.console.exe" -targetargs:"/logger:Appveyor .\SafeExamBrowser.Core.UnitTests\bin\%PLATFORM%\%CONFIGURATION%\SafeExamBrowser.Core.UnitTests.dll" -filter:"+[*]* -[*.UnitTests]* -[*Moq*]*" -mergebyhash -mergeoutput -output:"coverage.xml"
|
||||||
|
|
Loading…
Reference in a new issue