From 39613ae76e39b5a8ddaae50aa5d5665796acc726 Mon Sep 17 00:00:00 2001 From: sr55 Date: Sat, 12 Mar 2016 16:19:53 +0000 Subject: WinGui: Add SHA1 Verification of the update downloads and don't start the installer if the hash check fails. --- .../HandBrakeWPF/Model/UpdateCheckInformation.cs | 5 +++ .../Services/Interfaces/IUpdateService.cs | 5 ++- win/CS/HandBrakeWPF/Services/UpdateService.cs | 40 ++++++++++++++++++---- win/CS/HandBrakeWPF/Utilities/AppcastReader.cs | 6 ++++ win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs | 11 +++--- 5 files changed, 56 insertions(+), 11 deletions(-) (limited to 'win/CS/HandBrakeWPF') diff --git a/win/CS/HandBrakeWPF/Model/UpdateCheckInformation.cs b/win/CS/HandBrakeWPF/Model/UpdateCheckInformation.cs index bc49a2ee3..61c2bd36e 100644 --- a/win/CS/HandBrakeWPF/Model/UpdateCheckInformation.cs +++ b/win/CS/HandBrakeWPF/Model/UpdateCheckInformation.cs @@ -53,5 +53,10 @@ namespace HandBrakeWPF.Model /// Gets or sets the error that occurred, if any. This will be null if no error occured. /// public Exception Error { get; set; } + + /// + /// Gets or sets the expected sh a 1 hash. + /// + public string ExpectedSHA1Hash { get; set; } } } diff --git a/win/CS/HandBrakeWPF/Services/Interfaces/IUpdateService.cs b/win/CS/HandBrakeWPF/Services/Interfaces/IUpdateService.cs index cd1b50e9f..571d5c931 100644 --- a/win/CS/HandBrakeWPF/Services/Interfaces/IUpdateService.cs +++ b/win/CS/HandBrakeWPF/Services/Interfaces/IUpdateService.cs @@ -40,12 +40,15 @@ namespace HandBrakeWPF.Services.Interfaces /// /// The url. /// + /// + /// The expected SHA-1 Hash. + /// /// /// The complete. /// /// /// The progress. /// - void DownloadFile(string url, Action completed, Action progress); + void DownloadFile(string url, string expectedSHA1Hash, Action completed, Action progress); } } diff --git a/win/CS/HandBrakeWPF/Services/UpdateService.cs b/win/CS/HandBrakeWPF/Services/UpdateService.cs index f49836b6a..732193ac4 100644 --- a/win/CS/HandBrakeWPF/Services/UpdateService.cs +++ b/win/CS/HandBrakeWPF/Services/UpdateService.cs @@ -12,6 +12,8 @@ namespace HandBrakeWPF.Services using System; using System.IO; using System.Net; + using System.Security.Cryptography; + using System.Text; using System.Threading; using HandBrake.ApplicationServices.Utilities; @@ -125,6 +127,7 @@ namespace HandBrakeWPF.Services DownloadFile = reader.DownloadFile, Build = reader.Build, Version = reader.Version, + ExpectedSHA1Hash = reader.Hash }; callback(info2); @@ -142,13 +145,16 @@ namespace HandBrakeWPF.Services /// /// The url. /// + /// + /// The expected Sha 1 Hash. + /// /// /// The complete. /// /// /// The progress. /// - public void DownloadFile(string url, Action completed, Action progress) + public void DownloadFile(string url, string expectedSha1Hash, Action completed, Action progress) { ThreadPool.QueueUserWorkItem( delegate @@ -172,11 +178,9 @@ namespace HandBrakeWPF.Services int bytesSize; byte[] downBuffer = new byte[2048]; - long flength = 0; while ((bytesSize = responceStream.Read(downBuffer, 0, downBuffer.Length)) > 0) { localStream.Write(downBuffer, 0, bytesSize); - flength = localStream.Length; progress(new DownloadStatus { BytesRead = localStream.Length, TotalBytes = fileSize}); } @@ -184,21 +188,45 @@ namespace HandBrakeWPF.Services localStream.Close(); completed( - flength != fileSize + GetSHA1(tempPath) != expectedSha1Hash ? new DownloadStatus { WasSuccessful = false, - Message = "Partial Download. File is Incomplete. Please Retry the download." + Message = "Download Failed. SHA1 Checksum Failed. Please visit the website to download this update." } : new DownloadStatus { WasSuccessful = true, Message = "Download Complete." }); } catch (Exception exc) { - progress(new DownloadStatus { WasSuccessful = false, Exception = exc, Message = "Download Failed." }); + progress(new DownloadStatus { WasSuccessful = false, Exception = exc, Message = "Download Failed. Please visit the website to download this update." }); } }); } + /// + /// The get sh a 1. + /// + /// + /// The file name. + /// + /// + /// The . + /// + public static String GetSHA1(String fileName) + { + FileStream file = new FileStream(fileName, FileMode.Open); + SHA1 sha1 = new SHA1CryptoServiceProvider(); + byte[] retVal = sha1.ComputeHash(file); + file.Close(); + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < retVal.Length; i++) + { + sb.Append(retVal[i].ToString("x2")); + } + return sb.ToString(); + } + #endregion } } \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Utilities/AppcastReader.cs b/win/CS/HandBrakeWPF/Utilities/AppcastReader.cs index 49d7f4714..b534ee8c6 100644 --- a/win/CS/HandBrakeWPF/Utilities/AppcastReader.cs +++ b/win/CS/HandBrakeWPF/Utilities/AppcastReader.cs @@ -39,6 +39,11 @@ namespace HandBrakeWPF.Utilities /// public string DownloadFile { get; private set; } + /// + /// Gets the hash for verifying the download completed correctly. + /// + public string Hash { get; private set; } + /// /// Get the build information from the required appcasts. Run before accessing the public vars. /// @@ -61,6 +66,7 @@ namespace HandBrakeWPF.Utilities this.Version = verShort.ToString().Replace("sparkle:shortVersionString=", string.Empty).Replace( "\"", string.Empty); this.DownloadFile = nodeItem["windows"].InnerText; + this.Hash = nodeItem["windowsHash"].InnerText; this.DescriptionUrl = new Uri(nodeItem["sparkle:releaseNotesLink"].InnerText); } catch (Exception) diff --git a/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs index 3176070d0..69df5a635 100644 --- a/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs @@ -1124,7 +1124,7 @@ namespace HandBrakeWPF.ViewModels public void DownloadUpdate() { this.UpdateMessage = "Preparing for Update ..."; - this.updateService.DownloadFile(this.updateInfo.DownloadFile, this.DownloadComplete, this.DownloadProgress); + this.updateService.DownloadFile(this.updateInfo.DownloadFile, this.updateInfo.ExpectedSHA1Hash, this.DownloadComplete, this.DownloadProgress); } /// @@ -1412,10 +1412,13 @@ namespace HandBrakeWPF.ViewModels private void DownloadComplete(DownloadStatus info) { this.UpdateAvailable = false; - this.UpdateMessage = info.WasSuccessful ? Resources.OptionsViewModel_UpdateDownloaded : Resources.OptionsViewModel_UpdateFailed; + this.UpdateMessage = info.WasSuccessful ? Resources.OptionsViewModel_UpdateDownloaded : info.Message; - Process.Start(Path.Combine(Path.GetTempPath(), "handbrake-setup.exe")); - Execute.OnUIThread(() => Application.Current.Shutdown()); + if (info.WasSuccessful) + { + Process.Start(Path.Combine(Path.GetTempPath(), "handbrake-setup.exe")); + Execute.OnUIThread(() => Application.Current.Shutdown()); + } } /// -- cgit v1.2.3