예제 #1
0
        /// <summary>
        /// Downloads all new files and replaces old files in directory.
        /// </summary>
        /// <param name="info">Update information generated by <c>FetchUpdateInfoAsync</c></param>
        /// <returns>True on success, false on failure.</returns>
        /// <exception cref="KangarupException">On a file checksum error.</exception>
        public async Task <bool> UpdateNewFilesAsync(UpdateInfo info)
        {
            if (UpdateUri == null)
            {
                throw new ArgumentNullException("UpdateUri cannot be null");
            }

            var httpClient = new HttpClient();
            var tempPath   = Path.GetTempPath();
            var tempFolder = Directory.CreateDirectory(Path.Combine(tempPath, TempFolderName));

            foreach (var infoFile in info.Files)
            {
                var downloadStream = await httpClient.GetStreamAsync(UpdateUri.Append(infoFile.RelativeUrl)).ConfigureAwait(false);

                var fileToReplace = Path.GetFileName(infoFile.RelativeUrl);

                try
                {
                    // download file
                    var tmpFile = Path.GetTempFileName();
                    using (var fileStream = File.Create(tmpFile))
                    {
                        await downloadStream.CopyToAsync(fileStream).ConfigureAwait(false);
                    }

                    // verify file
                    var sha256 = SHA256.Create();
                    using (var inputStream = File.OpenRead(tmpFile))
                    {
                        var hash    = sha256.ComputeHash(inputStream);
                        var hashHex = BitConverter.ToString(hash).Replace("-", string.Empty);
                        if (infoFile.Checksum != hashHex)
                        {
                            // checksum wrong
                            throw new KangarupException($"Checksum mismatch of file '{fileToReplace}'.");
                        }
                    }

                    // place file
                    File.Move(fileToReplace, Path.Combine(tempFolder.FullName, $"{fileToReplace}"));
                    File.Move(tmpFile, fileToReplace);
                }
                catch (IOException e)
                {
                    Logger?.Error($"Unable to update file '{fileToReplace}': {e.Message}", e);
                    return(false);
                }

                //File.Delete($"{fileToReplace}.old"); // TODO not possible on running application
            }

            return(true);
        }
예제 #2
0
        /// <summary>
        /// Retrieves latest update information from server and verifies cryptographic signature.
        /// </summary>
        /// <exception cref="KangarupException">Cryptographic signature does not match update manifest</exception>
        /// <exception cref="ArgumentNullException">UpdateUri is null</exception>
        /// <returns>Latest update information.</returns>
        public async Task <UpdateInfo> FetchUpdateInfoAsync()
        {
            if (UpdateUri == null)
            {
                throw new ArgumentNullException("UpdateUri cannot be null");
            }

            if (_rsa == null)
            {
                LoadCertificate();
            }

            // download update manifest
            var httpClient = new HttpClient();

            try
            {
                var rawUpdateInfo =
                    await httpClient.GetByteArrayAsync(
                        UpdateUri.Append("update.yml"));

                // download update manifest signature
                var signature = await httpClient.GetByteArrayAsync(UpdateUri.Append("update.sig"));

                // verify manifest
                if (!_rsa.VerifyData(rawUpdateInfo, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
                {
                    throw new KangarupException("Update manifest signature is wrong.");
                }

                // construct UpdateInfo object from data
                var deserializer = new Deserializer();
                return(deserializer.Deserialize <UpdateInfo>(Encoding.UTF8.GetString(rawUpdateInfo)));
            }
            catch (HttpRequestException e)
            {
                Logger?.Error("Unable to contact update server.", e);
                return(null);
            }
        }