SEBWIN-312: Started implementing application factory and initialization of whitelisted applications.
This commit is contained in:
parent
2b976e8150
commit
7e76b029a6
26 changed files with 517 additions and 29 deletions
31
SafeExamBrowser.Applications.Contracts/FactoryResult.cs
Normal file
31
SafeExamBrowser.Applications.Contracts/FactoryResult.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Applications.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines all possible results of an attempt to create an application.
|
||||
/// </summary>
|
||||
public enum FactoryResult
|
||||
{
|
||||
/// <summary>
|
||||
/// An error occurred while trying to create the application.
|
||||
/// </summary>
|
||||
Error,
|
||||
|
||||
/// <summary>
|
||||
/// The application could not be found on the system.
|
||||
/// </summary>
|
||||
NotFound,
|
||||
|
||||
/// <summary>
|
||||
/// The application has been created successfully.
|
||||
/// </summary>
|
||||
Success
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ using SafeExamBrowser.Applications.Contracts.Events;
|
|||
namespace SafeExamBrowser.Applications.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Controls the lifetime and functionality of a (third-party) application.
|
||||
/// Controls the lifetime and functionality of an application.
|
||||
/// </summary>
|
||||
public interface IApplication
|
||||
{
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Settings.Applications;
|
||||
|
||||
namespace SafeExamBrowser.Applications.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides functionality to create external applications.
|
||||
/// </summary>
|
||||
public interface IApplicationFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to create an application according to the given settings.
|
||||
/// </summary>
|
||||
FactoryResult TryCreate(WhitelistApplication settings, out IApplication application);
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ using SafeExamBrowser.Core.Contracts;
|
|||
namespace SafeExamBrowser.Applications.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// The information about a (third-party) application which can be accessed via the shell.
|
||||
/// The information about an application which can be accessed via the shell.
|
||||
/// </summary>
|
||||
public interface IApplicationInfo
|
||||
{
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Applications.Contracts.Events;
|
||||
using SafeExamBrowser.Core.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Applications.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an instance of a (third-party) application which can be accessed via the shell.
|
||||
/// Defines an instance of an application which can be accessed via the shell.
|
||||
/// </summary>
|
||||
public interface IApplicationInstance
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
namespace SafeExamBrowser.Applications.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an identifier which uniquely identifies an instance in the context of a (third-party) application.
|
||||
/// Defines an identifier which uniquely identifies an instance in the context of an application.
|
||||
/// </summary>
|
||||
public abstract class InstanceIdentifier
|
||||
{
|
||||
|
|
|
@ -57,7 +57,9 @@
|
|||
<Compile Include="Events\InstanceStartedEventHandler.cs" />
|
||||
<Compile Include="Events\InstanceTerminatedEventHandler.cs" />
|
||||
<Compile Include="Events\NameChangedEventHandler.cs" />
|
||||
<Compile Include="FactoryResult.cs" />
|
||||
<Compile Include="IApplication.cs" />
|
||||
<Compile Include="IApplicationFactory.cs" />
|
||||
<Compile Include="IApplicationInfo.cs" />
|
||||
<Compile Include="IApplicationInstance.cs" />
|
||||
<Compile Include="InstanceIdentifier.cs" />
|
||||
|
@ -68,6 +70,10 @@
|
|||
<Project>{fe0e1224-b447-4b14-81e7-ed7d84822aa0}</Project>
|
||||
<Name>SafeExamBrowser.Core.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj">
|
||||
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
|
||||
<Name>SafeExamBrowser.Settings</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
128
SafeExamBrowser.Applications/ApplicationFactory.cs
Normal file
128
SafeExamBrowser.Applications/ApplicationFactory.cs
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Win32;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings.Applications;
|
||||
|
||||
namespace SafeExamBrowser.Applications
|
||||
{
|
||||
public class ApplicationFactory : IApplicationFactory
|
||||
{
|
||||
private ILogger logger;
|
||||
|
||||
public ApplicationFactory(ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public FactoryResult TryCreate(WhitelistApplication settings, out IApplication application)
|
||||
{
|
||||
application = default(IApplication);
|
||||
|
||||
try
|
||||
{
|
||||
var success = TryFindMainExecutable(settings, out var mainExecutable);
|
||||
|
||||
if (success)
|
||||
{
|
||||
application = new ExternalApplication();
|
||||
logger.Debug($"Successfully initialized application '{settings.DisplayName}' ({settings.ExecutableName}).");
|
||||
|
||||
return FactoryResult.Success;
|
||||
}
|
||||
|
||||
logger.Error($"Could not find application '{settings.DisplayName}' ({settings.ExecutableName})!");
|
||||
|
||||
return FactoryResult.NotFound;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Unexpected error while trying to create application '{settings.DisplayName}' ({settings.ExecutableName})!", e);
|
||||
}
|
||||
|
||||
return FactoryResult.Error;
|
||||
}
|
||||
|
||||
private bool TryFindMainExecutable(WhitelistApplication settings, out string mainExecutable)
|
||||
{
|
||||
var paths = new List<string[]>();
|
||||
var registryPath = QueryPathFromRegistry(settings);
|
||||
|
||||
mainExecutable = default(string);
|
||||
|
||||
paths.Add(new[] { "%ProgramW6432%", 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(string))
|
||||
{
|
||||
paths.Add(new[] { settings.ExecutablePath, settings.ExecutableName });
|
||||
paths.Add(new[] { "%ProgramW6432%", settings.ExecutablePath, settings.ExecutableName });
|
||||
paths.Add(new[] { Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), settings.ExecutablePath, settings.ExecutableName });
|
||||
paths.Add(new[] { Environment.GetFolderPath(Environment.SpecialFolder.System), settings.ExecutablePath, settings.ExecutableName });
|
||||
paths.Add(new[] { Environment.GetFolderPath(Environment.SpecialFolder.SystemX86), settings.ExecutablePath, settings.ExecutableName });
|
||||
}
|
||||
|
||||
if (registryPath != default(string))
|
||||
{
|
||||
paths.Add(new[] { registryPath, settings.ExecutableName });
|
||||
|
||||
if (settings.ExecutablePath != default(string))
|
||||
{
|
||||
paths.Add(new[] { registryPath, settings.ExecutablePath, settings.ExecutableName });
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var path in paths)
|
||||
{
|
||||
try
|
||||
{
|
||||
mainExecutable = Path.Combine(path);
|
||||
mainExecutable = Environment.ExpandEnvironmentVariables(mainExecutable);
|
||||
|
||||
if (File.Exists(mainExecutable))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to test path {string.Join(@"\", path)}!", e);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string QueryPathFromRegistry(WhitelistApplication settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
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(string);
|
||||
}
|
||||
}
|
||||
}
|
36
SafeExamBrowser.Applications/ExternalApplication.cs
Normal file
36
SafeExamBrowser.Applications/ExternalApplication.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Applications.Contracts.Events;
|
||||
|
||||
namespace SafeExamBrowser.Applications
|
||||
{
|
||||
internal class ExternalApplication : IApplication
|
||||
{
|
||||
public IApplicationInfo Info => throw new NotImplementedException();
|
||||
|
||||
public event InstanceStartedEventHandler InstanceStarted;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
33
SafeExamBrowser.Applications/Properties/AssemblyInfo.cs
Normal file
33
SafeExamBrowser.Applications/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SafeExamBrowser.Applications")]
|
||||
[assembly: AssemblyDescription("Safe Exam Browser")]
|
||||
[assembly: AssemblyCompany("ETH Zürich")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.Applications")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019 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)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("a113e68f-1209-4689-981a-15c554b2df4e")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("1.0.0.0")]
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<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>{A113E68F-1209-4689-981A-15C554B2DF4E}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SafeExamBrowser.Applications</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.Applications</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ApplicationFactory.cs" />
|
||||
<Compile Include="ExternalApplication.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</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.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj">
|
||||
<Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
|
||||
<Name>SafeExamBrowser.Logging.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj">
|
||||
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
|
||||
<Name>SafeExamBrowser.Settings</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Browser.Contracts;
|
||||
using SafeExamBrowser.Communication.Contracts.Hosts;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
|
@ -26,6 +27,11 @@ namespace SafeExamBrowser.Client
|
|||
/// </summary>
|
||||
internal IList<IActionCenterActivator> Activators { get; }
|
||||
|
||||
/// <summary>
|
||||
/// All applications allowed for the current session.
|
||||
/// </summary>
|
||||
internal IList<IApplication> Applications { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The global application configuration.
|
||||
/// </summary>
|
||||
|
@ -54,6 +60,7 @@ namespace SafeExamBrowser.Client
|
|||
internal ClientContext()
|
||||
{
|
||||
Activators = new List<IActionCenterActivator>();
|
||||
Applications = new List<IApplication>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Browser.Contracts;
|
||||
using SafeExamBrowser.Browser.Contracts.Events;
|
||||
using SafeExamBrowser.Client.Contracts;
|
||||
|
@ -409,6 +410,12 @@ namespace SafeExamBrowser.Client
|
|||
{
|
||||
switch (args)
|
||||
{
|
||||
case ApplicationNotFoundEventArgs a:
|
||||
AskForApplicationPath(a);
|
||||
break;
|
||||
case ApplicationInitializationFailedEventArgs a:
|
||||
InformAboutFailedApplicationInitialization(a);
|
||||
break;
|
||||
case ApplicationTerminationEventArgs a:
|
||||
AskForAutomaticApplicationTermination(a);
|
||||
break;
|
||||
|
@ -485,6 +492,30 @@ namespace SafeExamBrowser.Client
|
|||
args.TerminateProcesses = result == MessageBoxResult.Yes;
|
||||
}
|
||||
|
||||
private void AskForApplicationPath(ApplicationNotFoundEventArgs args)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
private void InformAboutFailedApplicationInitialization(ApplicationInitializationFailedEventArgs args)
|
||||
{
|
||||
var messageKey = TextKey.MessageBox_ApplicationInitializationFailure;
|
||||
var titleKey = TextKey.MessageBox_ApplicationInitializationFailureTitle;
|
||||
|
||||
switch (args.Result)
|
||||
{
|
||||
case FactoryResult.NotFound:
|
||||
messageKey = TextKey.MessageBox_ApplicationNotFound;
|
||||
titleKey = TextKey.MessageBox_ApplicationNotFoundTitle;
|
||||
break;
|
||||
}
|
||||
|
||||
var message = text.Get(messageKey).Replace("%%NAME%%", $"'{args.DisplayName}' ({args.ExecutableName})");
|
||||
var title = text.Get(titleKey);
|
||||
|
||||
messageBox.Show(message, title, icon: MessageBoxIcon.Error, parent: splashScreen);
|
||||
}
|
||||
|
||||
private void InformAboutFailedApplicationTermination(ApplicationTerminationFailedEventArgs args)
|
||||
{
|
||||
var applicationList = string.Join(Environment.NewLine, args.Applications.Select(a => a.Name));
|
||||
|
|
|
@ -11,6 +11,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using SafeExamBrowser.Applications;
|
||||
using SafeExamBrowser.Browser;
|
||||
using SafeExamBrowser.Client.Communication;
|
||||
using SafeExamBrowser.Client.Contracts;
|
||||
|
@ -95,6 +96,7 @@ namespace SafeExamBrowser.Client
|
|||
taskbar = BuildTaskbar();
|
||||
terminationActivator = new TerminationActivator(ModuleLogger(nameof(TerminationActivator)));
|
||||
|
||||
var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory)));
|
||||
var applicationMonitor = new ApplicationMonitor(TWO_SECONDS, ModuleLogger(nameof(ApplicationMonitor)), nativeMethods, new ProcessFactory(ModuleLogger(nameof(ProcessFactory))));
|
||||
var displayMonitor = new DisplayMonitor(ModuleLogger(nameof(DisplayMonitor)), nativeMethods, systemInfo);
|
||||
var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods);
|
||||
|
@ -110,7 +112,7 @@ namespace SafeExamBrowser.Client
|
|||
operations.Enqueue(new ClientHostDisconnectionOperation(context, logger, FIVE_SECONDS));
|
||||
operations.Enqueue(new LazyInitializationOperation(BuildKeyboardInterceptorOperation));
|
||||
operations.Enqueue(new LazyInitializationOperation(BuildMouseInterceptorOperation));
|
||||
operations.Enqueue(new ApplicationOperation(applicationMonitor, context, logger));
|
||||
operations.Enqueue(new ApplicationOperation(context, applicationFactory, applicationMonitor, logger, text));
|
||||
operations.Enqueue(new DisplayMonitorOperation(context, displayMonitor, logger, taskbar));
|
||||
operations.Enqueue(new LazyInitializationOperation(BuildShellOperation));
|
||||
operations.Enqueue(new LazyInitializationOperation(BuildBrowserOperation));
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Client.Operations.Events;
|
||||
using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||
|
@ -21,16 +22,25 @@ namespace SafeExamBrowser.Client.Operations
|
|||
{
|
||||
internal class ApplicationOperation : ClientOperation
|
||||
{
|
||||
private IApplicationFactory factory;
|
||||
private ILogger logger;
|
||||
private IApplicationMonitor applicationMonitor;
|
||||
private IApplicationMonitor monitor;
|
||||
private IText text;
|
||||
|
||||
public override event ActionRequiredEventHandler ActionRequired;
|
||||
public override event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ApplicationOperation(IApplicationMonitor applicationMonitor, ClientContext context, ILogger logger) : base(context)
|
||||
public ApplicationOperation(
|
||||
ClientContext context,
|
||||
IApplicationFactory factory,
|
||||
IApplicationMonitor monitor,
|
||||
ILogger logger,
|
||||
IText text) : base(context)
|
||||
{
|
||||
this.applicationMonitor = applicationMonitor;
|
||||
this.factory = factory;
|
||||
this.monitor = monitor;
|
||||
this.logger = logger;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public override OperationResult Perform()
|
||||
|
@ -61,7 +71,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
|
||||
private OperationResult InitializeApplications()
|
||||
{
|
||||
var initialization = applicationMonitor.Initialize(Context.Settings.Applications);
|
||||
var initialization = monitor.Initialize(Context.Settings.Applications);
|
||||
var result = OperationResult.Success;
|
||||
|
||||
if (initialization.FailedAutoTerminations.Any())
|
||||
|
@ -75,24 +85,46 @@ namespace SafeExamBrowser.Client.Operations
|
|||
|
||||
if (result == OperationResult.Success)
|
||||
{
|
||||
CreateApplications();
|
||||
foreach (var application in Context.Settings.Applications.Whitelist)
|
||||
{
|
||||
Initialize(application);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void CreateApplications()
|
||||
private void Initialize(WhitelistApplication settings)
|
||||
{
|
||||
foreach (var application in Context.Settings.Applications.Whitelist)
|
||||
{
|
||||
Create(application);
|
||||
}
|
||||
}
|
||||
var result = factory.TryCreate(settings, out var application);
|
||||
|
||||
private void Create(WhitelistApplication application)
|
||||
{
|
||||
// TODO: Use IApplicationFactory to create new application according to configuration, load into Context.Applications
|
||||
// StatusChanged?.Invoke();
|
||||
while (result == FactoryResult.NotFound && settings.AllowCustomPath)
|
||||
{
|
||||
var args = new ApplicationNotFoundEventArgs(settings.DisplayName, settings.ExecutableName);
|
||||
|
||||
ActionRequired?.Invoke(args);
|
||||
|
||||
if (args.Success)
|
||||
{
|
||||
settings.ExecutablePath = args.CustomPath;
|
||||
result = factory.TryCreate(settings, out application);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == FactoryResult.Success)
|
||||
{
|
||||
application.Initialize();
|
||||
Context.Applications.Add(application);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"Failed to initialize application '{settings.DisplayName}' ({settings.ExecutableName}). Reason: {result}.");
|
||||
ActionRequired?.Invoke(new ApplicationInitializationFailedEventArgs(settings.DisplayName, settings.ExecutableName, result));
|
||||
}
|
||||
}
|
||||
|
||||
private void FinalizeApplications()
|
||||
|
@ -112,7 +144,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
{
|
||||
if (Context.Settings.KioskMode != KioskMode.None)
|
||||
{
|
||||
applicationMonitor.Start();
|
||||
monitor.Start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,7 +152,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
{
|
||||
if (Context.Settings.KioskMode != KioskMode.None)
|
||||
{
|
||||
applicationMonitor.Stop();
|
||||
monitor.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +171,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
|
||||
foreach (var application in runningApplications)
|
||||
{
|
||||
var success = applicationMonitor.TryTerminate(application);
|
||||
var success = monitor.TryTerminate(application);
|
||||
|
||||
if (success)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations.Events
|
||||
{
|
||||
internal class ApplicationInitializationFailedEventArgs : ActionRequiredEventArgs
|
||||
{
|
||||
internal string DisplayName { get; }
|
||||
internal string ExecutableName { get; }
|
||||
internal FactoryResult Result { get; }
|
||||
|
||||
internal ApplicationInitializationFailedEventArgs(string displayName, string executableName, FactoryResult result)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
ExecutableName = executableName;
|
||||
Result = result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations.Events
|
||||
{
|
||||
internal class ApplicationNotFoundEventArgs : ActionRequiredEventArgs
|
||||
{
|
||||
internal string CustomPath { get; set; }
|
||||
internal string DisplayName { get; }
|
||||
internal string ExecutableName { get; }
|
||||
internal bool Success { get; set; }
|
||||
|
||||
internal ApplicationNotFoundEventArgs(string displayName, string executableName)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
ExecutableName = executableName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -76,6 +76,8 @@
|
|||
<Compile Include="Operations\ClientHostDisconnectionOperation.cs" />
|
||||
<Compile Include="Operations\ClientOperation.cs" />
|
||||
<Compile Include="Operations\ConfigurationOperation.cs" />
|
||||
<Compile Include="Operations\Events\ApplicationNotFoundEventArgs.cs" />
|
||||
<Compile Include="Operations\Events\ApplicationInitializationFailedEventArgs.cs" />
|
||||
<Compile Include="Operations\Events\ApplicationTerminationEventArgs.cs" />
|
||||
<Compile Include="Operations\Events\ApplicationTerminationFailedEventArgs.cs" />
|
||||
<Compile Include="Operations\RuntimeConnectionOperation.cs" />
|
||||
|
@ -127,6 +129,10 @@
|
|||
<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.Browser.Contracts\SafeExamBrowser.Browser.Contracts.csproj">
|
||||
<Project>{5fb5273d-277c-41dd-8593-a25ce1aff2e9}</Project>
|
||||
<Name>SafeExamBrowser.Browser.Contracts</Name>
|
||||
|
|
|
@ -32,6 +32,10 @@ namespace SafeExamBrowser.I18n.Contracts
|
|||
MessageBox_ApplicationAutoTerminationQuestionTitle,
|
||||
MessageBox_ApplicationError,
|
||||
MessageBox_ApplicationErrorTitle,
|
||||
MessageBox_ApplicationInitializationFailure,
|
||||
MessageBox_ApplicationInitializationFailureTitle,
|
||||
MessageBox_ApplicationNotFound,
|
||||
MessageBox_ApplicationNotFoundTitle,
|
||||
MessageBox_ApplicationTerminationFailure,
|
||||
MessageBox_ApplicationTerminationFailureTitle,
|
||||
MessageBox_BrowserNavigationBlocked,
|
||||
|
|
|
@ -54,6 +54,18 @@
|
|||
<Entry key="MessageBox_ApplicationErrorTitle">
|
||||
Application Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ApplicationInitializationFailure">
|
||||
Application %%NAME%% could not be initialized and will thus not be available for the new session! Please consult the log files for more information.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ApplicationInitializationFailureTitle">
|
||||
Application Initialization Failed
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ApplicationNotFound">
|
||||
Application %%NAME%% could not be found on the system and will thus not be available for the new session! Please consult the log files for more information.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ApplicationNotFoundTitle">
|
||||
Application Not Found
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ApplicationTerminationFailure">
|
||||
The applications listed below could not be terminated! Please terminate them manually and try again...
|
||||
</Entry>
|
||||
|
|
|
@ -11,7 +11,7 @@ using System;
|
|||
namespace SafeExamBrowser.Lockdown.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows to control a feature of the computer, the operating system or an installed third-party software.
|
||||
/// Allows to control a feature of the computer, the operating system or an installed software.
|
||||
/// </summary>
|
||||
public interface IFeatureConfiguration
|
||||
{
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace SafeExamBrowser.Settings
|
|||
public bool AllowApplicationLogAccess { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All settings related to third-party applications.
|
||||
/// All settings related to external applications.
|
||||
/// </summary>
|
||||
public ApplicationSettings Applications { get; set; }
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ using System.Collections.Generic;
|
|||
namespace SafeExamBrowser.Settings.Applications
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines all settings for third-party applications and application monitoring.
|
||||
/// Defines all settings for external applications and application monitoring.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ApplicationSettings
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
namespace SafeExamBrowser.UserInterface.Contracts.Shell
|
||||
{
|
||||
/// <summary>
|
||||
/// The control for a (third-party) application which can be loaded into the shell.
|
||||
/// The control for an application which can be loaded into the shell.
|
||||
/// </summary>
|
||||
public interface IApplicationControl
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Collections.Generic;
|
|||
namespace SafeExamBrowser.WindowsApi.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// The factory for processes, to be used whenever a new process needs to be created (for internal components and third-party applications).
|
||||
/// The factory for processes, to be used whenever a new process needs to be created (for internal components and external applications).
|
||||
/// </summary>
|
||||
public interface IProcessFactory
|
||||
{
|
||||
|
|
|
@ -106,6 +106,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Settings",
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Browser.UnitTests", "SafeExamBrowser.Browser.UnitTests\SafeExamBrowser.Browser.UnitTests.csproj", "{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Applications", "SafeExamBrowser.Applications\SafeExamBrowser.Applications.csproj", "{A113E68F-1209-4689-981A-15C554B2DF4E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -476,6 +478,14 @@ Global
|
|||
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Release|x86.ActiveCfg = Release|x86
|
||||
{F54C4C0E-4C72-4F88-A389-7F6DE3CCB745}.Release|x86.Build.0 = Release|x86
|
||||
{A113E68F-1209-4689-981A-15C554B2DF4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A113E68F-1209-4689-981A-15C554B2DF4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A113E68F-1209-4689-981A-15C554B2DF4E}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{A113E68F-1209-4689-981A-15C554B2DF4E}.Debug|x86.Build.0 = Debug|x86
|
||||
{A113E68F-1209-4689-981A-15C554B2DF4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A113E68F-1209-4689-981A-15C554B2DF4E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A113E68F-1209-4689-981A-15C554B2DF4E}.Release|x86.ActiveCfg = Release|x86
|
||||
{A113E68F-1209-4689-981A-15C554B2DF4E}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
Loading…
Reference in a new issue