/* * Copyright (c) 2023 Proton AG * * This file is part of ProtonVPN. * * ProtonVPN is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ProtonVPN is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ using System.Diagnostics; using System.Reflection; using System.Text; using ProtonVPN.Configurations.BigTestInfra; using ProtonVPN.Configurations.Defaults; using ProtonVPN.Files.Contracts; using ProtonVPN.Logging.Contracts; using ProtonVPN.Logging.Contracts.Events.SettingsLogs; using ProtonVPN.Serialization.Contracts; using ProtonVPN.Serialization.Contracts.Json; namespace ProtonVPN.Configurations.Files; public class DebugConfigurationFileManager : IConfigurationFileManager { private const string FILE_NAME = "_configuration.json"; private readonly ILogger _logger; private readonly IJsonSerializer _jsonSerializer; private readonly IFileReaderWriter _fileReaderWriter; private readonly Lazy _fullFolderPath; private readonly PropertyInfo[] _defaultProperties = typeof(DefaultConfiguration).GetProperties(); public DebugConfigurationFileManager(ILogger logger, IJsonSerializer jsonSerializer, IFileReaderWriter fileReaderWriter) { _logger = logger; _jsonSerializer = jsonSerializer; _fileReaderWriter = fileReaderWriter; _fullFolderPath = new Lazy(GetFullFolderPath); } private string? GetFullFolderPath() { string? processFullFilePath; using (Process process = Process.GetCurrentProcess()) { processFullFilePath = process.MainModule?.FileName; } string? directory = string.IsNullOrWhiteSpace(processFullFilePath) ? null : Path.GetDirectoryName(processFullFilePath); if (string.IsNullOrWhiteSpace(directory)) { _logger.Error("Could not obtain the directory of the current process."); return null; } return directory; } public IDictionary Read() { string? fullFilePath = null; try { fullFilePath = GetFullFilePath(); if (fullFilePath is not null) { bool isSaved = SaveFileIfNotExists(fullFilePath); if (!isSaved) { return ReadFile(fullFilePath); } } } catch (Exception ex) { _logger.Error($"Failed to read the configuration file {fullFilePath}.", ex); } return new Dictionary(); } private string? GetFullFilePath() { return _fullFolderPath.Value is null ? null : Path.Combine(_fullFolderPath.Value, FILE_NAME); } private IDictionary ReadFile(string fullFilePath) { using (FileStream fileStream = new(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) using (StreamReader streamReader = new(fileStream, new UTF8Encoding(true))) { _logger.Info($"Reading the configuration file {fullFilePath}."); string json = streamReader.ReadToEnd(); _logger.Info($"Deserializing the configuration file {fullFilePath}."); return _jsonSerializer.DeserializeFirstLevel(json); } } private bool SaveFileIfNotExists(string fullFilePath) { Dictionary configurations = GenerateDefaultConfigurationDictionary(); return _fileReaderWriter.CreateNew(configurations, fullFilePath, Serializers.PrettyJson) == FileOperationResult.Success; } private Dictionary GenerateDefaultConfigurationDictionary() { PropertyInfo[] properties = typeof(Configuration).GetProperties(BindingFlagsConstants.PUBLIC_DECLARED_ONLY); Dictionary dictionary = new(); foreach (PropertyInfo property in properties) { dictionary.Add(property.Name, GetValueFromBtiOrDefaultConfiguration(property)); } return dictionary; } private object? GetValueFromBtiOrDefaultConfiguration(PropertyInfo property) { object? defaultValue = null; PropertyInfo? defaultProperty = _defaultProperties.FirstOrDefault(dp => dp.Name == property.Name); if (defaultProperty is not null) { defaultValue = defaultProperty.GetValue(null); } return BtiConfigurationLoader.GetValue(property, defaultValue); } }