/// <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); }
public override void Insert(T instance, ResponseHandler callback) { string serializedObj = Serializer.Serialize <T>(instance); MimePart mimePart = new MimePart(MimePart.ApplicationXml, serializedObj); httpClient.Post(CreateUri, DefaultRetryCount, mimePart, (postResult) => { List <T> responseInstance = null; string error = null; try { using (HttpResult httpResult = postResult.AsyncState as HttpResult) { // Check server response if (CheckServerResult(httpResult, ref error)) { string responseObj = httpResult.Response; if (!string.IsNullOrEmpty(responseObj)) { RestResponse response = Serializer.Deserialize <R>(responseObj) as RestResponse; responseInstance = response.ToList <T>(); error = response.Error; } else { error = "Empty response for: " + UpdateUri.ToString(); } } } } catch (Exception e) { error = "Unable to upload data to the cloud. " + e.Message; } finally { if (!String.IsNullOrEmpty(error)) { DebugLog.Error(error); } if (callback != null) { callback(new Response(responseInstance, error)); } } }); }
public void Write(Stream stream) { EnsureState(); XmlDocument doc = new XmlDocument(); XmlElement root = doc.CreateElement("package"); PackageItem.AddAttribute(root, "id", Id); PackageItem.AddAttribute(root, "name", Name); if (Condition != null) { PackageItem.AddAttribute(root, "condition", Condition.ToString()); } PackageItem.AddAttribute(root, "version", Version.ToString()); PackageItem.AddAttribute(root, "attribution", Attribution); if (Website != null) { PackageItem.AddAttribute(root, "website", Website.ToString()); } if (UpdateUri != null) { PackageItem.AddAttribute(root, "updateUri", UpdateUri.ToString()); } if (FeedbackUri != null) { PackageItem.AddAttribute(root, "feedbackUri", FeedbackUri.ToString()); } doc.AppendChild(root); RootGroup.Write(root); XmlWriterSettings settings = new XmlWriterSettings(); settings.ConformanceLevel = ConformanceLevel.Document; settings.Encoding = Encoding.UTF8; settings.Indent = true; settings.IndentChars = "\t"; XmlWriter wtr = XmlWriter.Create(stream, settings); doc.WriteTo(wtr); wtr.Flush(); }
/// <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); } }