public void onSend(string str) { if (str.Length < 1) { return; } // TODOSPIXI /* // Send the message to the S2 nodes * byte[] recipient_address = friend.wallet_address; * byte[] encrypted_message = StreamProcessor.prepareSpixiMessage(SpixiMessageCode.chat, str, friend.pubkey); * // CryptoManager.lib.encryptData(Encoding.UTF8.GetBytes(string_to_send), friend.pubkey); * * // Check the relay ip * string relayip = friend.getRelayIP(); * if (relayip == null) * { * Logging.warn("No relay node to send message to!"); * return; * } * if (relayip.Equals(node_ip, StringComparison.Ordinal) == false) * { * * node_ip = relayip; * // Connect to the contact's S2 relay first * NetworkClientManager.connectToStreamNode(relayip); * * // TODO: optimize this * while (NetworkClientManager.isNodeConnected(relayip) == false) * { * * } * } * * Message message = new Message(); * message.recipientAddress = recipient_address; * message.data = encrypted_message; * * StreamProcessor.sendMessage(message, node_ip);*/ SpixiMessage spixi_message = new SpixiMessage(SpixiMessageCode.chat, Encoding.UTF8.GetBytes(str)); StreamMessage message = new StreamMessage(); message.type = StreamMessageCode.data; message.recipient = friend.walletAddress; message.sender = Node.walletStorage.getPrimaryAddress(); message.transaction = new byte[1]; message.sigdata = new byte[1]; message.data = spixi_message.getBytes(); string relayip = friend.searchForRelay(); StreamProcessor.sendMessage(message, relayip); // Finally, add the text bubble visually DateTime dt = DateTime.Now; FriendMessage msg = new FriendMessage(str, String.Format("{0:t}", dt), false); friend.messages.Add(msg); insertMessage(msg); // Finally, clear the input field webView.Eval("clearInput()"); }
public static bool sendFileData(Friend friend, string uid, ulong packet_number) { FileTransfer transfer = TransferManager.getOutgoingTransfer(uid); if (transfer == null) { return(false); } using (MemoryStream m = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(m)) { writer.Write(uid); writer.Write(packet_number); Logging.info("Sending file packet #{0}", packet_number); byte[] data = transfer.getPacketData(packet_number); // Write the data if (data != null) { writer.Write(data.Length); writer.Write(data); } else { writer.Write(0); } } SpixiMessage spixi_message = new SpixiMessage(SpixiMessageCode.fileData, m.ToArray()); StreamMessage message = new StreamMessage(); message.type = StreamMessageCode.data; message.recipient = friend.walletAddress; message.sender = Node.walletStorage.getPrimaryAddress(); message.transaction = new byte[1]; message.sigdata = new byte[1]; message.data = spixi_message.getBytes(); StreamProcessor.sendMessage(friend, message, false, false, false); } if (friend.chat_page != null) { ulong totalPackets = transfer.fileSize / (ulong)transfer.packetSize; ulong fp = 0; bool complete = false; if (totalPackets == packet_number) { fp = 100; complete = true; } else { fp = packet_number * 100 / totalPackets; } friend.chat_page.updateFile(uid, fp.ToString(), complete); } return(true); }
// Called when an encryption key is received from the S2 server, as per step 4 of the WhitePaper /*private static void sendRsaEncryptedMessage(StreamMessage msg, string key, RemoteEndpoint endpoint) * { * // TODO TODO use transaction code for S2 * using (MemoryStream m = new MemoryStream()) * { * using (BinaryWriter writer = new BinaryWriter(m)) * { * writer.Write(msg.getID()); * writer.Write(msg.recipientAddress); * writer.Write(msg.transactionID); * } * } * Console.WriteLine("Sending encrypted message with key {0}", key); * * using (MemoryStream m = new MemoryStream()) * { * using (BinaryWriter writer = new BinaryWriter(m)) * { * writer.Write(msg.getID()); * writer.Write(msg.recipientAddress); * writer.Write(msg.transactionID); * * byte[] encrypted_message = CryptoManager.lib.encryptDataS2(msg.data, key); * int encrypted_count = encrypted_message.Count(); * * writer.Write(encrypted_count); * writer.Write(encrypted_message); * * byte[] ba = ProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.s2data, m.ToArray()); * socket.Send(ba, SocketFlags.None); * * * // Update the DLT transaction as well * Transaction transaction = new Transaction(0, msg.recipientAddress, Node.walletStorage.address); * transaction.id = msg.transactionID; * //transaction.data = Encoding.UTF8.GetString(checksum); * //ProtocolMessage.broadcastProtocolMessage(ProtocolMessageCode.updateTransaction, transaction.getBytes()); * * } * } * }*/ // Called when receiving S2 data from clients public static void receiveData(byte[] bytes, RemoteEndpoint endpoint) { StreamMessage message = new StreamMessage(bytes); if (message.data == null) { Logging.error(string.Format("Null message data.")); return; } Logging.info("Received S2 data from {0} for {1}", Base58Check.Base58CheckEncoding.EncodePlain(message.sender), Base58Check.Base58CheckEncoding.EncodePlain(message.recipient)); Friend friend = null; // decrypt the message if necessary // TODO TODO TODO add message receive queue for when the keys aren't available yet if (message.encryptionType != StreamMessageEncryptionCode.none) { byte[] aes_key = null; byte[] chacha_key = null; friend = FriendList.getFriend(message.sender); if (friend != null) { aes_key = friend.aesKey; chacha_key = friend.chachaKey; } if (!message.decrypt(Node.walletStorage.getPrimaryPrivateKey(), aes_key, chacha_key)) { Logging.error("Could not decrypt message from {0}", Base58Check.Base58CheckEncoding.EncodePlain(friend.walletAddress)); return; } } // Extract the Spixi message SpixiMessage spixi_message = new SpixiMessage(message.data); switch (spixi_message.type) { case SpixiMessageCode.chat: { // Add the message to the friend list FriendList.addMessage(spixi_message.id, message.sender, Encoding.UTF8.GetString(spixi_message.data)); } break; case SpixiMessageCode.getNick: { // Send the nickname to the sender as requested handleGetNick(message.sender, Encoding.UTF8.GetString(spixi_message.data)); } break; case SpixiMessageCode.nick: { // Set the nickname for the corresponding address if (spixi_message.data != null) { FriendList.setNickname(message.sender, Encoding.UTF8.GetString(spixi_message.data)); } else { FriendList.setNickname(message.sender, Base58Check.Base58CheckEncoding.EncodePlain(message.sender)); } } break; case SpixiMessageCode.requestAdd: { // Friend request handleRequestAdd(spixi_message.id, message.sender, spixi_message.data); } break; case SpixiMessageCode.acceptAdd: { // Friend accepted request handleAcceptAdd(message.sender, spixi_message.data); } break; case SpixiMessageCode.sentFunds: { // Friend requested funds handleSentFunds(spixi_message.id, message.sender, Encoding.UTF8.GetString(spixi_message.data)); } break; case SpixiMessageCode.requestFunds: { // Friend requested funds handleRequestFunds(spixi_message.id, message.sender, Encoding.UTF8.GetString(spixi_message.data)); } break; case SpixiMessageCode.requestFundsResponse: { handleRequestFundsResponse(spixi_message.id, message.sender, Encoding.UTF8.GetString(spixi_message.data)); } break; case SpixiMessageCode.keys: { handleReceivedKeys(message.sender, spixi_message.data); } break; case SpixiMessageCode.msgReceived: { handleMsgReceived(message.sender, spixi_message); // don't send confirmation back, so just return return; } case SpixiMessageCode.msgRead: { handleMsgRead(message.sender, spixi_message); // don't send confirmation back, so just return return; } case SpixiMessageCode.fileHeader: { handleFileHeader(message.sender, spixi_message); } break; } if (friend == null) { friend = FriendList.getFriend(message.sender); } if (friend == null) { Logging.error("Cannot send received confirmation, friend is null"); return; } // Send received confirmation StreamMessage msg_received = new StreamMessage(); msg_received.type = StreamMessageCode.info; msg_received.sender = IxianHandler.getWalletStorage().getPrimaryAddress(); msg_received.recipient = message.sender; msg_received.data = new SpixiMessage(spixi_message.id, SpixiMessageCode.msgReceived, null).getBytes(); msg_received.transaction = new byte[1]; msg_received.sigdata = new byte[1]; msg_received.encryptionType = StreamMessageEncryptionCode.none; sendMessage(friend, msg_received, true); }
// Send an encrypted message using the S2 network public static bool sendMessage(Friend friend, StreamMessage msg, bool add_to_offline_messages = true) { // TODO this function has to be improved and node's wallet address has to be added string hostname = friend.searchForRelay(); if (friend.publicKey != null && (msg.encryptionType == StreamMessageEncryptionCode.rsa || (friend.aesKey != null && friend.chachaKey != null))) { msg.encrypt(friend.publicKey, friend.aesKey, friend.chachaKey); } else if (msg.encryptionType != StreamMessageEncryptionCode.none || !friend.online) { if (friend.publicKey == null) { byte[] pub_k = FriendList.findContactPubkey(friend.walletAddress); friend.publicKey = pub_k; } StreamClientManager.connectTo(hostname, null); // TODO replace null with node address Logging.warn("Could not send message to {0}, due to missing encryption keys, adding to offline queue!", Base58Check.Base58CheckEncoding.EncodePlain(msg.recipient)); if (add_to_offline_messages) { addOfflineMessage(msg); } return(false); } if (!StreamClientManager.sendToClient(hostname, ProtocolMessageCode.s2data, msg.getBytes(), Encoding.UTF8.GetBytes(msg.getID()))) { StreamClientManager.connectTo(hostname, null); // TODO replace null with node address Logging.warn("Could not send message to {0}, adding to offline queue!", Base58Check.Base58CheckEncoding.EncodePlain(msg.recipient)); if (add_to_offline_messages) { addOfflineMessage(msg); } return(false); } return(true); /* string pub_k = FriendList.findContactPubkey(msg.recipientAddress); * if (pub_k.Length < 1) * { * Console.WriteLine("Contact {0} not found, adding to offline queue!", msg.recipientAddress); * addOfflineMessage(msg); * return; * } * * * // Create a new IXIAN transaction * // byte[] checksum = Crypto.sha256(encrypted_message); * Transaction transaction = new Transaction(0, msg.recipientAddress, Node.walletStorage.address); * // transaction.data = Encoding.UTF8.GetString(checksum); * msg.transactionID = transaction.id; * //ProtocolMessage.broadcastProtocolMessage(ProtocolMessageCode.newTransaction, transaction.getBytes()); * * // Add message to the queue * messages.Add(msg); * * // Request a new keypair from the S2 Node * if(hostname == null) * ProtocolMessage.broadcastProtocolMessage(ProtocolMessageCode.s2generateKeys, Encoding.UTF8.GetBytes(msg.getID())); * else * { * NetworkClientManager.sendData(ProtocolMessageCode.s2generateKeys, Encoding.UTF8.GetBytes(msg.getID()), hostname); * }*/ }
public async Task onSendFile() { // Show file picker and send the file try { Stream stream = null; string fileName = null; string filePath = null; // Special case for iOS platform if (Device.RuntimePlatform == Device.iOS) { var picker_service = DependencyService.Get <IPicturePicker>(); SpixiImageData spixi_img_data = await picker_service.PickImageAsync(); stream = spixi_img_data.stream; if (stream == null) { return; } fileName = spixi_img_data.name; filePath = spixi_img_data.path; } else { FileData fileData = await CrossFilePicker.Current.PickFile(); if (fileData == null) { return; // User canceled file picking } stream = fileData.GetStream(); fileName = fileData.FileName; filePath = fileData.FilePath; } FileTransfer transfer = TransferManager.prepareFileTransfer(fileName, stream, filePath); Logging.info("File Transfer uid: " + transfer.uid); SpixiMessage spixi_message = new SpixiMessage(SpixiMessageCode.fileHeader, transfer.getBytes()); StreamMessage message = new StreamMessage(); message.type = StreamMessageCode.data; message.recipient = friend.walletAddress; message.sender = Node.walletStorage.getPrimaryAddress(); message.transaction = new byte[1]; message.sigdata = new byte[1]; message.data = spixi_message.getBytes(); StreamProcessor.sendMessage(friend, message); string message_data = string.Format("{0}:{1}", transfer.uid, transfer.fileName); // store the message and display it FriendMessage friend_message = FriendList.addMessageWithType(message.id, FriendMessageType.fileHeader, friend.walletAddress, message_data, true); friend_message.transferId = transfer.uid; friend_message.filePath = transfer.filePath; Node.localStorage.writeMessages(friend.walletAddress, friend.messages); } catch (Exception ex) { Logging.error("Exception choosing file: " + ex.ToString()); } }
public async void onSend(string str) { if (str.Length < 1) { return; } await Task.Run(() => { // TODOSPIXI /* // Send the message to the S2 nodes * byte[] recipient_address = friend.wallet_address; * byte[] encrypted_message = StreamProcessor.prepareSpixiMessage(SpixiMessageCode.chat, str, friend.pubkey); * // CryptoManager.lib.encryptData(Encoding.UTF8.GetBytes(string_to_send), friend.pubkey); * * // Check the relay ip * string relayip = friend.getRelayIP(); * if (relayip == null) * { * Logging.warn("No relay node to send message to!"); * return; * } * if (relayip.Equals(node_ip, StringComparison.Ordinal) == false) * { * * node_ip = relayip; * // Connect to the contact's S2 relay first * NetworkClientManager.connectToStreamNode(relayip); * * // TODO: optimize this * while (NetworkClientManager.isNodeConnected(relayip) == false) * { * * } * } * * Message message = new Message(); * message.recipientAddress = recipient_address; * message.data = encrypted_message; * * StreamProcessor.sendMessage(message, node_ip);*/ // store the message and display it FriendMessage friend_message = FriendList.addMessageWithType(null, FriendMessageType.standard, friend.walletAddress, str, true); // Finally, clear the input field Utils.sendUiCommand(webView, "clearInput"); // Send the message SpixiMessage spixi_message = new SpixiMessage(SpixiMessageCode.chat, Encoding.UTF8.GetBytes(str)); StreamMessage message = new StreamMessage(); message.type = StreamMessageCode.data; message.recipient = friend.walletAddress; message.sender = Node.walletStorage.getPrimaryAddress(); message.transaction = new byte[1]; message.sigdata = new byte[1]; message.data = spixi_message.getBytes(); message.id = friend_message.id; if (friend.bot) { message.encryptionType = StreamMessageEncryptionCode.none; message.sign(IxianHandler.getWalletStorage().getPrimaryPrivateKey()); } StreamProcessor.sendMessage(friend, message); }); }
public void insertMessage(FriendMessage message) { if (friend.approved == false) { if (message.type == FriendMessageType.requestAdd) { // Call webview methods on the main UI thread only Utils.sendUiCommand(webView, "showContactRequest", "1"); message.read = true; return; } } else { // Don't show if the friend is already approved if (message.type == FriendMessageType.requestAdd) { return; } } string prefix = "addMe"; string avatar = "";//Node.localStorage.getOwnAvatarPath(); if (!message.localSender) { prefix = "addThem"; avatar = "img/spixiavatar.png"; } if (message.type == FriendMessageType.requestFunds) { string status = "PENDING"; string status_icon = "fa-clock"; string amount = message.message; if (message.message.StartsWith("::")) { status = "DECLINED"; status_icon = "fa-exclamation-circle"; amount = message.message.Substring(2); } else if (message.message.StartsWith(":")) { Transaction transaction = TransactionCache.getTransaction(message.message.Substring(1)); if (transaction == null) { transaction = TransactionCache.getUnconfirmedTransaction(message.message.Substring(1)); } amount = "?"; if (transaction != null) { amount = transaction.amount.ToString(); if (transaction.applied > 0) { status = "CONFIRMED"; status_icon = "fa-check-circle"; } } } if (message.localSender) { Utils.sendUiCommand(webView, "addPaymentRequest", Crypto.hashToString(message.id), avatar, "Payment request SENT", amount, status, status_icon, Clock.getRelativeTime(message.timestamp), message.localSender.ToString()); } else { Utils.sendUiCommand(webView, "addPaymentRequest", Crypto.hashToString(message.id), avatar, "Payment request RECEIVED", amount, status, status_icon, Clock.getRelativeTime(message.timestamp)); } message.read = true; return; } if (message.type == FriendMessageType.sentFunds) { message.read = true; Transaction transaction = TransactionCache.getTransaction(message.message); if (transaction == null) { transaction = TransactionCache.getUnconfirmedTransaction(message.message); } string status = "PENDING"; string status_icon = "fa-clock"; string amount = "?"; if (transaction != null) { if (transaction.applied > 0) { status = "CONFIRMED"; status_icon = "fa-check-circle"; } amount = transaction.amount.ToString(); } // Call webview methods on the main UI thread only if (message.localSender) { Utils.sendUiCommand(webView, "addPaymentRequest", Crypto.hashToString(message.id), avatar, "Payment SENT", amount, status, status_icon, Clock.getRelativeTime(message.timestamp), message.localSender.ToString()); } else { Utils.sendUiCommand(webView, "addPaymentRequest", Crypto.hashToString(message.id), avatar, "Payment RECEIVED", amount, status, status_icon, Clock.getRelativeTime(message.timestamp)); } return; } if (message.type == FriendMessageType.fileHeader) { prefix = "addFile"; } // Call webview methods on the main UI thread only Utils.sendUiCommand(webView, prefix, Crypto.hashToString(message.id), avatar, message.message, Clock.getRelativeTime(message.timestamp), message.confirmed.ToString(), message.read.ToString()); if (!message.read && !message.localSender) { message.read = true; Node.localStorage.writeMessagesFile(friend.walletAddress, friend.messages); // Send read confirmation StreamMessage msg_received = new StreamMessage(); msg_received.type = StreamMessageCode.info; msg_received.sender = IxianHandler.getWalletStorage().getPrimaryAddress(); msg_received.recipient = friend.walletAddress; msg_received.data = new SpixiMessage(message.id, SpixiMessageCode.msgRead, null).getBytes(); msg_received.transaction = new byte[1]; msg_received.sigdata = new byte[1]; msg_received.encryptionType = StreamMessageEncryptionCode.none; StreamProcessor.sendMessage(friend, msg_received, true); } }