Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
|
516b75942a | ||
|
276555cc35 | ||
|
f5e4016dfd | ||
|
21aa407d2b |
1106 changed files with 5709 additions and 21943 deletions
8
.github/ISSUE_TEMPLATE/bug-report.md
vendored
8
.github/ISSUE_TEMPLATE/bug-report.md
vendored
|
@ -1,15 +1,15 @@
|
|||
---
|
||||
name: Bug Report
|
||||
about: Create a bug report to help us improve Safe Exam Browser.
|
||||
about: Create a report to help us improve Safe Exam Browser
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: dbuechel
|
||||
|
||||
---
|
||||
|
||||
> [!IMPORTANT]
|
||||
> - Please _always_ consult the documentation first before creating a bug report: https://safeexambrowser.org/windows/win_usermanual_en.html.
|
||||
> - Please _always_ attach the log file(s) of the affected session(s)! They can be found under `%LocalAppData%\SafeExamBrowser\Logs`.
|
||||
**IMPORTANT**
|
||||
Please _always_ consult the documentation first before creating a bug report!
|
||||
https://safeexambrowser.org/windows/win_usermanual_en.html
|
||||
|
||||
**Describe the Bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
|
2
.github/ISSUE_TEMPLATE/feature-request.md
vendored
2
.github/ISSUE_TEMPLATE/feature-request.md
vendored
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: Feature Request
|
||||
about: Suggest an idea or new feature for Safe Exam Browser.
|
||||
about: Suggest an idea for Safe Exam Browser
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: dbuechel
|
||||
|
|
54
.github/workflows/codeql.yml
vendored
54
.github/workflows/codeql.yml
vendored
|
@ -1,54 +0,0 @@
|
|||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master", "*" ]
|
||||
pull_request:
|
||||
branches: [ "master", "*" ]
|
||||
schedule:
|
||||
- cron: '0 0 * * 1'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: "windows-latest"
|
||||
timeout-minutes: 360
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'csharp', 'javascript-typescript' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: security-extended,security-and-quality
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
25
.github/workflows/issues.yml
vendored
25
.github/workflows/issues.yml
vendored
|
@ -1,25 +0,0 @@
|
|||
name: Issue Maintenance
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
close-issues:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
# https://github.com/marketplace/actions/close-stale-issues
|
||||
days-before-issue-stale: 28
|
||||
days-before-issue-close: 14
|
||||
stale-issue-label: "stale"
|
||||
stale-issue-message: "This issue is stale because it has been open for 28 days with no activity. It will soon be closed automatically if there are no updates."
|
||||
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
|
||||
days-before-pr-stale: -1
|
||||
days-before-pr-close: -1
|
||||
exempt-issue-labels: "bug,enhancement,feature request,known issue"
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
BIN
Libraries/SimpleWifi.dll
Normal file
BIN
Libraries/SimpleWifi.dll
Normal file
Binary file not shown.
|
@ -6,17 +6,18 @@ Refactored version of Safe Exam Browser for Windows with Chromium as integrated
|
|||
|
||||
SEB 3.x requires the prerequisites listed below in order to work correctly. These are automatically installed with the setup bundle and need only be manually installed when using the MSI packages.
|
||||
|
||||
* .NET Framework 4.8 Runtime: https://dotnet.microsoft.com/download/dotnet-framework/net48
|
||||
* .NET Framework 4.7.2 Runtime: https://dotnet.microsoft.com/download/dotnet-framework/net472
|
||||
* Microsoft Edge WebView2 Runtime: https://go.microsoft.com/fwlink/p/?LinkId=2124703
|
||||
* Visual C++ 2015-2019 Redistributable: https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads
|
||||
|
||||
## Project Status
|
||||
|
||||
> [!WARNING]
|
||||
> **The builds linked below are for testing purposes only.** They may be unstable and should thus _never_ be used in a production environment! Always use the latest, official release version of SEB.
|
||||
**_DISCLAIMER_**\
|
||||
**The builds linked below are for testing purposes only.** They may be unstable and should thus _never_ be used in a production environment! Always use the latest, official release version of SEB.
|
||||
|
||||
| Aspect | Status | Details |
|
||||
| ----------------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
||||
| Development Build | ![Development Build Status](https://sebdev.ethz.ch/api/projects/status/kq78qrjtnpk82ti0?svg=true) | https://sebdev.ethz.ch/project/appveyor/seb-win-refactoring |
|
||||
| Development Build | ![Development Build Status](https://sebdev-let.ethz.ch/api/projects/status/kq78qrjtnpk82ti0?svg=true) | https://sebdev-let.ethz.ch/project/appveyor/seb-win-refactoring |
|
||||
| Test Build | ![Test Build Status](https://ci.appveyor.com/api/projects/status/a56akt9r174570m7?svg=true) | https://ci.appveyor.com/project/dbuechel/seb-win-refactoring |
|
||||
| Test Run | ![AppVeyor Tests](https://img.shields.io/appveyor/tests/dbuechel/seb-win-refactoring?logo=appveyor&logoColor=%23ccc) | https://ci.appveyor.com/project/dbuechel/seb-win-refactoring |
|
||||
| Code Coverage | ![Code Coverage](https://codecov.io/gh/SafeExamBrowser/seb-win-refactoring/branch/master/graph/badge.svg) | https://codecov.io/gh/SafeExamBrowser/seb-win-refactoring |
|
||||
|
|
35
SECURITY.md
35
SECURITY.md
|
@ -1,35 +0,0 @@
|
|||
# Security Policy
|
||||
|
||||
We only support the latest official relese version with respect to security vulnerabilities. Thus, only the latest or then the upcoming next release version
|
||||
will receive vulnerability fixes and security updates. A vulnerability may however be reported for any version, unless it already has been fixed with a later
|
||||
release version.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
> [!IMPORTANT]
|
||||
> - Please _always_ verify that no later release version exists which fixes the vulnerability.
|
||||
> - Please _always_ consult the documentation first before creating a vulnerability report: https://safeexambrowser.org/windows/win_usermanual_en.html.
|
||||
> - Please _always_ attach the log file(s) of the affected session(s)! They can be found under `%LocalAppData%\SafeExamBrowser\Logs`.
|
||||
|
||||
**Describe the Vulnerability**
|
||||
A clear and concise description of what the vulnerability is.
|
||||
|
||||
**Steps to Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See ...
|
||||
|
||||
**Expected Behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Version Information**
|
||||
- OS: [e.g. Windows 10 Professional, Version 1803]
|
||||
- SEB-Version [e.g. SEB 3.0.1]
|
||||
|
||||
**Additional Context**
|
||||
Add any other context about the vulnerability here.
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -16,7 +16,7 @@ namespace SafeExamBrowser.Applications.Contracts
|
|||
/// <summary>
|
||||
/// Controls the lifetime and functionality of an application.
|
||||
/// </summary>
|
||||
public interface IApplication<out TWindow> where TWindow : IApplicationWindow
|
||||
public interface IApplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the application should be automatically started.
|
||||
|
@ -51,7 +51,7 @@ namespace SafeExamBrowser.Applications.Contracts
|
|||
/// <summary>
|
||||
/// Returns all windows of the application.
|
||||
/// </summary>
|
||||
IEnumerable<TWindow> GetWindows();
|
||||
IEnumerable<IApplicationWindow> GetWindows();
|
||||
|
||||
/// <summary>
|
||||
/// Performs any initialization work, if necessary.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -18,6 +18,6 @@ namespace SafeExamBrowser.Applications.Contracts
|
|||
/// <summary>
|
||||
/// Attempts to create an application according to the given settings.
|
||||
/// </summary>
|
||||
FactoryResult TryCreate(WhitelistApplication settings, out IApplication<IApplicationWindow> application);
|
||||
FactoryResult TryCreate(WhitelistApplication settings, out IApplication application);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -13,7 +13,7 @@ using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
|||
namespace SafeExamBrowser.Applications.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a window of an <see cref="IApplication{TWindow}"/>.
|
||||
/// Defines a window of an <see cref="IApplication"/>.
|
||||
/// </summary>
|
||||
public interface IApplicationWindow
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyDescription("Safe Exam Browser")]
|
||||
[assembly: AssemblyCompany("ETH Zürich")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.Applications.Contracts")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2024 ETH Zürich, IT Services")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2022 ETH Zürich, Educational Development and Technology (LET)")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SafeExamBrowser.Applications.Contracts</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.Applications.Contracts</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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 Moq;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Monitoring.Contracts.Applications;
|
||||
using SafeExamBrowser.Settings.Applications;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Registry;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Applications.UnitTests
|
||||
{
|
||||
[TestClass]
|
||||
public class ApplicationFactoryTests
|
||||
{
|
||||
private Mock<IApplicationMonitor> applicationMonitor;
|
||||
private Mock<IModuleLogger> logger;
|
||||
private Mock<INativeMethods> nativeMethods;
|
||||
private Mock<IProcessFactory> processFactory;
|
||||
private Mock<IRegistry> registry;
|
||||
|
||||
private ApplicationFactory sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
applicationMonitor = new Mock<IApplicationMonitor>();
|
||||
logger = new Mock<IModuleLogger>();
|
||||
nativeMethods = new Mock<INativeMethods>();
|
||||
processFactory = new Mock<IProcessFactory>();
|
||||
registry = new Mock<IRegistry>();
|
||||
|
||||
sut = new ApplicationFactory(applicationMonitor.Object, logger.Object, nativeMethods.Object, processFactory.Object, registry.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustCorrectlyCreateApplication()
|
||||
{
|
||||
var settings = new WhitelistApplication
|
||||
{
|
||||
DisplayName = "Windows Command Prompt",
|
||||
ExecutableName = "cmd.exe",
|
||||
};
|
||||
|
||||
var result = sut.TryCreate(settings, out var application);
|
||||
|
||||
Assert.AreEqual(FactoryResult.Success, result);
|
||||
Assert.IsNotNull(application);
|
||||
Assert.IsInstanceOfType<ExternalApplication>(application);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustCorrectlyReadPathFromRegistry()
|
||||
{
|
||||
object o = @"C:\Some\Registry\Path";
|
||||
var settings = new WhitelistApplication
|
||||
{
|
||||
DisplayName = "Windows Command Prompt",
|
||||
ExecutableName = "cmd.exe",
|
||||
ExecutablePath = @"C:\Some\Path"
|
||||
};
|
||||
|
||||
registry.Setup(r => r.TryRead(It.Is<string>(s => s.Contains(RegistryValue.MachineHive.AppPaths_Key)), It.Is<string>(s => s == "Path"), out o)).Returns(true);
|
||||
|
||||
var result = sut.TryCreate(settings, out var application);
|
||||
|
||||
registry.Verify(r => r.TryRead(It.Is<string>(s => s.Contains(RegistryValue.MachineHive.AppPaths_Key)), It.Is<string>(s => s == "Path"), out o), Times.Once);
|
||||
|
||||
Assert.AreEqual(FactoryResult.Success, result);
|
||||
Assert.IsNotNull(application);
|
||||
Assert.IsInstanceOfType<ExternalApplication>(application);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustIndicateIfApplicationNotFound()
|
||||
{
|
||||
var settings = new WhitelistApplication
|
||||
{
|
||||
ExecutableName = "some_random_application_which_does_not_exist_on_a_normal_system.exe",
|
||||
ExecutablePath = "Some/Path/Which/Does/Not/Exist"
|
||||
};
|
||||
|
||||
var result = sut.TryCreate(settings, out var application);
|
||||
|
||||
Assert.AreEqual(FactoryResult.NotFound, result);
|
||||
Assert.IsNull(application);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustFailGracefullyWhenPathIsInvalid()
|
||||
{
|
||||
var settings = new WhitelistApplication
|
||||
{
|
||||
ExecutableName = "asdfg(/ç)&=%\"fsdg..exe..",
|
||||
ExecutablePath = "[]#°§¬#°¢@tu03450'w89tz!$£äöüèé:"
|
||||
};
|
||||
|
||||
var result = sut.TryCreate(settings, out _);
|
||||
|
||||
logger.Verify(l => l.Error(It.IsAny<string>(), It.IsAny<Exception>()), Times.AtLeastOnce);
|
||||
|
||||
Assert.AreEqual(FactoryResult.NotFound, result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustFailGracefullyAndIndicateThatErrorOccurred()
|
||||
{
|
||||
var o = default(object);
|
||||
var settings = new WhitelistApplication();
|
||||
|
||||
registry.Setup(r => r.TryRead(It.IsAny<string>(), It.IsAny<string>(), out o)).Throws<Exception>();
|
||||
|
||||
var result = sut.TryCreate(settings, out var application);
|
||||
|
||||
Assert.AreEqual(FactoryResult.Error, result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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 Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Applications.UnitTests
|
||||
{
|
||||
[TestClass]
|
||||
public class ExternalApplicationInstanceTests
|
||||
{
|
||||
private NativeIconResource icon;
|
||||
private Mock<ILogger> logger;
|
||||
private Mock<INativeMethods> nativeMethods;
|
||||
private Mock<IProcess> process;
|
||||
private ExternalApplicationInstance sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
icon = new NativeIconResource();
|
||||
logger = new Mock<ILogger>();
|
||||
nativeMethods = new Mock<INativeMethods>();
|
||||
process = new Mock<IProcess>();
|
||||
|
||||
sut = new ExternalApplicationInstance(icon, logger.Object, nativeMethods.Object, process.Object, 1);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Terminate_MustDoNothingIfAlreadyTerminated()
|
||||
{
|
||||
process.SetupGet(p => p.HasTerminated).Returns(true);
|
||||
|
||||
sut.Terminate();
|
||||
|
||||
process.Verify(p => p.TryClose(It.IsAny<int>()), Times.Never());
|
||||
process.Verify(p => p.TryKill(It.IsAny<int>()), Times.Never());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Terminate_MustLogIfTerminationFailed()
|
||||
{
|
||||
process.Setup(p => p.TryClose(It.IsAny<int>())).Returns(false);
|
||||
process.Setup(p => p.TryKill(It.IsAny<int>())).Returns(false);
|
||||
process.SetupGet(p => p.HasTerminated).Returns(false);
|
||||
|
||||
sut.Terminate();
|
||||
|
||||
logger.Verify(l => l.Warn(It.IsAny<string>()), Times.AtLeastOnce);
|
||||
process.Verify(p => p.TryClose(It.IsAny<int>()), Times.AtLeastOnce());
|
||||
process.Verify(p => p.TryKill(It.IsAny<int>()), Times.AtLeastOnce());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,216 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Monitoring.Contracts.Applications;
|
||||
using SafeExamBrowser.Monitoring.Contracts.Applications.Events;
|
||||
using SafeExamBrowser.Settings.Applications;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Applications.UnitTests
|
||||
{
|
||||
[TestClass]
|
||||
public class ExternalApplicationTests
|
||||
{
|
||||
private Mock<IApplicationMonitor> applicationMonitor;
|
||||
private string executablePath;
|
||||
private Mock<IModuleLogger> logger;
|
||||
private Mock<INativeMethods> nativeMethods;
|
||||
private Mock<IProcessFactory> processFactory;
|
||||
private WhitelistApplication settings;
|
||||
|
||||
private ExternalApplication sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
applicationMonitor = new Mock<IApplicationMonitor>();
|
||||
executablePath = @"C:\Some\Random\Path\Application.exe";
|
||||
logger = new Mock<IModuleLogger>();
|
||||
nativeMethods = new Mock<INativeMethods>();
|
||||
processFactory = new Mock<IProcessFactory>();
|
||||
settings = new WhitelistApplication();
|
||||
|
||||
logger.Setup(l => l.CloneFor(It.IsAny<string>())).Returns(new Mock<IModuleLogger>().Object);
|
||||
|
||||
sut = new ExternalApplication(applicationMonitor.Object, executablePath, logger.Object, nativeMethods.Object, processFactory.Object, settings, 1);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetWindows_MustCorrectlyReturnOpenWindows()
|
||||
{
|
||||
var openWindows = new List<IntPtr> { new IntPtr(123), new IntPtr(234), new IntPtr(456), new IntPtr(345), new IntPtr(567), new IntPtr(789) };
|
||||
var process1 = new Mock<IProcess>();
|
||||
var process2 = new Mock<IProcess>();
|
||||
var sync = new AutoResetEvent(false);
|
||||
|
||||
nativeMethods.Setup(n => n.GetOpenWindows()).Returns(openWindows);
|
||||
nativeMethods.Setup(n => n.GetProcessIdFor(It.Is<IntPtr>(p => p == new IntPtr(234)))).Returns(1234);
|
||||
nativeMethods.Setup(n => n.GetProcessIdFor(It.Is<IntPtr>(p => p == new IntPtr(345)))).Returns(1234);
|
||||
nativeMethods.Setup(n => n.GetProcessIdFor(It.Is<IntPtr>(p => p == new IntPtr(567)))).Returns(5678);
|
||||
process1.Setup(p => p.TryClose(It.IsAny<int>())).Returns(false);
|
||||
process1.Setup(p => p.TryKill(It.IsAny<int>())).Returns(true);
|
||||
process1.SetupGet(p => p.Id).Returns(1234);
|
||||
process2.Setup(p => p.TryClose(It.IsAny<int>())).Returns(true);
|
||||
process2.SetupGet(p => p.Id).Returns(5678);
|
||||
processFactory.Setup(f => f.StartNew(It.IsAny<string>(), It.IsAny<string[]>())).Returns(process1.Object);
|
||||
|
||||
sut.WindowsChanged += () => sync.Set();
|
||||
sut.Initialize();
|
||||
sut.Start();
|
||||
|
||||
applicationMonitor.Raise(m => m.InstanceStarted += null, sut.Id, process2.Object);
|
||||
|
||||
sync.WaitOne();
|
||||
sync.WaitOne();
|
||||
|
||||
var windows = sut.GetWindows();
|
||||
|
||||
Assert.AreEqual(3, windows.Count());
|
||||
Assert.IsTrue(windows.Any(w => w.Handle == new IntPtr(234)));
|
||||
Assert.IsTrue(windows.Any(w => w.Handle == new IntPtr(345)));
|
||||
Assert.IsTrue(windows.Any(w => w.Handle == new IntPtr(567)));
|
||||
|
||||
nativeMethods.Setup(n => n.GetOpenWindows()).Returns(openWindows.Skip(2));
|
||||
Task.Run(() => process2.Raise(p => p.Terminated += null, default(int)));
|
||||
|
||||
sync.WaitOne();
|
||||
sync.WaitOne();
|
||||
|
||||
windows = sut.GetWindows();
|
||||
|
||||
Assert.AreEqual(1, windows.Count());
|
||||
Assert.IsTrue(windows.Any(w => w.Handle != new IntPtr(234)));
|
||||
Assert.IsTrue(windows.Any(w => w.Handle == new IntPtr(345)));
|
||||
Assert.IsTrue(windows.All(w => w.Handle != new IntPtr(567)));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Initialize_MustInitializeCorrectly()
|
||||
{
|
||||
settings.AutoStart = new Random().Next(2) == 1;
|
||||
settings.Description = "Some Description";
|
||||
|
||||
sut.Initialize();
|
||||
|
||||
applicationMonitor.VerifyAdd(a => a.InstanceStarted += It.IsAny<InstanceStartedEventHandler>(), Times.Once);
|
||||
|
||||
Assert.AreEqual(settings.AutoStart, sut.AutoStart);
|
||||
Assert.AreEqual(executablePath, (sut.Icon as EmbeddedIconResource).FilePath);
|
||||
Assert.AreEqual(settings.Id, settings.Id);
|
||||
Assert.AreEqual(settings.DisplayName, sut.Name);
|
||||
Assert.AreEqual(settings.Description ?? settings.DisplayName, sut.Tooltip);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Start_MustCreateInstanceCorrectly()
|
||||
{
|
||||
settings.Arguments.Add("some_parameter");
|
||||
settings.Arguments.Add("another_parameter");
|
||||
settings.Arguments.Add("yet another parameter");
|
||||
|
||||
sut.Start();
|
||||
|
||||
processFactory.Verify(f => f.StartNew(executablePath, It.Is<string[]>(args => args.All(a => settings.Arguments.Contains(a)))), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Start_MustHandleFailureGracefully()
|
||||
{
|
||||
processFactory.Setup(f => f.StartNew(It.IsAny<string>(), It.IsAny<string[]>())).Throws<Exception>();
|
||||
|
||||
sut.Start();
|
||||
|
||||
logger.Verify(l => l.Error(It.IsAny<string>(), It.IsAny<Exception>()), Times.AtLeastOnce);
|
||||
processFactory.Verify(f => f.StartNew(It.IsAny<string>(), It.IsAny<string[]>()), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Start_MustRemoveInstanceCorrectlyWhenTerminated()
|
||||
{
|
||||
var eventCount = 0;
|
||||
var openWindows = new List<IntPtr> { new IntPtr(123), new IntPtr(234), new IntPtr(456), new IntPtr(345), new IntPtr(567), new IntPtr(789), };
|
||||
var process = new Mock<IProcess>();
|
||||
var sync = new AutoResetEvent(false);
|
||||
|
||||
nativeMethods.Setup(n => n.GetOpenWindows()).Returns(openWindows);
|
||||
nativeMethods.Setup(n => n.GetProcessIdFor(It.Is<IntPtr>(p => p == new IntPtr(234)))).Returns(1234);
|
||||
process.Setup(p => p.TryClose(It.IsAny<int>())).Returns(false);
|
||||
process.Setup(p => p.TryKill(It.IsAny<int>())).Returns(true);
|
||||
process.SetupGet(p => p.Id).Returns(1234);
|
||||
processFactory.Setup(f => f.StartNew(It.IsAny<string>(), It.IsAny<string[]>())).Returns(process.Object);
|
||||
|
||||
sut.WindowsChanged += () =>
|
||||
{
|
||||
eventCount++;
|
||||
sync.Set();
|
||||
};
|
||||
|
||||
sut.Initialize();
|
||||
sut.Start();
|
||||
|
||||
sync.WaitOne();
|
||||
|
||||
Assert.AreEqual(1, sut.GetWindows().Count());
|
||||
|
||||
process.Raise(p => p.Terminated += null, default(int));
|
||||
|
||||
Assert.AreEqual(2, eventCount);
|
||||
Assert.AreEqual(0, sut.GetWindows().Count());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Terminate_MustStopAllInstancesCorrectly()
|
||||
{
|
||||
var process1 = new Mock<IProcess>();
|
||||
var process2 = new Mock<IProcess>();
|
||||
|
||||
process1.Setup(p => p.TryClose(It.IsAny<int>())).Returns(false);
|
||||
process1.Setup(p => p.TryKill(It.IsAny<int>())).Returns(true);
|
||||
process1.SetupGet(p => p.Id).Returns(1234);
|
||||
process2.Setup(p => p.TryClose(It.IsAny<int>())).Returns(true);
|
||||
process2.SetupGet(p => p.Id).Returns(5678);
|
||||
processFactory.Setup(f => f.StartNew(It.IsAny<string>(), It.IsAny<string[]>())).Returns(process1.Object);
|
||||
|
||||
sut.Initialize();
|
||||
sut.Start();
|
||||
|
||||
applicationMonitor.Raise(m => m.InstanceStarted += null, sut.Id, process2.Object);
|
||||
sut.Terminate();
|
||||
|
||||
process1.Verify(p => p.TryClose(It.IsAny<int>()), Times.AtLeastOnce);
|
||||
process1.Verify(p => p.TryKill(It.IsAny<int>()), Times.Once);
|
||||
process2.Verify(p => p.TryClose(It.IsAny<int>()), Times.Once);
|
||||
process2.Verify(p => p.TryKill(It.IsAny<int>()), Times.Never);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Terminate_MustHandleFailureGracefully()
|
||||
{
|
||||
var process = new Mock<IProcess>();
|
||||
|
||||
process.Setup(p => p.TryClose(It.IsAny<int>())).Throws<Exception>();
|
||||
processFactory.Setup(f => f.StartNew(It.IsAny<string>(), It.IsAny<string[]>())).Returns(process.Object);
|
||||
|
||||
sut.Initialize();
|
||||
sut.Start();
|
||||
sut.Terminate();
|
||||
|
||||
process.Verify(p => p.TryClose(It.IsAny<int>()), Times.AtLeastOnce);
|
||||
process.Verify(p => p.TryKill(It.IsAny<int>()), Times.Never);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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 Moq;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Applications.UnitTests
|
||||
{
|
||||
[TestClass]
|
||||
public class ExternalApplicationWindowTests
|
||||
{
|
||||
private IntPtr handle;
|
||||
private NativeIconResource icon;
|
||||
private Mock<INativeMethods> nativeMethods;
|
||||
|
||||
private ExternalApplicationWindow sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
handle = new IntPtr(123);
|
||||
icon = new NativeIconResource();
|
||||
nativeMethods = new Mock<INativeMethods>();
|
||||
|
||||
sut = new ExternalApplicationWindow(icon, nativeMethods.Object, handle);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Activate_MustCorrectlyActivateWindow()
|
||||
{
|
||||
sut.Activate();
|
||||
nativeMethods.Verify(n => n.ActivateWindow(It.Is<IntPtr>(h => h == handle)));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Update_MustCorrectlyUpdateWindow()
|
||||
{
|
||||
var iconChanged = false;
|
||||
var titleChanged = false;
|
||||
|
||||
nativeMethods.Setup(m => m.GetWindowIcon(It.IsAny<IntPtr>())).Returns(new IntPtr(456));
|
||||
nativeMethods.Setup(m => m.GetWindowTitle((It.IsAny<IntPtr>()))).Returns("Some New Window Title");
|
||||
|
||||
sut.IconChanged += (_) => iconChanged = true;
|
||||
sut.TitleChanged += (_) => titleChanged = true;
|
||||
|
||||
sut.Update();
|
||||
|
||||
nativeMethods.Verify(m => m.GetWindowIcon(handle), Times.Once);
|
||||
nativeMethods.Verify(m => m.GetWindowTitle(handle), Times.Once);
|
||||
|
||||
Assert.IsTrue(iconChanged);
|
||||
Assert.IsTrue(titleChanged);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("SafeExamBrowser.Applications.UnitTests")]
|
||||
[assembly: AssemblyDescription("Safe Exam Browser")]
|
||||
[assembly: AssemblyCompany("ETH Zürich")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.Applications.UnitTests")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2024 ETH Zürich, IT Services")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
[assembly: Guid("fc6d80ec-8611-4287-87e2-17c028a10858")]
|
||||
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("1.0.0.0")]
|
|
@ -1,199 +0,0 @@
|
|||
<?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.3.2.2\build\net462\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.props')" />
|
||||
<Import Project="..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.2\build\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.props" Condition="Exists('..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.2\build\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.props')" />
|
||||
<Import Project="..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.props" Condition="Exists('..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.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>{FC6D80EC-8611-4287-87E2-17C028A10858}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SafeExamBrowser.Applications.UnitTests</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.Applications.UnitTests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</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>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</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>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Castle.Core, Version=5.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ApplicationInsights, Version=2.22.0.997, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ApplicationInsights.2.22.0\lib\net46\Microsoft.ApplicationInsights.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Testing.Extensions.Telemetry, Version=1.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.2\lib\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Testing.Extensions.TrxReport.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Testing.Extensions.TrxReport.Abstractions.1.0.2\lib\netstandard2.0\Microsoft.Testing.Extensions.TrxReport.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Testing.Extensions.VSTestBridge, Version=1.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Testing.Extensions.VSTestBridge.1.0.2\lib\netstandard2.0\Microsoft.Testing.Extensions.VSTestBridge.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Testing.Platform, Version=1.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\lib\netstandard2.0\Microsoft.Testing.Platform.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Testing.Platform.MSBuild, Version=1.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\lib\netstandard2.0\Microsoft.Testing.Platform.MSBuild.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.TestPlatform.CoreUtilities, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.TestPlatform.ObjectModel.17.9.0\lib\net462\Microsoft.TestPlatform.CoreUtilities.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.TestPlatform.PlatformAbstractions, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.TestPlatform.ObjectModel.17.9.0\lib\net462\Microsoft.TestPlatform.PlatformAbstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.ObjectModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.TestPlatform.ObjectModel.17.9.0\lib\net462\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.3.2.2\lib\net462\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.3.2.2\lib\net462\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Moq, Version=4.20.70.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Moq.4.20.70\lib\net462\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NuGet.Frameworks, Version=6.9.1.3, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NuGet.Frameworks.6.9.1\lib\net472\NuGet.Frameworks.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Collections.Immutable, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.8.0.0\lib\net462\System.Collections.Immutable.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Diagnostics.DiagnosticSource, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.8.0.0\lib\net462\System.Diagnostics.DiagnosticSource.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reflection.Metadata, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.Metadata.8.0.0\lib\net462\System.Reflection.Metadata.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime" />
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ApplicationFactoryTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ExternalApplicationTests.cs" />
|
||||
<Compile Include="ExternalApplicationWindowTests.cs" />
|
||||
<Compile Include="ExternalApplicationInstanceTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Applications.Contracts\SafeExamBrowser.Applications.Contracts.csproj">
|
||||
<Project>{ac77745d-3b41-43e2-8e84-d40e5a4ee77f}</Project>
|
||||
<Name>SafeExamBrowser.Applications.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Applications\SafeExamBrowser.Applications.csproj">
|
||||
<Project>{a113e68f-1209-4689-981a-15c554b2df4e}</Project>
|
||||
<Name>SafeExamBrowser.Applications</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Core.Contracts\SafeExamBrowser.Core.Contracts.csproj">
|
||||
<Project>{fe0e1224-b447-4b14-81e7-ed7d84822aa0}</Project>
|
||||
<Name>SafeExamBrowser.Core.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj">
|
||||
<Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
|
||||
<Name>SafeExamBrowser.Logging.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Monitoring.Contracts\SafeExamBrowser.Monitoring.Contracts.csproj">
|
||||
<Project>{6d563a30-366d-4c35-815b-2c9e6872278b}</Project>
|
||||
<Name>SafeExamBrowser.Monitoring.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj">
|
||||
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
|
||||
<Name>SafeExamBrowser.Settings</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.SystemComponents.Contracts\SafeExamBrowser.SystemComponents.Contracts.csproj">
|
||||
<Project>{903129c6-e236-493b-9ad6-c6a57f647a3a}</Project>
|
||||
<Name>SafeExamBrowser.SystemComponents.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.WindowsApi.Contracts\SafeExamBrowser.WindowsApi.Contracts.csproj">
|
||||
<Project>{7016f080-9aa5-41b2-a225-385ad877c171}</Project>
|
||||
<Name>SafeExamBrowser.WindowsApi.Contracts</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\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.2\build\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.2\build\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.targets" Condition="Exists('..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.targets')" />
|
||||
<Import Project="..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.targets')" />
|
||||
</Project>
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="NuGet.Frameworks" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.11.3.1" newVersion="5.11.3.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.ApplicationInsights" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.22.0.997" newVersion="2.22.0.997" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" /></startup></configuration>
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Castle.Core" version="5.1.1" targetFramework="net48" />
|
||||
<package id="Microsoft.ApplicationInsights" version="2.22.0" targetFramework="net48" />
|
||||
<package id="Microsoft.Testing.Extensions.Telemetry" version="1.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Testing.Extensions.TrxReport.Abstractions" version="1.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Testing.Extensions.VSTestBridge" version="1.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Testing.Platform" version="1.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Testing.Platform.MSBuild" version="1.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.TestPlatform.ObjectModel" version="17.9.0" targetFramework="net48" />
|
||||
<package id="Moq" version="4.20.70" targetFramework="net48" />
|
||||
<package id="MSTest.TestAdapter" version="3.2.2" targetFramework="net48" />
|
||||
<package id="MSTest.TestFramework" version="3.2.2" targetFramework="net48" />
|
||||
<package id="NuGet.Frameworks" version="6.9.1" targetFramework="net48" />
|
||||
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
|
||||
<package id="System.Collections.Immutable" version="8.0.0" targetFramework="net48" />
|
||||
<package id="System.Diagnostics.DiagnosticSource" version="8.0.0" targetFramework="net48" />
|
||||
<package id="System.Memory" version="4.5.5" targetFramework="net48" />
|
||||
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
|
||||
<package id="System.Reflection.Metadata" version="8.0.0" targetFramework="net48" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
|
||||
</packages>
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -9,42 +9,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Win32;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Monitoring.Contracts.Applications;
|
||||
using SafeExamBrowser.Settings.Applications;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Registry;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Applications
|
||||
{
|
||||
public class ApplicationFactory : IApplicationFactory
|
||||
{
|
||||
private readonly IApplicationMonitor applicationMonitor;
|
||||
private readonly IModuleLogger logger;
|
||||
private readonly INativeMethods nativeMethods;
|
||||
private readonly IProcessFactory processFactory;
|
||||
private readonly IRegistry registry;
|
||||
private IApplicationMonitor applicationMonitor;
|
||||
private IModuleLogger logger;
|
||||
private INativeMethods nativeMethods;
|
||||
private IProcessFactory processFactory;
|
||||
|
||||
public ApplicationFactory(
|
||||
IApplicationMonitor applicationMonitor,
|
||||
IModuleLogger logger,
|
||||
INativeMethods nativeMethods,
|
||||
IProcessFactory processFactory,
|
||||
IRegistry registry)
|
||||
IProcessFactory processFactory)
|
||||
{
|
||||
this.applicationMonitor = applicationMonitor;
|
||||
this.logger = logger;
|
||||
this.nativeMethods = nativeMethods;
|
||||
this.processFactory = processFactory;
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
public FactoryResult TryCreate(WhitelistApplication settings, out IApplication<IApplicationWindow> application)
|
||||
public FactoryResult TryCreate(WhitelistApplication settings, out IApplication application)
|
||||
{
|
||||
var name = $"'{settings.DisplayName}' ({settings.ExecutableName})";
|
||||
var name = $"'{settings.DisplayName}' ({ settings.ExecutableName})";
|
||||
|
||||
application = default;
|
||||
application = default(IApplication);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -72,12 +69,10 @@ namespace SafeExamBrowser.Applications
|
|||
return FactoryResult.Error;
|
||||
}
|
||||
|
||||
private IApplication<IApplicationWindow> BuildApplication(string executablePath, WhitelistApplication settings)
|
||||
private IApplication BuildApplication(string executablePath, WhitelistApplication settings)
|
||||
{
|
||||
const int ONE_SECOND = 1000;
|
||||
|
||||
var applicationLogger = logger.CloneFor(settings.DisplayName);
|
||||
var application = new ExternalApplication(applicationMonitor, executablePath, applicationLogger, nativeMethods, processFactory, settings, ONE_SECOND);
|
||||
var application = new ExternalApplication(applicationMonitor, executablePath, applicationLogger, nativeMethods, processFactory, settings);
|
||||
|
||||
return application;
|
||||
}
|
||||
|
@ -87,14 +82,14 @@ namespace SafeExamBrowser.Applications
|
|||
var paths = new List<string[]>();
|
||||
var registryPath = QueryPathFromRegistry(settings);
|
||||
|
||||
mainExecutable = default;
|
||||
mainExecutable = default(string);
|
||||
|
||||
paths.Add(new[] { Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), settings.ExecutableName });
|
||||
paths.Add(new[] { Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), settings.ExecutableName });
|
||||
paths.Add(new[] { Environment.GetFolderPath(Environment.SpecialFolder.System), settings.ExecutableName });
|
||||
paths.Add(new[] { Environment.GetFolderPath(Environment.SpecialFolder.SystemX86), settings.ExecutableName });
|
||||
|
||||
if (settings.ExecutablePath != default)
|
||||
if (settings.ExecutablePath != default(string))
|
||||
{
|
||||
paths.Add(new[] { settings.ExecutablePath, settings.ExecutableName });
|
||||
paths.Add(new[] { Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), settings.ExecutablePath, settings.ExecutableName });
|
||||
|
@ -103,11 +98,11 @@ namespace SafeExamBrowser.Applications
|
|||
paths.Add(new[] { Environment.GetFolderPath(Environment.SpecialFolder.SystemX86), settings.ExecutablePath, settings.ExecutableName });
|
||||
}
|
||||
|
||||
if (registryPath != default)
|
||||
if (registryPath != default(string))
|
||||
{
|
||||
paths.Add(new[] { registryPath, settings.ExecutableName });
|
||||
|
||||
if (settings.ExecutablePath != default)
|
||||
if (settings.ExecutablePath != default(string))
|
||||
{
|
||||
paths.Add(new[] { registryPath, settings.ExecutablePath, settings.ExecutableName });
|
||||
}
|
||||
|
@ -136,12 +131,22 @@ namespace SafeExamBrowser.Applications
|
|||
|
||||
private string QueryPathFromRegistry(WhitelistApplication settings)
|
||||
{
|
||||
if (registry.TryRead($@"{RegistryValue.MachineHive.AppPaths_Key}\{settings.ExecutableName}", "Path", out var value))
|
||||
try
|
||||
{
|
||||
return value as string;
|
||||
using (var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\{settings.ExecutableName}"))
|
||||
{
|
||||
if (key != null)
|
||||
{
|
||||
return key.GetValue("Path") as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to query path in registry for '{settings.ExecutableName}'!", e);
|
||||
}
|
||||
|
||||
return default;
|
||||
return default(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -19,18 +19,17 @@ using SafeExamBrowser.WindowsApi.Contracts;
|
|||
|
||||
namespace SafeExamBrowser.Applications
|
||||
{
|
||||
internal class ExternalApplication : IApplication<IApplicationWindow>
|
||||
internal class ExternalApplication : IApplication
|
||||
{
|
||||
private readonly object @lock = new object();
|
||||
|
||||
private readonly IApplicationMonitor applicationMonitor;
|
||||
private readonly string executablePath;
|
||||
private readonly IList<ExternalApplicationInstance> instances;
|
||||
private readonly IModuleLogger logger;
|
||||
private readonly INativeMethods nativeMethods;
|
||||
private readonly IProcessFactory processFactory;
|
||||
private readonly WhitelistApplication settings;
|
||||
private readonly int windowMonitoringInterval;
|
||||
private IApplicationMonitor applicationMonitor;
|
||||
private string executablePath;
|
||||
private IModuleLogger logger;
|
||||
private INativeMethods nativeMethods;
|
||||
private IList<ExternalApplicationInstance> instances;
|
||||
private IProcessFactory processFactory;
|
||||
private WhitelistApplication settings;
|
||||
|
||||
public bool AutoStart { get; private set; }
|
||||
public IconResource Icon { get; private set; }
|
||||
|
@ -46,8 +45,7 @@ namespace SafeExamBrowser.Applications
|
|||
IModuleLogger logger,
|
||||
INativeMethods nativeMethods,
|
||||
IProcessFactory processFactory,
|
||||
WhitelistApplication settings,
|
||||
int windowMonitoringInterval_ms)
|
||||
WhitelistApplication settings)
|
||||
{
|
||||
this.applicationMonitor = applicationMonitor;
|
||||
this.executablePath = executablePath;
|
||||
|
@ -56,7 +54,6 @@ namespace SafeExamBrowser.Applications
|
|||
this.instances = new List<ExternalApplicationInstance>();
|
||||
this.processFactory = processFactory;
|
||||
this.settings = settings;
|
||||
this.windowMonitoringInterval = windowMonitoringInterval_ms;
|
||||
}
|
||||
|
||||
public IEnumerable<IApplicationWindow> GetWindows()
|
||||
|
@ -92,6 +89,18 @@ namespace SafeExamBrowser.Applications
|
|||
}
|
||||
}
|
||||
|
||||
private string[] BuildArguments()
|
||||
{
|
||||
var arguments = new List<string>();
|
||||
|
||||
foreach (var argument in settings.Arguments)
|
||||
{
|
||||
arguments.Add(Environment.ExpandEnvironmentVariables(argument));
|
||||
}
|
||||
|
||||
return arguments.ToArray();
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
applicationMonitor.InstanceStarted -= ApplicationMonitor_InstanceStarted;
|
||||
|
@ -144,24 +153,12 @@ namespace SafeExamBrowser.Applications
|
|||
WindowsChanged?.Invoke();
|
||||
}
|
||||
|
||||
private string[] BuildArguments()
|
||||
{
|
||||
var arguments = new List<string>();
|
||||
|
||||
foreach (var argument in settings.Arguments)
|
||||
{
|
||||
arguments.Add(Environment.ExpandEnvironmentVariables(argument));
|
||||
}
|
||||
|
||||
return arguments.ToArray();
|
||||
}
|
||||
|
||||
private void InitializeInstance(IProcess process)
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
var instanceLogger = logger.CloneFor($"{Name} ({process.Id})");
|
||||
var instance = new ExternalApplicationInstance(Icon, instanceLogger, nativeMethods, process, windowMonitoringInterval);
|
||||
var instance = new ExternalApplicationInstance(Icon, instanceLogger, nativeMethods, process);
|
||||
|
||||
instance.Terminated += Instance_Terminated;
|
||||
instance.WindowsChanged += () => WindowsChanged?.Invoke();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -12,8 +12,8 @@ using System.Linq;
|
|||
using System.Timers;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Applications.Contracts.Events;
|
||||
using SafeExamBrowser.Applications.Events;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.Applications.Events;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
|
@ -23,32 +23,24 @@ namespace SafeExamBrowser.Applications
|
|||
{
|
||||
private readonly object @lock = new object();
|
||||
|
||||
private readonly IconResource icon;
|
||||
private readonly ILogger logger;
|
||||
private readonly INativeMethods nativeMethods;
|
||||
private readonly IProcess process;
|
||||
private readonly int windowMonitoringInterval;
|
||||
private readonly IList<ExternalApplicationWindow> windows;
|
||||
|
||||
private IconResource icon;
|
||||
private ILogger logger;
|
||||
private INativeMethods nativeMethods;
|
||||
private IProcess process;
|
||||
private Timer timer;
|
||||
private IList<ExternalApplicationWindow> windows;
|
||||
|
||||
internal int Id { get; private set; }
|
||||
|
||||
internal event InstanceTerminatedEventHandler Terminated;
|
||||
internal event WindowsChangedEventHandler WindowsChanged;
|
||||
|
||||
internal ExternalApplicationInstance(
|
||||
IconResource icon,
|
||||
ILogger logger,
|
||||
INativeMethods nativeMethods,
|
||||
IProcess process,
|
||||
int windowMonitoringInterval_ms)
|
||||
internal ExternalApplicationInstance(IconResource icon, ILogger logger, INativeMethods nativeMethods, IProcess process)
|
||||
{
|
||||
this.icon = icon;
|
||||
this.logger = logger;
|
||||
this.nativeMethods = nativeMethods;
|
||||
this.process = process;
|
||||
this.windowMonitoringInterval = windowMonitoringInterval_ms;
|
||||
this.windows = new List<ExternalApplicationWindow>();
|
||||
}
|
||||
|
||||
|
@ -153,20 +145,19 @@ namespace SafeExamBrowser.Applications
|
|||
|
||||
private void InitializeEvents()
|
||||
{
|
||||
const int ONE_SECOND = 1000;
|
||||
|
||||
process.Terminated += Process_Terminated;
|
||||
|
||||
timer = new Timer(windowMonitoringInterval);
|
||||
timer = new Timer(ONE_SECOND);
|
||||
timer.Elapsed += Timer_Elapsed;
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
private void FinalizeEvents()
|
||||
{
|
||||
if (timer != default)
|
||||
{
|
||||
timer.Elapsed -= Timer_Elapsed;
|
||||
timer.Stop();
|
||||
}
|
||||
timer.Elapsed -= Timer_Elapsed;
|
||||
timer.Stop();
|
||||
|
||||
process.Terminated -= Process_Terminated;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -16,7 +16,7 @@ namespace SafeExamBrowser.Applications
|
|||
{
|
||||
internal class ExternalApplicationWindow : IApplicationWindow
|
||||
{
|
||||
private readonly INativeMethods nativeMethods;
|
||||
private INativeMethods nativeMethods;
|
||||
|
||||
public IntPtr Handle { get; }
|
||||
public IconResource Icon { get; private set; }
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
|
@ -9,13 +8,12 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyDescription("Safe Exam Browser")]
|
||||
[assembly: AssemblyCompany("ETH Zürich")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.Applications")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2024 ETH Zürich, IT Services")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2022 ETH Zürich, Educational Development and Technology (LET)")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: InternalsVisibleTo("SafeExamBrowser.Applications.UnitTests")]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("a113e68f-1209-4689-981a-15c554b2df4e")]
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SafeExamBrowser.Applications</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.Applications</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -83,10 +82,6 @@
|
|||
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
|
||||
<Name>SafeExamBrowser.Settings</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.SystemComponents.Contracts\SafeExamBrowser.SystemComponents.Contracts.csproj">
|
||||
<Project>{903129c6-e236-493b-9ad6-c6a57f647a3a}</Project>
|
||||
<Name>SafeExamBrowser.SystemComponents.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.WindowsApi.Contracts\SafeExamBrowser.WindowsApi.Contracts.csproj">
|
||||
<Project>{7016f080-9aa5-41b2-a225-385ad877c171}</Project>
|
||||
<Name>SafeExamBrowser.WindowsApi.Contracts</Name>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -9,7 +9,7 @@
|
|||
namespace SafeExamBrowser.Browser.Contracts.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Event handler used to indicate that the browser has detected a user identifier of an LMS.
|
||||
/// Event handler used to indicate that the browser has detected a session identifier of a LMS.
|
||||
/// </summary>
|
||||
public delegate void UserIdentifierDetectedEventHandler(string identifier);
|
||||
public delegate void SessionIdentifierDetectedEventHandler(string identifier);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -14,7 +14,7 @@ namespace SafeExamBrowser.Browser.Contracts
|
|||
/// <summary>
|
||||
/// Controls the lifetime and functionality of the browser application.
|
||||
/// </summary>
|
||||
public interface IBrowserApplication : IApplication<IBrowserWindow>
|
||||
public interface IBrowserApplication : IApplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Event fired when the browser application detects a download request for an application configuration file.
|
||||
|
@ -22,9 +22,9 @@ namespace SafeExamBrowser.Browser.Contracts
|
|||
event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the user tries to focus the taskbar.
|
||||
/// Event fired when the browser application detects a session identifier of an LMS.
|
||||
/// </summary>
|
||||
event LoseFocusRequestedEventHandler LoseFocusRequested;
|
||||
event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the browser application detects a request to terminate SEB.
|
||||
|
@ -32,9 +32,9 @@ namespace SafeExamBrowser.Browser.Contracts
|
|||
event TerminationRequestedEventHandler TerminationRequested;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the browser application detects a user identifier of an LMS.
|
||||
/// Event fired when the user tries to focus the taskbar.
|
||||
/// </summary>
|
||||
event UserIdentifierDetectedEventHandler UserIdentifierDetected;
|
||||
event LoseFocusRequestedEventHandler LoseFocusRequested;
|
||||
|
||||
/// <summary>
|
||||
/// Transfers the focus to the browser application. If the parameter is <c>true</c>, the first focusable element in the browser window
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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 SafeExamBrowser.Applications.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a window of the <see cref="IBrowserApplication"/>.
|
||||
/// </summary>
|
||||
public interface IBrowserWindow : IApplicationWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the window is the main browser window.
|
||||
/// </summary>
|
||||
bool IsMainWindow { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The currently loaded URL, or <c>default(string)</c> in case no navigation has happened yet.
|
||||
/// </summary>
|
||||
string Url { get; }
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyDescription("Safe Exam Browser")]
|
||||
[assembly: AssemblyCompany("ETH Zürich")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.Browser.Contracts")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2024 ETH Zürich, IT Services")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2022 ETH Zürich, Educational Development and Technology (LET)")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SafeExamBrowser.Browser.Contracts</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.Browser.Contracts</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -60,14 +59,13 @@
|
|||
<Compile Include="Events\DownloadRequestedEventHandler.cs" />
|
||||
<Compile Include="Events\TabPressedEventHandler.cs" />
|
||||
<Compile Include="Events\LoseFocusRequestedEventHandler.cs" />
|
||||
<Compile Include="Events\UserIdentifierDetectedEventHandler.cs" />
|
||||
<Compile Include="Events\SessionIdentifierDetectedEventHandler.cs" />
|
||||
<Compile Include="Events\TerminationRequestedEventHandler.cs" />
|
||||
<Compile Include="Filters\IRequestFilter.cs" />
|
||||
<Compile Include="Filters\IRule.cs" />
|
||||
<Compile Include="Filters\IRuleFactory.cs" />
|
||||
<Compile Include="Filters\Request.cs" />
|
||||
<Compile Include="IBrowserApplication.cs" />
|
||||
<Compile Include="IBrowserWindow.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla internal
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -48,7 +48,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
settings = new BrowserSettings();
|
||||
windowSettings = new WindowSettings();
|
||||
text = new Mock<IText>();
|
||||
resourceHandler = new ResourceHandler(appConfig, filter.Object, keyGenerator.Object, logger.Object, default, settings, windowSettings, text.Object);
|
||||
resourceHandler = new ResourceHandler(appConfig, filter.Object, keyGenerator.Object, logger.Object, settings, windowSettings, text.Object);
|
||||
|
||||
sut = new TestableRequestHandler(appConfig, filter.Object, logger.Object, resourceHandler, settings, windowSettings);
|
||||
}
|
||||
|
@ -69,7 +69,6 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
var quitUrl = "http://www.byebye.com";
|
||||
var request = new Mock<IRequest>();
|
||||
|
||||
appConfig.ConfigurationFileMimeType = "application/seb";
|
||||
request.SetupGet(r => r.Url).Returns(quitUrl);
|
||||
settings.QuitUrl = quitUrl;
|
||||
sut.QuitUrlVisited += (url) => eventFired = true;
|
||||
|
@ -123,7 +122,6 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
var request = new Mock<IRequest>();
|
||||
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);
|
||||
request.SetupGet(r => r.ResourceType).Returns(ResourceType.MainFrame);
|
||||
request.SetupGet(r => r.Url).Returns(url);
|
||||
|
@ -157,7 +155,6 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
var request = new Mock<IRequest>();
|
||||
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);
|
||||
request.SetupGet(r => r.ResourceType).Returns(ResourceType.SubFrame);
|
||||
request.SetupGet(r => r.Url).Returns(url);
|
||||
|
@ -185,34 +182,13 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustInitiateDataUriConfigurationFileDownload()
|
||||
public void MustInitiateConfigurationFileDownload()
|
||||
{
|
||||
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}://{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.SebUriSchemeSecure = "abcd";
|
||||
browser.Setup(b => b.GetHost()).Returns(host.Object);
|
||||
|
@ -222,23 +198,13 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
|
||||
host.Verify(h => h.StartDownload(It.Is<string>(u => u == $"{Uri.UriSchemeHttp}://host.com/path/file{appConfig.ConfigurationFileExtension}")));
|
||||
Assert.IsTrue(handled);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustInitiateHttpsConfigurationFileDownload()
|
||||
{
|
||||
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);
|
||||
handled = false;
|
||||
host.Reset();
|
||||
request.Reset();
|
||||
request.SetupGet(r => r.Url).Returns($"{appConfig.SebUriSchemeSecure}://host.com/path/file{appConfig.ConfigurationFileExtension}");
|
||||
|
||||
var handled = sut.OnBeforeBrowse(Mock.Of<IWebBrowser>(), browser.Object, Mock.Of<IFrame>(), request.Object, false, false);
|
||||
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}")));
|
||||
Assert.IsTrue(handled);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -18,7 +18,6 @@ using SafeExamBrowser.Configuration.Contracts;
|
|||
using SafeExamBrowser.Configuration.Contracts.Cryptography;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.Settings.Browser.Filter;
|
||||
using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings;
|
||||
|
@ -50,7 +49,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
windowSettings = new WindowSettings();
|
||||
text = new Mock<IText>();
|
||||
|
||||
sut = new TestableResourceHandler(appConfig, filter.Object, keyGenerator.Object, logger.Object, SessionMode.Server, settings, windowSettings, text.Object);
|
||||
sut = new TestableResourceHandler(appConfig, filter.Object, keyGenerator.Object, logger.Object, settings, windowSettings, text.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -61,8 +60,8 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
var request = new Mock<IRequest>();
|
||||
|
||||
browser.SetupGet(b => b.Address).Returns("http://www.host.org");
|
||||
keyGenerator.Setup(g => g.CalculateBrowserExamKeyHash(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<string>())).Returns(new Random().Next().ToString());
|
||||
keyGenerator.Setup(g => g.CalculateConfigurationKeyHash(It.IsAny<string>(), It.IsAny<string>())).Returns(new Random().Next().ToString());
|
||||
keyGenerator.Setup(g => g.CalculateBrowserExamKeyHash(It.IsAny<string>())).Returns(new Random().Next().ToString());
|
||||
keyGenerator.Setup(g => g.CalculateConfigurationKeyHash(It.IsAny<string>())).Returns(new Random().Next().ToString());
|
||||
request.SetupGet(r => r.Headers).Returns(new NameValueCollection());
|
||||
request.SetupGet(r => r.Url).Returns("http://www.host.org");
|
||||
request.SetupSet(r => r.Headers = It.IsAny<NameValueCollection>()).Callback<NameValueCollection>((h) => headers = h);
|
||||
|
@ -80,41 +79,13 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustAppendCustomHeadersForCrossDomainResourceRequestAndMainFrame()
|
||||
public void MustNotAppendCustomHeadersForCrossDomain()
|
||||
{
|
||||
var browser = new Mock<IWebBrowser>();
|
||||
var headers = new NameValueCollection();
|
||||
var request = new Mock<IRequest>();
|
||||
|
||||
browser.SetupGet(b => b.Address).Returns("http://www.otherhost.org");
|
||||
keyGenerator.Setup(g => g.CalculateBrowserExamKeyHash(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<string>())).Returns(new Random().Next().ToString());
|
||||
keyGenerator.Setup(g => g.CalculateConfigurationKeyHash(It.IsAny<string>(), It.IsAny<string>())).Returns(new Random().Next().ToString());
|
||||
request.SetupGet(r => r.ResourceType).Returns(ResourceType.MainFrame);
|
||||
request.SetupGet(r => r.Headers).Returns(new NameValueCollection());
|
||||
request.SetupGet(r => r.Url).Returns("http://www.host.org");
|
||||
request.SetupSet(r => r.Headers = It.IsAny<NameValueCollection>()).Callback<NameValueCollection>((h) => headers = h);
|
||||
settings.SendConfigurationKey = true;
|
||||
settings.SendBrowserExamKey = true;
|
||||
|
||||
var result = sut.OnBeforeResourceLoad(browser.Object, Mock.Of<IBrowser>(), Mock.Of<IFrame>(), request.Object, Mock.Of<IRequestCallback>());
|
||||
|
||||
request.VerifyGet(r => r.Headers, Times.AtLeastOnce);
|
||||
request.VerifySet(r => r.Headers = It.IsAny<NameValueCollection>(), Times.AtLeastOnce);
|
||||
|
||||
Assert.AreEqual(CefReturnValue.Continue, result);
|
||||
Assert.IsNotNull(headers["X-SafeExamBrowser-ConfigKeyHash"]);
|
||||
Assert.IsNotNull(headers["X-SafeExamBrowser-RequestHash"]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotAppendCustomHeadersForCrossDomainResourceRequestAndSubResource()
|
||||
{
|
||||
var browser = new Mock<IWebBrowser>();
|
||||
var headers = new NameValueCollection();
|
||||
var request = new Mock<IRequest>();
|
||||
|
||||
browser.SetupGet(b => b.Address).Returns("http://www.otherhost.org");
|
||||
request.SetupGet(r => r.ResourceType).Returns(ResourceType.SubResource);
|
||||
request.SetupGet(r => r.Headers).Returns(new NameValueCollection());
|
||||
request.SetupGet(r => r.Url).Returns("http://www.host.org");
|
||||
request.SetupSet(r => r.Headers = It.IsAny<NameValueCollection>()).Callback<NameValueCollection>((h) => headers = h);
|
||||
|
@ -166,7 +137,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
[TestMethod]
|
||||
public void MustLetOperatingSystemHandleUnknownProtocols()
|
||||
{
|
||||
Assert.IsTrue(sut.OnProtocolExecution(default, default, default, default));
|
||||
Assert.IsTrue(sut.OnProtocolExecution(default(IWebBrowser), default(IBrowser), default(IFrame), default(IRequest)));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -232,28 +203,28 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
var newUrl = default(string);
|
||||
var request = new Mock<IRequest>();
|
||||
var response = new Mock<IResponse>();
|
||||
var userId = default(string);
|
||||
var sessionId = default(string);
|
||||
|
||||
headers.Add("X-LMS-USER-ID", "some-session-id-123");
|
||||
request.SetupGet(r => r.Url).Returns("https://www.somelms.org");
|
||||
response.SetupGet(r => r.Headers).Returns(headers);
|
||||
sut.UserIdentifierDetected += (id) =>
|
||||
sut.SessionIdentifierDetected += (id) =>
|
||||
{
|
||||
userId = id;
|
||||
sessionId = id;
|
||||
@event.Set();
|
||||
};
|
||||
|
||||
sut.OnResourceRedirect(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), Mock.Of<IRequest>(), response.Object, ref newUrl);
|
||||
@event.WaitOne();
|
||||
Assert.AreEqual("some-session-id-123", userId);
|
||||
Assert.AreEqual("some-session-id-123", sessionId);
|
||||
|
||||
headers.Clear();
|
||||
headers.Add("X-LMS-USER-ID", "other-session-id-123");
|
||||
userId = default;
|
||||
sessionId = default(string);
|
||||
|
||||
sut.OnResourceResponse(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), request.Object, response.Object);
|
||||
@event.WaitOne();
|
||||
Assert.AreEqual("other-session-id-123", userId);
|
||||
Assert.AreEqual("other-session-id-123", sessionId);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -264,28 +235,28 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
var newUrl = default(string);
|
||||
var request = new Mock<IRequest>();
|
||||
var response = new Mock<IResponse>();
|
||||
var userId = default(string);
|
||||
var sessionId = default(string);
|
||||
|
||||
headers.Add("Set-Cookie", "edx-user-info=\"{\\\"username\\\": \\\"edx-123\\\"}\"; expires");
|
||||
request.SetupGet(r => r.Url).Returns("https://www.somelms.org");
|
||||
response.SetupGet(r => r.Headers).Returns(headers);
|
||||
sut.UserIdentifierDetected += (id) =>
|
||||
sut.SessionIdentifierDetected += (id) =>
|
||||
{
|
||||
userId = id;
|
||||
sessionId = id;
|
||||
@event.Set();
|
||||
};
|
||||
|
||||
sut.OnResourceRedirect(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), Mock.Of<IRequest>(), response.Object, ref newUrl);
|
||||
@event.WaitOne();
|
||||
Assert.AreEqual("edx-123", userId);
|
||||
Assert.AreEqual("edx-123", sessionId);
|
||||
|
||||
headers.Clear();
|
||||
headers.Add("Set-Cookie", "edx-user-info=\"{\\\"username\\\": \\\"edx-345\\\"}\"; expires");
|
||||
userId = default;
|
||||
sessionId = default(string);
|
||||
|
||||
sut.OnResourceResponse(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), request.Object, response.Object);
|
||||
@event.WaitOne();
|
||||
Assert.AreEqual("edx-345", userId);
|
||||
Assert.AreEqual("edx-345", sessionId);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -296,28 +267,28 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
var newUrl = default(string);
|
||||
var request = new Mock<IRequest>();
|
||||
var response = new Mock<IResponse>();
|
||||
var userId = default(string);
|
||||
var sessionId = default(string);
|
||||
|
||||
headers.Add("Location", "https://www.some-moodle-instance.org/moodle/login/index.php?testsession=123");
|
||||
request.SetupGet(r => r.Url).Returns("https://www.some-moodle-instance.org");
|
||||
response.SetupGet(r => r.Headers).Returns(headers);
|
||||
sut.UserIdentifierDetected += (id) =>
|
||||
sut.SessionIdentifierDetected += (id) =>
|
||||
{
|
||||
userId = id;
|
||||
sessionId = id;
|
||||
@event.Set();
|
||||
};
|
||||
|
||||
sut.OnResourceRedirect(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), Mock.Of<IRequest>(), response.Object, ref newUrl);
|
||||
@event.WaitOne();
|
||||
Assert.AreEqual("123", userId);
|
||||
Assert.AreEqual("123", sessionId);
|
||||
|
||||
headers.Clear();
|
||||
headers.Add("Location", "https://www.some-moodle-instance.org/moodle/login/index.php?testsession=456");
|
||||
userId = default;
|
||||
sessionId = default(string);
|
||||
|
||||
sut.OnResourceResponse(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), request.Object, response.Object);
|
||||
@event.WaitOne();
|
||||
Assert.AreEqual("456", userId);
|
||||
Assert.AreEqual("456", sessionId);
|
||||
}
|
||||
|
||||
private class TestableResourceHandler : ResourceHandler
|
||||
|
@ -327,10 +298,9 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
IRequestFilter filter,
|
||||
IKeyGenerator keyGenerator,
|
||||
ILogger logger,
|
||||
SessionMode sessionMode,
|
||||
BrowserSettings settings,
|
||||
WindowSettings windowSettings,
|
||||
IText text) : base(appConfig, filter, keyGenerator, logger, sessionMode, settings, windowSettings, text)
|
||||
IText text) : base(appConfig, filter, keyGenerator, logger, settings, windowSettings, text)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyDescription("Safe Exam Browser")]
|
||||
[assembly: AssemblyCompany("ETH Zürich")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.Browser.UnitTests")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2024 ETH Zürich, IT Services")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2022 ETH Zürich, Educational Development and Technology (LET)")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
<?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.3.2.2\build\net462\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.props')" />
|
||||
<Import Project="..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.2\build\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.props" Condition="Exists('..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.2\build\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.props')" />
|
||||
<Import Project="..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.props" Condition="Exists('..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.props')" />
|
||||
<Import Project="..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.props')" />
|
||||
<Import Project="..\packages\chromiumembeddedframework.runtime.win-x86.121.3.13\build\chromiumembeddedframework.runtime.win-x86.props" Condition="Exists('..\packages\chromiumembeddedframework.runtime.win-x86.121.3.13\build\chromiumembeddedframework.runtime.win-x86.props')" />
|
||||
<Import Project="..\packages\chromiumembeddedframework.runtime.win-x64.121.3.13\build\chromiumembeddedframework.runtime.win-x64.props" Condition="Exists('..\packages\chromiumembeddedframework.runtime.win-x64.121.3.13\build\chromiumembeddedframework.runtime.win-x64.props')" />
|
||||
<Import Project="..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.props')" />
|
||||
<Import Project="..\packages\cef.redist.x86.107.1.4\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.107.1.4\build\cef.redist.x86.props')" />
|
||||
<Import Project="..\packages\cef.redist.x64.107.1.4\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.107.1.4\build\cef.redist.x64.props')" />
|
||||
<Import Project="..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
|
@ -15,7 +13,7 @@
|
|||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SafeExamBrowser.Browser.UnitTests</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.Browser.UnitTests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<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>
|
||||
|
@ -25,7 +23,6 @@
|
|||
<TestProjectType>UnitTest</TestProjectType>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -65,87 +62,33 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Castle.Core, Version=5.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll</HintPath>
|
||||
<HintPath>..\packages\Castle.Core.5.1.0\lib\net462\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CefSharp, Version=121.3.130.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.121.3.130\lib\net462\CefSharp.dll</HintPath>
|
||||
<Reference Include="CefSharp, Version=107.1.40.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.107.1.40\lib\net452\CefSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CefSharp.Core, Version=121.3.130.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.121.3.130\lib\net462\CefSharp.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ApplicationInsights, Version=2.22.0.997, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ApplicationInsights.2.22.0\lib\net46\Microsoft.ApplicationInsights.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Testing.Extensions.Telemetry, Version=1.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.2\lib\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Testing.Extensions.TrxReport.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Testing.Extensions.TrxReport.Abstractions.1.0.2\lib\netstandard2.0\Microsoft.Testing.Extensions.TrxReport.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Testing.Extensions.VSTestBridge, Version=1.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Testing.Extensions.VSTestBridge.1.0.2\lib\netstandard2.0\Microsoft.Testing.Extensions.VSTestBridge.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Testing.Platform, Version=1.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\lib\netstandard2.0\Microsoft.Testing.Platform.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Testing.Platform.MSBuild, Version=1.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\lib\netstandard2.0\Microsoft.Testing.Platform.MSBuild.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.TestPlatform.CoreUtilities, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.TestPlatform.ObjectModel.17.9.0\lib\net462\Microsoft.TestPlatform.CoreUtilities.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.TestPlatform.PlatformAbstractions, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.TestPlatform.ObjectModel.17.9.0\lib\net462\Microsoft.TestPlatform.PlatformAbstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.ObjectModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.TestPlatform.ObjectModel.17.9.0\lib\net462\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll</HintPath>
|
||||
<Reference Include="CefSharp.Core, Version=107.1.40.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.107.1.40\lib\net452\CefSharp.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.3.2.2\lib\net462\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.2.10\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.3.2.2\lib\net462\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Moq, Version=4.20.70.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Moq.4.20.70\lib\net462\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NuGet.Frameworks, Version=6.9.1.3, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NuGet.Frameworks.6.9.1\lib\net472\NuGet.Frameworks.dll</HintPath>
|
||||
<Reference Include="Moq, Version=4.18.0.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Moq.4.18.2\lib\net462\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Collections.Immutable, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.8.0.0\lib\net462\System.Collections.Immutable.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Diagnostics.DiagnosticSource, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.8.0.0\lib\net462\System.Diagnostics.DiagnosticSource.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reflection.Metadata, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.Metadata.8.0.0\lib\net462\System.Reflection.Metadata.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime" />
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Filters\LegacyFilter.cs" />
|
||||
|
@ -166,7 +109,9 @@
|
|||
<None Include="app.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Browser.Contracts\SafeExamBrowser.Browser.Contracts.csproj">
|
||||
|
@ -204,17 +149,13 @@
|
|||
<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\chromiumembeddedframework.runtime.win-x64.121.3.13\build\chromiumembeddedframework.runtime.win-x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\chromiumembeddedframework.runtime.win-x64.121.3.13\build\chromiumembeddedframework.runtime.win-x64.props'))" />
|
||||
<Error Condition="!Exists('..\packages\chromiumembeddedframework.runtime.win-x86.121.3.13\build\chromiumembeddedframework.runtime.win-x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\chromiumembeddedframework.runtime.win-x86.121.3.13\build\chromiumembeddedframework.runtime.win-x86.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.2\build\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.2\build\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x64.107.1.4\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.107.1.4\build\cef.redist.x64.props'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x86.107.1.4\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.107.1.4\build\cef.redist.x86.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.targets')" />
|
||||
<Import Project="..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.targets" Condition="Exists('..\packages\Microsoft.Testing.Platform.MSBuild.1.0.2\build\netstandard2.0\Microsoft.Testing.Platform.MSBuild.targets')" />
|
||||
<Import Project="..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.3.2.2\build\net462\MSTest.TestAdapter.targets')" />
|
||||
<Import Project="..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')" />
|
||||
<Import Project="..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.targets')" />
|
||||
</Project>
|
|
@ -16,36 +16,12 @@
|
|||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="CefSharp" publicKeyToken="40c4b6fc221f4138" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-118.6.80.0" newVersion="118.6.80.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-103.0.120.0" newVersion="103.0.120.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="CefSharp.Core" publicKeyToken="40c4b6fc221f4138" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-118.6.80.0" newVersion="118.6.80.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="NuGet.Frameworks" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.11.3.1" newVersion="5.11.3.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.ApplicationInsights" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.22.0.997" newVersion="2.22.0.997" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-103.0.120.0" newVersion="103.0.120.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" /></startup></configuration>
|
||||
</configuration>
|
|
@ -1,26 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Castle.Core" version="5.1.1" targetFramework="net48" />
|
||||
<package id="CefSharp.Common" version="121.3.130" targetFramework="net48" />
|
||||
<package id="chromiumembeddedframework.runtime.win-x64" version="121.3.13" targetFramework="net48" />
|
||||
<package id="chromiumembeddedframework.runtime.win-x86" version="121.3.13" targetFramework="net48" />
|
||||
<package id="Microsoft.ApplicationInsights" version="2.22.0" targetFramework="net48" />
|
||||
<package id="Microsoft.Testing.Extensions.Telemetry" version="1.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Testing.Extensions.TrxReport.Abstractions" version="1.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Testing.Extensions.VSTestBridge" version="1.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Testing.Platform" version="1.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Testing.Platform.MSBuild" version="1.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.TestPlatform.ObjectModel" version="17.9.0" targetFramework="net48" />
|
||||
<package id="Moq" version="4.20.70" targetFramework="net48" />
|
||||
<package id="MSTest.TestAdapter" version="3.2.2" targetFramework="net48" />
|
||||
<package id="MSTest.TestFramework" version="3.2.2" targetFramework="net48" />
|
||||
<package id="NuGet.Frameworks" version="6.9.1" targetFramework="net48" />
|
||||
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
|
||||
<package id="System.Collections.Immutable" version="8.0.0" targetFramework="net48" />
|
||||
<package id="System.Diagnostics.DiagnosticSource" version="8.0.0" targetFramework="net48" />
|
||||
<package id="System.Memory" version="4.5.5" targetFramework="net48" />
|
||||
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
|
||||
<package id="System.Reflection.Metadata" version="8.0.0" targetFramework="net48" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
|
||||
<package id="Castle.Core" version="5.1.0" targetFramework="net472" />
|
||||
<package id="cef.redist.x64" version="107.1.4" targetFramework="net472" />
|
||||
<package id="cef.redist.x86" version="107.1.4" targetFramework="net472" />
|
||||
<package id="CefSharp.Common" version="107.1.40" targetFramework="net472" />
|
||||
<package id="Moq" version="4.18.2" targetFramework="net472" />
|
||||
<package id="MSTest.TestAdapter" version="2.2.10" targetFramework="net472" />
|
||||
<package id="MSTest.TestFramework" version="2.2.10" targetFramework="net472" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net472" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net472" />
|
||||
</packages>
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -14,6 +14,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Applications.Contracts.Events;
|
||||
using SafeExamBrowser.Browser.Contracts;
|
||||
using SafeExamBrowser.Browser.Contracts.Events;
|
||||
|
@ -23,7 +24,6 @@ using SafeExamBrowser.Configuration.Contracts.Cryptography;
|
|||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings;
|
||||
using SafeExamBrowser.Settings.Browser.Proxy;
|
||||
using SafeExamBrowser.Settings.Logging;
|
||||
using SafeExamBrowser.UserInterface.Contracts;
|
||||
|
@ -39,14 +39,12 @@ namespace SafeExamBrowser.Browser
|
|||
private int windowIdCounter = default;
|
||||
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly Clipboard clipboard;
|
||||
private readonly IFileSystemDialog fileSystemDialog;
|
||||
private readonly IHashAlgorithm hashAlgorithm;
|
||||
private readonly IKeyGenerator keyGenerator;
|
||||
private readonly IModuleLogger logger;
|
||||
private readonly IMessageBox messageBox;
|
||||
private readonly INativeMethods nativeMethods;
|
||||
private readonly SessionMode sessionMode;
|
||||
private readonly BrowserSettings settings;
|
||||
private readonly IText text;
|
||||
private readonly IUserInterfaceFactory uiFactory;
|
||||
|
@ -59,9 +57,9 @@ namespace SafeExamBrowser.Browser
|
|||
public string Tooltip { get; private set; }
|
||||
|
||||
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||
public event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
|
||||
public event LoseFocusRequestedEventHandler LoseFocusRequested;
|
||||
public event TerminationRequestedEventHandler TerminationRequested;
|
||||
public event UserIdentifierDetectedEventHandler UserIdentifierDetected;
|
||||
public event WindowsChangedEventHandler WindowsChanged;
|
||||
|
||||
public BrowserApplication(
|
||||
|
@ -70,22 +68,19 @@ namespace SafeExamBrowser.Browser
|
|||
IFileSystemDialog fileSystemDialog,
|
||||
IHashAlgorithm hashAlgorithm,
|
||||
IKeyGenerator keyGenerator,
|
||||
INativeMethods nativeMethods,
|
||||
IMessageBox messageBox,
|
||||
IModuleLogger logger,
|
||||
INativeMethods nativeMethods,
|
||||
SessionMode sessionMode,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.clipboard = new Clipboard(logger.CloneFor(nameof(Clipboard)), settings);
|
||||
this.fileSystemDialog = fileSystemDialog;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.logger = logger;
|
||||
this.messageBox = messageBox;
|
||||
this.nativeMethods = nativeMethods;
|
||||
this.sessionMode = sessionMode;
|
||||
this.settings = settings;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
|
@ -100,9 +95,9 @@ namespace SafeExamBrowser.Browser
|
|||
});
|
||||
}
|
||||
|
||||
public IEnumerable<IBrowserWindow> GetWindows()
|
||||
public IEnumerable<IApplicationWindow> GetWindows()
|
||||
{
|
||||
return new List<IBrowserWindow>(windows);
|
||||
return new List<IApplicationWindow>(windows);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
|
@ -116,18 +111,16 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
if (success)
|
||||
{
|
||||
InitializeIntegrityKeys();
|
||||
if (settings.UseTemporaryDownAndUploadDirectory)
|
||||
{
|
||||
CreateTemporaryDownAndUploadDirectory();
|
||||
}
|
||||
|
||||
if (settings.DeleteCookiesOnStartup)
|
||||
{
|
||||
DeleteCookies();
|
||||
}
|
||||
|
||||
if (settings.UseTemporaryDownAndUploadDirectory)
|
||||
{
|
||||
CreateTemporaryDownAndUploadDirectory();
|
||||
}
|
||||
|
||||
logger.Info("Initialized browser.");
|
||||
}
|
||||
else
|
||||
|
@ -193,7 +186,6 @@ namespace SafeExamBrowser.Browser
|
|||
var windowLogger = logger.CloneFor($"Browser Window #{id}");
|
||||
var window = new BrowserWindow(
|
||||
appConfig,
|
||||
clipboard,
|
||||
fileSystemDialog,
|
||||
hashAlgorithm,
|
||||
id,
|
||||
|
@ -201,7 +193,6 @@ namespace SafeExamBrowser.Browser
|
|||
keyGenerator,
|
||||
windowLogger,
|
||||
messageBox,
|
||||
sessionMode,
|
||||
settings,
|
||||
startUrl,
|
||||
text,
|
||||
|
@ -211,7 +202,7 @@ namespace SafeExamBrowser.Browser
|
|||
window.ConfigurationDownloadRequested += (f, a) => ConfigurationDownloadRequested?.Invoke(f, a);
|
||||
window.PopupRequested += Window_PopupRequested;
|
||||
window.ResetRequested += Window_ResetRequested;
|
||||
window.UserIdentifierDetected += (i) => UserIdentifierDetected?.Invoke(i);
|
||||
window.SessionIdentifierDetected += (i) => SessionIdentifierDetected?.Invoke(i);
|
||||
window.TerminationRequested += () => TerminationRequested?.Invoke();
|
||||
window.LoseFocusRequested += (forward) => LoseFocusRequested?.Invoke(forward);
|
||||
|
||||
|
@ -339,11 +330,6 @@ namespace SafeExamBrowser.Browser
|
|||
cefSettings.PersistSessionCookies = !settings.DeleteCookiesOnStartup || !settings.DeleteCookiesOnShutdown;
|
||||
cefSettings.UserAgent = InitializeUserAgent();
|
||||
|
||||
if (!settings.AllowPageZoom)
|
||||
{
|
||||
cefSettings.CefCommandLineArgs.Add("disable-pinch");
|
||||
}
|
||||
|
||||
if (!settings.AllowPdfReader)
|
||||
{
|
||||
cefSettings.CefCommandLineArgs.Add("disable-pdf-extension");
|
||||
|
@ -371,22 +357,6 @@ namespace SafeExamBrowser.Browser
|
|||
return cefSettings;
|
||||
}
|
||||
|
||||
private void InitializeIntegrityKeys()
|
||||
{
|
||||
logger.Debug($"Browser Exam Key (BEK) transmission is {(settings.SendBrowserExamKey ? "enabled" : "disabled")}.");
|
||||
logger.Debug($"Configuration Key (CK) transmission is {(settings.SendConfigurationKey ? "enabled" : "disabled")}.");
|
||||
|
||||
if (settings.CustomBrowserExamKey != default)
|
||||
{
|
||||
keyGenerator.UseCustomBrowserExamKey(settings.CustomBrowserExamKey);
|
||||
logger.Debug($"The browser application will be using a custom browser exam key.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Debug($"The browser application will be using the default browser exam key.");
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeProxySettings(CefSettings cefSettings)
|
||||
{
|
||||
if (settings.Proxy.Policy == ProxyPolicy.Custom)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -7,12 +7,10 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CefSharp;
|
||||
using SafeExamBrowser.Browser.Wrapper;
|
||||
using SafeExamBrowser.Browser.Wrapper.Events;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Browser.Data;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Browser.Events;
|
||||
|
@ -21,19 +19,17 @@ namespace SafeExamBrowser.Browser
|
|||
{
|
||||
internal class BrowserControl : IBrowserControl
|
||||
{
|
||||
private readonly Clipboard clipboard;
|
||||
private readonly ICefSharpControl control;
|
||||
private readonly IDialogHandler dialogHandler;
|
||||
private readonly IDisplayHandler displayHandler;
|
||||
private readonly IDownloadHandler downloadHandler;
|
||||
private readonly IKeyboardHandler keyboardHandler;
|
||||
private readonly ILogger logger;
|
||||
private readonly IRenderProcessMessageHandler renderProcessMessageHandler;
|
||||
private readonly IRequestHandler requestHandler;
|
||||
|
||||
public string Address => control.Address;
|
||||
public bool CanNavigateBackwards => control.IsBrowserInitialized && control.BrowserCore.CanGoBack;
|
||||
public bool CanNavigateForwards => control.IsBrowserInitialized && control.BrowserCore.CanGoForward;
|
||||
public bool CanNavigateBackwards => control.BrowserCore.CanGoBack;
|
||||
public bool CanNavigateForwards => control.BrowserCore.CanGoForward;
|
||||
public object EmbeddableControl => control;
|
||||
|
||||
public event AddressChangedEventHandler AddressChanged;
|
||||
|
@ -42,23 +38,19 @@ namespace SafeExamBrowser.Browser
|
|||
public event TitleChangedEventHandler TitleChanged;
|
||||
|
||||
public BrowserControl(
|
||||
Clipboard clipboard,
|
||||
ICefSharpControl control,
|
||||
IDialogHandler dialogHandler,
|
||||
IDisplayHandler displayHandler,
|
||||
IDownloadHandler downloadHandler,
|
||||
IKeyboardHandler keyboardHandler,
|
||||
ILogger logger,
|
||||
IRenderProcessMessageHandler renderProcessMessageHandler,
|
||||
IRequestHandler requestHandler)
|
||||
{
|
||||
this.control = control;
|
||||
this.clipboard = clipboard;
|
||||
this.dialogHandler = dialogHandler;
|
||||
this.displayHandler = displayHandler;
|
||||
this.downloadHandler = downloadHandler;
|
||||
this.keyboardHandler = keyboardHandler;
|
||||
this.logger = logger;
|
||||
this.renderProcessMessageHandler = renderProcessMessageHandler;
|
||||
this.requestHandler = requestHandler;
|
||||
}
|
||||
|
@ -71,37 +63,25 @@ namespace SafeExamBrowser.Browser
|
|||
}
|
||||
}
|
||||
|
||||
public void ExecuteJavaScript(string code, Action<JavaScriptResult> callback = default)
|
||||
public void ExecuteJavascript(string javascript, Action<JavascriptResult> callback)
|
||||
{
|
||||
try
|
||||
if ((control as IWebBrowser)?.CanExecuteJavascriptInMainFrame == true)
|
||||
{
|
||||
if (control.BrowserCore != default && control.BrowserCore.MainFrame != default)
|
||||
control.EvaluateScriptAsync(javascript).ContinueWith(t =>
|
||||
{
|
||||
control.BrowserCore.EvaluateScriptAsync(code).ContinueWith(t =>
|
||||
callback(new JavascriptResult
|
||||
{
|
||||
callback?.Invoke(new JavaScriptResult
|
||||
{
|
||||
Message = t.Result.Message,
|
||||
Result = t.Result.Result,
|
||||
Success = t.Result.Success
|
||||
});
|
||||
Message = t.Result.Message,
|
||||
Result = t.Result.Result,
|
||||
Success = t.Result.Success
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.Run(() => callback?.Invoke(new JavaScriptResult
|
||||
{
|
||||
Message = "JavaScript can't be executed in main frame!",
|
||||
Success = false
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
logger.Error($"Failed to execute JavaScript '{(code.Length > 50 ? code.Take(50) : code)}'!", e);
|
||||
Task.Run(() => callback?.Invoke(new JavaScriptResult
|
||||
Task.Run(() => callback(new JavascriptResult
|
||||
{
|
||||
Message = $"Failed to execute JavaScript '{(code.Length > 50 ? code.Take(50) : code)}'! Reason: {e.Message}",
|
||||
Message = "JavaScript can't be executed in main frame!",
|
||||
Success = false
|
||||
}));
|
||||
}
|
||||
|
@ -114,8 +94,6 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
public void Initialize()
|
||||
{
|
||||
clipboard.Changed += Clipboard_Changed;
|
||||
|
||||
control.AddressChanged += (o, e) => AddressChanged?.Invoke(e.Address);
|
||||
control.AuthCredentialsRequired += (w, b, o, i, h, p, r, s, c, a) => a.Value = requestHandler.GetAuthCredentials(w, b, o, i, h, p, r, s, c);
|
||||
control.BeforeBrowse += (w, b, f, r, u, i, a) => a.Value = requestHandler.OnBeforeBrowse(w, b, f, r, u, i);
|
||||
|
@ -137,11 +115,6 @@ namespace SafeExamBrowser.Browser
|
|||
control.ResourceRequestHandlerRequired += (IWebBrowser w, IBrowser b, IFrame f, IRequest r, bool n, bool d, string i, ref bool h, ResourceRequestEventArgs a) => a.Handler = requestHandler.GetResourceRequestHandler(w, b, f, r, n, d, i, ref h);
|
||||
control.TitleChanged += (o, e) => TitleChanged?.Invoke(e.Title);
|
||||
control.UncaughtExceptionEvent += (w, b, f, e) => renderProcessMessageHandler.OnUncaughtException(w, b, f, e);
|
||||
|
||||
if (control is IWebBrowser webBrowser)
|
||||
{
|
||||
webBrowser.JavascriptMessageReceived += WebBrowser_JavascriptMessageReceived;
|
||||
}
|
||||
}
|
||||
|
||||
public void NavigateBackwards()
|
||||
|
@ -174,11 +147,6 @@ namespace SafeExamBrowser.Browser
|
|||
control.BrowserCore.SetZoomLevel(level);
|
||||
}
|
||||
|
||||
private void Clipboard_Changed(long id)
|
||||
{
|
||||
ExecuteJavaScript($"SafeExamBrowser.clipboard.update({id}, '{clipboard.Content}');");
|
||||
}
|
||||
|
||||
private void Control_IsBrowserInitializedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (control.IsBrowserInitialized)
|
||||
|
@ -186,10 +154,5 @@ namespace SafeExamBrowser.Browser
|
|||
control.BrowserCore.GetHost().SetFocus(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void WebBrowser_JavascriptMessageReceived(object sender, JavascriptMessageReceivedEventArgs e)
|
||||
{
|
||||
clipboard.Process(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -13,6 +13,7 @@ using System.Threading.Tasks;
|
|||
using CefSharp;
|
||||
using CefSharp.WinForms.Handler;
|
||||
using CefSharp.WinForms.Host;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Applications.Contracts.Events;
|
||||
using SafeExamBrowser.Browser.Contracts.Events;
|
||||
using SafeExamBrowser.Browser.Contracts.Filters;
|
||||
|
@ -25,7 +26,6 @@ using SafeExamBrowser.Configuration.Contracts.Cryptography;
|
|||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.Settings.Browser.Filter;
|
||||
using SafeExamBrowser.UserInterface.Contracts;
|
||||
|
@ -42,20 +42,19 @@ using TitleChangedEventHandler = SafeExamBrowser.Applications.Contracts.Events.T
|
|||
|
||||
namespace SafeExamBrowser.Browser
|
||||
{
|
||||
internal class BrowserWindow : Contracts.IBrowserWindow
|
||||
internal class BrowserWindow : IApplicationWindow
|
||||
{
|
||||
private const string CLEAR_FIND_TERM = "thisisahacktoclearthesearchresultsasitappearsthatthereisnosuchfunctionalityincef";
|
||||
private const double ZOOM_FACTOR = 0.2;
|
||||
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly Clipboard clipboard;
|
||||
private readonly IFileSystemDialog fileSystemDialog;
|
||||
private readonly IHashAlgorithm hashAlgorithm;
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly bool isMainWindow;
|
||||
private readonly IKeyGenerator keyGenerator;
|
||||
private readonly IModuleLogger logger;
|
||||
private readonly IMessageBox messageBox;
|
||||
private readonly SessionMode sessionMode;
|
||||
private readonly Dictionary<int, BrowserWindow> popups;
|
||||
private readonly BrowserSettings settings;
|
||||
private readonly string startUrl;
|
||||
|
@ -68,7 +67,7 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
private WindowSettings WindowSettings
|
||||
{
|
||||
get { return IsMainWindow ? settings.MainWindow : settings.AdditionalWindow; }
|
||||
get { return isMainWindow ? settings.MainWindow : settings.AdditionalWindow; }
|
||||
}
|
||||
|
||||
internal IBrowserControl Control { get; private set; }
|
||||
|
@ -76,24 +75,21 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
public IntPtr Handle { get; private set; }
|
||||
public IconResource Icon { get; private set; }
|
||||
public bool IsMainWindow { get; private set; }
|
||||
public string Title { get; private set; }
|
||||
public string Url { get; private set; }
|
||||
|
||||
internal event WindowClosedEventHandler Closed;
|
||||
internal event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||
internal event LoseFocusRequestedEventHandler LoseFocusRequested;
|
||||
internal event PopupRequestedEventHandler PopupRequested;
|
||||
internal event ResetRequestedEventHandler ResetRequested;
|
||||
internal event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
|
||||
internal event LoseFocusRequestedEventHandler LoseFocusRequested;
|
||||
internal event TerminationRequestedEventHandler TerminationRequested;
|
||||
internal event UserIdentifierDetectedEventHandler UserIdentifierDetected;
|
||||
|
||||
public event IconChangedEventHandler IconChanged;
|
||||
public event TitleChangedEventHandler TitleChanged;
|
||||
|
||||
public BrowserWindow(
|
||||
AppConfig appConfig,
|
||||
Clipboard clipboard,
|
||||
IFileSystemDialog fileSystemDialog,
|
||||
IHashAlgorithm hashAlgorithm,
|
||||
int id,
|
||||
|
@ -101,24 +97,21 @@ namespace SafeExamBrowser.Browser
|
|||
IKeyGenerator keyGenerator,
|
||||
IModuleLogger logger,
|
||||
IMessageBox messageBox,
|
||||
SessionMode sessionMode,
|
||||
BrowserSettings settings,
|
||||
string startUrl,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.clipboard = clipboard;
|
||||
this.fileSystemDialog = fileSystemDialog;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
this.httpClient = new HttpClient();
|
||||
this.Id = id;
|
||||
this.IsMainWindow = isMainWindow;
|
||||
this.isMainWindow = isMainWindow;
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.logger = logger;
|
||||
this.messageBox = messageBox;
|
||||
this.popups = new Dictionary<int, BrowserWindow>();
|
||||
this.sessionMode = sessionMode;
|
||||
this.settings = settings;
|
||||
this.startUrl = startUrl;
|
||||
this.text = text;
|
||||
|
@ -152,21 +145,20 @@ namespace SafeExamBrowser.Browser
|
|||
internal void InitializeControl()
|
||||
{
|
||||
var cefSharpControl = default(ICefSharpControl);
|
||||
var controlLogger = logger.CloneFor($"{nameof(BrowserControl)} #{Id}");
|
||||
var dialogHandler = new DialogHandler();
|
||||
var displayHandler = new DisplayHandler();
|
||||
var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} #{Id}");
|
||||
var downloadHandler = new DownloadHandler(appConfig, downloadLogger, settings, WindowSettings);
|
||||
var keyboardHandler = new KeyboardHandler();
|
||||
var renderHandler = new RenderProcessMessageHandler(appConfig, clipboard, keyGenerator, settings, text);
|
||||
var renderHandler = new RenderProcessMessageHandler(appConfig, keyGenerator, settings, text);
|
||||
var requestFilter = new RequestFilter();
|
||||
var requestLogger = logger.CloneFor($"{nameof(RequestHandler)} #{Id}");
|
||||
var resourceHandler = new ResourceHandler(appConfig, requestFilter, keyGenerator, logger, sessionMode, settings, WindowSettings, text);
|
||||
var resourceHandler = new ResourceHandler(appConfig, requestFilter, keyGenerator, logger, settings, WindowSettings, text);
|
||||
var requestHandler = new RequestHandler(appConfig, requestFilter, requestLogger, resourceHandler, settings, WindowSettings);
|
||||
|
||||
Icon = new BrowserIconResource();
|
||||
|
||||
if (IsMainWindow)
|
||||
if (isMainWindow)
|
||||
{
|
||||
cefSharpControl = new CefSharpBrowserControl(CreateLifeSpanHandlerForMainWindow(), startUrl);
|
||||
}
|
||||
|
@ -189,13 +181,13 @@ namespace SafeExamBrowser.Browser
|
|||
keyboardHandler.ZoomInRequested += ZoomInRequested;
|
||||
keyboardHandler.ZoomOutRequested += ZoomOutRequested;
|
||||
keyboardHandler.ZoomResetRequested += ZoomResetRequested;
|
||||
resourceHandler.SessionIdentifierDetected += (id) => SessionIdentifierDetected?.Invoke(id);
|
||||
requestHandler.QuitUrlVisited += RequestHandler_QuitUrlVisited;
|
||||
requestHandler.RequestBlocked += RequestHandler_RequestBlocked;
|
||||
resourceHandler.UserIdentifierDetected += (id) => UserIdentifierDetected?.Invoke(id);
|
||||
|
||||
InitializeRequestFilter(requestFilter);
|
||||
|
||||
Control = new BrowserControl(clipboard, cefSharpControl, dialogHandler, displayHandler, downloadHandler, keyboardHandler, controlLogger, renderHandler, requestHandler);
|
||||
Control = new BrowserControl(cefSharpControl, dialogHandler, displayHandler, downloadHandler, keyboardHandler, renderHandler, requestHandler);
|
||||
Control.AddressChanged += Control_AddressChanged;
|
||||
Control.LoadFailed += Control_LoadFailed;
|
||||
Control.LoadingStateChanged += Control_LoadingStateChanged;
|
||||
|
@ -207,7 +199,7 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
internal void InitializeWindow()
|
||||
{
|
||||
window = uiFactory.CreateBrowserWindow(Control, settings, IsMainWindow, this.logger);
|
||||
window = uiFactory.CreateBrowserWindow(Control, settings, isMainWindow, this.logger);
|
||||
window.AddressChanged += Window_AddressChanged;
|
||||
window.BackwardNavigationRequested += Window_BackwardNavigationRequested;
|
||||
window.Closed += Window_Closed;
|
||||
|
@ -271,8 +263,6 @@ namespace SafeExamBrowser.Browser
|
|||
private void Control_AddressChanged(string address)
|
||||
{
|
||||
logger.Info($"Navigated{(WindowSettings.UrlPolicy.CanLog() ? $" to '{address}'" : "")}.");
|
||||
|
||||
Url = address;
|
||||
window.UpdateAddress(address);
|
||||
|
||||
if (WindowSettings.UrlPolicy == UrlPolicy.Always || WindowSettings.UrlPolicy == UrlPolicy.BeforeTitle)
|
||||
|
@ -367,8 +357,7 @@ namespace SafeExamBrowser.Browser
|
|||
initialPath,
|
||||
title: args.Title,
|
||||
parent: window,
|
||||
restrictNavigation: !settings.AllowCustomDownAndUploadLocation,
|
||||
showElementPath: settings.ShowFileSystemElementPath);
|
||||
restrictNavigation: !settings.AllowCustomDownAndUploadLocation);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
|
@ -446,7 +435,7 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
private void HomeNavigationRequested()
|
||||
{
|
||||
if (IsMainWindow && (settings.UseStartUrlAsHomeUrl || !string.IsNullOrWhiteSpace(settings.HomeUrl)))
|
||||
if (isMainWindow && (settings.UseStartUrlAsHomeUrl || !string.IsNullOrWhiteSpace(settings.HomeUrl)))
|
||||
{
|
||||
var navigate = false;
|
||||
var url = settings.UseStartUrlAsHomeUrl ? settings.StartUrl : settings.HomeUrl;
|
||||
|
@ -503,7 +492,7 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
private void KeyboardHandler_TabPressed(bool shiftPressed)
|
||||
{
|
||||
Control.ExecuteJavaScript("document.activeElement.tagName", result =>
|
||||
Control.ExecuteJavascript("document.activeElement.tagName", result =>
|
||||
{
|
||||
if (result.Result is string tagName && tagName?.ToUpper() == "BODY")
|
||||
{
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Threading.Tasks;
|
||||
using CefSharp;
|
||||
using SafeExamBrowser.Browser.Events;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings;
|
||||
|
||||
namespace SafeExamBrowser.Browser
|
||||
{
|
||||
internal class Clipboard
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly BrowserSettings settings;
|
||||
|
||||
internal string Content { get; private set; }
|
||||
|
||||
internal event ClipboardChangedEventHandler Changed;
|
||||
|
||||
internal Clipboard(ILogger logger, BrowserSettings settings)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
internal void Process(JavascriptMessageReceivedEventArgs message)
|
||||
{
|
||||
if (settings.UseIsolatedClipboard)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = message.ConvertMessageTo<Data>();
|
||||
|
||||
if (data != default && data.Type == "Clipboard" && TrySetContent(data.Content))
|
||||
{
|
||||
Task.Run(() => Changed?.Invoke(data.Id));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to process browser message '{message}'!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool TrySetContent(object value)
|
||||
{
|
||||
var text = value as string;
|
||||
|
||||
if (text != default)
|
||||
{
|
||||
Content = text;
|
||||
}
|
||||
|
||||
return text != default;
|
||||
}
|
||||
|
||||
private class Data
|
||||
{
|
||||
public string Content { get; set; }
|
||||
public long Id { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,4 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
SafeExamBrowser = {
|
||||
SafeExamBrowser = {
|
||||
version: 'SEB_Windows_%%_VERSION_%%',
|
||||
security: {
|
||||
browserExamKey: '%%_BEK_%%',
|
||||
|
|
|
@ -1,195 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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/.
|
||||
*
|
||||
* Original code taken and slightly adapted from https://github.com/eqsoft/seb2/blob/master/browser/app/modules/SebBrowser.jsm#L1215.
|
||||
*/
|
||||
|
||||
SafeExamBrowser.clipboard = {
|
||||
id: Math.round((Date.now() + Math.random()) * 1000),
|
||||
ranges: [],
|
||||
text: "",
|
||||
|
||||
clear: function () {
|
||||
this.ranges = [];
|
||||
this.text = "";
|
||||
},
|
||||
|
||||
getContentEncoded: function () {
|
||||
var bytes = new TextEncoder().encode(this.text);
|
||||
var base64 = btoa(String.fromCodePoint(...bytes));
|
||||
|
||||
return base64;
|
||||
},
|
||||
|
||||
update: function (id, base64) {
|
||||
if (this.id != id) {
|
||||
var bytes = Uint8Array.from(atob(base64), (m) => m.codePointAt(0));
|
||||
var content = new TextDecoder().decode(bytes);
|
||||
|
||||
this.ranges = [];
|
||||
this.text = content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function copySelectedData(e) {
|
||||
if (e.target.contentEditable && e.target.setRangeText) {
|
||||
SafeExamBrowser.clipboard.text = e.target.value.substring(e.target.selectionStart, e.target.selectionEnd);
|
||||
SafeExamBrowser.clipboard.ranges = [];
|
||||
} else {
|
||||
var selection = e.target.ownerDocument.defaultView.getSelection();
|
||||
var text = "";
|
||||
|
||||
for (var i = 0; i < selection.rangeCount; i++) {
|
||||
SafeExamBrowser.clipboard.ranges[i] = selection.getRangeAt(i).cloneContents();
|
||||
text += SafeExamBrowser.clipboard.ranges[i].textContent;
|
||||
}
|
||||
|
||||
SafeExamBrowser.clipboard.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
function cutSelectedData(e) {
|
||||
if (e.target.contentEditable && e.target.setRangeText) {
|
||||
e.target.setRangeText("", e.target.selectionStart, e.target.selectionEnd, 'select');
|
||||
} else {
|
||||
var designMode = e.target.ownerDocument.designMode;
|
||||
var contentEditables = e.target.ownerDocument.querySelectorAll('*[contenteditable]');
|
||||
var selection = e.target.ownerDocument.defaultView.getSelection();
|
||||
|
||||
for (var i = 0; i < selection.rangeCount; i++) {
|
||||
var range = selection.getRangeAt(i);
|
||||
|
||||
if (designMode === 'on') {
|
||||
range.deleteContents();
|
||||
} else {
|
||||
if (contentEditables.length) {
|
||||
contentEditables.forEach(node => {
|
||||
if (node.contains(range.commonAncestorContainer)) {
|
||||
range.deleteContents();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pasteSelectedData(e) {
|
||||
if (e.target.contentEditable && e.target.setRangeText) {
|
||||
e.target.setRangeText("", e.target.selectionStart, e.target.selectionEnd, 'select');
|
||||
e.target.setRangeText(SafeExamBrowser.clipboard.text, e.target.selectionStart, e.target.selectionStart + SafeExamBrowser.clipboard.text.length, 'end');
|
||||
} else {
|
||||
var w = e.target.ownerDocument.defaultView;
|
||||
var designMode = e.target.ownerDocument.designMode;
|
||||
var contentEditables = e.target.ownerDocument.querySelectorAll('*[contenteditable]');
|
||||
var selection = w.getSelection();
|
||||
|
||||
for (var i = 0; i < selection.rangeCount; i++) {
|
||||
var r = selection.getRangeAt(i);
|
||||
|
||||
if (designMode === 'on') {
|
||||
r.deleteContents();
|
||||
} else {
|
||||
if (contentEditables.length) {
|
||||
contentEditables.forEach(node => {
|
||||
if (node.contains(r.commonAncestorContainer)) {
|
||||
r.deleteContents();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (designMode === 'on') {
|
||||
var range = w.getSelection().getRangeAt(0);
|
||||
|
||||
if (SafeExamBrowser.clipboard.ranges.length > 0) {
|
||||
SafeExamBrowser.clipboard.ranges.map(r => {
|
||||
range = w.getSelection().getRangeAt(0);
|
||||
range.collapse();
|
||||
const newNode = r.cloneNode(true);
|
||||
range.insertNode(newNode);
|
||||
range.collapse();
|
||||
});
|
||||
} else {
|
||||
range.collapse();
|
||||
range.insertNode(w.document.createTextNode(SafeExamBrowser.clipboard.text));
|
||||
range.collapse();
|
||||
}
|
||||
} else {
|
||||
if (contentEditables.length) {
|
||||
contentEditables.forEach(node => {
|
||||
var range = w.getSelection().getRangeAt(0);
|
||||
|
||||
if (node.contains(range.commonAncestorContainer)) {
|
||||
if (SafeExamBrowser.clipboard.ranges.length > 0) {
|
||||
SafeExamBrowser.clipboard.ranges.map(r => {
|
||||
range = w.getSelection().getRangeAt(0);
|
||||
range.collapse();
|
||||
const newNode = r.cloneNode(true);
|
||||
range.insertNode(newNode);
|
||||
range.collapse();
|
||||
});
|
||||
} else {
|
||||
range = w.getSelection().getRangeAt(0);
|
||||
range.collapse();
|
||||
range.insertNode(w.document.createTextNode(SafeExamBrowser.clipboard.text));
|
||||
range.collapse();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onCopy(e) {
|
||||
SafeExamBrowser.clipboard.clear();
|
||||
|
||||
try {
|
||||
copySelectedData(e);
|
||||
|
||||
CefSharp.PostMessage({ Type: "Clipboard", Id: SafeExamBrowser.clipboard.id, Content: SafeExamBrowser.clipboard.getContentEncoded() });
|
||||
} finally {
|
||||
e.preventDefault();
|
||||
e.returnValue = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function onCut(e) {
|
||||
SafeExamBrowser.clipboard.clear();
|
||||
|
||||
try {
|
||||
copySelectedData(e);
|
||||
cutSelectedData(e);
|
||||
|
||||
CefSharp.PostMessage({ Type: "Clipboard", Id: SafeExamBrowser.clipboard.id, Content: SafeExamBrowser.clipboard.getContentEncoded() });
|
||||
} finally {
|
||||
e.preventDefault();
|
||||
e.returnValue = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function onPaste(e) {
|
||||
try {
|
||||
pasteSelectedData(e);
|
||||
} finally {
|
||||
e.preventDefault();
|
||||
e.returnValue = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
window.document.addEventListener("copy", onCopy, true);
|
||||
window.document.addEventListener("cut", onCut, true);
|
||||
window.document.addEventListener("paste", onPaste, true);
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -14,11 +14,8 @@ namespace SafeExamBrowser.Browser.Content
|
|||
{
|
||||
internal class ContentLoader
|
||||
{
|
||||
private readonly IText text;
|
||||
|
||||
private string api;
|
||||
private string clipboard;
|
||||
private string pageZoom;
|
||||
private IText text;
|
||||
|
||||
internal ContentLoader(IText text)
|
||||
{
|
||||
|
@ -27,7 +24,7 @@ namespace SafeExamBrowser.Browser.Content
|
|||
|
||||
internal string LoadApi(string browserExamKey, string configurationKey, string version)
|
||||
{
|
||||
if (api == default)
|
||||
if (api == default(string))
|
||||
{
|
||||
var assembly = Assembly.GetAssembly(typeof(ContentLoader));
|
||||
var path = $"{typeof(ContentLoader).Namespace}.Api.js";
|
||||
|
@ -81,39 +78,5 @@ namespace SafeExamBrowser.Browser.Content
|
|||
return html;
|
||||
}
|
||||
}
|
||||
|
||||
internal string LoadClipboard()
|
||||
{
|
||||
if (clipboard == default)
|
||||
{
|
||||
var assembly = Assembly.GetAssembly(typeof(ContentLoader));
|
||||
var path = $"{typeof(ContentLoader).Namespace}.Clipboard.js";
|
||||
|
||||
using (var stream = assembly.GetManifestResourceStream(path))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
clipboard = reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
internal string LoadPageZoom()
|
||||
{
|
||||
if (pageZoom == default)
|
||||
{
|
||||
var assembly = Assembly.GetAssembly(typeof(ContentLoader));
|
||||
var path = $"{typeof(ContentLoader).Namespace}.PageZoom.js";
|
||||
|
||||
using (var stream = assembly.GetManifestResourceStream(path))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
pageZoom = reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
return pageZoom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
function disableMouseWheelZoom(e) {
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('wheel', disableMouseWheelZoom, { passive: false });
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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 ClipboardChangedEventHandler(long id);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -138,11 +138,6 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
filePath = Path.Combine(KnownFolders.Downloads.ExpandedPath, downloadItem.SuggestedFileName);
|
||||
}
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
filePath = AppendIndexSuffixTo(filePath);
|
||||
}
|
||||
|
||||
if (showDialog)
|
||||
{
|
||||
logger.Debug($"Allowing user to select custom download location, with '{filePath}' as suggestion.");
|
||||
|
@ -160,26 +155,6 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
}
|
||||
}
|
||||
|
||||
private string AppendIndexSuffixTo(string filePath)
|
||||
{
|
||||
var directory = Path.GetDirectoryName(filePath);
|
||||
var extension = Path.GetExtension(filePath);
|
||||
var name = Path.GetFileNameWithoutExtension(filePath);
|
||||
var path = default(string);
|
||||
|
||||
for (var suffix = 1; suffix < int.MaxValue; suffix++)
|
||||
{
|
||||
path = Path.Combine(directory, $"{name}({suffix}){extension}");
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private void RequestConfigurationFileDownload(DownloadItem downloadItem, IBeforeDownloadCallback callback)
|
||||
{
|
||||
var args = new DownloadEventArgs { Url = downloadItem.Url };
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -63,7 +63,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
ZoomResetRequested?.Invoke();
|
||||
}
|
||||
|
||||
if (keyCode == (int) Keys.Tab && keyCode == currentKeyDown)
|
||||
if (keyCode == (int)Keys.Tab && keyCode == currentKeyDown)
|
||||
{
|
||||
TabPressed?.Invoke(shift);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -18,16 +18,14 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
internal class RenderProcessMessageHandler : IRenderProcessMessageHandler
|
||||
{
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly Clipboard clipboard;
|
||||
private readonly ContentLoader contentLoader;
|
||||
private readonly IKeyGenerator keyGenerator;
|
||||
private readonly BrowserSettings settings;
|
||||
private readonly IText text;
|
||||
|
||||
internal RenderProcessMessageHandler(AppConfig appConfig, Clipboard clipboard, IKeyGenerator keyGenerator, BrowserSettings settings, IText text)
|
||||
internal RenderProcessMessageHandler(AppConfig appConfig, IKeyGenerator keyGenerator, BrowserSettings settings, IText text)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.clipboard = clipboard;
|
||||
this.contentLoader = new ContentLoader(text);
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.settings = settings;
|
||||
|
@ -36,32 +34,15 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
|
||||
public void OnContextCreated(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame)
|
||||
{
|
||||
var browserExamKey = keyGenerator.CalculateBrowserExamKeyHash(settings.ConfigurationKey, settings.BrowserExamKeySalt, frame.Url);
|
||||
var configurationKey = keyGenerator.CalculateConfigurationKeyHash(settings.ConfigurationKey, frame.Url);
|
||||
var browserExamKey = keyGenerator.CalculateBrowserExamKeyHash(frame.Url);
|
||||
var configurationKey = keyGenerator.CalculateConfigurationKeyHash(frame.Url);
|
||||
var api = contentLoader.LoadApi(browserExamKey, configurationKey, appConfig.ProgramBuildVersion);
|
||||
var clipboardScript = contentLoader.LoadClipboard();
|
||||
var pageZoomScript = contentLoader.LoadPageZoom();
|
||||
|
||||
frame.ExecuteJavaScriptAsync(api);
|
||||
|
||||
if (!settings.AllowPageZoom)
|
||||
{
|
||||
frame.ExecuteJavaScriptAsync(pageZoomScript);
|
||||
}
|
||||
|
||||
if (!settings.AllowPrint)
|
||||
{
|
||||
frame.ExecuteJavaScriptAsync($"window.print = function() {{ alert('{text.Get(TextKey.Browser_PrintNotAllowed)}') }}");
|
||||
}
|
||||
|
||||
if (settings.UseIsolatedClipboard)
|
||||
{
|
||||
frame.ExecuteJavaScriptAsync(clipboardScript);
|
||||
|
||||
if (clipboard.Content != default)
|
||||
{
|
||||
frame.ExecuteJavaScriptAsync($"SafeExamBrowser.clipboard.update('', '{clipboard.Content}');");
|
||||
}
|
||||
frame.ExecuteJavaScriptAsync($"window.print = function(){{ alert('{text.Get(TextKey.Browser_PrintNotAllowed)}') }}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -121,35 +121,19 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
private bool IsConfigurationFile(IRequest request, out string downloadUrl)
|
||||
{
|
||||
var isValidUri = Uri.TryCreate(request.Url, UriKind.RelativeOrAbsolute, out var uri);
|
||||
var hasFileExtension = string.Equals(appConfig.ConfigurationFileExtension, Path.GetExtension(uri.AbsolutePath), StringComparison.OrdinalIgnoreCase);
|
||||
var isDataUri = request.Url.Contains(appConfig.ConfigurationFileMimeType);
|
||||
var isConfigurationFile = isValidUri && (hasFileExtension || isDataUri);
|
||||
var isConfigurationFile = isValidUri && string.Equals(appConfig.ConfigurationFileExtension, Path.GetExtension(uri.AbsolutePath), StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
downloadUrl = request.Url;
|
||||
|
||||
if (isConfigurationFile)
|
||||
{
|
||||
if (isDataUri)
|
||||
if (uri.Scheme == appConfig.SebUriScheme)
|
||||
{
|
||||
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:");
|
||||
}
|
||||
downloadUrl = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri.AbsoluteUri;
|
||||
}
|
||||
else
|
||||
else if (uri.Scheme == appConfig.SebUriSchemeSecure)
|
||||
{
|
||||
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;
|
||||
}
|
||||
downloadUrl = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttps }.Uri.AbsoluteUri;
|
||||
}
|
||||
|
||||
logger.Debug($"Detected configuration file {(windowSettings.UrlPolicy.CanLog() ? $"'{uri}'" : "")}.");
|
||||
|
@ -166,7 +150,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
{
|
||||
if (quitUrlPattern == default)
|
||||
{
|
||||
quitUrlPattern = $"^{Regex.Escape(settings.QuitUrl.TrimEnd('/'))}/?$";
|
||||
quitUrlPattern = Regex.Escape(settings.QuitUrl.TrimEnd('/')) + @"\/?";
|
||||
}
|
||||
|
||||
isQuitUrl = Regex.IsMatch(request.Url, quitUrlPattern, RegexOptions.IgnoreCase);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
@ -23,7 +23,6 @@ using SafeExamBrowser.Configuration.Contracts;
|
|||
using SafeExamBrowser.Configuration.Contracts.Cryptography;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.Settings.Browser.Filter;
|
||||
using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings;
|
||||
|
@ -38,22 +37,20 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
private readonly IRequestFilter filter;
|
||||
private readonly IKeyGenerator keyGenerator;
|
||||
private readonly ILogger logger;
|
||||
private readonly SessionMode sessionMode;
|
||||
private readonly BrowserSettings settings;
|
||||
private readonly WindowSettings windowSettings;
|
||||
|
||||
private IResourceHandler contentHandler;
|
||||
private IResourceHandler pageHandler;
|
||||
private string userIdentifier;
|
||||
private string sessionIdentifier;
|
||||
|
||||
internal event UserIdentifierDetectedEventHandler UserIdentifierDetected;
|
||||
internal event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
|
||||
|
||||
internal ResourceHandler(
|
||||
AppConfig appConfig,
|
||||
IRequestFilter filter,
|
||||
IKeyGenerator keyGenerator,
|
||||
ILogger logger,
|
||||
SessionMode sessionMode,
|
||||
BrowserSettings settings,
|
||||
WindowSettings windowSettings,
|
||||
IText text)
|
||||
|
@ -63,7 +60,6 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
this.contentLoader = new ContentLoader(text);
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.logger = logger;
|
||||
this.sessionMode = sessionMode;
|
||||
this.settings = settings;
|
||||
this.windowSettings = windowSettings;
|
||||
}
|
||||
|
@ -98,10 +94,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
|
||||
protected override void OnResourceRedirect(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response, ref string newUrl)
|
||||
{
|
||||
if (sessionMode == SessionMode.Server)
|
||||
{
|
||||
SearchUserIdentifier(request, response);
|
||||
}
|
||||
SearchSessionIdentifiers(request, response);
|
||||
|
||||
base.OnResourceRedirect(chromiumWebBrowser, browser, frame, request, response, ref newUrl);
|
||||
}
|
||||
|
@ -115,10 +108,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
return true;
|
||||
}
|
||||
|
||||
if (sessionMode == SessionMode.Server)
|
||||
{
|
||||
SearchUserIdentifier(request, response);
|
||||
}
|
||||
SearchSessionIdentifiers(request, response);
|
||||
|
||||
return base.OnResourceResponse(webBrowser, browser, frame, request, response);
|
||||
}
|
||||
|
@ -128,18 +118,18 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
Uri.TryCreate(webBrowser.Address, UriKind.Absolute, out var pageUrl);
|
||||
Uri.TryCreate(request.Url, UriKind.Absolute, out var requestUrl);
|
||||
|
||||
if (request.ResourceType == ResourceType.MainFrame || pageUrl?.Host?.Equals(requestUrl?.Host) == true)
|
||||
if (pageUrl?.Host?.Equals(requestUrl?.Host) == true)
|
||||
{
|
||||
var headers = new NameValueCollection(request.Headers);
|
||||
|
||||
if (settings.SendConfigurationKey)
|
||||
{
|
||||
headers["X-SafeExamBrowser-ConfigKeyHash"] = keyGenerator.CalculateConfigurationKeyHash(settings.ConfigurationKey, request.Url);
|
||||
headers["X-SafeExamBrowser-ConfigKeyHash"] = keyGenerator.CalculateConfigurationKeyHash(request.Url);
|
||||
}
|
||||
|
||||
if (settings.SendBrowserExamKey)
|
||||
{
|
||||
headers["X-SafeExamBrowser-RequestHash"] = keyGenerator.CalculateBrowserExamKeyHash(settings.ConfigurationKey, settings.BrowserExamKeySalt, request.Url);
|
||||
headers["X-SafeExamBrowser-RequestHash"] = keyGenerator.CalculateBrowserExamKeyHash(request.Url);
|
||||
}
|
||||
|
||||
request.Headers = headers;
|
||||
|
@ -233,46 +223,41 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
}
|
||||
}
|
||||
|
||||
private void SearchUserIdentifier(IRequest request, IResponse response)
|
||||
private void SearchSessionIdentifiers(IRequest request, IResponse response)
|
||||
{
|
||||
var success = TrySearchGenericUserIdentifier(response);
|
||||
var success = TrySearchGenericSessionIdentifier(response);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
success = TrySearchEdxUserIdentifier(response);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
TrySearchMoodleUserIdentifier(request, response);
|
||||
SearchEdxIdentifier(response);
|
||||
SearchMoodleIdentifier(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TrySearchGenericUserIdentifier(IResponse response)
|
||||
private bool TrySearchGenericSessionIdentifier(IResponse response)
|
||||
{
|
||||
var ids = response.Headers.GetValues("X-LMS-USER-ID");
|
||||
var success = false;
|
||||
|
||||
if (ids != default(string[]))
|
||||
{
|
||||
var userId = ids.FirstOrDefault();
|
||||
|
||||
if (userId != default && userIdentifier != userId)
|
||||
if (userId != default && sessionIdentifier != userId)
|
||||
{
|
||||
userIdentifier = userId;
|
||||
Task.Run(() => UserIdentifierDetected?.Invoke(userIdentifier));
|
||||
logger.Info("Generic LMS user identifier detected.");
|
||||
success = true;
|
||||
sessionIdentifier = userId;
|
||||
Task.Run(() => SessionIdentifierDetected?.Invoke(sessionIdentifier));
|
||||
logger.Info("Generic LMS session detected.");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TrySearchEdxUserIdentifier(IResponse response)
|
||||
private void SearchEdxIdentifier(IResponse response)
|
||||
{
|
||||
var cookies = response.Headers.GetValues("Set-Cookie");
|
||||
var success = false;
|
||||
|
||||
if (cookies != default(string[]))
|
||||
{
|
||||
|
@ -289,42 +274,32 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
var json = JsonConvert.DeserializeObject(sanitized) as JObject;
|
||||
var userName = json["username"].Value<string>();
|
||||
|
||||
if (userIdentifier != userName)
|
||||
if (sessionIdentifier != userName)
|
||||
{
|
||||
userIdentifier = userName;
|
||||
Task.Run(() => UserIdentifierDetected?.Invoke(userIdentifier));
|
||||
logger.Info("EdX user identifier detected.");
|
||||
success = true;
|
||||
sessionIdentifier = userName;
|
||||
Task.Run(() => SessionIdentifierDetected?.Invoke(sessionIdentifier));
|
||||
logger.Info("EdX session detected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to parse edX user identifier!", e);
|
||||
logger.Error("Failed to parse edX session identifier!", e);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TrySearchMoodleUserIdentifier(IRequest request, IResponse response)
|
||||
private void SearchMoodleIdentifier(IRequest request, IResponse response)
|
||||
{
|
||||
var success = TrySearchMoodleUserIdentifierByLocation(response);
|
||||
var success = TrySearchByLocation(response);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
success = TrySearchMoodleUserIdentifierByRequest(MoodleRequestType.Plugin, request, response);
|
||||
TrySearchBySession(request, response);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
success = TrySearchMoodleUserIdentifierByRequest(MoodleRequestType.Theme, request, response);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TrySearchMoodleUserIdentifierByLocation(IResponse response)
|
||||
private bool TrySearchByLocation(IResponse response)
|
||||
{
|
||||
var locations = response.Headers.GetValues("Location");
|
||||
|
||||
|
@ -338,11 +313,11 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
{
|
||||
var userId = location.Substring(location.IndexOf("=") + 1);
|
||||
|
||||
if (userIdentifier != userId)
|
||||
if (sessionIdentifier != userId)
|
||||
{
|
||||
userIdentifier = userId;
|
||||
Task.Run(() => UserIdentifierDetected?.Invoke(userIdentifier));
|
||||
logger.Info("Moodle user identifier detected by location.");
|
||||
sessionIdentifier = userId;
|
||||
Task.Run(() => SessionIdentifierDetected?.Invoke(sessionIdentifier));
|
||||
logger.Info("Moodle session detected.");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -350,17 +325,16 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to parse Moodle user identifier by location!", e);
|
||||
logger.Error("Failed to parse Moodle session identifier!", e);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TrySearchMoodleUserIdentifierByRequest(MoodleRequestType type, IRequest request, IResponse response)
|
||||
private void TrySearchBySession(IRequest request, IResponse response)
|
||||
{
|
||||
var cookies = response.Headers.GetValues("Set-Cookie");
|
||||
var success = false;
|
||||
|
||||
if (cookies != default(string[]))
|
||||
{
|
||||
|
@ -368,84 +342,51 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
|
||||
if (session != default)
|
||||
{
|
||||
var userId = ExecuteMoodleUserIdentifierRequest(request.Url, session, type);
|
||||
var requestUrl = request.Url;
|
||||
|
||||
if (int.TryParse(userId, out var id) && id > 0 && userIdentifier != userId)
|
||||
Task.Run(async () =>
|
||||
{
|
||||
userIdentifier = userId;
|
||||
Task.Run(() => UserIdentifierDetected?.Invoke(userIdentifier));
|
||||
logger.Info($"Moodle user identifier detected by request ({type}).");
|
||||
success = true;
|
||||
}
|
||||
try
|
||||
{
|
||||
var start = session.IndexOf("=") + 1;
|
||||
var end = session.IndexOf(";");
|
||||
var value = session.Substring(start, end - start);
|
||||
var uri = new Uri(requestUrl);
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{uri.Scheme}{Uri.SchemeDelimiter}{uri.Host}/theme/boost_ethz/sebuser.php");
|
||||
|
||||
using (var handler = new HttpClientHandler { UseCookies = false })
|
||||
using (var client = new HttpClient(handler))
|
||||
{
|
||||
message.Headers.Add("Cookie", $"MoodleSession={value}");
|
||||
|
||||
var result = await client.SendAsync(message);
|
||||
|
||||
if (result.IsSuccessStatusCode)
|
||||
{
|
||||
var userId = await result.Content.ReadAsStringAsync();
|
||||
|
||||
if (int.TryParse(userId, out var id) && id > 0 && sessionIdentifier != userId)
|
||||
{
|
||||
#pragma warning disable CS4014
|
||||
sessionIdentifier = userId;
|
||||
Task.Run(() => SessionIdentifierDetected?.Invoke(sessionIdentifier));
|
||||
logger.Info("Moodle session detected.");
|
||||
#pragma warning restore CS4014
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"Failed to retrieve Moodle session identifier! Response: {result.StatusCode} {result.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to parse Moodle session identifier!", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private string ExecuteMoodleUserIdentifierRequest(string requestUrl, string session, MoodleRequestType type)
|
||||
{
|
||||
var userId = default(string);
|
||||
|
||||
try
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var endpointUrl = default(string);
|
||||
var start = session.IndexOf("=") + 1;
|
||||
var end = session.IndexOf(";");
|
||||
var name = session.Substring(0, start - 1);
|
||||
var value = session.Substring(start, end - start);
|
||||
var uri = new Uri(requestUrl);
|
||||
|
||||
if (type == MoodleRequestType.Plugin)
|
||||
{
|
||||
endpointUrl = $"{uri.Scheme}{Uri.SchemeDelimiter}{uri.Host}/mod/quiz/accessrule/sebserver/classes/external/user.php";
|
||||
}
|
||||
else
|
||||
{
|
||||
endpointUrl = $"{uri.Scheme}{Uri.SchemeDelimiter}{uri.Host}/theme/boost_ethz/sebuser.php";
|
||||
}
|
||||
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, endpointUrl);
|
||||
|
||||
using (var handler = new HttpClientHandler { UseCookies = false })
|
||||
using (var client = new HttpClient(handler))
|
||||
{
|
||||
message.Headers.Add("Cookie", $"{name}={value}");
|
||||
|
||||
var result = await client.SendAsync(message);
|
||||
|
||||
if (result.IsSuccessStatusCode)
|
||||
{
|
||||
userId = await result.Content.ReadAsStringAsync();
|
||||
}
|
||||
else if (result.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
logger.Error($"Failed to retrieve Moodle user identifier by request ({type})! Response: {(int) result.StatusCode} {result.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to parse Moodle user identifier by request ({type})!", e);
|
||||
}
|
||||
}).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to execute Moodle user identifier request ({type})!", e);
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
private enum MoodleRequestType
|
||||
{
|
||||
Plugin,
|
||||
Theme
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyDescription("Safe Exam Browser")]
|
||||
[assembly: AssemblyCompany("ETH Zürich")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.Browser")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2024 ETH Zürich, IT Services")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2022 ETH Zürich, Educational Development and Technology (LET)")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.props')" />
|
||||
<Import Project="..\packages\chromiumembeddedframework.runtime.win-x86.121.3.13\build\chromiumembeddedframework.runtime.win-x86.props" Condition="Exists('..\packages\chromiumembeddedframework.runtime.win-x86.121.3.13\build\chromiumembeddedframework.runtime.win-x86.props')" />
|
||||
<Import Project="..\packages\chromiumembeddedframework.runtime.win-x64.121.3.13\build\chromiumembeddedframework.runtime.win-x64.props" Condition="Exists('..\packages\chromiumembeddedframework.runtime.win-x64.121.3.13\build\chromiumembeddedframework.runtime.win-x64.props')" />
|
||||
<Import Project="..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.props')" />
|
||||
<Import Project="..\packages\cef.redist.x86.107.1.4\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.107.1.4\build\cef.redist.x86.props')" />
|
||||
<Import Project="..\packages\cef.redist.x64.107.1.4\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.107.1.4\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>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SafeExamBrowser.Browser</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.Browser</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
|
@ -53,17 +53,17 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="CefSharp, Version=121.3.130.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.121.3.130\lib\net462\CefSharp.dll</HintPath>
|
||||
<Reference Include="CefSharp, Version=107.1.40.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.107.1.40\lib\net452\CefSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CefSharp.Core, Version=121.3.130.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.121.3.130\lib\net462\CefSharp.Core.dll</HintPath>
|
||||
<Reference Include="CefSharp.Core, Version=107.1.40.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.107.1.40\lib\net452\CefSharp.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CefSharp.WinForms, Version=121.3.130.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.WinForms.121.3.130\lib\net462\CefSharp.WinForms.dll</HintPath>
|
||||
<Reference Include="CefSharp.WinForms, Version=107.1.40.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.WinForms.107.1.40\lib\net462\CefSharp.WinForms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Syroot.KnownFolders, Version=1.3.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Syroot.Windows.IO.KnownFolders.1.3.0\lib\netstandard2.0\Syroot.KnownFolders.dll</HintPath>
|
||||
|
@ -80,8 +80,6 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="BrowserApplication.cs" />
|
||||
<Compile Include="BrowserWindow.cs" />
|
||||
<Compile Include="Clipboard.cs" />
|
||||
<Compile Include="Events\ClipboardChangedEventHandler.cs" />
|
||||
<Compile Include="Events\DialogRequestedEventArgs.cs" />
|
||||
<Compile Include="Events\DialogRequestedEventHandler.cs" />
|
||||
<Compile Include="Events\DownloadAbortedEventHandler.cs" />
|
||||
|
@ -191,12 +189,6 @@
|
|||
<ItemGroup>
|
||||
<EmbeddedResource Include="Content\Api.js" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Content\Clipboard.js" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Content\PageZoom.js" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
|
@ -209,10 +201,10 @@
|
|||
<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\chromiumembeddedframework.runtime.win-x64.121.3.13\build\chromiumembeddedframework.runtime.win-x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\chromiumembeddedframework.runtime.win-x64.121.3.13\build\chromiumembeddedframework.runtime.win-x64.props'))" />
|
||||
<Error Condition="!Exists('..\packages\chromiumembeddedframework.runtime.win-x86.121.3.13\build\chromiumembeddedframework.runtime.win-x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\chromiumembeddedframework.runtime.win-x86.121.3.13\build\chromiumembeddedframework.runtime.win-x86.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x64.107.1.4\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.107.1.4\build\cef.redist.x64.props'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x86.107.1.4\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.107.1.4\build\cef.redist.x86.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.121.3.130\build\CefSharp.Common.targets')" />
|
||||
<Import Project="..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.107.1.40\build\CefSharp.Common.targets')" />
|
||||
</Project>
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
* Copyright (c) 2022 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
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue