You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
6.1 KiB

  1. #nullable enable
  2. using IPA.AntiMalware;
  3. using IPA.Config;
  4. using IPA.Utilities;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Reflection;
  11. using static IPA.Logging.Logger;
  12. #if NET3
  13. using Net3_Proxy;
  14. using Path = Net3_Proxy.Path;
  15. using File = Net3_Proxy.File;
  16. using Directory = Net3_Proxy.Directory;
  17. using Array = Net3_Proxy.Array;
  18. #endif
  19. namespace IPA.Injector
  20. {
  21. internal static class Updates
  22. {
  23. private const string DeleteFileName = "$$delete";
  24. public static void InstallPendingUpdates()
  25. {
  26. InstallPendingSelfUpdates();
  27. InstallPendingModUpdates();
  28. }
  29. private static void InstallPendingSelfUpdates()
  30. {
  31. var path = Path.Combine(UnityGame.InstallPath, "IPA.exe");
  32. if (!File.Exists(path)) return;
  33. var ipaVersion = new Version(FileVersionInfo.GetVersionInfo(path).FileVersion);
  34. var selfVersion = Injector.ExecutingAssembly.GetName().Version;
  35. if (ipaVersion > selfVersion)
  36. {
  37. var scanResult = AntiMalwareEngine.Engine.ScanFile(new FileInfo(path));
  38. if (scanResult == ScanResult.Detected)
  39. {
  40. Updater.Error("Scan of BSIPA installer found malware; not updating");
  41. return;
  42. }
  43. if (!SelfConfig.AntiMalware_.RunPartialThreatCode_ && scanResult is not ScanResult.KnownSafe and not ScanResult.NotDetected)
  44. {
  45. Updater.Error("Scan of BSIPA installer returned partial threat; not updating. To allow this, enable AntiMalware.RunPartialThreatCode in the config.");
  46. return;
  47. }
  48. _ = Process.Start(new ProcessStartInfo
  49. {
  50. FileName = path,
  51. Arguments = $"\"-nw={Process.GetCurrentProcess().Id}," +
  52. $"s={string.Join(" ", Environment.GetCommandLineArgs().Skip(1).StrJP()).Replace("\\", "\\\\").Replace(",", "\\,")}\"",
  53. UseShellExecute = false
  54. });
  55. Updater.Info("Updating BSIPA...");
  56. Environment.Exit(0);
  57. }
  58. }
  59. private static void InstallPendingModUpdates()
  60. {
  61. var pendingDir = Path.Combine(UnityGame.InstallPath, "IPA", "Pending");
  62. if (!Directory.Exists(pendingDir)) return;
  63. // there are pending updates, install
  64. Updater.Info("Installing pending updates");
  65. var toDelete = Array.Empty<string>();
  66. var delFn = Path.Combine(pendingDir, DeleteFileName);
  67. if (File.Exists(delFn))
  68. {
  69. toDelete = File.ReadAllLines(delFn);
  70. File.Delete(delFn);
  71. }
  72. foreach (var file in toDelete)
  73. {
  74. try
  75. {
  76. File.Delete(Path.Combine(UnityGame.InstallPath, file));
  77. }
  78. catch (Exception e)
  79. {
  80. Updater.Error("While trying to install pending updates: Error deleting file marked for deletion");
  81. Updater.Error(e);
  82. }
  83. }
  84. #region Self Protection
  85. string path;
  86. if (Directory.Exists(path = Path.Combine(pendingDir, "IPA")))
  87. {
  88. var dirs = new Stack<string>(20);
  89. dirs.Push(path);
  90. while (dirs.Count > 0)
  91. {
  92. var currentDir = dirs.Pop();
  93. string[] subDirs;
  94. string[] files;
  95. try
  96. {
  97. subDirs = Directory.GetDirectories(currentDir);
  98. files = Directory.GetFiles(currentDir);
  99. }
  100. catch (UnauthorizedAccessException e)
  101. {
  102. Updater.Error(e);
  103. continue;
  104. }
  105. catch (DirectoryNotFoundException e)
  106. {
  107. Updater.Error(e);
  108. continue;
  109. }
  110. foreach (var file in files)
  111. {
  112. try
  113. {
  114. if (!Utils.GetRelativePath(file, path).Split(Path.PathSeparator).Contains("Pending"))
  115. File.Delete(file);
  116. }
  117. catch (FileNotFoundException e)
  118. {
  119. Updater.Error(e);
  120. }
  121. }
  122. foreach (var str in subDirs)
  123. dirs.Push(str);
  124. }
  125. }
  126. if (File.Exists(path = Path.Combine(pendingDir, "IPA.exe")))
  127. {
  128. File.Delete(path);
  129. if (File.Exists(path = Path.Combine(pendingDir, "Mono.Cecil.dll")))
  130. File.Delete(path);
  131. }
  132. #endregion
  133. try
  134. {
  135. Utils.CopyAll(new DirectoryInfo(pendingDir), new DirectoryInfo(UnityGame.InstallPath), onCopyException: (e, f) =>
  136. {
  137. Updater.Error($"Error copying file {Utils.GetRelativePath(f.FullName, pendingDir)} from Pending:");
  138. Updater.Error(e);
  139. return true;
  140. });
  141. }
  142. catch (Exception e)
  143. {
  144. Updater.Error("While trying to install pending updates: Error copying files in");
  145. Updater.Error(e);
  146. }
  147. try
  148. {
  149. Directory.Delete(pendingDir, true);
  150. }
  151. catch (Exception e)
  152. {
  153. Updater.Error("Something went wrong performing an operation that should never fail!");
  154. Updater.Error(e);
  155. }
  156. }
  157. }
  158. }