SEBWIN-612, #625: Implemented basic clipboard functionality.
This commit is contained in:
parent
940baae655
commit
eff0051469
27 changed files with 463 additions and 47 deletions
|
@ -1,4 +1,12 @@
|
||||||
SafeExamBrowser = {
|
/*
|
||||||
|
* Copyright (c) 2023 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SafeExamBrowser = {
|
||||||
version: 'SEB_Windows_%%_VERSION_%%',
|
version: 'SEB_Windows_%%_VERSION_%%',
|
||||||
security: {
|
security: {
|
||||||
browserExamKey: '%%_BEK_%%',
|
browserExamKey: '%%_BEK_%%',
|
||||||
|
|
172
SafeExamBrowser.Browser/Content/Clipboard.js
Normal file
172
SafeExamBrowser.Browser/Content/Clipboard.js
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Original code taken and slightly adapted from https://github.com/eqsoft/seb2/blob/master/browser/app/modules/SebBrowser.jsm#L1215.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SafeExamBrowser.clipboard = {
|
||||||
|
clear: function () {
|
||||||
|
ranges = [];
|
||||||
|
text = "";
|
||||||
|
},
|
||||||
|
ranges: [],
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
} finally {
|
||||||
|
e.preventDefault();
|
||||||
|
e.returnValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCut(e) {
|
||||||
|
SafeExamBrowser.clipboard.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
copySelectedData(e);
|
||||||
|
cutSelectedData(e);
|
||||||
|
} 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);
|
|
@ -14,8 +14,10 @@ namespace SafeExamBrowser.Browser.Content
|
||||||
{
|
{
|
||||||
internal class ContentLoader
|
internal class ContentLoader
|
||||||
{
|
{
|
||||||
|
private readonly IText text;
|
||||||
|
|
||||||
private string api;
|
private string api;
|
||||||
private IText text;
|
private string clipboard;
|
||||||
|
|
||||||
internal ContentLoader(IText text)
|
internal ContentLoader(IText text)
|
||||||
{
|
{
|
||||||
|
@ -24,7 +26,7 @@ namespace SafeExamBrowser.Browser.Content
|
||||||
|
|
||||||
internal string LoadApi(string browserExamKey, string configurationKey, string version)
|
internal string LoadApi(string browserExamKey, string configurationKey, string version)
|
||||||
{
|
{
|
||||||
if (api == default(string))
|
if (api == default)
|
||||||
{
|
{
|
||||||
var assembly = Assembly.GetAssembly(typeof(ContentLoader));
|
var assembly = Assembly.GetAssembly(typeof(ContentLoader));
|
||||||
var path = $"{typeof(ContentLoader).Namespace}.Api.js";
|
var path = $"{typeof(ContentLoader).Namespace}.Api.js";
|
||||||
|
@ -78,5 +80,22 @@ namespace SafeExamBrowser.Browser.Content
|
||||||
return html;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
||||||
var browserExamKey = keyGenerator.CalculateBrowserExamKeyHash(settings.ConfigurationKey, settings.BrowserExamKeySalt, frame.Url);
|
var browserExamKey = keyGenerator.CalculateBrowserExamKeyHash(settings.ConfigurationKey, settings.BrowserExamKeySalt, frame.Url);
|
||||||
var configurationKey = keyGenerator.CalculateConfigurationKeyHash(settings.ConfigurationKey, frame.Url);
|
var configurationKey = keyGenerator.CalculateConfigurationKeyHash(settings.ConfigurationKey, frame.Url);
|
||||||
var api = contentLoader.LoadApi(browserExamKey, configurationKey, appConfig.ProgramBuildVersion);
|
var api = contentLoader.LoadApi(browserExamKey, configurationKey, appConfig.ProgramBuildVersion);
|
||||||
|
var clipboard = contentLoader.LoadClipboard();
|
||||||
|
|
||||||
frame.ExecuteJavaScriptAsync(api);
|
frame.ExecuteJavaScriptAsync(api);
|
||||||
|
|
||||||
|
@ -44,6 +45,11 @@ namespace SafeExamBrowser.Browser.Handlers
|
||||||
{
|
{
|
||||||
frame.ExecuteJavaScriptAsync($"window.print = function(){{ alert('{text.Get(TextKey.Browser_PrintNotAllowed)}') }}");
|
frame.ExecuteJavaScriptAsync($"window.print = function(){{ alert('{text.Get(TextKey.Browser_PrintNotAllowed)}') }}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settings.UseIsolatedClipboard)
|
||||||
|
{
|
||||||
|
frame.ExecuteJavaScriptAsync(clipboard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnContextReleased(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame)
|
public void OnContextReleased(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame)
|
||||||
|
|
|
@ -189,6 +189,9 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Content\Api.js" />
|
<EmbeddedResource Include="Content\Api.js" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Content\Clipboard.js" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
|
|
|
@ -10,43 +10,44 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
using SafeExamBrowser.Client.Operations;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.Monitoring.Contracts;
|
||||||
|
using SafeExamBrowser.Settings;
|
||||||
|
using SafeExamBrowser.Settings.Security;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Client.UnitTests.Operations
|
namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class ClipboardOperationTests
|
public class ClipboardOperationTests
|
||||||
{
|
{
|
||||||
|
private Mock<IClipboard> clipboard;
|
||||||
private ClientContext context;
|
private ClientContext context;
|
||||||
private Mock<ILogger> loggerMock;
|
private Mock<ILogger> loggerMock;
|
||||||
private Mock<INativeMethods> nativeMethodsMock;
|
|
||||||
|
|
||||||
private ClipboardOperation sut;
|
private ClipboardOperation sut;
|
||||||
|
|
||||||
[TestInitialize]
|
[TestInitialize]
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
|
clipboard = new Mock<IClipboard>();
|
||||||
context = new ClientContext();
|
context = new ClientContext();
|
||||||
|
context.Settings = new AppSettings();
|
||||||
loggerMock = new Mock<ILogger>();
|
loggerMock = new Mock<ILogger>();
|
||||||
nativeMethodsMock = new Mock<INativeMethods>();
|
|
||||||
|
|
||||||
sut = new ClipboardOperation(context, loggerMock.Object, nativeMethodsMock.Object);
|
sut = new ClipboardOperation(context, clipboard.Object, loggerMock.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustPerformCorrectly()
|
public void MustPerformCorrectly()
|
||||||
{
|
{
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
clipboard.Verify(n => n.Initialize(It.IsAny<ClipboardPolicy>()), Times.Once);
|
||||||
nativeMethodsMock.Verify(n => n.EmptyClipboard(), Times.Once);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustRevertCorrectly()
|
public void MustRevertCorrectly()
|
||||||
{
|
{
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
|
clipboard.Verify(n => n.Terminate(), Times.Once);
|
||||||
nativeMethodsMock.Verify(n => n.EmptyClipboard(), Times.Once);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ using SafeExamBrowser.I18n;
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging;
|
using SafeExamBrowser.Logging;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.Monitoring;
|
||||||
using SafeExamBrowser.Monitoring.Applications;
|
using SafeExamBrowser.Monitoring.Applications;
|
||||||
using SafeExamBrowser.Monitoring.Display;
|
using SafeExamBrowser.Monitoring.Display;
|
||||||
using SafeExamBrowser.Monitoring.Keyboard;
|
using SafeExamBrowser.Monitoring.Keyboard;
|
||||||
|
@ -110,6 +111,7 @@ namespace SafeExamBrowser.Client
|
||||||
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
|
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
|
||||||
var applicationMonitor = new ApplicationMonitor(TWO_SECONDS, ModuleLogger(nameof(ApplicationMonitor)), nativeMethods, processFactory);
|
var applicationMonitor = new ApplicationMonitor(TWO_SECONDS, ModuleLogger(nameof(ApplicationMonitor)), nativeMethods, processFactory);
|
||||||
var applicationFactory = new ApplicationFactory(applicationMonitor, ModuleLogger(nameof(ApplicationFactory)), nativeMethods, processFactory, new Registry(ModuleLogger(nameof(Registry))));
|
var applicationFactory = new ApplicationFactory(applicationMonitor, ModuleLogger(nameof(ApplicationFactory)), nativeMethods, processFactory, new Registry(ModuleLogger(nameof(Registry))));
|
||||||
|
var clipboard = new Clipboard(ModuleLogger(nameof(Clipboard)), nativeMethods);
|
||||||
var displayMonitor = new DisplayMonitor(ModuleLogger(nameof(DisplayMonitor)), nativeMethods, systemInfo);
|
var displayMonitor = new DisplayMonitor(ModuleLogger(nameof(DisplayMonitor)), nativeMethods, systemInfo);
|
||||||
var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods);
|
var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods);
|
||||||
var fileSystemDialog = BuildFileSystemDialog();
|
var fileSystemDialog = BuildFileSystemDialog();
|
||||||
|
@ -136,7 +138,7 @@ namespace SafeExamBrowser.Client
|
||||||
operations.Enqueue(new LazyInitializationOperation(BuildBrowserOperation));
|
operations.Enqueue(new LazyInitializationOperation(BuildBrowserOperation));
|
||||||
operations.Enqueue(new LazyInitializationOperation(BuildServerOperation));
|
operations.Enqueue(new LazyInitializationOperation(BuildServerOperation));
|
||||||
operations.Enqueue(new LazyInitializationOperation(BuildProctoringOperation));
|
operations.Enqueue(new LazyInitializationOperation(BuildProctoringOperation));
|
||||||
operations.Enqueue(new ClipboardOperation(context, logger, nativeMethods));
|
operations.Enqueue(new ClipboardOperation(context, clipboard, logger));
|
||||||
|
|
||||||
var sequence = new OperationSequence(logger, operations);
|
var sequence = new OperationSequence(logger, operations);
|
||||||
|
|
||||||
|
|
|
@ -10,44 +10,50 @@ using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.Monitoring.Contracts;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Client.Operations
|
namespace SafeExamBrowser.Client.Operations
|
||||||
{
|
{
|
||||||
internal class ClipboardOperation : ClientOperation
|
internal class ClipboardOperation : ClientOperation
|
||||||
{
|
{
|
||||||
private ILogger logger;
|
private readonly IClipboard clipboard;
|
||||||
private INativeMethods nativeMethods;
|
private readonly ILogger logger;
|
||||||
|
|
||||||
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||||
public override event StatusChangedEventHandler StatusChanged;
|
public override event StatusChangedEventHandler StatusChanged;
|
||||||
|
|
||||||
public ClipboardOperation(ClientContext context, ILogger logger, INativeMethods nativeMethods) : base(context)
|
public ClipboardOperation(ClientContext context, IClipboard clipboard, ILogger logger) : base(context)
|
||||||
{
|
{
|
||||||
|
this.clipboard = clipboard;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.nativeMethods = nativeMethods;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override OperationResult Perform()
|
public override OperationResult Perform()
|
||||||
{
|
{
|
||||||
EmptyClipboard();
|
InitializeClipboard();
|
||||||
|
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override OperationResult Revert()
|
public override OperationResult Revert()
|
||||||
{
|
{
|
||||||
EmptyClipboard();
|
FinalizeClipboard();
|
||||||
|
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmptyClipboard()
|
private void InitializeClipboard()
|
||||||
{
|
{
|
||||||
logger.Info("Emptying clipboard...");
|
logger.Info("Initializing clipboard...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_EmptyClipboard);
|
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeClipboard);
|
||||||
|
clipboard.Initialize(Context.Settings.Security.ClipboardPolicy);
|
||||||
|
}
|
||||||
|
|
||||||
nativeMethods.EmptyClipboard();
|
private void FinalizeClipboard()
|
||||||
|
{
|
||||||
|
logger.Info("Finalizing clipboard...");
|
||||||
|
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeClipboard);
|
||||||
|
clipboard.Terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ using System.Security.Cryptography;
|
||||||
using SafeExamBrowser.Settings;
|
using SafeExamBrowser.Settings;
|
||||||
using SafeExamBrowser.Settings.Applications;
|
using SafeExamBrowser.Settings.Applications;
|
||||||
using SafeExamBrowser.Settings.Proctoring;
|
using SafeExamBrowser.Settings.Proctoring;
|
||||||
|
using SafeExamBrowser.Settings.Security;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Configuration.ConfigurationData
|
namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
{
|
{
|
||||||
|
@ -22,7 +23,8 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
{
|
{
|
||||||
AllowBrowserToolbarForReloading(settings);
|
AllowBrowserToolbarForReloading(settings);
|
||||||
CalculateConfigurationKey(rawData, settings);
|
CalculateConfigurationKey(rawData, settings);
|
||||||
HandleBrowserHomeFunctionality(settings);
|
InitializeBrowserHomeFunctionality(settings);
|
||||||
|
InitializeClipboardSettings(settings);
|
||||||
InitializeProctoringSettings(settings);
|
InitializeProctoringSettings(settings);
|
||||||
RemoveLegacyBrowsers(settings);
|
RemoveLegacyBrowsers(settings);
|
||||||
}
|
}
|
||||||
|
@ -58,12 +60,20 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleBrowserHomeFunctionality(AppSettings settings)
|
private void InitializeBrowserHomeFunctionality(AppSettings settings)
|
||||||
{
|
{
|
||||||
settings.Browser.MainWindow.ShowHomeButton = settings.Browser.UseStartUrlAsHomeUrl || !string.IsNullOrWhiteSpace(settings.Browser.HomeUrl);
|
settings.Browser.MainWindow.ShowHomeButton = settings.Browser.UseStartUrlAsHomeUrl || !string.IsNullOrWhiteSpace(settings.Browser.HomeUrl);
|
||||||
settings.Browser.HomePasswordHash = settings.Security.QuitPasswordHash;
|
settings.Browser.HomePasswordHash = settings.Security.QuitPasswordHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitializeClipboardSettings(AppSettings settings)
|
||||||
|
{
|
||||||
|
settings.Browser.UseIsolatedClipboard = settings.Security.ClipboardPolicy == ClipboardPolicy.Isolated;
|
||||||
|
settings.Keyboard.AllowCtrlC = settings.Security.ClipboardPolicy != ClipboardPolicy.Block;
|
||||||
|
settings.Keyboard.AllowCtrlV = settings.Security.ClipboardPolicy != ClipboardPolicy.Block;
|
||||||
|
settings.Keyboard.AllowCtrlX = settings.Security.ClipboardPolicy != ClipboardPolicy.Block;
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeProctoringSettings(AppSettings settings)
|
private void InitializeProctoringSettings(AppSettings settings)
|
||||||
{
|
{
|
||||||
settings.Proctoring.Enabled = settings.Proctoring.JitsiMeet.Enabled || settings.Proctoring.Zoom.Enabled;
|
settings.Proctoring.Enabled = settings.Proctoring.JitsiMeet.Enabled || settings.Proctoring.Zoom.Enabled;
|
||||||
|
|
|
@ -260,6 +260,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
settings.Security.AllowApplicationLogAccess = false;
|
settings.Security.AllowApplicationLogAccess = false;
|
||||||
settings.Security.AllowTermination = true;
|
settings.Security.AllowTermination = true;
|
||||||
settings.Security.AllowReconfiguration = false;
|
settings.Security.AllowReconfiguration = false;
|
||||||
|
settings.Security.ClipboardPolicy = ClipboardPolicy.Isolated;
|
||||||
settings.Security.KioskMode = KioskMode.CreateNewDesktop;
|
settings.Security.KioskMode = KioskMode.CreateNewDesktop;
|
||||||
settings.Security.VirtualMachinePolicy = VirtualMachinePolicy.Deny;
|
settings.Security.VirtualMachinePolicy = VirtualMachinePolicy.Deny;
|
||||||
|
|
||||||
|
|
|
@ -172,13 +172,14 @@ namespace SafeExamBrowser.I18n.Contracts
|
||||||
Notification_ProctoringLowerHand,
|
Notification_ProctoringLowerHand,
|
||||||
Notification_ProctoringRaiseHand,
|
Notification_ProctoringRaiseHand,
|
||||||
OperationStatus_CloseRuntimeConnection,
|
OperationStatus_CloseRuntimeConnection,
|
||||||
OperationStatus_EmptyClipboard,
|
|
||||||
OperationStatus_FinalizeApplications,
|
OperationStatus_FinalizeApplications,
|
||||||
|
OperationStatus_FinalizeClipboard,
|
||||||
OperationStatus_FinalizeServer,
|
OperationStatus_FinalizeServer,
|
||||||
OperationStatus_FinalizeServiceSession,
|
OperationStatus_FinalizeServiceSession,
|
||||||
OperationStatus_FinalizeSystemEvents,
|
OperationStatus_FinalizeSystemEvents,
|
||||||
OperationStatus_InitializeApplications,
|
OperationStatus_InitializeApplications,
|
||||||
OperationStatus_InitializeBrowser,
|
OperationStatus_InitializeBrowser,
|
||||||
|
OperationStatus_InitializeClipboard,
|
||||||
OperationStatus_InitializeConfiguration,
|
OperationStatus_InitializeConfiguration,
|
||||||
OperationStatus_InitializeKioskMode,
|
OperationStatus_InitializeKioskMode,
|
||||||
OperationStatus_InitializeProctoring,
|
OperationStatus_InitializeProctoring,
|
||||||
|
|
|
@ -474,12 +474,12 @@
|
||||||
<Entry key="OperationStatus_CloseRuntimeConnection">
|
<Entry key="OperationStatus_CloseRuntimeConnection">
|
||||||
Schliesse Verbindung zur Runtime
|
Schliesse Verbindung zur Runtime
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="OperationStatus_EmptyClipboard">
|
|
||||||
Lösche Zwischenablage
|
|
||||||
</Entry>
|
|
||||||
<Entry key="OperationStatus_FinalizeApplications">
|
<Entry key="OperationStatus_FinalizeApplications">
|
||||||
Beende Applikationen
|
Beende Applikationen
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_FinalizeClipboard">
|
||||||
|
Finalisiere Zwischenablage
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_FinalizeServer">
|
<Entry key="OperationStatus_FinalizeServer">
|
||||||
Finalisiere SEB-Server
|
Finalisiere SEB-Server
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -495,6 +495,9 @@
|
||||||
<Entry key="OperationStatus_InitializeBrowser">
|
<Entry key="OperationStatus_InitializeBrowser">
|
||||||
Initialisiere Browser
|
Initialisiere Browser
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_InitializeClipboard">
|
||||||
|
Initialisiere Zwischenablage
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_InitializeConfiguration">
|
<Entry key="OperationStatus_InitializeConfiguration">
|
||||||
Initialisiere Konfiguration
|
Initialisiere Konfiguration
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -474,12 +474,12 @@
|
||||||
<Entry key="OperationStatus_CloseRuntimeConnection">
|
<Entry key="OperationStatus_CloseRuntimeConnection">
|
||||||
Closing runtime connection
|
Closing runtime connection
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="OperationStatus_EmptyClipboard">
|
|
||||||
Emptying clipboard
|
|
||||||
</Entry>
|
|
||||||
<Entry key="OperationStatus_FinalizeApplications">
|
<Entry key="OperationStatus_FinalizeApplications">
|
||||||
Finalizing applications
|
Finalizing applications
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_FinalizeClipboard">
|
||||||
|
Finalizing clipboard
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_FinalizeServer">
|
<Entry key="OperationStatus_FinalizeServer">
|
||||||
Finalizing SEB-Server
|
Finalizing SEB-Server
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -495,6 +495,9 @@
|
||||||
<Entry key="OperationStatus_InitializeBrowser">
|
<Entry key="OperationStatus_InitializeBrowser">
|
||||||
Initializing browser
|
Initializing browser
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_InitializeClipboard">
|
||||||
|
Initializing clipboard
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_InitializeConfiguration">
|
<Entry key="OperationStatus_InitializeConfiguration">
|
||||||
Initializing configuration
|
Initializing configuration
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -474,12 +474,12 @@
|
||||||
<Entry key="OperationStatus_CloseRuntimeConnection">
|
<Entry key="OperationStatus_CloseRuntimeConnection">
|
||||||
Cierre de la conexión con runtime
|
Cierre de la conexión con runtime
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="OperationStatus_EmptyClipboard">
|
|
||||||
Vaciado del portapapeles
|
|
||||||
</Entry>
|
|
||||||
<Entry key="OperationStatus_FinalizeApplications">
|
<Entry key="OperationStatus_FinalizeApplications">
|
||||||
Finalización de las aplicaciones
|
Finalización de las aplicaciones
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_FinalizeClipboard">
|
||||||
|
Finalización del portapapeles
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_FinalizeServer">
|
<Entry key="OperationStatus_FinalizeServer">
|
||||||
Finalización del SEB-Server
|
Finalización del SEB-Server
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -495,6 +495,9 @@
|
||||||
<Entry key="OperationStatus_InitializeBrowser">
|
<Entry key="OperationStatus_InitializeBrowser">
|
||||||
Inicialización del navegador
|
Inicialización del navegador
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_InitializeClipboard">
|
||||||
|
Inicialización del portapapeles
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_InitializeConfiguration">
|
<Entry key="OperationStatus_InitializeConfiguration">
|
||||||
Inicialización de la configuración
|
Inicialización de la configuración
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -474,12 +474,12 @@
|
||||||
<Entry key="OperationStatus_CloseRuntimeConnection">
|
<Entry key="OperationStatus_CloseRuntimeConnection">
|
||||||
Fermeture de la connexion
|
Fermeture de la connexion
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="OperationStatus_EmptyClipboard">
|
|
||||||
Vidage du presse-papiers
|
|
||||||
</Entry>
|
|
||||||
<Entry key="OperationStatus_FinalizeApplications">
|
<Entry key="OperationStatus_FinalizeApplications">
|
||||||
Finalisation des applications
|
Finalisation des applications
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_FinalizeClipboard">
|
||||||
|
Finalisation du presse-papiers
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_FinalizeServer">
|
<Entry key="OperationStatus_FinalizeServer">
|
||||||
Finalisation du serveur SEB
|
Finalisation du serveur SEB
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -495,6 +495,9 @@
|
||||||
<Entry key="OperationStatus_InitializeBrowser">
|
<Entry key="OperationStatus_InitializeBrowser">
|
||||||
Initialisation du navigateur
|
Initialisation du navigateur
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_InitializeClipboard">
|
||||||
|
Initialisation du presse-papiers
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_InitializeConfiguration">
|
<Entry key="OperationStatus_InitializeConfiguration">
|
||||||
Initialisation de la configuration
|
Initialisation de la configuration
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -474,12 +474,12 @@
|
||||||
<Entry key="OperationStatus_CloseRuntimeConnection">
|
<Entry key="OperationStatus_CloseRuntimeConnection">
|
||||||
Chiusura della connessione runtime
|
Chiusura della connessione runtime
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="OperationStatus_EmptyClipboard">
|
|
||||||
Eliminazione appunti
|
|
||||||
</Entry>
|
|
||||||
<Entry key="OperationStatus_FinalizeApplications">
|
<Entry key="OperationStatus_FinalizeApplications">
|
||||||
Finalizzazione delle applicazioni
|
Finalizzazione delle applicazioni
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_FinalizeClipboard">
|
||||||
|
Finalizzazione degli appunti
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_FinalizeServer">
|
<Entry key="OperationStatus_FinalizeServer">
|
||||||
Finalizzazione server SEB
|
Finalizzazione server SEB
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -495,6 +495,9 @@
|
||||||
<Entry key="OperationStatus_InitializeBrowser">
|
<Entry key="OperationStatus_InitializeBrowser">
|
||||||
Inizializzazione del browser
|
Inizializzazione del browser
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_InitializeClipboard">
|
||||||
|
Inizializzazione degli appunti
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_InitializeConfiguration">
|
<Entry key="OperationStatus_InitializeConfiguration">
|
||||||
Inizializzazione della configurazione
|
Inizializzazione della configurazione
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -438,12 +438,12 @@
|
||||||
<Entry key="OperationStatus_CloseRuntimeConnection">
|
<Entry key="OperationStatus_CloseRuntimeConnection">
|
||||||
关闭运行时连接
|
关闭运行时连接
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="OperationStatus_EmptyClipboard">
|
|
||||||
清空剪贴板
|
|
||||||
</Entry>
|
|
||||||
<Entry key="OperationStatus_FinalizeApplications">
|
<Entry key="OperationStatus_FinalizeApplications">
|
||||||
完成应用程序(运行已定型)
|
完成应用程序(运行已定型)
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_FinalizeClipboard">
|
||||||
|
剪贴板定稿
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_FinalizeServiceSession">
|
<Entry key="OperationStatus_FinalizeServiceSession">
|
||||||
完成服务会话(运行已定型)
|
完成服务会话(运行已定型)
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -453,6 +453,9 @@
|
||||||
<Entry key="OperationStatus_InitializeBrowser">
|
<Entry key="OperationStatus_InitializeBrowser">
|
||||||
初始化浏览器
|
初始化浏览器
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_InitializeClipboard">
|
||||||
|
初始化剪贴板
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_InitializeConfiguration">
|
<Entry key="OperationStatus_InitializeConfiguration">
|
||||||
初始化配置
|
初始化配置
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
28
SafeExamBrowser.Monitoring.Contracts/IClipboard.cs
Normal file
28
SafeExamBrowser.Monitoring.Contracts/IClipboard.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using SafeExamBrowser.Settings.Security;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Monitoring.Contracts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Monitors the system clipboard and provides related functionality.
|
||||||
|
/// </summary>
|
||||||
|
public interface IClipboard
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the system clipboard according to the given policy.
|
||||||
|
/// </summary>
|
||||||
|
void Initialize(ClipboardPolicy policy);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finalizes the system clipboard.
|
||||||
|
/// </summary>
|
||||||
|
void Terminate();
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,6 +62,7 @@
|
||||||
<Compile Include="Applications\Events\ExplorerStartedEventHandler.cs" />
|
<Compile Include="Applications\Events\ExplorerStartedEventHandler.cs" />
|
||||||
<Compile Include="Display\IDisplayMonitor.cs" />
|
<Compile Include="Display\IDisplayMonitor.cs" />
|
||||||
<Compile Include="Display\ValidationResult.cs" />
|
<Compile Include="Display\ValidationResult.cs" />
|
||||||
|
<Compile Include="IClipboard.cs" />
|
||||||
<Compile Include="Keyboard\IKeyboardInterceptor.cs" />
|
<Compile Include="Keyboard\IKeyboardInterceptor.cs" />
|
||||||
<Compile Include="Mouse\IMouseInterceptor.cs" />
|
<Compile Include="Mouse\IMouseInterceptor.cs" />
|
||||||
<Compile Include="Applications\InitializationResult.cs" />
|
<Compile Include="Applications\InitializationResult.cs" />
|
||||||
|
|
77
SafeExamBrowser.Monitoring/Clipboard.cs
Normal file
77
SafeExamBrowser.Monitoring/Clipboard.cs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Timers;
|
||||||
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.Monitoring.Contracts;
|
||||||
|
using SafeExamBrowser.Settings.Security;
|
||||||
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Monitoring
|
||||||
|
{
|
||||||
|
public class Clipboard : IClipboard
|
||||||
|
{
|
||||||
|
private readonly ILogger logger;
|
||||||
|
private readonly INativeMethods nativeMethods;
|
||||||
|
private readonly Timer timer;
|
||||||
|
|
||||||
|
private ClipboardPolicy policy;
|
||||||
|
|
||||||
|
public Clipboard(ILogger logger, INativeMethods nativeMethods, int timeout_ms = 50)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
this.nativeMethods = nativeMethods;
|
||||||
|
this.timer = new Timer(timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize(ClipboardPolicy policy)
|
||||||
|
{
|
||||||
|
this.policy = policy;
|
||||||
|
|
||||||
|
nativeMethods.EmptyClipboard();
|
||||||
|
logger.Debug("Cleared clipboard.");
|
||||||
|
|
||||||
|
if (policy != ClipboardPolicy.Allow)
|
||||||
|
{
|
||||||
|
timer.Elapsed += Timer_Elapsed;
|
||||||
|
timer.Start();
|
||||||
|
|
||||||
|
logger.Debug($"Started clipboard monitoring with interval {timer.Interval} ms.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Debug("Clipboard is allowed, not starting monitoring.");
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info($"Initialized clipboard for policy '{policy}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Terminate()
|
||||||
|
{
|
||||||
|
nativeMethods.EmptyClipboard();
|
||||||
|
logger.Debug("Cleared clipboard.");
|
||||||
|
|
||||||
|
if (policy != ClipboardPolicy.Allow)
|
||||||
|
{
|
||||||
|
timer.Stop();
|
||||||
|
logger.Debug("Stopped clipboard monitoring.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Debug("Clipboard monitoring was not active.");
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info($"Finalized clipboard.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
nativeMethods.EmptyClipboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,9 +20,9 @@ namespace SafeExamBrowser.Monitoring.Keyboard
|
||||||
public class KeyboardInterceptor : IKeyboardInterceptor
|
public class KeyboardInterceptor : IKeyboardInterceptor
|
||||||
{
|
{
|
||||||
private Guid? hookId;
|
private Guid? hookId;
|
||||||
private ILogger logger;
|
private readonly ILogger logger;
|
||||||
private INativeMethods nativeMethods;
|
private readonly INativeMethods nativeMethods;
|
||||||
private KeyboardSettings settings;
|
private readonly KeyboardSettings settings;
|
||||||
|
|
||||||
public KeyboardInterceptor(ILogger logger, INativeMethods nativeMethods, KeyboardSettings settings)
|
public KeyboardInterceptor(ILogger logger, INativeMethods nativeMethods, KeyboardSettings settings)
|
||||||
{
|
{
|
||||||
|
@ -66,11 +66,16 @@ namespace SafeExamBrowser.Monitoring.Keyboard
|
||||||
block |= key == Key.LWin && !settings.AllowSystemKey;
|
block |= key == Key.LWin && !settings.AllowSystemKey;
|
||||||
block |= key == Key.PrintScreen && !settings.AllowPrintScreen;
|
block |= key == Key.PrintScreen && !settings.AllowPrintScreen;
|
||||||
block |= key == Key.RWin && !settings.AllowSystemKey;
|
block |= key == Key.RWin && !settings.AllowSystemKey;
|
||||||
|
|
||||||
block |= modifier.HasFlag(KeyModifier.Alt) && key == Key.Escape && !settings.AllowAltEsc;
|
block |= modifier.HasFlag(KeyModifier.Alt) && key == Key.Escape && !settings.AllowAltEsc;
|
||||||
block |= modifier.HasFlag(KeyModifier.Alt) && key == Key.F4 && !settings.AllowAltF4;
|
block |= modifier.HasFlag(KeyModifier.Alt) && key == Key.F4 && !settings.AllowAltF4;
|
||||||
block |= modifier.HasFlag(KeyModifier.Alt) && key == Key.Space;
|
block |= modifier.HasFlag(KeyModifier.Alt) && key == Key.Space;
|
||||||
block |= modifier.HasFlag(KeyModifier.Alt) && key == Key.Tab;
|
block |= modifier.HasFlag(KeyModifier.Alt) && key == Key.Tab;
|
||||||
|
|
||||||
|
block |= modifier.HasFlag(KeyModifier.Ctrl) && key == Key.C && !settings.AllowCtrlC;
|
||||||
block |= modifier.HasFlag(KeyModifier.Ctrl) && key == Key.Escape && !settings.AllowCtrlEsc;
|
block |= modifier.HasFlag(KeyModifier.Ctrl) && key == Key.Escape && !settings.AllowCtrlEsc;
|
||||||
|
block |= modifier.HasFlag(KeyModifier.Ctrl) && key == Key.V && !settings.AllowCtrlV;
|
||||||
|
block |= modifier.HasFlag(KeyModifier.Ctrl) && key == Key.X && !settings.AllowCtrlX;
|
||||||
|
|
||||||
if (block)
|
if (block)
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Applications\Window.cs" />
|
<Compile Include="Applications\Window.cs" />
|
||||||
|
<Compile Include="Clipboard.cs" />
|
||||||
<Compile Include="Display\Bounds.cs" />
|
<Compile Include="Display\Bounds.cs" />
|
||||||
<Compile Include="Display\Display.cs" />
|
<Compile Include="Display\Display.cs" />
|
||||||
<Compile Include="Display\DisplayMonitor.cs" />
|
<Compile Include="Display\DisplayMonitor.cs" />
|
||||||
|
|
|
@ -203,6 +203,11 @@ namespace SafeExamBrowser.Settings.Browser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseCustomUserAgent { get; set; }
|
public bool UseCustomUserAgent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the browser application will use an isolated clipboard only working within the browser itself.
|
||||||
|
/// </summary>
|
||||||
|
public bool UseIsolatedClipboard { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the <see cref="StartUrlQuery"/> will be appended to the <see cref="StartUrl"/>.
|
/// Determines whether the <see cref="StartUrlQuery"/> will be appended to the <see cref="StartUrl"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -31,11 +31,26 @@ namespace SafeExamBrowser.Settings.Monitoring
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowAltTab { get; set; }
|
public bool AllowAltTab { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the user may use the CTRL+C shortcut.
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowCtrlC { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user may use the CTRL+ESC shortcut.
|
/// Determines whether the user may use the CTRL+ESC shortcut.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowCtrlEsc { get; set; }
|
public bool AllowCtrlEsc { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the user may use the CTRL+V shortcut.
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowCtrlV { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the user may use the CTRL+X shortcut.
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowCtrlX { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user may use the escape key.
|
/// Determines whether the user may use the escape key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
<Compile Include="Proctoring\ProctoringSettings.cs" />
|
<Compile Include="Proctoring\ProctoringSettings.cs" />
|
||||||
<Compile Include="Proctoring\WindowVisibility.cs" />
|
<Compile Include="Proctoring\WindowVisibility.cs" />
|
||||||
<Compile Include="Proctoring\ZoomSettings.cs" />
|
<Compile Include="Proctoring\ZoomSettings.cs" />
|
||||||
|
<Compile Include="Security\ClipboardPolicy.cs" />
|
||||||
<Compile Include="Security\VersionRestriction.cs" />
|
<Compile Include="Security\VersionRestriction.cs" />
|
||||||
<Compile Include="SessionMode.cs" />
|
<Compile Include="SessionMode.cs" />
|
||||||
<Compile Include="Security\KioskMode.cs" />
|
<Compile Include="Security\KioskMode.cs" />
|
||||||
|
|
31
SafeExamBrowser.Settings/Security/ClipboardPolicy.cs
Normal file
31
SafeExamBrowser.Settings/Security/ClipboardPolicy.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Settings.Security
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines all policies with respect to the usage of the clipboard.
|
||||||
|
/// </summary>
|
||||||
|
public enum ClipboardPolicy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Allows the usage of the system clipboard without restrictions.
|
||||||
|
/// </summary>
|
||||||
|
Allow,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Completely blocks the usage of the system clipboard by continuously clearing its content and blocking all related keyboard shortcuts.
|
||||||
|
/// </summary>
|
||||||
|
Block,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Continuously clears the content of the system clipboard and enables an isolated clipboard only working within the browser application.
|
||||||
|
/// </summary>
|
||||||
|
Isolated
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,11 @@ namespace SafeExamBrowser.Settings.Security
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowReconfiguration { get; set; }
|
public bool AllowReconfiguration { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the user is allowed to use the system clipboard, a custom clipboard or no clipboard at all.
|
||||||
|
/// </summary>
|
||||||
|
public ClipboardPolicy ClipboardPolicy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The kiosk mode which determines how the computer is locked down.
|
/// The kiosk mode which determines how the computer is locked down.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in a new issue