2019-05-29 10:52:46 +02:00
|
|
|
|
/*
|
2024-03-05 18:37:42 +01:00
|
|
|
|
* Copyright (c) 2024 ETH Zürich, IT Services
|
2019-05-29 10:52:46 +02:00
|
|
|
|
*
|
|
|
|
|
* 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/.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-06-06 15:44:03 +02:00
|
|
|
|
using System;
|
2019-06-07 15:26:03 +02:00
|
|
|
|
using System.Collections.Generic;
|
2019-06-06 15:44:03 +02:00
|
|
|
|
using System.IO;
|
2019-06-19 15:40:21 +02:00
|
|
|
|
using System.Security.AccessControl;
|
|
|
|
|
using System.Security.Principal;
|
|
|
|
|
using System.Threading;
|
2019-06-07 15:26:03 +02:00
|
|
|
|
using SafeExamBrowser.Communication.Hosts;
|
2019-06-18 10:18:56 +02:00
|
|
|
|
using SafeExamBrowser.Communication.Proxies;
|
2019-08-30 09:55:26 +02:00
|
|
|
|
using SafeExamBrowser.Configuration.Contracts;
|
|
|
|
|
using SafeExamBrowser.Core.Contracts.OperationModel;
|
2019-06-07 15:26:03 +02:00
|
|
|
|
using SafeExamBrowser.Core.OperationModel;
|
|
|
|
|
using SafeExamBrowser.Core.Operations;
|
2019-06-21 15:05:31 +02:00
|
|
|
|
using SafeExamBrowser.Lockdown;
|
2019-06-06 15:44:03 +02:00
|
|
|
|
using SafeExamBrowser.Logging;
|
2019-09-06 09:39:28 +02:00
|
|
|
|
using SafeExamBrowser.Logging.Contracts;
|
2019-06-07 15:26:03 +02:00
|
|
|
|
using SafeExamBrowser.Service.Communication;
|
2019-06-18 10:18:56 +02:00
|
|
|
|
using SafeExamBrowser.Service.Operations;
|
2019-09-06 09:39:28 +02:00
|
|
|
|
using SafeExamBrowser.Settings.Logging;
|
2019-06-06 15:44:03 +02:00
|
|
|
|
|
2019-05-29 10:52:46 +02:00
|
|
|
|
namespace SafeExamBrowser.Service
|
|
|
|
|
{
|
|
|
|
|
internal class CompositionRoot
|
|
|
|
|
{
|
2019-06-06 15:44:03 +02:00
|
|
|
|
private ILogger logger;
|
|
|
|
|
|
2020-03-16 13:38:25 +01:00
|
|
|
|
internal ServiceController ServiceController { get; private set; }
|
2019-06-06 15:44:03 +02:00
|
|
|
|
|
2019-05-29 10:52:46 +02:00
|
|
|
|
internal void BuildObjectGraph()
|
|
|
|
|
{
|
2019-07-05 12:28:42 +02:00
|
|
|
|
const int ONE_SECOND = 1000;
|
2019-06-07 15:26:03 +02:00
|
|
|
|
const int FIVE_SECONDS = 5000;
|
2020-09-29 14:14:26 +02:00
|
|
|
|
const int FIFTEEN_SECONDS = 15000;
|
2019-06-27 08:32:37 +02:00
|
|
|
|
|
|
|
|
|
var backupFilePath = BuildBackupFilePath();
|
2019-06-06 15:44:03 +02:00
|
|
|
|
|
|
|
|
|
InitializeLogging();
|
|
|
|
|
|
2019-06-27 08:32:37 +02:00
|
|
|
|
var featureBackup = new FeatureConfigurationBackup(backupFilePath, new ModuleLogger(logger, nameof(FeatureConfigurationBackup)));
|
2019-06-21 15:05:31 +02:00
|
|
|
|
var featureFactory = new FeatureConfigurationFactory(new ModuleLogger(logger, nameof(FeatureConfigurationFactory)));
|
2019-07-05 12:28:42 +02:00
|
|
|
|
var featureMonitor = new FeatureConfigurationMonitor(new ModuleLogger(logger, nameof(FeatureConfigurationMonitor)), ONE_SECOND);
|
2019-06-18 10:18:56 +02:00
|
|
|
|
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), new ModuleLogger(logger, nameof(ProxyFactory)));
|
2020-09-29 14:14:26 +02:00
|
|
|
|
var serviceHost = new ServiceHost(AppConfig.SERVICE_ADDRESS, new HostObjectFactory(), new ModuleLogger(logger, nameof(ServiceHost)), FIFTEEN_SECONDS);
|
2019-06-07 15:26:03 +02:00
|
|
|
|
var sessionContext = new SessionContext();
|
2019-07-03 12:27:02 +02:00
|
|
|
|
var systemConfigurationUpdate = new SystemConfigurationUpdate(new ModuleLogger(logger, nameof(SystemConfigurationUpdate)));
|
2019-06-07 15:26:03 +02:00
|
|
|
|
|
|
|
|
|
var bootstrapOperations = new Queue<IOperation>();
|
2019-06-18 10:18:56 +02:00
|
|
|
|
var sessionOperations = new Queue<IOperation>();
|
2019-06-07 15:26:03 +02:00
|
|
|
|
|
2019-07-03 12:27:02 +02:00
|
|
|
|
sessionContext.AutoRestoreMechanism = new AutoRestoreMechanism(featureBackup, new ModuleLogger(logger, nameof(AutoRestoreMechanism)), systemConfigurationUpdate, FIVE_SECONDS);
|
2019-06-26 10:13:11 +02:00
|
|
|
|
|
|
|
|
|
bootstrapOperations.Enqueue(new RestoreOperation(featureBackup, logger, sessionContext));
|
2019-06-07 15:26:03 +02:00
|
|
|
|
bootstrapOperations.Enqueue(new CommunicationHostOperation(serviceHost, logger));
|
2019-06-18 10:18:56 +02:00
|
|
|
|
bootstrapOperations.Enqueue(new ServiceEventCleanupOperation(logger, sessionContext));
|
2019-06-07 15:26:03 +02:00
|
|
|
|
|
2019-07-04 09:12:28 +02:00
|
|
|
|
sessionOperations.Enqueue(new SessionInitializationOperation(logger, ServiceEventFactory, sessionContext));
|
2019-07-05 12:28:42 +02:00
|
|
|
|
sessionOperations.Enqueue(new LockdownOperation(featureBackup, featureFactory, featureMonitor, logger, sessionContext));
|
2019-06-18 10:18:56 +02:00
|
|
|
|
sessionOperations.Enqueue(new SessionActivationOperation(logger, sessionContext));
|
2019-06-07 15:26:03 +02:00
|
|
|
|
|
|
|
|
|
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
|
2019-06-18 10:18:56 +02:00
|
|
|
|
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
2019-06-07 15:26:03 +02:00
|
|
|
|
|
2019-07-04 09:12:28 +02:00
|
|
|
|
ServiceController = new ServiceController(logger, LogWriterFactory, bootstrapSequence, sessionSequence, serviceHost, sessionContext, systemConfigurationUpdate);
|
2019-06-06 15:44:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-26 10:13:11 +02:00
|
|
|
|
private string BuildBackupFilePath()
|
|
|
|
|
{
|
|
|
|
|
var appDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), nameof(SafeExamBrowser));
|
|
|
|
|
var filePath = Path.Combine(appDataFolder, AppConfig.BACKUP_FILE_NAME);
|
|
|
|
|
|
|
|
|
|
return filePath;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-06 15:44:03 +02:00
|
|
|
|
internal void LogStartupInformation()
|
|
|
|
|
{
|
|
|
|
|
logger.Log($"# Service started at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
|
|
|
|
logger.Log(string.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void LogShutdownInformation()
|
|
|
|
|
{
|
|
|
|
|
logger?.Log($"# Service terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void InitializeLogging()
|
|
|
|
|
{
|
|
|
|
|
var appDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), nameof(SafeExamBrowser));
|
|
|
|
|
var logFolder = Path.Combine(appDataFolder, "Logs");
|
|
|
|
|
var logFilePrefix = DateTime.Now.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
|
|
|
|
|
var logFilePath = Path.Combine(logFolder, $"{logFilePrefix}_Service.log");
|
|
|
|
|
var logFileWriter = new LogFileWriter(new DefaultLogFormatter(), logFilePath);
|
2019-05-29 10:52:46 +02:00
|
|
|
|
|
2019-06-07 15:26:03 +02:00
|
|
|
|
logger = new Logger();
|
2019-06-06 15:44:03 +02:00
|
|
|
|
logger.LogLevel = LogLevel.Debug;
|
|
|
|
|
logger.Subscribe(logFileWriter);
|
2019-06-07 15:26:03 +02:00
|
|
|
|
logFileWriter.Initialize();
|
2019-05-29 10:52:46 +02:00
|
|
|
|
}
|
2019-06-18 15:51:35 +02:00
|
|
|
|
|
2019-06-19 15:40:21 +02:00
|
|
|
|
private ILogObserver LogWriterFactory(string filePath)
|
2019-06-18 15:51:35 +02:00
|
|
|
|
{
|
|
|
|
|
var writer = new LogFileWriter(new DefaultLogFormatter(), filePath);
|
|
|
|
|
|
|
|
|
|
writer.Initialize();
|
|
|
|
|
|
|
|
|
|
return writer;
|
|
|
|
|
}
|
2019-06-19 15:40:21 +02:00
|
|
|
|
|
|
|
|
|
private EventWaitHandle ServiceEventFactory(string eventName)
|
|
|
|
|
{
|
|
|
|
|
var securityIdentifier = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);
|
|
|
|
|
var accessRule = new EventWaitHandleAccessRule(securityIdentifier, EventWaitHandleRights.Synchronize, AccessControlType.Allow);
|
|
|
|
|
var security = new EventWaitHandleSecurity();
|
|
|
|
|
|
|
|
|
|
security.AddAccessRule(accessRule);
|
|
|
|
|
|
|
|
|
|
return new EventWaitHandle(false, EventResetMode.AutoReset, eventName, out _, security);
|
|
|
|
|
}
|
2019-05-29 10:52:46 +02:00
|
|
|
|
}
|
|
|
|
|
}
|