public static void sendNickname(byte[] recipient, byte[] contact_address) { if (contact_address != null && contact_address.Length > 1) { if (!Node.users.hasUser(contact_address)) { return; } byte[] nickData = Node.users.getUser(contact_address).nickData; if (nickData != null) { sendMessage(recipient, new StreamMessage(nickData)); } return; } SpixiMessage reply_spixi_message = new SpixiMessage(SpixiMessageCode.nick, Encoding.UTF8.GetBytes(Config.botName)); byte[] sender = IxianHandler.getWalletStorage().getPrimaryAddress(); // Send the nickname message to friend StreamMessage reply_message = new StreamMessage(); reply_message.type = StreamMessageCode.info; reply_message.recipient = recipient; reply_message.sender = sender; reply_message.data = reply_spixi_message.getBytes(); reply_message.encryptionType = StreamMessageEncryptionCode.none; reply_message.id = new byte[] { 5 }; reply_message.sign(IxianHandler.getWalletStorage().getPrimaryPrivateKey()); sendMessage(recipient, reply_message); }
public static void sendAcceptAdd(byte[] recipient, byte[] pub_key) { Node.users.setPubKey(recipient, pub_key, false); var user = Node.users.getUser(recipient); if (user != null && user.status != BotContactStatus.banned) { user.status = BotContactStatus.normal; } SpixiMessage spixi_message = new SpixiMessage(SpixiMessageCode.acceptAddBot, null); StreamMessage message = new StreamMessage(); message.type = StreamMessageCode.info; message.recipient = recipient; message.sender = IxianHandler.getWalletStorage().getPrimaryAddress(); message.data = spixi_message.getBytes(); message.encryptionType = StreamMessageEncryptionCode.none; message.id = new byte[] { 1 }; message.sign(IxianHandler.getWalletStorage().getPrimaryPrivateKey()); sendMessage(recipient, message); }
public static void onMsgDelete(byte[] msg_id, int channel, RemoteEndpoint endpoint) { StreamMessage msg = Messages.getMessage(msg_id, channel); if (msg == null) { return; } if (isAdmin(endpoint.presence.wallet) || msg.sender.SequenceEqual(endpoint.presence.wallet)) { Messages.removeMessage(msg_id, channel); SpixiMessage spixi_message = new SpixiMessage(SpixiMessageCode.msgDelete, msg_id, channel); StreamMessage message = new StreamMessage(); message.type = StreamMessageCode.info; message.sender = IxianHandler.getWalletStorage().getPrimaryAddress(); message.recipient = message.sender; message.data = spixi_message.getBytes(); message.encryptionType = StreamMessageEncryptionCode.none; message.sign(IxianHandler.getWalletStorage().getPrimaryPrivateKey()); Messages.addMessage(message, channel, false); NetworkServer.forwardMessage(ProtocolMessageCode.s2data, message.getBytes()); } }
public static void sendAvatar(byte[] recipient, byte[] contact_address) { if (contact_address != null && contact_address.Length > 1) { if (!Node.users.hasUser(contact_address)) { return; } string path = Node.users.getAvatarPath(contact_address); if (path == null) { return; } byte[] avatar_data = File.ReadAllBytes(path); if (avatar_data != null) { sendMessage(recipient, new StreamMessage(avatar_data)); } return; } byte[] avatar_bytes = Node.getAvatarBytes(); if (avatar_bytes == null) { return; } SpixiMessage reply_spixi_message = new SpixiMessage(SpixiMessageCode.avatar, avatar_bytes); byte[] sender = IxianHandler.getWalletStorage().getPrimaryAddress(); // Send the nickname message to friend StreamMessage reply_message = new StreamMessage(); reply_message.type = StreamMessageCode.info; reply_message.recipient = recipient; reply_message.sender = sender; reply_message.data = reply_spixi_message.getBytes(); reply_message.encryptionType = StreamMessageEncryptionCode.none; reply_message.id = new byte[] { 6 }; reply_message.sign(IxianHandler.getWalletStorage().getPrimaryPrivateKey()); sendMessage(recipient, reply_message); }
// Requests the avatar of the sender public static void requestAvatar(byte[] recipient) { // Prepare the message and send to the S2 nodes SpixiMessage spixi_message = new SpixiMessage(SpixiMessageCode.getAvatar, new byte[1]); StreamMessage message = new StreamMessage(); message.type = StreamMessageCode.info; message.recipient = recipient; message.sender = IxianHandler.getWalletStorage().getPrimaryAddress(); message.data = spixi_message.getBytes(); message.encryptionType = StreamMessageEncryptionCode.none; message.id = new byte[] { 4 }; sendMessage(recipient, message); }
public static void sendBotAction(byte[] recipient, SpixiBotActionCode action, byte[] data, int channel = 0) { SpixiBotAction sba = new SpixiBotAction(action, data); // Prepare the message and send to the S2 nodes SpixiMessage spixi_message = new SpixiMessage(SpixiMessageCode.botAction, sba.getBytes(), channel); StreamMessage message = new StreamMessage(); message.type = StreamMessageCode.info; message.recipient = recipient; message.sender = IxianHandler.getWalletStorage().getPrimaryAddress(); message.data = spixi_message.getBytes(); message.encryptionType = StreamMessageEncryptionCode.none; sendMessage(recipient, message); }
// Called when receiving S2 data from clients public static void receiveData(byte[] bytes, RemoteEndpoint endpoint) { // TODO Verify signature for all relevant messages string endpoint_wallet_string = Base58Check.Base58CheckEncoding.EncodePlain(endpoint.presence.wallet); Logging.info(string.Format("Receiving S2 data from {0}", endpoint_wallet_string)); StreamMessage message = new StreamMessage(bytes); // Don't allow clients to send error stream messages, as it's reserved for S2 nodes only if (message.type == StreamMessageCode.error) { Logging.warn(string.Format("Discarding error message type from {0}", endpoint_wallet_string)); return; } // Discard messages not sent to this node if (!IxianHandler.getWalletStorage().isMyAddress(message.recipient)) { Logging.warn(string.Format("Discarding message that wasn't sent to this node from {0}", endpoint_wallet_string)); return; } if (message.encryptionType != StreamMessageEncryptionCode.none && !message.decrypt(IxianHandler.getWalletStorage().getPrimaryPrivateKey(), null, null)) { Logging.error("Could not decrypt message from {0}", Base58Check.Base58CheckEncoding.EncodePlain(message.sender)); return; } SpixiMessage spixi_msg = new SpixiMessage(message.data); int channel = 0; if (spixi_msg != null) { channel = spixi_msg.channel; } if (message.requireRcvConfirmation) { switch (spixi_msg.type) { case SpixiMessageCode.msgReceived: case SpixiMessageCode.msgRead: case SpixiMessageCode.requestFileData: case SpixiMessageCode.fileData: case SpixiMessageCode.appData: case SpixiMessageCode.msgTyping: // do not send received confirmation break; case SpixiMessageCode.chat: sendReceivedConfirmation(message.sender, message.id, channel, endpoint); break; default: sendReceivedConfirmation(message.sender, message.id, -1, endpoint); break; } } switch (spixi_msg.type) { case SpixiMessageCode.requestAdd: // Friend request if (!new Address(spixi_msg.data).address.SequenceEqual(message.sender) || !message.verifySignature(spixi_msg.data)) { Logging.error("Unable to verify signature for message type: {0}, id: {1}, from: {2}.", message.type, Crypto.hashToString(message.id), Base58Check.Base58CheckEncoding.EncodePlain(message.sender)); } else { sendAcceptAdd(endpoint.presence.wallet, endpoint.presence.pubkey); sendAvatar(endpoint.presence.wallet, null); } break; case SpixiMessageCode.getPubKey: if (Node.users.hasUser(spixi_msg.data)) { StreamMessage sm = new StreamMessage(); sm.type = StreamMessageCode.info; sm.sender = IxianHandler.getWalletStorage().getPrimaryAddress(); sm.recipient = message.sender; sm.data = new SpixiMessage(SpixiMessageCode.pubKey, Node.users.getUser(spixi_msg.data).publicKey).getBytes(); sm.encryptionType = StreamMessageEncryptionCode.none; sendMessage(endpoint.presence.wallet, sm); } break; case SpixiMessageCode.getNick: sendNickname(endpoint.presence.wallet, spixi_msg.data); break; case SpixiMessageCode.getAvatar: sendAvatar(endpoint.presence.wallet, spixi_msg.data); break; case SpixiMessageCode.nick: Node.users.setPubKey(endpoint.presence.wallet, endpoint.serverPubKey, false); Node.users.setNick(endpoint.presence.wallet, message.getBytes()); break; case SpixiMessageCode.avatar: Node.users.setPubKey(endpoint.presence.wallet, endpoint.serverPubKey, false); if (message.data.Length < 500000) { if (message.data == null) { Node.users.setAvatar(endpoint.presence.wallet, null); } else { Node.users.setAvatar(endpoint.presence.wallet, message.getBytes()); } } break; case SpixiMessageCode.chat: onChat(bytes, message, channel, endpoint); break; case SpixiMessageCode.botGetMessages: Messages.sendMessages(endpoint.presence.wallet, channel, spixi_msg.data); break; case SpixiMessageCode.msgReceived: { // don't send confirmation back, so just return return; } case SpixiMessageCode.msgRead: { // don't send confirmation back, so just return return; } case SpixiMessageCode.botAction: onBotAction(spixi_msg.data, endpoint); break; case SpixiMessageCode.msgDelete: onMsgDelete(spixi_msg.data, channel, endpoint); break; case SpixiMessageCode.msgReaction: onMsgReaction(message, spixi_msg.data, channel, endpoint); break; case SpixiMessageCode.leave: onLeave(message.sender); break; default: Logging.warn("Received message type that isn't handled {0}", spixi_msg.type); break; } // TODO: commented for development purposes ONLY! /* * // Extract the transaction * Transaction transaction = new Transaction(message.transaction); * * // Validate transaction sender * if(transaction.from.SequenceEqual(message.sender) == false) * { * Logging.error(string.Format("Relayed message transaction mismatch for {0}", endpoint_wallet_string)); * sendError(message.sender); * return; * } * * // Validate transaction amount and fee * if(transaction.amount < CoreConfig.relayPriceInitial || transaction.fee < CoreConfig.transactionPrice) * { * Logging.error(string.Format("Relayed message transaction amount too low for {0}", endpoint_wallet_string)); * sendError(message.sender); * return; * } * * // Validate transaction receiver * if (transaction.toList.Keys.First().SequenceEqual(IxianHandler.getWalletStorage().address) == false) * { * Logging.error("Relayed message transaction receiver is not this S2 node"); * sendError(message.sender); * return; * } * * // Update the recipient dictionary * if (dataRelays.ContainsKey(message.recipient)) * { * dataRelays[message.recipient]++; * if(dataRelays[message.recipient] > Config.relayDataMessageQuota) * { * Logging.error(string.Format("Exceeded amount of unpaid data relay messages for {0}", endpoint_wallet_string)); * sendError(message.sender); * return; * } * } * else * { * dataRelays.Add(message.recipient, 1); * } * * * // Store the transaction * StreamTransaction streamTransaction = new StreamTransaction(); * streamTransaction.messageID = message.getID(); * streamTransaction.transaction = transaction; * lock (transactions) * { * transactions.Add(streamTransaction); * } * * // For testing purposes, allow the S2 node to receive relay data itself * if (message.recipient.SequenceEqual(IxianHandler.getWalletStorage().getWalletAddress())) * { * string test = Encoding.UTF8.GetString(message.data); * Logging.info(test); * * return; * } * * Logging.info("NET: Forwarding S2 data"); * NetworkStreamServer.forwardMessage(message.recipient, DLT.Network.ProtocolMessageCode.s2data, bytes); */ }