using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using PureCrack.Util; namespace PureCrack.Setup; public static class HostsManager { private const string HostsPath = "C:\\Windows\\System32\\drivers\\etc\\hosts"; private const string BackupSuffix = ".purecrack-backup"; public static readonly string[] Domains = new string[3] { "api.purecoder.io", "api1.purecoder.io", "api2.purecoder.io" }; public static string Path => "C:\\Windows\\System32\\drivers\\etc\\hosts"; public static string BackupPath => "C:\\Windows\\System32\\drivers\\etc\\hosts.purecrack-backup"; public static bool Ensure() { if (!File.Exists("C:\\Windows\\System32\\drivers\\etc\\hosts")) { throw new FileNotFoundException("C:\\Windows\\System32\\drivers\\etc\\hosts missing — Windows install looks broken"); } string content = File.ReadAllText("C:\\Windows\\System32\\drivers\\etc\\hosts"); HashSet present = ScanPresent(content); List list = Domains.Where((string d) => !present.Contains(d)).ToList(); if (list.Count == 0) { Log.Info($"hosts: all {Domains.Length} entries already present"); return false; } if (!File.Exists(BackupPath)) { File.Copy("C:\\Windows\\System32\\drivers\\etc\\hosts", BackupPath); Log.Bullet("hosts: backup saved to " + BackupPath); } string text = EnsureTrailingNewline(content); foreach (string item in list) { text = text + "127.0.0.1 " + item + "\n"; Log.Bullet("hosts: add 127.0.0.1 " + item); } File.WriteAllText("C:\\Windows\\System32\\drivers\\etc\\hosts", text); FlushDns(); return true; } public static void Remove() { if (!File.Exists("C:\\Windows\\System32\\drivers\\etc\\hosts")) { return; } string[] array = File.ReadAllLines("C:\\Windows\\System32\\drivers\\etc\\hosts"); List list = new List(array.Length); int num = 0; string[] array2 = array; foreach (string text in array2) { string trimmed = text.Trim(); if (trimmed.StartsWith("#") || trimmed.Length == 0) { list.Add(text); } else if (Domains.Any((string d) => LineMapsDomainToLoopback(trimmed, d))) { num++; } else { list.Add(text); } } if (num > 0) { File.WriteAllText("C:\\Windows\\System32\\drivers\\etc\\hosts", string.Join("\n", list)); Log.Ok($"hosts: removed {num} entries"); FlushDns(); } } public static bool IsWritable() { try { using (File.Open("C:\\Windows\\System32\\drivers\\etc\\hosts", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { return true; } } catch (UnauthorizedAccessException) { return false; } catch (IOException) { return false; } } private static HashSet ScanPresent(string content) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); string[] array = content.Split(new char[1] { '\n' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0 || text.StartsWith("#")) { continue; } string[] domains = Domains; foreach (string text2 in domains) { if (LineMapsDomainToLoopback(text, text2)) { hashSet.Add(text2); } } } return hashSet; } private static bool LineMapsDomainToLoopback(string line, string domain) { string[] array = line.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length < 2) { return false; } if (!array[0].StartsWith("127.")) { return false; } for (int i = 1; i < array.Length; i++) { string text = array[i]; if (text.StartsWith("#")) { break; } if (string.Equals(text, domain, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static string EnsureTrailingNewline(string content) { if (content.Length != 0 && content[content.Length - 1] != '\n') { return content + "\n"; } return content; } private static void FlushDns() { try { using Process process = Process.Start(new ProcessStartInfo("ipconfig", "/flushdns") { UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true }); process?.WaitForExit(5000); Log.Bullet("hosts: dns cache flushed"); } catch (Exception ex) { Log.Warn("ipconfig /flushdns failed (non-fatal): " + ex.Message); } } }