/* * 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.Linq; using Microsoft.Win32; using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations { [Serializable] internal abstract class RegistryConfiguration : FeatureConfiguration { private IList itemsToDelete; private IList itemsToRestore; protected abstract IEnumerable Items { get; } protected abstract RegistryKey RootKey { get; } public RegistryConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) { itemsToDelete = new List(); itemsToRestore = new List(); } public override bool DisableFeature() { var success = true; foreach (var item in Items) { success &= TrySet(new RegistryDataItem { Key = item.Key, Value = item.Value, Data = item.Disabled }); } if (success) { logger.Info("Successfully disabled feature."); } else { logger.Warn("Failed to disable feature!"); } return success; } public override bool EnableFeature() { var success = true; foreach (var item in Items) { success &= TrySet(new RegistryDataItem { Key = item.Key, Value = item.Value, Data = item.Enabled }); } if (success) { logger.Info("Successfully enabled feature."); } else { logger.Warn("Failed to enabled feature!"); } return success; } public override void Initialize() { foreach (var item in Items) { var original = ReadItem(item.Key, item.Value); if (original.Data == null) { itemsToDelete.Add(original); } else { itemsToRestore.Add(original); } } } public override void Monitor() { // TODO! } public override bool Restore() { foreach (var item in new List(itemsToDelete)) { if (TryDelete(item)) { itemsToDelete.Remove(item); } } foreach (var item in new List(itemsToRestore)) { if (TrySet(item)) { itemsToRestore.Remove(item); } } var success = !itemsToDelete.Any() && !itemsToRestore.Any(); if (success) { logger.Info("Successfully restored feature."); } else { logger.Warn("Failed to restore feature!"); } return success; } protected abstract bool IsHiveAvailable(RegistryDataItem item); private RegistryDataItem ReadItem(string key, string value) { var data = Registry.GetValue(key, value, null); var original = new RegistryDataItem { Key = key, Value = value, Data = data }; return original; } private bool TryDelete(RegistryDataItem item) { var success = false; try { if (IsHiveAvailable(item)) { var keyWithoutRoot = item.Key.Substring(item.Key.IndexOf('\\') + 1); using (var key = RootKey.OpenSubKey(keyWithoutRoot, true)) { if (key.GetValue(item.Value) != null) { key.DeleteValue(item.Value); logger.Debug($"Successfully deleted registry item {item}."); } else { logger.Debug($"No need to delete registry item {item} as it does not exist."); } success = true; } } else { logger.Warn($"Cannot delete item {item} as its registry hive is not available!"); } } catch (Exception e) { logger.Error($"Failed to delete registry item {item}!", e); } return success; } private bool TrySet(RegistryDataItem item) { var success = false; try { if (IsHiveAvailable(item)) { Registry.SetValue(item.Key, item.Value, item.Data); logger.Debug($"Successfully set registry item {item}."); success = true; } else { logger.Warn($"Cannot set item {item} as its registry hive is not available!"); } } catch (Exception e) { logger.Error($"Failed to set registry item {item}!", e); } return success; } } }