diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..909ec1d --- /dev/null +++ b/Program.cs @@ -0,0 +1,244 @@ +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Text; + +namespace SshStatusUpdater +{ + internal class Program + { + // ================= НАСТРОЙКИ ПОДКЛЮЧЕНИЯ ================= + private const string RemoteUser = "depfile"; // Логин пользователя на сервере + private const string RemoteHost = "10.228.48.110"; // IP-адрес или DNS-имя сервера + private const int RemotePort = 22; // Порт SSH-сервера + + // Путь к приватному ключу по умолчанию (если не задан аргументом) + private const string DefaultKeyPath = @"D:\sys\C-Sharp\deployfile\key\test_key.key"; + // ======================================================== + + static int Main(string[] args) + { + // 1. Определение пути к ключу + string rawKeyPath = (args.Length > 0 && !string.IsNullOrWhiteSpace(args[0])) + ? args[0].Trim('"') + : DefaultKeyPath; + + string keyPath = Environment.ExpandEnvironmentVariables(rawKeyPath); + + if (!File.Exists(keyPath)) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"Ошибка: Файл ключа не найден по указанному пути: {keyPath}"); + Console.ResetColor(); + return 2; + } + + Console.WriteLine($"Используется ключ: {keyPath}"); + + // 2. Проверка доступности OpenSSH клиента (с возможностью автоустановки) + string sshExecutable = EnsureOpenSshAvailable(); + if (string.IsNullOrEmpty(sshExecutable)) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("\n[ОШИБКА] Клиент OpenSSH не найден в системе и не удалось выполнить его установку."); + Console.WriteLine("Для работы приложения необходимо установить компонент OpenSSH вручную."); + Console.WriteLine("Откройте PowerShell от имени Администратора и выполните:"); + Console.WriteLine(" Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0"); + Console.ResetColor(); + return 4; + } + + // 3. Формирование полезной нагрузки и удаленной команды + string randomContent = GenerateRandomPayload(linesCount: 5, charsPerLine: 32); + + // Относительные пути от домашнего каталога /var/lib/depfile + string remoteCommand = "mkdir -p status && cat > status/change.me && (cd status && sha256sum change.me > sha256.hash)"; + + string sshArgs = $"-i \"{keyPath}\" -p {RemotePort} -o BatchMode=yes -o StrictHostKeyChecking=accept-new {RemoteUser}@{RemoteHost} \"{remoteCommand}\""; + + ProcessStartInfo psi = new ProcessStartInfo + { + FileName = sshExecutable, + Arguments = sshArgs, + UseShellExecute = false, + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + + Console.WriteLine($"Подключение к {RemoteUser}@{RemoteHost}:{RemotePort}..."); + + try + { + using (Process proc = new Process { StartInfo = psi }) + { + proc.Start(); + + // Передаем сгенерированный текст в STDIN удаленного процесса ssh + using (StreamWriter sw = new StreamWriter(proc.StandardInput.BaseStream, new UTF8Encoding(false))) + { + sw.Write(randomContent); + } + + string stdOut = proc.StandardOutput.ReadToEnd(); + string stdErr = proc.StandardError.ReadToEnd(); + + proc.WaitForExit(); + + if (proc.ExitCode == 0) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Файл status/change.me и хеш status/sha256.hash успешно созданы на сервере."); + Console.ResetColor(); + return 0; + } + else + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"Ошибка выполнения SSH (Код: {proc.ExitCode}):"); + if (!string.IsNullOrWhiteSpace(stdErr)) + Console.WriteLine(stdErr.Trim()); + if (!string.IsNullOrWhiteSpace(stdOut)) + Console.WriteLine(stdOut.Trim()); + Console.ResetColor(); + return proc.ExitCode; + } + } + } + catch (Exception ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"Критическая ошибка выполнения SSH: {ex.Message}"); + Console.ResetColor(); + return 3; + } + } + + private static string EnsureOpenSshAvailable() + { + string path = FindSshPath(); + if (!string.IsNullOrEmpty(path)) + return path; + + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine("Клиент OpenSSH не обнаружен. Попытка автоматической установки компонента Windows..."); + Console.ResetColor(); + + bool installed = TryInstallOpenSsh(); + if (installed) + { + path = FindSshPath(); + if (!string.IsNullOrEmpty(path)) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Клиент OpenSSH успешно установлен."); + Console.ResetColor(); + return path; + } + } + + return null; + } + + private static string FindSshPath() + { + string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows); + + string[] candidates = new[] + { + Path.Combine(windir, "Sysnative", "OpenSSH", "ssh.exe"), + Path.Combine(windir, "System32", "OpenSSH", "ssh.exe"), + @"C:\Windows\System32\OpenSSH\ssh.exe" + }; + + foreach (var candidate in candidates) + { + if (File.Exists(candidate)) + return candidate; + } + + try + { + ProcessStartInfo testPsi = new ProcessStartInfo + { + FileName = "ssh", + Arguments = "-V", + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true, + CreateNoWindow = true + }; + + using (var testProc = Process.Start(testPsi)) + { + testProc?.WaitForExit(1000); + return "ssh"; + } + } + catch + { + } + + return null; + } + + private static string TryInstallOpenSsh() + { + try + { + ProcessStartInfo installPsi = new ProcessStartInfo + { + FileName = "powershell.exe", + Arguments = "-NoProfile -ExecutionPolicy Bypass -Command \"Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0\"", + UseShellExecute = true, + Verb = "runas", + WindowStyle = ProcessWindowStyle.Normal + }; + + using (Process installProc = Process.Start(installPsi)) + { + if (installProc == null) + return false; + + installProc.WaitForExit(); + return installProc.ExitCode == 0; + } + } + catch (Win32Exception) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine("Запрос прав Администратора был отклонён пользователем."); + Console.ResetColor(); + return false; + } + catch (Exception ex) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($"Не удалось запустить автоматическую установку: {ex.Message}"); + Console.ResetColor(); + return false; + } + } + + private static string GenerateRandomPayload(int linesCount, int charsPerLine) + { + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + StringBuilder sb = new StringBuilder(); + Random rng = new Random(); + + for (int i = 0; i < linesCount; i++) + { + char[] buffer = new char[charsPerLine]; + for (int j = 0; j < charsPerLine; j++) + { + buffer[j] = chars[rng.Next(chars.Length)]; + } + sb.AppendLine(new string(buffer)); + } + + return sb.ToString(); + } + } +} \ No newline at end of file