private async void OpenFileClicked(object sender, RoutedEventArgs e) { if (sender is Button btn) { if (btn.CommandParameter is string token) { DatabaseHelper.Files f = new DatabaseHelper.Files(); try { f = await SharedStuff.Database.Table <DatabaseHelper.Files>() .Where(file => file.Token == token).FirstAsync(); if (string.IsNullOrEmpty(f.Location)) { throw new InvalidOperationException(); } if (f.Location == " ") // null means the file is not downloaded. ' ' means it does not exists { throw new FileNotFoundException(); } if (File.Exists(f.Location)) // check if the downloaded file exists { System.Diagnostics.Process.Start(f.Location); } else { await SharedStuff.Database.ExecuteAsync( "UPDATE Files SET Location = ? WHERE Token = ?" , " ", token); throw new FileNotFoundException(); } } catch (FileNotFoundException) { // at first check if server has the file var err = new ErrorDialogSample { ErrorText = { Text = "This file does not exists on your computer. Ask other user to send this file again." }, ErrorTitle = { Text = "Cannot Open File" } }; await DialogHost.Show(err, "ChatDialogHost" + Username); } catch (InvalidOperationException) // this token does not exists in database { // download this file await Application.Current.Dispatcher.Invoke(async delegate { ProgressBar bar = ((StackPanel)((DockPanel)((Button)sender).Parent).Parent) .Children[1] as ProgressBar; try { string downloadFileUrl = $"https://{Properties.Settings.Default.ServerAddress}/download?token={token}"; // token does not contain special characters so we are good string destinationFilePath = Path.GetTempFileName(); using (var client = new HttpClientDownloadWithProgress(downloadFileUrl, destinationFilePath)) { client.ProgressChanged += (totalFileSize, totalBytesDownloaded, progressPercentage) => { bar.Value = progressPercentage ?? 0; }; await client.StartDownload(); } // get the key string key = (await SharedStuff.Database.Table <DatabaseHelper.Users>() .Where(user => user.Username == Username).FirstAsync()).Key; BouncyCastleHelper.AesGcmDecrypt(new FileInfo(destinationFilePath), new FileInfo(Path.Combine(SharedStuff.DownloadPath, f.Name)), key); await SharedStuff.Database.ExecuteAsync( "UPDATE Files SET Location = ? WHERE Token = ?" , Path.Combine(SharedStuff.DownloadPath, f.Name), token); } catch (FileNotFoundException) // This error means that the files does not exists on server. (it's too old) { await SharedStuff.Database.ExecuteAsync( "UPDATE Files SET Location = ? WHERE Token = ?" , " ", token); // this will make the File.Exists always return false MessagesList.First(msg => msg.Token == token).DownloadButtonIcon = PackIconKind.DownloadOff; var err = new ErrorDialogSample { ErrorText = { Text = "This file is too old and could not be downloaded. Ask other user to send this file again." }, ErrorTitle = { Text = "Cannot Download File" } }; await DialogHost.Show(err, "ChatDialogHost" + Username); } catch (Exception ex) { var err = new ErrorDialogSample { ErrorText = { Text = ex.Message }, ErrorTitle = { Text = "Cannot Download File" } }; await DialogHost.Show(err, "ChatDialogHost" + Username); } finally { bar.Value = 101; } }); } } } }
private async void WS_OnMessage(object sender, MessageEventArgs e) { // at first try to parse the message as Server status. try { var status = JsonConvert.DeserializeObject <JsonTypes.MessageStatus>(e.Data); if (status.Id != null) // a real message status { if (!status.Ok) { Console.WriteLine("Error on message " + status.Id + ": " + status.Message); } if (status.Message != "sent") // this is a file token update { SharedStuff.PendingMessages[status.Id].Token = status.Message; // now start upload SharedStuff.UploadFile(status.Id); } else { SharedStuff.PendingMessages[status.Id].Sent = status.Ok ? (byte)0 : (byte)2; // Do not remove files from here; They are removed at "finally" block of SharedStuff.UploadFile if (SharedStuff.PendingMessages[status.Id].Type != 1) { SharedStuff.PendingMessages.Remove(status.Id); } } return; } if (status.Message != null && !status.Ok) { // TODO: HANDLE THIS SHIT return; } } catch (Exception) { // ignored : the type might be something else } // try ClientUpdateTypeStruct await _mu.WaitAsync(); // get the data in order that server sends them string nameSafe = ""; try { var msg = JsonConvert.DeserializeObject <JsonTypes.Updates>(e.Data); var keyList = await SharedStuff.Database.Table <DatabaseHelper.Users>().Where(k => k.Username == msg.Payload.From) .ToArrayAsync(); // get the key of the user string key; if (keyList.Length == 0) // Key agreement { var data = await SharedStuff.GetUserData(msg.Payload.From); key = Convert.ToBase64String(SharedStuff.Curve.calculateAgreement( Convert.FromBase64String(_savedData.PrivateKey), Convert.FromBase64String(data.PublicKey))); await SharedStuff.Database.InsertAsync(new DatabaseHelper.Users // save the key in database { Username = data.Username, Name = data.Name, Key = key, }); nameSafe = data.Name; } else // get the key from database; There is only one row because Username is unique { key = keyList[0].Key; } string toShowOnMainMenu = ""; JsonTypes.FilePayload filePayload = new JsonTypes.FilePayload(); switch (msg.Type) { case 0: // Text message // decrypt the message or assign the file token try { string message = BouncyCastleHelper.AesGcmDecrypt(msg.Payload.Message, key); await SharedStuff.Database.InsertAsync(new DatabaseHelper.Messages { Username = msg.Payload.From, Type = msg.Type, Date = msg.Payload.Date, Payload = message }); toShowOnMainMenu = message; } catch (Exception) { // TODO: RE-REQUEST public key } break; case 1: // File message filePayload = JsonConvert.DeserializeObject <JsonTypes.FilePayload>(msg.Payload.Message); await SharedStuff.Database.RunInTransactionAsync(trans => { trans.Insert(new DatabaseHelper.Messages { Username = msg.Payload.From, Type = msg.Type, Date = msg.Payload.Date, Payload = filePayload.Token }); trans.Insert(new DatabaseHelper.Files { Token = filePayload.Token, Name = filePayload.FileName }); }); toShowOnMainMenu = filePayload.FileName; break; } // save the value bool inserted = false, open = OpenWindowsList.ContainsKey(msg.Payload.From); int index = -1; try { index = MessagesList.IndexOf(MessagesList.First(x => x.Username == msg.Payload.From)); // get index of the UI if (index == -1) { throw new Exception(); } } catch (Exception) { string name = nameSafe; if (name == "") { name = (await SharedStuff.GetUserData(msg.Payload.From)).Name; } Application.Current.Dispatcher.Invoke(delegate { MessagesList.Insert(0, new MainMessagesNotify { FullDate = msg.Payload.Date, Message = toShowOnMainMenu, IsLastMessageForUser = false, Name = name, NewMessages = 1, Username = msg.Payload.From }); }); inserted = true; } if (index == -1) { return; } if (!open) // increase unread messages { await SharedStuff.Database.ExecuteAsync("UPDATE Users SET UnreadMessages = ? WHERE Username = ?", MessagesList[index].NewMessages + 1, msg.Payload.From); } if (!inserted) { Application.Current.Dispatcher.Invoke(delegate { // Show the user the update MessagesList.Move(index, 0); MessagesList[0].FullDate = msg.Payload.Date; MessagesList[0].Message = toShowOnMainMenu; MessagesList[0].IsLastMessageForUser = false; if (!open) { MessagesList[0].NewMessages++; } }); } // update the open windows if (open) { if (msg.Type == 0) // add text messages { OpenWindowsList[msg.Payload.From].AddMessageText(toShowOnMainMenu, msg.Payload.Date); } else if (msg.Type == 1) // add files { OpenWindowsList[msg.Payload.From].AddMessageFile(filePayload.Token, filePayload.FileName, msg.Payload.Date); } } } catch (Exception ex) { // TODO: HANDLE THIS SHIT } finally { _mu.Release(); } }