SEBWIN-727: Implemented support for configuration data URIs.

This commit is contained in:
Damian Büchel 2023-09-05 17:47:05 +02:00
parent bbfa720b21
commit 3711555f70
5 changed files with 68 additions and 13 deletions

View file

@ -69,6 +69,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
var quitUrl = "http://www.byebye.com"; var quitUrl = "http://www.byebye.com";
var request = new Mock<IRequest>(); var request = new Mock<IRequest>();
appConfig.ConfigurationFileMimeType = "application/seb";
request.SetupGet(r => r.Url).Returns(quitUrl); request.SetupGet(r => r.Url).Returns(quitUrl);
settings.QuitUrl = quitUrl; settings.QuitUrl = quitUrl;
sut.QuitUrlVisited += (url) => eventFired = true; sut.QuitUrlVisited += (url) => eventFired = true;
@ -122,6 +123,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
var request = new Mock<IRequest>(); var request = new Mock<IRequest>();
var url = "https://www.test.org"; var url = "https://www.test.org";
appConfig.ConfigurationFileMimeType = "application/seb";
filter.Setup(f => f.Process(It.Is<Request>(r => r.Url.Equals(url)))).Returns(FilterResult.Block); filter.Setup(f => f.Process(It.Is<Request>(r => r.Url.Equals(url)))).Returns(FilterResult.Block);
request.SetupGet(r => r.ResourceType).Returns(ResourceType.MainFrame); request.SetupGet(r => r.ResourceType).Returns(ResourceType.MainFrame);
request.SetupGet(r => r.Url).Returns(url); request.SetupGet(r => r.Url).Returns(url);
@ -155,6 +157,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
var request = new Mock<IRequest>(); var request = new Mock<IRequest>();
var url = "https://www.test.org"; var url = "https://www.test.org";
appConfig.ConfigurationFileMimeType = "application/seb";
filter.Setup(f => f.Process(It.Is<Request>(r => r.Url.Equals(url)))).Returns(FilterResult.Block); filter.Setup(f => f.Process(It.Is<Request>(r => r.Url.Equals(url)))).Returns(FilterResult.Block);
request.SetupGet(r => r.ResourceType).Returns(ResourceType.SubFrame); request.SetupGet(r => r.ResourceType).Returns(ResourceType.SubFrame);
request.SetupGet(r => r.Url).Returns(url); request.SetupGet(r => r.Url).Returns(url);
@ -182,13 +185,34 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
} }
[TestMethod] [TestMethod]
public void MustInitiateConfigurationFileDownload() public void MustInitiateDataUriConfigurationFileDownload()
{ {
var browser = new Mock<IBrowser>(); var browser = new Mock<IBrowser>();
var host = new Mock<IBrowserHost>(); var host = new Mock<IBrowserHost>();
var request = new Mock<IRequest>(); var request = new Mock<IRequest>();
appConfig.ConfigurationFileExtension = ".xyz"; appConfig.ConfigurationFileExtension = ".xyz";
appConfig.ConfigurationFileMimeType = "application/seb";
appConfig.SebUriScheme = "abc";
appConfig.SebUriSchemeSecure = "abcd";
browser.Setup(b => b.GetHost()).Returns(host.Object);
request.SetupGet(r => r.Url).Returns($"{appConfig.SebUriSchemeSecure}://{appConfig.ConfigurationFileMimeType};base64,H4sIAAAAAAAAE41WbXPaRhD...");
var handled = sut.OnBeforeBrowse(Mock.Of<IWebBrowser>(), browser.Object, Mock.Of<IFrame>(), request.Object, false, false);
host.Verify(h => h.StartDownload(It.Is<string>(u => u == $"data:{appConfig.ConfigurationFileMimeType};base64,H4sIAAAAAAAAE41WbXPaRhD...")));
Assert.IsTrue(handled);
}
[TestMethod]
public void MustInitiateHttpConfigurationFileDownload()
{
var browser = new Mock<IBrowser>();
var host = new Mock<IBrowserHost>();
var request = new Mock<IRequest>();
appConfig.ConfigurationFileExtension = ".xyz";
appConfig.ConfigurationFileMimeType = "application/seb";
appConfig.SebUriScheme = "abc"; appConfig.SebUriScheme = "abc";
appConfig.SebUriSchemeSecure = "abcd"; appConfig.SebUriSchemeSecure = "abcd";
browser.Setup(b => b.GetHost()).Returns(host.Object); browser.Setup(b => b.GetHost()).Returns(host.Object);
@ -198,13 +222,23 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
host.Verify(h => h.StartDownload(It.Is<string>(u => u == $"{Uri.UriSchemeHttp}://host.com/path/file{appConfig.ConfigurationFileExtension}"))); host.Verify(h => h.StartDownload(It.Is<string>(u => u == $"{Uri.UriSchemeHttp}://host.com/path/file{appConfig.ConfigurationFileExtension}")));
Assert.IsTrue(handled); Assert.IsTrue(handled);
}
handled = false; [TestMethod]
host.Reset(); public void MustInitiateHttpsConfigurationFileDownload()
request.Reset(); {
var browser = new Mock<IBrowser>();
var host = new Mock<IBrowserHost>();
var request = new Mock<IRequest>();
appConfig.ConfigurationFileExtension = ".xyz";
appConfig.ConfigurationFileMimeType = "application/seb";
appConfig.SebUriScheme = "abc";
appConfig.SebUriSchemeSecure = "abcd";
browser.Setup(b => b.GetHost()).Returns(host.Object);
request.SetupGet(r => r.Url).Returns($"{appConfig.SebUriSchemeSecure}://host.com/path/file{appConfig.ConfigurationFileExtension}"); request.SetupGet(r => r.Url).Returns($"{appConfig.SebUriSchemeSecure}://host.com/path/file{appConfig.ConfigurationFileExtension}");
handled = sut.OnBeforeBrowse(Mock.Of<IWebBrowser>(), browser.Object, Mock.Of<IFrame>(), request.Object, false, false); var handled = sut.OnBeforeBrowse(Mock.Of<IWebBrowser>(), browser.Object, Mock.Of<IFrame>(), request.Object, false, false);
host.Verify(h => h.StartDownload(It.Is<string>(u => u == $"{Uri.UriSchemeHttps}://host.com/path/file{appConfig.ConfigurationFileExtension}"))); host.Verify(h => h.StartDownload(It.Is<string>(u => u == $"{Uri.UriSchemeHttps}://host.com/path/file{appConfig.ConfigurationFileExtension}")));
Assert.IsTrue(handled); Assert.IsTrue(handled);

View file

@ -121,19 +121,35 @@ namespace SafeExamBrowser.Browser.Handlers
private bool IsConfigurationFile(IRequest request, out string downloadUrl) private bool IsConfigurationFile(IRequest request, out string downloadUrl)
{ {
var isValidUri = Uri.TryCreate(request.Url, UriKind.RelativeOrAbsolute, out var uri); var isValidUri = Uri.TryCreate(request.Url, UriKind.RelativeOrAbsolute, out var uri);
var isConfigurationFile = isValidUri && string.Equals(appConfig.ConfigurationFileExtension, Path.GetExtension(uri.AbsolutePath), StringComparison.OrdinalIgnoreCase); var hasFileExtension = string.Equals(appConfig.ConfigurationFileExtension, Path.GetExtension(uri.AbsolutePath), StringComparison.OrdinalIgnoreCase);
var isDataUri = request.Url.Contains(appConfig.ConfigurationFileMimeType);
var isConfigurationFile = isValidUri && (hasFileExtension || isDataUri);
downloadUrl = request.Url; downloadUrl = request.Url;
if (isConfigurationFile) if (isConfigurationFile)
{ {
if (uri.Scheme == appConfig.SebUriScheme) if (isDataUri)
{ {
downloadUrl = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri.AbsoluteUri; if (uri.Scheme == appConfig.SebUriScheme)
{
downloadUrl = request.Url.Replace($"{appConfig.SebUriScheme}{Uri.SchemeDelimiter}", "data:");
}
else if (uri.Scheme == appConfig.SebUriSchemeSecure)
{
downloadUrl = request.Url.Replace($"{appConfig.SebUriSchemeSecure}{Uri.SchemeDelimiter}", "data:");
}
} }
else if (uri.Scheme == appConfig.SebUriSchemeSecure) else
{ {
downloadUrl = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttps }.Uri.AbsoluteUri; if (uri.Scheme == appConfig.SebUriScheme)
{
downloadUrl = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri.AbsoluteUri;
}
else if (uri.Scheme == appConfig.SebUriSchemeSecure)
{
downloadUrl = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttps }.Uri.AbsoluteUri;
}
} }
logger.Debug($"Detected configuration file {(windowSettings.UrlPolicy.CanLog() ? $"'{uri}'" : "")}."); logger.Debug($"Detected configuration file {(windowSettings.UrlPolicy.CanLog() ? $"'{uri}'" : "")}.");

View file

@ -624,10 +624,10 @@ namespace SafeExamBrowser.Client
logger.Info($"Received server failure action request with id '{args.RequestId}'."); logger.Info($"Received server failure action request with id '{args.RequestId}'.");
var dialog = uiFactory.CreateServerFailureDialog(args.Message, args.ShowFallback); var dialog = uiFactory.CreateServerFailureDialog(args.Message, args.ShowFallback);
var result = dialog.Show(splashScreen); var result = dialog.Show();
runtime.SubmitServerFailureActionResult(args.RequestId, result.Abort, result.Fallback, result.Retry); runtime.SubmitServerFailureActionResult(args.RequestId, result.Abort, result.Fallback, result.Retry);
logger.Info($"Server failure action request with id '{args.RequestId}' is complete."); logger.Info($"Server failure action request with id '{args.RequestId}' is complete, the user chose to {(result.Abort ? "abort" : (result.Fallback ? "fallback" : "retry"))}.");
} }
private void ClientHost_Shutdown() private void ClientHost_Shutdown()

View file

@ -241,6 +241,11 @@ namespace SafeExamBrowser.Runtime.Operations
abort = args.Abort; abort = args.Abort;
fallback = args.Fallback; fallback = args.Fallback;
if (args.Retry)
{
logger.Debug("The user chose to retry the current server request.");
}
return args.Retry; return args.Retry;
} }

View file

@ -5,7 +5,7 @@
xmlns:fa="http://schemas.fontawesome.io/icons/" xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Windows" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Windows"
mc:Ignorable="d" Height="250" Width="450" ResizeMode="NoResize" Topmost="True"> mc:Ignorable="d" Height="250" Width="450" ResizeMode="NoResize" Topmost="True" WindowStartupLocation="CenterScreen">
<Window.Resources> <Window.Resources>
<ResourceDictionary> <ResourceDictionary>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>