Example #1
0
        /// <summary>
        /// Adds a file to the list of changed files and backups it.
        /// </summary>
        /// <param name="path"></param>
        public void Add(FileInfo file)
        {
            var relativePath = LoneFunctions.GetRelativePath(Environment.CurrentDirectory, file.FullName);
            var backupPath   = new FileInfo(Path.Combine(_BackupPath.FullName, relativePath));

            if (_Files.Contains(relativePath))
            {
                Console.WriteLine("Skipping backup of {0}", relativePath);
                return;
            }


            // Copy over
            backupPath.Directory.Create();
            if (file.Exists)
            {
                file.CopyTo(backupPath.FullName, true);
            }
            else
            {
                // Make empty file
                backupPath.Create().Close();
            }

            // Add to list
            _Files.Add(relativePath);
        }
 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
 {
     if (value == null)
     {
         writer.WriteNull();
     }
     else
     {
         if (!(value is byte[]))
         {
             throw new JsonSerializationException("Expected byte[] object value");
         }
         writer.WriteValue(LoneFunctions.ByteArrayToString(value as byte[]));
     }
 }
 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
 {
     if (reader.TokenType == JsonToken.Null)
     {
         return(null);
     }
     if (reader.TokenType == JsonToken.String)
     {
         try
         {
             return(LoneFunctions.StringToByteArray((string)reader.Value));
         }
         catch (Exception ex)
         {
             throw new Exception(string.Format("Error parsing version string: {0}", reader.Value), ex);
         }
     }
     throw new Exception(string.Format("Unexpected token or value when parsing hex string. Token: {0}, Value: {1}", reader.TokenType, reader.Value));
 }
        /// <summary>
        /// Adds a file to the list of changed files and backups it.
        /// </summary>
        /// <param name="file"></param>
        public void Add(FileInfo file)
        {
            var relativePath = LoneFunctions.GetRelativePath(file.FullName, Environment.CurrentDirectory);
            var backupPath   = new FileInfo(Path.Combine(_backupPath.FullName, relativePath));

            // Copy over
            backupPath.Directory?.Create();
            if (file.Exists)
            {
                if (File.Exists(backupPath.FullName))
                {
                    File.Delete(backupPath.FullName);
                }
                file.CopyTo(backupPath.FullName);
            }
            else
            {
                // Make empty file
                backupPath.Create().Close();
            }

            if (_files.Contains(relativePath))
            {
                return;
            }
            if (!File.Exists(_manifestFile.FullName))
            {
                _manifestFile.Create().Close();
            }
            var stream = _manifestFile.AppendText();

            stream.WriteLine(relativePath);
            stream.Close();

            // Add to list
            _files.Add(relativePath);
        }
        private static void LoadPlugins()
        {
            string pluginDirectory = Path.Combine(Environment.CurrentDirectory, "Plugins");

            // Process.GetCurrentProcess().MainModule crashes the game and Assembly.GetEntryAssembly() is NULL,
            // so we need to resort to P/Invoke
            string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath);

            Logger.log.Info(exeName);
            _bsPlugins  = new List <BSPluginMeta>();
            _ipaPlugins = new List <IPlugin>();

            if (!Directory.Exists(pluginDirectory))
            {
                return;
            }

            string cacheDir = Path.Combine(pluginDirectory, ".cache");

            if (!Directory.Exists(cacheDir))
            {
                Directory.CreateDirectory(cacheDir);
            }
            else
            {
                foreach (string plugin in Directory.GetFiles(cacheDir, "*"))
                {
                    File.Delete(plugin);
                }
            }

            //Copy plugins to .cache
            string[] originalPlugins = Directory.GetFiles(pluginDirectory, "*.dll");
            foreach (string s in originalPlugins)
            {
                string pluginCopy = Path.Combine(cacheDir, Path.GetFileName(s));
                File.Copy(Path.Combine(pluginDirectory, s), pluginCopy);
            }

            var selfPlugin = new BSPluginMeta
            {
                Filename = Path.Combine(Environment.CurrentDirectory, "IPA.exe"),
                Plugin   = new SelfPlugin()
            };

            selfPlugin.ModsaberInfo = selfPlugin.Plugin.ModInfo;

            _bsPlugins.Add(selfPlugin);

            //Load copied plugins
            string[] copiedPlugins = Directory.GetFiles(cacheDir, "*.dll");
            foreach (string s in copiedPlugins)
            {
                var result = LoadPluginsFromFile(s, exeName);
                _bsPlugins.AddRange(result.Item1);
                _ipaPlugins.AddRange(result.Item2);
            }


            // DEBUG
            Logger.log.Info($"Running on Unity {UnityEngine.Application.unityVersion}");
            Logger.log.Info($"Game version {UnityEngine.Application.version}");
            Logger.log.Info("-----------------------------");
            Logger.log.Info($"Loading plugins from {LoneFunctions.GetRelativePath(pluginDirectory, Environment.CurrentDirectory)} and found {_bsPlugins.Count + _ipaPlugins.Count}");
            Logger.log.Info("-----------------------------");
            foreach (var plugin in _bsPlugins)
            {
                Logger.log.Info($"{plugin.Plugin.Name}: {plugin.Plugin.Version}");
            }
            Logger.log.Info("-----------------------------");
            foreach (var plugin in _ipaPlugins)
            {
                Logger.log.Info($"{plugin.Name}: {plugin.Version}");
            }
            Logger.log.Info("-----------------------------");
        }
        private void ExtractPluginAsync(MemoryStream stream, DependencyObject item, ApiEndpoint.Mod.PlatformFile fileInfo)
        { // (3.3)
            Logger.updater.Debug($"Extracting ZIP file for {item.Name}");

            var  data = stream.GetBuffer();
            SHA1 sha  = new SHA1CryptoServiceProvider();
            var  hash = sha.ComputeHash(data);

            if (!LoneFunctions.UnsafeCompare(hash, fileInfo.Hash))
            {
                throw new Exception("The hash for the file doesn't match what is defined");
            }

            var targetDir = Path.Combine(BeatSaber.InstallPath, "IPA", Path.GetRandomFileName() + "_Pending");

            Directory.CreateDirectory(targetDir);

            var eventualOutput = Path.Combine(BeatSaber.InstallPath, "IPA", "Pending");

            if (!Directory.Exists(eventualOutput))
            {
                Directory.CreateDirectory(eventualOutput);
            }

            try
            {
                bool shouldDeleteOldFile = !(item.LocalPluginMeta?.Plugin is SelfPlugin);

                using (var zipFile = ZipFile.Read(stream))
                {
                    Logger.updater.Debug("Streams opened");
                    foreach (var entry in zipFile)
                    {
                        if (entry.IsDirectory)
                        {
                            Logger.updater.Debug($"Creating directory {entry.FileName}");
                            Directory.CreateDirectory(Path.Combine(targetDir, entry.FileName));
                        }
                        else
                        {
                            using (var ostream = new MemoryStream((int)entry.UncompressedSize))
                            {
                                entry.Extract(ostream);
                                ostream.Seek(0, SeekOrigin.Begin);

                                sha = new SHA1CryptoServiceProvider();
                                var fileHash = sha.ComputeHash(ostream);

                                try
                                {
                                    if (!LoneFunctions.UnsafeCompare(fileHash, fileInfo.FileHashes[entry.FileName]))
                                    {
                                        throw new Exception("The hash for the file doesn't match what is defined");
                                    }
                                }
                                catch (KeyNotFoundException)
                                {
                                    throw new ModsaberInterceptException("ModSaber did not send the hashes for the zip's content!");
                                }

                                ostream.Seek(0, SeekOrigin.Begin);
                                FileInfo targetFile = new FileInfo(Path.Combine(targetDir, entry.FileName));
                                Directory.CreateDirectory(targetFile.DirectoryName ?? throw new InvalidOperationException());

                                if (LoneFunctions.GetRelativePath(targetFile.FullName, targetDir) == LoneFunctions.GetRelativePath(item.LocalPluginMeta?.Filename, BeatSaber.InstallPath))
                                {
                                    shouldDeleteOldFile = false; // overwriting old file, no need to delete
                                }

                                /*if (targetFile.Exists)
                                 *  backup.Add(targetFile);
                                 * else
                                 *  newFiles.Add(targetFile);*/

                                Logger.updater.Debug($"Extracting file {targetFile.FullName}");

                                targetFile.Delete();
                                using (var fstream = targetFile.Create())
                                    ostream.CopyTo(fstream);
                            }
                        }
                    }
                }

                if (shouldDeleteOldFile && item.LocalPluginMeta != null)
                {
                    File.AppendAllLines(Path.Combine(targetDir, SpecialDeletionsFile), new[] { LoneFunctions.GetRelativePath(item.LocalPluginMeta.Filename, BeatSaber.InstallPath) });
                }
            }
            catch (Exception)
            {                                      // something failed; restore
                /*foreach (var file in newFiles)
                 *  file.Delete();
                 * backup.Restore();
                 * backup.Delete();*/
                Directory.Delete(targetDir, true); // delete extraction site

                throw;
            }

            if (item.LocalPluginMeta?.Plugin is SelfPlugin)
            { // currently updating self, so copy to working dir and update
                LoneFunctions.CopyAll(new DirectoryInfo(targetDir), new DirectoryInfo(BeatSaber.InstallPath));
                if (File.Exists(Path.Combine(BeatSaber.InstallPath, SpecialDeletionsFile)))
                {
                    File.Delete(Path.Combine(BeatSaber.InstallPath, SpecialDeletionsFile));
                }
                Process.Start(new ProcessStartInfo
                {
                    FileName        = item.LocalPluginMeta.Filename,
                    Arguments       = $"-nw={Process.GetCurrentProcess().Id}",
                    UseShellExecute = false
                });
            }
            else
            {
                LoneFunctions.CopyAll(new DirectoryInfo(targetDir), new DirectoryInfo(eventualOutput), SpecialDeletionsFile);
            }
            Directory.Delete(targetDir, true); // delete extraction site

            Logger.updater.Debug("Extractor exited");
        }
        private static void LoadPlugins()
        {
            string pluginDirectory = Path.Combine(Environment.CurrentDirectory, "Plugins");

            // Process.GetCurrentProcess().MainModule crashes the game and Assembly.GetEntryAssembly() is NULL,
            // so we need to resort to P/Invoke
            string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath);

            _bsPlugins  = new List <PluginInfo>();
            _ipaPlugins = new List <IPlugin>();

            if (!Directory.Exists(pluginDirectory))
            {
                return;
            }

            string cacheDir = Path.Combine(pluginDirectory, ".cache");

            if (!Directory.Exists(cacheDir))
            {
                Directory.CreateDirectory(cacheDir);
            }
            else
            {
                foreach (string plugin in Directory.GetFiles(cacheDir, "*"))
                {
                    File.Delete(plugin);
                }
            }

            //Copy plugins to .cache
            string[] originalPlugins = Directory.GetFiles(pluginDirectory, "*.dll");
            foreach (string s in originalPlugins)
            {
                string pluginCopy = Path.Combine(cacheDir, Path.GetFileName(s));
                File.Copy(Path.Combine(pluginDirectory, s), pluginCopy);

                #region Fix assemblies for refactor

                var module = ModuleDefinition.ReadModule(Path.Combine(pluginDirectory, s));
                foreach (var @ref in module.AssemblyReferences)
                { // fix assembly references
                    if (@ref.Name == "IllusionPlugin" || @ref.Name == "IllusionInjector")
                    {
                        @ref.Name = "IPA.Loader";
                    }
                }

                foreach (var @ref in module.GetTypeReferences())
                { // fix type references
                    if (@ref.FullName == "IllusionPlugin.IPlugin")
                    {
                        @ref.Namespace = "IPA.Old";                                            //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.IEnhancedPlugin")
                    {
                        @ref.Namespace = "IPA.Old";                                                    //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.IBeatSaberPlugin")
                    {
                        @ref.Namespace = "IPA";                                                     //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.IEnhancedBeatSaberPlugin")
                    {
                        @ref.Namespace = "IPA";                                                             //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.BeatSaber.ModsaberModInfo")
                    {
                        @ref.Namespace = "IPA";                                                              //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.IniFile")
                    {
                        @ref.Namespace = "IPA.Config";                                            //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.IModPrefs")
                    {
                        @ref.Namespace = "IPA.Config";                                              //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.ModPrefs")
                    {
                        @ref.Namespace = "IPA.Config";                                             //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.Utils.ReflectionUtil")
                    {
                        @ref.Namespace = "IPA.Utilities";                                                         //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.Logging.Logger")
                    {
                        @ref.Namespace = "IPA.Logging";                                                   //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.Logging.LogPrinter")
                    {
                        @ref.Namespace = "IPA.Logging";                                                       //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.PluginManager")
                    {
                        @ref.Namespace = "IPA.Loader";                                                    //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.PluginComponent")
                    {
                        @ref.Namespace = "IPA.Loader";                                                      //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.CompositeBSPlugin")
                    {
                        @ref.Namespace = "IPA.Loader.Composite";                                                        //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.CompositeIPAPlugin")
                    {
                        @ref.Namespace = "IPA.Loader.Composite";                                                         //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.Logging.UnityLogInterceptor")
                    {
                        @ref.Namespace = "IPA.Logging";                                                                  //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.Logging.StandardLogger")
                    {
                        @ref.Namespace = "IPA.Logging";                                                             //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.Updating.SelfPlugin")
                    {
                        @ref.Namespace = "IPA.Updating";                                                          //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.Updating.Backup.BackupUnit")
                    {
                        @ref.Namespace = "IPA.Updating.Backup";                                                                 //@ref.Name = "";
                    }
                    if (@ref.Namespace == "IllusionInjector.Utilities")
                    {
                        @ref.Namespace = "IPA.Utilities";                                                 //@ref.Name = "";
                    }
                    if (@ref.Namespace == "IllusionInjector.Logging.Printers")
                    {
                        @ref.Namespace = "IPA.Logging.Printers";                                                        //@ref.Name = "";
                    }
                    if (@ref.Namespace == "IllusionInjector.Updating.ModsaberML")
                    {
                        @ref.Namespace = "IPA.Updating.ModSaber";                                                           //@ref.Name = "";
                    }
                }
                module.Write(pluginCopy);

                #endregion
            }

            var selfPlugin = new PluginInfo
            {
                Filename = Path.Combine(Environment.CurrentDirectory, "IPA.exe"),
                Plugin   = SelfPlugin.Instance
            };
            selfPlugin.ModSaberInfo = selfPlugin.Plugin.ModInfo;

            _bsPlugins.Add(selfPlugin);

            configProviders.Add(new KeyValuePair <IConfigProvider, Ref <DateTime> >(SelfConfigProvider = new JsonConfigProvider {
                Filename = Path.Combine("UserData", SelfPlugin.IPA_Name)
            }, new Ref <DateTime>(SelfConfigProvider.LastModified)));
            SelfConfigProvider.Load();

            //Load copied plugins
            string[] copiedPlugins = Directory.GetFiles(cacheDir, "*.dll");
            foreach (string s in copiedPlugins)
            {
                var result = LoadPluginsFromFile(s, exeName);
                _bsPlugins.AddRange(result.Item1);
                _ipaPlugins.AddRange(result.Item2);
            }

            Logger.log.Info(exeName);
            Logger.log.Info($"Running on Unity {Application.unityVersion}");
            Logger.log.Info($"Game version {BeatSaber.GameVersion}");
            Logger.log.Info("-----------------------------");
            Logger.log.Info($"Loading plugins from {LoneFunctions.GetRelativePath(pluginDirectory, Environment.CurrentDirectory)} and found {_bsPlugins.Count + _ipaPlugins.Count}");
            Logger.log.Info("-----------------------------");
            foreach (var plugin in _bsPlugins)
            {
                Logger.log.Info($"{plugin.Plugin.Name}: {plugin.Plugin.Version}");
            }
            Logger.log.Info("-----------------------------");
            foreach (var plugin in _ipaPlugins)
            {
                Logger.log.Info($"{plugin.Name}: {plugin.Version}");
            }
            Logger.log.Info("-----------------------------");
        }
 public override string ToString()
 {
     return($"{LoneFunctions.ByteArrayToString(Hash)}@{DownloadPath}({string.Join(",",FileHashes.Select(o=>$"\"{o.Key}\":\"{LoneFunctions.ByteArrayToString(o.Value)}\""))})");
 }
Example #9
0
        private void ExtractPluginAsync(MemoryStream stream, UpdateStruct item, ApiEndpoint.Mod.PlatformFile fileInfo, string tempDirectory)
        {
            Logger.log.Debug($"Extracting ZIP file for {item.plugin.Plugin.Name}");

            var  data = stream.GetBuffer();
            SHA1 sha  = new SHA1CryptoServiceProvider();
            var  hash = sha.ComputeHash(data);

            if (!LoneFunctions.UnsafeCompare(hash, fileInfo.Hash))
            {
                throw new Exception("The hash for the file doesn't match what is defined");
            }

            var newFiles = new List <FileInfo>();
            var backup   = new BackupUnit(tempDirectory, $"backup-{item.plugin.ModsaberInfo.InternalName}");

            try
            {
                bool shouldDeleteOldFile = true;

                using (var zipFile = ZipFile.Read(stream))
                {
                    Logger.log.Debug("Streams opened");
                    foreach (var entry in zipFile)
                    {
                        if (entry.IsDirectory)
                        {
                            Logger.log.Debug($"Creating directory {entry.FileName}");
                            Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, entry.FileName));
                        }
                        else
                        {
                            using (var ostream = new MemoryStream((int)entry.UncompressedSize))
                            {
                                entry.Extract(ostream);
                                ostream.Seek(0, SeekOrigin.Begin);

                                sha = new SHA1CryptoServiceProvider();
                                var fileHash = sha.ComputeHash(ostream);
                                if (!LoneFunctions.UnsafeCompare(fileHash, fileInfo.FileHashes[entry.FileName]))
                                {
                                    throw new Exception("The hash for the file doesn't match what is defined");
                                }

                                ostream.Seek(0, SeekOrigin.Begin);
                                FileInfo targetFile = new FileInfo(Path.Combine(Environment.CurrentDirectory, entry.FileName));
                                Directory.CreateDirectory(targetFile.DirectoryName);

                                if (targetFile.FullName == item.plugin.Filename)
                                {
                                    shouldDeleteOldFile = false; // overwriting old file, no need to delete
                                }
                                if (targetFile.Exists)
                                {
                                    backup.Add(targetFile);
                                }
                                else
                                {
                                    newFiles.Add(targetFile);
                                }

                                Logger.log.Debug($"Extracting file {targetFile.FullName}");

                                var fstream = targetFile.Create();
                                ostream.CopyTo(fstream);
                            }
                        }
                    }
                }

                if (item.plugin.Plugin is SelfPlugin)
                { // currently updating self
                    Process.Start(new ProcessStartInfo
                    {
                        FileName        = item.plugin.Filename,
                        Arguments       = $"--waitfor={Process.GetCurrentProcess().Id} --nowait",
                        UseShellExecute = false
                    });
                }
                else if (shouldDeleteOldFile)
                {
                    File.Delete(item.plugin.Filename);
                }
            }
            catch (Exception)
            { // something failed; restore
                foreach (var file in newFiles)
                {
                    file.Delete();
                }
                backup.Restore();
                backup.Delete();

                throw;
            }

            backup.Delete();

            Logger.log.Debug("Downloader exited");
        }
Example #10
0
        public static void InstallPendingUpdates()
        {
            var pendingDir = Path.Combine(BeatSaber.InstallPath, "IPA", "Pending");

            if (!Directory.Exists(pendingDir))
            {
                return;
            }

            // there are pending updates, install
            updater.Info("Installing pending updates");

            var toDelete = new string[0];
            var delFn    = Path.Combine(pendingDir, DeleteFileName);

            if (File.Exists(delFn))
            {
                toDelete = File.ReadAllLines(delFn);
                File.Delete(delFn);
            }

            foreach (var file in toDelete)
            {
                try
                {
                    File.Delete(Path.Combine(BeatSaber.InstallPath, file));
                }
                catch (Exception e)
                {
                    updater.Error("While trying to install pending updates: Error deleting file marked for deletion");
                    updater.Error(e);
                }
            }

            #region Self Protection
            if (Directory.Exists(Path.Combine(pendingDir, "IPA")))
            {
                Directory.Delete(Path.Combine(pendingDir, "IPA"), true);
            }
            if (File.Exists(Path.Combine(pendingDir, "IPA.exe")))
            {
                File.Delete(Path.Combine(pendingDir, "IPA.exe"));
                if (File.Exists(Path.Combine(pendingDir, "Mono.Cecil.dll")))
                {
                    File.Delete(Path.Combine(pendingDir, "Mono.Cecil.dll"));
                }
            }

            #endregion

            try
            {
                LoneFunctions.CopyAll(new DirectoryInfo(pendingDir), new DirectoryInfo(BeatSaber.InstallPath));
            }
            catch (Exception e)
            {
                updater.Error("While trying to install pending updates: Error copying files in");
                updater.Error(e);
            }

            Directory.Delete(pendingDir, true);
        }