private async void TryJoinConvos() { if (!appSettings["SaveConvoPasswords", true]) { return; } var userConvos = (await userService.GetConvos(user.Id, user.Token.Item2)) .Select(c => (Convo)c) .Distinct() .Where(convo => !convo.IsExpired()).ToArray(); foreach (var convo in userConvos) { string cachedPwSHA512 = convoPasswordProvider.GetPasswordSHA512(convo.Id); if (cachedPwSHA512.NullOrEmpty()) { cachedPwSHA512 = await SecureStorage.GetAsync($"convo:{convo.Id}_pw:SHA512"); } if (cachedPwSHA512.NotNullNotEmpty()) { var dto = new ConvoJoinRequestDto { ConvoId = convo.Id, ConvoPasswordSHA512 = cachedPwSHA512 }; var body = new EpistleRequestBody { UserId = user.Id, Auth = user.Token.Item2, Body = JsonSerializer.Serialize(dto) }; if (await convoService.JoinConvo(body.Sign(crypto, user.PrivateKeyPem))) { convoPasswordProvider.SetPasswordSHA512(convo.Id, cachedPwSHA512); ConvoMetadataDto metadata = await convoService.GetConvoMetadata(convo.Id, cachedPwSHA512, user.Id, user.Token.Item2); if (metadata != null) { var viewModel = viewModelFactory.Create <ActiveConvoViewModel>(); viewModel.ActiveConvo = convo; viewModel.OnAppearing(); activeConvos[convo.Id] = viewModel; } } } } eventAggregator.GetEvent <TriggerUpdateConvosListEvent>().Publish(); }
/// <summary> /// Submits a message to a <see cref="Convo"/>. /// </summary> /// <param name="convo">The <see cref="Convo"/> to post the message into.</param> /// <param name="messageType">The type of message (e.g. "TEXT=UTF8", "FILE=example.png", etc...).</param> /// <param name="message">The message body to encrypt and post.</param> /// <returns>Whether the message could be submitted successfully or not.</returns> private async Task <bool> PostMessageToConvo(Convo convo, string messageType, byte[] message) { if (message.NullOrEmpty()) { return(false); } Task <IDictionary <string, string> > publicKeys = userService.GetUserPublicKeys(user.Id, convo.GetParticipantIdsCommaSeparated(), user.Token.Item2); byte[] compressedMessage = await compressionUtility.Compress(message, CompressionSettings.Default).ConfigureAwait(false); using var encryptionResult = await aes.EncryptAsync(compressedMessage).ConfigureAwait(false); byte[] key = new byte[48]; for (int i = 0; i < 32; i++) { key[i] = encryptionResult.Key[i]; } for (int i = 0; i < 16; i++) { key[i + 32] = encryptionResult.IV[i]; } // Encrypt the message decryption key for every convo participant individually. var encryptedKeys = new ConcurrentBag <string>(); Parallel.ForEach(await publicKeys.ConfigureAwait(false), kvp => { (string userId, string userPublicKey) = kvp; if (userId.NotNullNotEmpty() && userPublicKey.NotNullNotEmpty()) { string decompressedPublicKey = keyExchange.DecompressPublicKey(userPublicKey); encryptedKeys.Add(userId + ':' + Convert.ToBase64String(rsa.Encrypt(key, decompressedPublicKey))); } }); try { var postParamsDto = new PostMessageParamsDto { Type = messageType, SenderName = userSettings.Username, ConvoId = convo.Id, ConvoPasswordSHA512 = convoPasswordProvider.GetPasswordSHA512(convo.Id), EncryptedKeys = encryptedKeys.ToCommaSeparatedString(), EncryptedBody = Convert.ToBase64String(encryptionResult.EncryptedData) }; var body = new EpistleRequestBody { UserId = user.Id, Auth = user.Token.Item2, Body = JsonSerializer.Serialize(postParamsDto) }; return(await convoService.PostMessage(body.Sign(rsa, user.PrivateKeyPem)).ConfigureAwait(false)); } catch { return(false); } }