Преглед изворни кода

Bug-fixing new update verification

Antony Male пре 10 година
родитељ
комит
19eece8030

+ 21 - 5
server/version_check.php

@@ -65,19 +65,21 @@ function get_with_wildcard($src, $value, $default = null)
 }
 
 $versions = [
-   '1.0.22' => [
+   '1.0.23' => [
       'installed' => [
          'direct_download_url' => [
-            'x64' => 'https://github.com/canton7/SyncTrayzor/releases/download/v1.0.22/SyncTrayzorSetup-x64.exe',
-            'x86' => 'https://github.com/canton7/SyncTrayzor/releases/download/v1.0.22/SyncTrayzorSetup-x86.exe',
+            'x64' => 'https://github.com/canton7/SyncTrayzor/releases/download/v1.0.23/SyncTrayzorSetup-x64.exe',
+            'x86' => 'https://github.com/canton7/SyncTrayzor/releases/download/v1.0.23/SyncTrayzorSetup-x86.exe',
          ],
       ],
-      'release_page_url' => 'https://github.com/canton7/SyncTrayzor/releases/tag/v1.0.22',
+      'sha1sum_download_url' => 'https://github.com/canton7/SyncTrayzor/releases/download/v1.0.23/sha1sum.txt.asc',
+      'release_page_url' => 'https://github.com/canton7/SyncTrayzor/releases/tag/v1.0.23',
       'release_notes' => "- Improvements to the \"File Transfers\" view (single-click tray icon)\n- Better error message handling (#93, #96)\n- Update translations",
    ]
 ];
 
 $upgrades = [
+   '1.0.22' => ['to' => 'latest', 'formatter' => '3'],
    '1.0.21' => ['to' => 'latest', 'formatter' => '2'],
    '1.0.20' => ['to' => 'latest', 'formatter' => '2'],
    // 1.0.19 was never actually released, so no need to represent it
@@ -103,7 +105,7 @@ $response_formatters = [
 
       return $data;
    },
-   // For when everything's working....
+   // Prior to sha1sum_download_url
    '2' => function($arch, $variant, $to_version, $to_version_info, $overrides)
    {
       $variant_info = isset($overrides[$variant]) ? get_with_wildcard($overrides, $variant) : get_with_wildcard($to_version_info, $variant);
@@ -115,6 +117,20 @@ $response_formatters = [
          'release_notes' => isset($overrides['release_notes']) ? $overrides['release_notes'] : $to_version_info['release_notes'],
       ];
 
+      return $data;
+   },
+   '3' => function($arch, $variant, $to_version, $to_version_info, $overrides)
+   {
+      $variant_info = isset($overrides[$variant]) ? get_with_wildcard($overrides, $variant) : get_with_wildcard($to_version_info, $variant);
+
+      $data = [
+         'version' => $to_version,
+         'direct_download_url' => get_with_wildcard($variant_info['direct_download_url'], $arch),
+         'sha1sum_download_url' => $to_version_info['sha1sum_download_url'],
+         'release_page_url' => $to_version_info['release_page_url'],
+         'release_notes' => isset($overrides['release_notes']) ? $overrides['release_notes'] : $to_version_info['release_notes'],
+      ];
+
       return $data;
    },
 ];

+ 2 - 2
src/SyncTrayzor/Services/UpdateManagement/InstalledUpdateVariantHandler.cs

@@ -32,9 +32,9 @@ namespace SyncTrayzor.Services.UpdateManagement
 
         public async Task<bool> TryHandleUpdateAvailableAsync(VersionCheckResults checkResult)
         {
-            if (!String.IsNullOrWhiteSpace(checkResult.DownloadUrl))
+            if (!String.IsNullOrWhiteSpace(checkResult.DownloadUrl) && !String.IsNullOrWhiteSpace(checkResult.Sha1sumDownloadUrl))
             {
-                this.installerPath = await this.updateDownloader.DownloadUpdateAsync(checkResult.DownloadUrl, checkResult.NewVersion);
+                this.installerPath = await this.updateDownloader.DownloadUpdateAsync(checkResult.DownloadUrl, checkResult.Sha1sumDownloadUrl, checkResult.NewVersion);
                 this.CanAutoInstall = true;
 
                 // If we return false, the upgrade will be aborted

+ 11 - 3
src/SyncTrayzor/Services/UpdateManagement/InstallerCertificateVerifier.cs

@@ -14,7 +14,7 @@ namespace SyncTrayzor.Services.UpdateManagement
     public interface IInstallerCertificateVerifier
     {
         bool VerifySha1sum(string filePath, out Stream cleartext);
-        bool VerifyUpdate(string filePath, Stream sha1sumFile);
+        bool VerifyUpdate(string filePath, Stream sha1sumFile, string originalFileName);
     }
 
     public class InstallerCertificateVerifier : IInstallerCertificateVerifier
@@ -45,12 +45,20 @@ namespace SyncTrayzor.Services.UpdateManagement
             }
         }
 
-        public bool VerifyUpdate(string filePath, Stream sha1sumFile)
+        public bool VerifyUpdate(string filePath, Stream sha1sumFile, string originalFileName)
         {
             using (var hashAlgorithm = new SHA1Managed())
             using (var file = this.filesystemProvider.OpenRead(filePath))
             {
-                return ChecksumFileUtilities.ValidateChecksum(hashAlgorithm, sha1sumFile, Path.GetFileName(filePath), file);
+                try
+                {
+                    return ChecksumFileUtilities.ValidateChecksum(hashAlgorithm, sha1sumFile, originalFileName, file);
+                }
+                catch (ArgumentException)
+                {
+                    logger.Warn("Could not find checksum for file {0}", originalFileName);
+                    return false;
+                }
             }
         }
     }

+ 1 - 1
src/SyncTrayzor/Services/UpdateManagement/UpdateChecker.cs

@@ -36,7 +36,7 @@ namespace SyncTrayzor.Services.UpdateManagement
 
         public override string ToString()
         {
-            return String.Format("<VersionCheckResults NewVersion={0} DownloadUrl={1} Sha1sumDownloadUrl={2} ReleaseNotes={3} ReleasePageUrl=43}>",
+            return String.Format("<VersionCheckResults NewVersion={0} DownloadUrl={1} Sha1sumDownloadUrl={2} ReleaseNotes={3} ReleasePageUrl={4}>",
                 this.NewVersion, this.DownloadUrl, this.Sha1sumDownloadUrl, this.ReleaseNotes, this.ReleasePageUrl);
         }
     }

+ 8 - 5
src/SyncTrayzor/Services/UpdateManagement/UpdateDownloader.cs

@@ -14,7 +14,7 @@ namespace SyncTrayzor.Services.UpdateManagement
 {
     public interface IUpdateDownloader
     {
-        Task<string> DownloadUpdateAsync(string url, Version version);
+        Task<string> DownloadUpdateAsync(string updateUrl, string sha1sumUrl, Version version);
     }
 
     public class UpdateDownloader : IUpdateDownloader
@@ -36,12 +36,12 @@ namespace SyncTrayzor.Services.UpdateManagement
             this.installerVerifier = installerVerifier;
         }
 
-        public async Task<string> DownloadUpdateAsync(string url, Version version)
+        public async Task<string> DownloadUpdateAsync(string updateUrl, string sha1sumUrl, Version version)
         {
             var sha1sumDownloadPath = Path.Combine(this.downloadsDir, String.Format(sham1sumDownloadFileName, version.ToString(3)));
             var updateDownloadPath = Path.Combine(this.downloadsDir, String.Format(updateDownloadFileName, version.ToString(3)));
 
-            var sha1sumOutcome = await this.DownloadAndVerifyFileAsync<Stream>(url, version, sha1sumDownloadPath, () =>
+            var sha1sumOutcome = await this.DownloadAndVerifyFileAsync<Stream>(sha1sumUrl, version, sha1sumDownloadPath, () =>
                 {
                     Stream sha1sumContents;
                     var passed = this.installerVerifier.VerifySha1sum(sha1sumDownloadPath, out sha1sumContents);
@@ -54,9 +54,12 @@ namespace SyncTrayzor.Services.UpdateManagement
             {
                 if (sha1sumOutcome.Item1)
                 {
-                    updateSucceeded = (await this.DownloadAndVerifyFileAsync<object>(url, version, updateDownloadPath, () =>
+                    updateSucceeded = (await this.DownloadAndVerifyFileAsync<object>(updateUrl, version, updateDownloadPath, () =>
                     {
-                        var updatePassed = this.installerVerifier.VerifyUpdate(updateDownloadPath, sha1sumOutcome.Item2);
+                        var updateUri = new Uri(updateUrl);
+                        // Make sure this is rewound - we might read from it multiple times
+                        sha1sumOutcome.Item2.Position = 0;
+                        var updatePassed = this.installerVerifier.VerifyUpdate(updateDownloadPath, sha1sumOutcome.Item2, updateUri.Segments.Last());
                         return Tuple.Create(updatePassed, (object)null);
                     })).Item1;
                 }

+ 2 - 2
src/SyncTrayzor/SyncTrayzor.csproj

@@ -352,9 +352,9 @@
     <Compile Include="Properties\AssemblyInfo.cs">
       <SubType>Code</SubType>
     </Compile>
-    <None Include="..\..\security\synctrayzor_releases_cert.asc">
+    <EmbeddedResource Include="..\..\security\synctrayzor_releases_cert.asc">
       <Link>Resources\synctrayzor_releases_cert.asc</Link>
-    </None>
+    </EmbeddedResource>
     <None Include="packages.config" />
     <None Include="Properties\Settings.settings">
       <Generator>SettingsSingleFileGenerator</Generator>

+ 43 - 33
src/SyncTrayzor/Utils/PgpClearsignUtilities.cs

@@ -72,52 +72,62 @@ namespace SyncTrayzor.Utils
 
         public static bool ReadAndVerifyFile(Stream inputStream, Stream keyIn, out Stream cleartextOut)
         {
-            // Disposing this will close the underlying stream, which we don't want to do
-            var armouredInputStream = new ArmoredInputStream(inputStream);
+            // Count any exception as BouncyCastle failing to parse something, because of corruption maybe?
+            try
+            {
 
-            // This stream is returned, so is not disposed
-            var cleartextStream = new MemoryStream();
+                // Disposing this will close the underlying stream, which we don't want to do
+                var armouredInputStream = new ArmoredInputStream(inputStream);
 
-            int chr;
+                // This stream is returned, so is not disposed
+                var cleartextStream = new MemoryStream();
 
-            while ((chr = armouredInputStream.ReadByte()) >= 0 && armouredInputStream.IsClearText())
-            {
-                cleartextStream.WriteByte((byte)chr);
-            }
+                int chr;
+
+                while ((chr = armouredInputStream.ReadByte()) >= 0 && armouredInputStream.IsClearText())
+                {
+                    cleartextStream.WriteByte((byte)chr);
+                }
+
+                // Strip the trailing newline if set...
+                cleartextStream.Position = Math.Max(0, cleartextStream.Position - 2);
+                int count = 0;
+                if (cleartextStream.ReadByte() == '\r')
+                    count++;
+                if (cleartextStream.ReadByte() == '\n')
+                    count++;
+                cleartextStream.SetLength(cleartextStream.Length - count);
 
-            // Strip the trailing newline if set...
-            cleartextStream.Seek(-2, SeekOrigin.End);
-            int count = 0;
-            if (cleartextStream.ReadByte() == '\r')
-                count++;
-            if (cleartextStream.ReadByte() == '\n')
-                count++;
-            cleartextStream.SetLength(cleartextStream.Length - count);
+                cleartextStream.Position = 0;
 
-            cleartextStream.Position = 0;
+                // This will either return inputStream, or a new ArmouredStream(inputStream)
+                // Either way, disposing it will close the underlying stream, which we don't want to do
+                var decoderStream = PgpUtilities.GetDecoderStream(inputStream);
 
-            // This will either return inputStream, or a new ArmouredStream(inputStream)
-            // Either way, disposing it will close the underlying stream, which we don't want to do
-            var decoderStream = PgpUtilities.GetDecoderStream(inputStream);
+                var pgpObjectFactory = new PgpObjectFactory(decoderStream);
 
-            var pgpObjectFactory = new PgpObjectFactory(decoderStream);
+                var signatureList = (PgpSignatureList)pgpObjectFactory.NextPgpObject();
+                var signature = signatureList[0];
 
-            var signatureList = (PgpSignatureList)pgpObjectFactory.NextPgpObject();
-            var signature = signatureList[0];
+                var publicKeyRing = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(keyIn));
+                var publicKey = publicKeyRing.GetPublicKey(signature.KeyId);
 
-            var publicKeyRing = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(keyIn));
-            var publicKey = publicKeyRing.GetPublicKey(signature.KeyId);
+                signature.InitVerify(publicKey);
 
-            signature.InitVerify(publicKey);
+                while ((chr = cleartextStream.ReadByte()) > 0)
+                {
+                    signature.Update((byte)chr);
+                }
+                cleartextStream.Position = 0;
 
-            while ((chr = cleartextStream.ReadByte()) > 0)
+                cleartextOut = cleartextStream;
+                return signature.Verify();
+            }
+            catch
             {
-                signature.Update((byte)chr);
+                cleartextOut = null;
+                return false;
             }
-            cleartextStream.Position = 0;
-
-            cleartextOut = cleartextStream;
-            return signature.Verify();
         }
     }
 }