/*
* 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 ProtonVPN.Logging.Contracts;
using ProtonVPN.Logging.Contracts.Events.ProcessLogs;
using ProtonVPN.OperatingSystems.Processes.Contracts;
namespace ProtonVPN.OperatingSystems.Processes;
public class CommandLineCaller : ICommandLineCaller
{
private const int PROCESS_TIMEOUT_IN_MILLISECONDS = 1000;
private readonly ILogger _logger;
public CommandLineCaller(ILogger logger)
{
_logger = logger;
}
public void Execute(string arguments)
{
RunCommand(arguments, isElevated: false);
}
public void ExecuteElevated(string arguments)
{
RunCommand(arguments, isElevated: true);
}
private void RunCommand(string arguments, bool isElevated)
{
string commandDescription = (isElevated ? "elevated " : "") + "command line argument";
_logger.Info($"Running {commandDescription} '{arguments}'.");
try
{
Process process = new()
{
StartInfo = new ProcessStartInfo("cmd.exe", arguments)
{
UseShellExecute = true,
WindowStyle = ProcessWindowStyle.Hidden
// Because UseShellExecute is true, the property CreateNoWindow is ignored and therefore there is no need to set it
}
};
if (isElevated)
{
process.StartInfo.Verb = "runas";
}
process.Start();
process.WaitForExit(PROCESS_TIMEOUT_IN_MILLISECONDS);
_logger.Info($"Finished running the {commandDescription} '{arguments}'.");
}
catch (Exception e)
{
_logger.Error($"Failed to run {commandDescription} '{arguments}'.", e);
}
}
public async Task ExecuteMultipleAsync(List commands)
{
ProcessStartInfo startInfo = new()
{
FileName = "cmd.exe",
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = false,
RedirectStandardError = true,
CreateNoWindow = true,
};
try
{
Process? process = Process.Start(startInfo);
if (process == null)
{
_logger.Error("Failed to start cmd.exe process.");
return;
}
Task errorTask = process.StandardError.ReadToEndAsync();
foreach (string command in commands)
{
process.StandardInput.WriteLine(command);
}
process.StandardInput.WriteLine("exit");
process.StandardInput.Flush();
process.StandardInput.Close();
await process.WaitForExitAsync().ConfigureAwait(false);
string errors = await errorTask.ConfigureAwait(false);
if (!string.IsNullOrEmpty(errors))
{
_logger.Error($"Failed to execute multiple commands. Errors: {errors}");
}
}
catch (Exception e)
{
_logger.Error("Failed to execute multiple commands.", e);
}
}
}