From 921cbd050fba252566f73071ad6b75fc987156cf Mon Sep 17 00:00:00 2001 From: Vitaliy Balukh Date: Sun, 28 Aug 2022 17:06:13 +0200 Subject: [PATCH] =?UTF-8?q?Primera=20versi=C3=B3n=20de=20sumarios=20implem?= =?UTF-8?q?entada.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BlockTheSpot/Form1.Designer.cs | 4 +- BlockTheSpot/Form1.cs | 305 ++++++++++++++++++++++++--------- 2 files changed, 223 insertions(+), 86 deletions(-) diff --git a/BlockTheSpot/Form1.Designer.cs b/BlockTheSpot/Form1.Designer.cs index 4f9c34d..00dee26 100644 --- a/BlockTheSpot/Form1.Designer.cs +++ b/BlockTheSpot/Form1.Designer.cs @@ -50,7 +50,7 @@ private void InitializeComponent() this.patchButton.TabIndex = 12; this.patchButton.Text = "Bloquear anuncios"; this.patchButton.UseVisualStyleBackColor = true; - this.patchButton.Click += new System.EventHandler(this.patchButton_Click); + this.patchButton.Click += new System.EventHandler(this.PatchButton_Click); // // resetButton // @@ -62,7 +62,7 @@ private void InitializeComponent() this.resetButton.TabIndex = 13; this.resetButton.Text = "Restablecer Spotify"; this.resetButton.UseVisualStyleBackColor = true; - this.resetButton.Click += new System.EventHandler(this.resetButton_Click); + this.resetButton.Click += new System.EventHandler(this.ResetButton_Click); // // spotifyPictureBox // diff --git a/BlockTheSpot/Form1.cs b/BlockTheSpot/Form1.cs index 4a7d19c..3332bbf 100644 --- a/BlockTheSpot/Form1.cs +++ b/BlockTheSpot/Form1.cs @@ -14,34 +14,65 @@ namespace BlockTheSpot { public partial class BlockTheSpot : Form { - private static string RepositoryUrl = "https://github.com/bitasuperactive/BlockTheSpot-C-Sharp"; - private static Uri SpotifyUri { get; } = new Uri("https://download.scdn.co/SpotifySetup.exe"); - private static Uri SpotifyDowngradedUri { get; } = new Uri("https://upgrade.scdn.co/upgrade/client/win32-x86/spotify_installer-1.1.89.862.g94554d24-13.exe"); - private static Uri ChromeElfUri { get; } = new Uri("https://github.com/mrpond/BlockTheSpot/releases/latest/download/chrome_elf.zip"); - private static string SpotifyDir { get; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Spotify"; - private static string SpotifyLocalDir { get; } = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Spotify"; - - + /// + /// Dirección Uri de este repositorio en GitHub. + /// + private static Uri RepositoryUri { get; } = + new Uri("https://github.com/bitasuperactive/BlockTheSpot-C-Sharp"); + /// + /// Dirección Uri de la última versión de Spotify. + /// + private static Uri SpotifyUri { get; } = + new Uri("https://download.scdn.co/SpotifySetup.exe"); + /// + /// Dirección Uri de la última versión de Spotify, compatible con BTS (1.1.89.862.g94554d24-13). + /// + private static Uri SpotifyDowngradedUri { get; } = + new Uri("https://upgrade.scdn.co/upgrade/client/win32-x86/spotify_installer-1.1.89.862.g94554d24-13.exe"); + /// + /// Dirección Uri de la última versión de chrome_elf.zip. + /// + private static Uri ChromeElfUri { get; } = + new Uri("https://github.com/mrpond/BlockTheSpot/releases/latest/download/chrome_elf.zip"); + /// + /// Ruta principal de Spotify. + /// + private static string SpotifyDir { get; } = + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Spotify"; + /// + /// Ruta local de Spotify. + /// + private static string SpotifyLocalDir { get; } = + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Spotify"; + + /// + /// Inicio de la aplicación. + /// public BlockTheSpot() { - CheckIfAlreadyLaunched(); + CheckIfAlreadyRunning(); InitializeComponent(); } - // - // Comprueba si BlockTheSpot se encuentra ya en ejecución. - private void CheckIfAlreadyLaunched() + /// + /// Comprueba si el programa ya se encuentra en ejecución, + /// en cuyo caso finaliza la instancia actual. + /// + private void CheckIfAlreadyRunning() { if (Process.GetProcesses().Count(p => p.ProcessName.Equals(Process.GetCurrentProcess().ProcessName)) > 1) { - MessageBox.Show("Ya existe una instancia activa de BlockTheSpot.", "BlockTheSpot", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + MessageBox.Show("BlockTheSpot ya se encuentra en ejecución.", "BlockTheSpot", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); Application.Exit(); } } - // - // Comprueba si el parcheado ya ha sido realizado y, si Spotify versión de escritorio esta instalado. - private void BlockTheSpot_Load(object sender, EventArgs e) + /// + /// Comprueba si el parche ya ha sido aplicado o, + /// si la versión de escritorio de Spotify esta instalada en el equipo, + /// modificando la IGU en consecuencia. + /// + private void SetGuiValues() { if (!DowngradeRequired() && File.Exists($@"{SpotifyDir}\chrome_elf_bak.dll") && @@ -65,8 +96,12 @@ private void BlockTheSpot_Load(object sender, EventArgs e) progressLabel.Visible = false; } - // - // Método accionado por el evento . + /// + /// Método asincrónico accionado por el evento "PatchButton_Click". + ///
+ /// Ejecuta todos los métodos correspondientes al evento desencadenado. + ///
+ /// private async Task PatchButtonMethod() { Cursor = Cursors.Default; @@ -82,16 +117,14 @@ private async Task PatchButtonMethod() await Patch(); DisableAutoUpdate(); - // Si existe un acceso directo a Spotify en el escritorio, eliminalo. + // Elimina el acceso directo a Spotify del escritorio. if (File.Exists($@"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\Spotify.lnk")) File.Delete($@"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\Spotify.lnk"); } catch (Exception ex) { AskUserToGenerateLogs(ref ex); - - // Habilita los botones correspondientes. - BlockTheSpot_Load(this, EventArgs.Empty); + SetGuiValues(); return; } @@ -107,8 +140,15 @@ private async Task PatchButtonMethod() Application.Exit(); } - // - // Desinstala el paquete UWP , si lo hubiera, dado que es incompatible con la metodología de parcheo de BTS. + /// + /// Desinstala el paquete UWP "SpotifyAB.SpotifyMusic", si lo hubiera, + /// dado que es incompatible con la metodología del parche. + /// + /// + /// Excepción, equivalente a AccessDeniedException, lanzada al no poder enumerar + /// todos los paquetes UWP instalados en el grupo de usuarios actual o, + /// cuando la desinstalación no ha sido completada por cualquier motivo. + /// private void UwpPackageRemoval() { outputLabel.Text = "Desinstalando Microsoft Store Spotify ..."; @@ -119,17 +159,17 @@ private void UwpPackageRemoval() var spotifyPkg = pkgManager.FindPackagesForUser(string.Empty).FirstOrDefault( pkg => pkg.Id.Name.Equals("SpotifyAB.SpotifyMusic")); - // El paquete no esta instalado en la cuenta usuario actual. + // El paquete no esta instalado en el grupo de usuarios actual. if (spotifyPkg == null) return; - // Desinstala el paquete de la cuenta usuario actual. + // Desinstala el paquete del grupo de usuarios actual. var removal = pkgManager.RemovePackageAsync(spotifyPkg.Id.FullName); /// RemovalOptions.RemoveForAllUsers // Este evento es señalado cunado la operación finaliza. ManualResetEvent removalEvent = new ManualResetEvent(false); - // Define el delago con un argumento lambda. + // Define al delegado del evento accionado al finalizar la desinstalación, con un argumento lambda. removal.Completed = (depProgress, status) => { removalEvent.Set(); }; // Espera a que la operación finalice. @@ -143,15 +183,21 @@ private void UwpPackageRemoval() } catch (Exception ex) // AccessDeniedException { - // removal.GetResults().ErrorText + /// removal.GetResults().ErrorText throw new UnauthorizedAccessException( "La desintalación del paquete SpotifyAB.SpotifyMusic (Microsoft Store) ha fallado:\n" + "Prueba a ejecutar BlockTheSpot como administrador o realiza la desinstalación manualmente.", ex); } } - // - // Instala o realiza un downgrade a la versión 1.1.89.862.g94554d24-13 de Spotify, - // en la cual se explotará la vulnerabilidad que permite a BTS bloquear sus anuncios. + /// + /// Instala o realiza un downgrade a la versión 1.1.89.862.g94554d24-13 de Spotify, + /// en la cual se explotará la vulnerabilidad que permite a BTS bloquear sus anuncios. + /// + /// + /// Excepción lanzada al producirse un error en la descarga + /// de la versión mencionada. + /// Excepción lanzada al no completar la instalación + /// de la versión mencionada correctamente. private async Task DowngradeClientAsync() { if (!DowngradeRequired()) @@ -194,8 +240,13 @@ private async Task DowngradeClientAsync() if (DowngradeRequired()) throw new FileNotFoundException($"El downgrade de Spotify ha fallado, intentalo de nuevo."); } - // - // Inyecta los archivos chrome_elf.dll y config.ini, encargados de llevar a cabo el bloqueo de anuncios, en el directorio principal de Spotify. + /// + /// Inyecta los archivos chrome_elf.dll y config.ini, + /// encargados de llevar a cabo el bloqueo de anuncios, en el directorio principal de Spotify. + /// + /// + /// Generada al producirse un error en la descarga. + /// Generada al negarse el acceso al directorio SpotifyDir private async Task Patch() { outputLabel.Text = "Parcheando ..."; @@ -230,8 +281,11 @@ private async Task Patch() "Prueba a ejecutar BlockTheSpot como administrador.", ex); } } - // - // Bloquea las actualizaciones automáticas restringiéndo todos los permisos de acceso a la carpeta "%LocalAppData%\Spotify\Update". + /// + /// Bloquea las actualizaciones automáticas restringiéndo todos los permisos de acceso + /// a la carpeta SpotifyLocalDir\Update. + /// + /// private void DisableAutoUpdate() { outputLabel.Text = "Bloqueando actualizaciones automáticas ..."; @@ -257,8 +311,13 @@ private void DisableAutoUpdate() } } - // - // Método accionado por el evento . + /// + /// Método accionado por el evento resetButton_Click(object, EventArgs). + ///
+ /// Ejecuta todos los métodos correspondientes al evento desencadenado. + ///
+ /// + /// private async Task ResetButtonMethod() { Cursor = Cursors.Default; @@ -292,8 +351,11 @@ private async Task ResetButtonMethod() Application.Exit(); } - // - // Elimina los archivos chrome_elf.dll y config.ini, además de restablecer el primero a su versión original. + /// + /// Elimina los archivos chrome_elf.dll y config.ini, además de restablecer el primero a su versión original. + /// + /// Generada al denegarse el acceso a SpotifyDir + /// private void UndoPatch() { outputLabel.Text = "Deshaciendo parcheo ..."; @@ -318,8 +380,11 @@ private void UndoPatch() "Prueba a ejecutar BlockTheSpot como administrador.", ex); } } - // - // Restablece los permisos de acceso obre el directorio "%LocalAppData%\Spotify\Update". + /// + /// Restablece los permisos de acceso sobre el directorio SpotifyLocalDir\Update. + /// + /// + /// private void EnableAutoUpdates() { outputLabel.Text = "Desbloqueando actualizaciones automáticas ..."; @@ -335,8 +400,10 @@ private void EnableAutoUpdates() "Prueba a ejecutar BlockTheSpot como administrador.", ex); } } - // - // Descarga e inicia el instalador de la última versión de Spotify. + /// + /// Descarga e inicia el instalador de la última versión de Spotify. + /// + /// private async Task UpdateClientAsync() { try @@ -370,21 +437,32 @@ private async Task UpdateClientAsync() } } - // - // Cierra todas las instancias de Spotify. + /// + /// Cierra todas las instancias de Spotify. + /// + /// + /// Excepción equivalente a AccessDeniedException. private async Task TerminateSpotifyAsync() { outputLabel.Text = "Finalizando Spotify ..."; - foreach (Process p in Process.GetProcessesByName("Spotify")) - p.Kill(); + try + { + foreach (Process p in Process.GetProcessesByName("Spotify")) + p.Kill(); - while (Process.GetProcessesByName("Spotify").Length > 0) - await Task.Run(() => Thread.Sleep(100)); + while (Process.GetProcessesByName("Spotify").Length > 0) + await Task.Run(() => Thread.Sleep(100)); + } + catch (Exception ex) // AccessDeniedException + { + throw new UnauthorizedAccessException("Acceso denegado, intentalo de nuevo.", ex); + } } - // - // Comprueba si la versión actual de Spotify es superior a la compatible (1.1.89.862). - // Si Spotify no está instalado, devuelve . + /// + /// Compara la versión actual de Spotify con la versión compatible 1.1.89.862.g94554d24-13. + /// + /// Verdadero si es mayor a la compatible, falso si es igual o menor. private bool DowngradeRequired() { bool spotifyIsInstalled = File.Exists($@"{SpotifyDir}\Spotify.exe"); @@ -393,14 +471,16 @@ private bool DowngradeRequired() Version actualVer = (!spotifyIsInstalled) ? null : new Version(FileVersionInfo.GetVersionInfo(SpotifyDir + "\\Spotify.exe").FileVersion); - return (!spotifyIsInstalled || - !chromeElfExists || - actualVer.CompareTo(new Version("1.1.89.862")) > 0) ? true : false; + return !spotifyIsInstalled || !chromeElfExists || actualVer.CompareTo(new Version("1.1.89.862")) > 0; } - // - // Elimina todos los archivos relativos a la versión de escritorio de Spotify, si la hubiera instalada, - // a excepción de los archivos propios de la configuración y caché del usuario, - // permitiendo realizar una instalación limpia de Spotify sin perder la información del usuario. + /// + /// Elimina todos los archivos relativos a la versión de escritorio de Spotify, si la hubiera instalada, + /// a excepción de los archivos propios de la configuración y caché del usuario, + /// permitiendo realizar una instalación limpia de Spotify sin perder la información del usuario. + /// + /// Directorio padre a inspeccionar/limpiar. + /// Sub-directorios a omitir. + /// Archivos a omitir. private void ClearSpotifyDirs(string targetDir, List dirNamesToSkip, List fileNamesToSkip) { List availableDirs = new List() { targetDir }; @@ -416,14 +496,23 @@ private void ClearSpotifyDirs(string targetDir, List dirNamesToSkip, Lis foreach (string file in availableFiles) File.Delete(file); } - // - // Realiza una descarga asincrónica mostrando el progreso en una barra de progreso. + /// + /// Realiza una descarga asincrónica delegando el evento de progreso al método progressBar_ProgressChanged. + /// + /// Uri a descargar. + /// Nombre del archivo a descargar. + /// + /// private async Task DownloadAsync(Uri uri, string fileName) { WebClient webClient = new WebClient(); - webClient.DownloadProgressChanged += (sender, e) => progressBar_UpdateProgress(e.ProgressPercentage, e.BytesReceived == e.TotalBytesToReceive); + webClient.DownloadProgressChanged += (sender, e) => DownloadProgressChanged(e.ProgressPercentage); + webClient.DownloadFileCompleted += (sender, e) => DownloadCompleted(); + // Prepara la IGU para la mostrar el progreso de la descarga. this.outputLabel.Text = $"Descargando {fileName} ..."; + this.progressBar.Visible = true; + this.progressLabel.Visible = true; this.toolTip.SetToolTip(this.outputLabel, this.outputLabel.Text); // Realiza una descarga asincrónica del pasado por parámetro. @@ -432,9 +521,33 @@ private async Task DownloadAsync(Uri uri, string fileName) // Libera los recursos utilizados tras finalizar la descarga. webClient.Dispose(); } - // - // Maneja el control de acceso para el directorio "Update" de Spotify, - // permitiéndo o negando los permisos de escritura y eliminación. + /// + /// Método accionado cuando el progreso de la descarga cambia. + ///
+ /// Manipula la IGU en consecuencia. + ///
+ /// Porcentaje del progreso de descarga. + private void DownloadProgressChanged(int progress) + { + this.progressBar.Value = progress; + this.progressLabel.Text = progress + "%"; + } + /// + /// Método accionado cuando la descarga finaliza. + ///
+ /// Manipula la IGU en consecuencia. + ///
+ private void DownloadCompleted() + { + this.progressBar.Visible = false; + this.progressLabel.Visible = false; + this.toolTip.SetToolTip(this.outputLabel, ""); + } + /// + /// Maneja el control de acceso para el directorio "Update" de Spotify, + /// permitiéndo o negando los permisos de escritura y eliminación. + /// + /// Tipo de acceso a implementar (permitir/denegar). private void FileSecurity(AccessControlType controlType) { string dir = $@"{SpotifyLocalDir}\Update"; @@ -453,9 +566,11 @@ private void FileSecurity(AccessControlType controlType) Directory.SetAccessControl(dir, dirSecurity); } - // - // Informa al usuario del mensaje de la excepción generada y le consulta - // si desea generar "logs" y subirlos al repositorio en GitHub. + /// + /// Informa al usuario del mensaje de la excepción generada y le consulta + /// si desea generar "logs" y subirlos al repositorio en GitHub. + /// + /// Excepción capturada. private void AskUserToGenerateLogs(ref Exception ex) { // Consulta al usuario si desea subir estos logs al repositorio de GitHub para investigar el error. @@ -478,33 +593,55 @@ private void AskUserToGenerateLogs(ref Exception ex) File.WriteAllText(Path.GetTempPath() + "blockthespot_log.txt", stackTraces); // Abre el repositorio en GitHub y la carpeta de archivos temporales. - Process.Start(RepositoryUrl + @"/issues/new"); + Process.Start(RepositoryUri + @"/issues/new"); Process.Start(Path.GetTempPath()); Application.Exit(); } - private async void patchButton_Click(object sender, EventArgs args) => await PatchButtonMethod(); - private async void resetButton_Click(object sender, EventArgs args) => await ResetButtonMethod(); - private void progressBar_UpdateProgress(int progress, bool completed) - { - this.progressBar.Visible = completed ? false : true; - this.progressLabel.Visible = completed ? false : true; - this.progressBar.Value = progress; - this.progressLabel.Text = progress + "%"; - - if (completed) - this.toolTip.SetToolTip(this.outputLabel, ""); - } - private void BlockTheSpot_HelpButtonClicked(object sender, EventArgs args) => Process.Start(RepositoryUrl); + /// + /// Evento desencadenado al cargar la IGU. + /// + /// Objeto que desencadena el evento. + /// Argumentos asociados al evento. + private void BlockTheSpot_Load(object sender, EventArgs e) => SetGuiValues(); + /// + /// Evento desencadenado al hacer clic en el botón "patchButton". + /// + /// Objeto que desencadena el evento. + /// Argumentos asociados al evento. + private async void PatchButton_Click(object sender, EventArgs args) => await PatchButtonMethod(); + /// + /// Evento desencadenado al hacer clic en el botón "resetButton". + /// + /// Objeto que desencadena el evento. + /// Argumentos asociados al evento. + private async void ResetButton_Click(object sender, EventArgs args) => await ResetButtonMethod(); + /// + /// Evento desencadenado al hacer clic en el botón "HelpButton". + /// + /// Objeto que desencadena el evento. + /// Argumentos asociados al evento. + private void BlockTheSpot_HelpButtonClicked(object sender, EventArgs args) => Process.Start(RepositoryUri.ToString()); + /// + /// Evento desencadenado al cerrar la IGU. + ///
+ /// Comprueba si el cierre ha sido solicitado por el usuario mientras + /// el programa se encontraba en ejecución y, + /// confirma la solicitud con un cuadro diálogo. + ///
+ /// Objeto que desencadena el evento. + /// Argumentos asociados al evento. private void BlockTheSpot_FormClosing(object sender, FormClosingEventArgs close) { // Si el usuario trata de cerrar BlockTheSpot mientras se encuentra en medio de la ejecución, // confirmar la solicitud de cierre. - if (close.CloseReason == CloseReason.UserClosing && patchButton.Enabled == false && resetButton.Enabled == false) + if (close.CloseReason == CloseReason.UserClosing && !patchButton.Enabled && !resetButton.Enabled) { - DialogResult exitMessage = MessageBox.Show(this, "BlockTheSpot no ha terminado su trabajo, ¿Deseas cerrar la aplicación de todas formas?", "BlockTheSpot", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); + DialogResult exitMessage = MessageBox.Show(this, "BlockTheSpot no ha terminado su trabajo, " + + "¿Deseas cerrar la aplicación de todas formas?", "BlockTheSpot", + MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); if (exitMessage == DialogResult.No) close.Cancel = true;