def rpc_edit(self, node, data): """ Implements inter-instance EDIT. Message data should be of the form { 'stream': 'stream_id', 'from': ['uid', 'username'], 'edit': '<span>Some DOM nodes to match and replace</span>' } """ data = base64.b64encode(json.dumps(data)) key = RSA.importKey(node.pubkey) data = key.encrypt(data, 32) dht.transmit(self.router, addr, {'rpc_edit': data})
def rpc_chat(self, nodeple, data): """ Implements CHAT where we encrypt a message destined for the user with UID on the receiving node. Message data should be of the form { 'to': 'uid', 'from': ['uid', 'username'], 'type': Can be any of "message", "init", "close" 'body': {'m':'content'} } """ # Worth retaining this ping call for the routing information we get. node = self.rpc_ping(nodeple) if node == None: return data = base64.b64encode(json.dumps(data)) key = RSA.importKey(node.pubkey) data = key.encrypt(data, 32) data = base64.b64encode(data[0]) response = dht.transmit(self.router, node, {'rpc_chat': data}) dht.log(response, "debug") return response
def rpc_republish(self, node, data): """ Please refer to SynchronyProtocol.republish_keys to see what's really going on here. The data argument here is a list that looks like this: [{'node': [[nodeple], 'pubkey'],'keys': {signature: key_data}}, ...] Where "key_data" is a b64encoded JSON dump of the return value for self.storage.get_entries_for(self.source_node). Peers save this message, as we remember when they send rpc_republish messages to us. We forward previous rpc_republish messages for peers we still have as a contact. """ addr = self.get_address(node) data = {'rpc_republish': data} return dht.transmit(self.router, addr, data)
def rpc_add_friend(self, local_uid, addr): """ addr is of the form "network_name/node_id/remote_user_id" Implements ADD_FRIEND where we find the node in addr and tell them a local user wants to add the remote UID as a friend. """ if addr.count("/") != 2: return False, None network, node_id, remote_uid = addr.split("/") if network != self.router.network: return False, None node = dht.Node(long(node_id)) nearest = self.router.find_neighbours(node) if len(nearest) == 0: dht.log("There are no neighbours to help us add users on %s as friends." % node_id) return False, None spider = NodeSpider(self, node, nearest, self.ksize, self.router.alpha) nodes = spider.find() if len(nodes) != 1: return False, None node = nodes[0] # Sometimes spidering doesn't get us all the way there. # Check who we already know: if node.long_id != long(node_id): nodes = [n for n in self.router if n.long_id == long(node_id)] if len(nodes) != 1: return False, None node = nodes[0] dht.log(node_id, "debug") dht.log(node.long_id, "debug") dht.log("Found remote instance %s." % node) message = {"rpc_add_friend": {"from": local_uid, "to": remote_uid}} response = dht.transmit(self.router, node, message) if not isinstance(response, dict) or not "response" in response: return False, None return response['response'], node
def rpc_append(self, node, url_hash, content_hash): """ Allows senders to tell peers they have the data for the hash of a path. Hash here is the hash made from the content the peer has stored. They're letting you know they have data that corresponds to the hash. { peers: [], pubkey: "", signature: "", time: 1440064069.0, rpc_append: {url_hash: content_hash}, } """ # Append this peer to the list of nodes storing data for this path # urls[data['url']].append(sender) addr = self.get_address(node) data = {"rpc_append": {url_hash: content_hash}} # if addr.threeple == self.source_node.threeple: # self.storage[url_hash] = (content_hash, addr) return dht.transmit(self.router, addr, data)
def rpc_ping(self, addr): # "addr" may be an (addr, port) tuple data = dht.transmit(self.router, addr, {"rpc_ping":True}) # Remove peer if not data: if isinstance(addr, Node): self.router.remove_node(addr) return node = dht.Node(*data['node'], pubkey=data['pubkey'], router=self.router) self.router.add_contact(node) # FIXME: Ping nodes in the 'peers' part of the response. # Don't let malicious nodes fill the routing table with # information for peers who won't respond. if 'peers' in data: for peer in data['peers']: if peer['node'][0] == self.source_node.long_id: continue peer = dht.Node(*peer['node'], pubkey=peer['pubkey'], router=self.router) self.router.add_contact(peer) # self.rpc_ping(node) return node
def rpc_find_value(self, node_to_ask, node_to_find): address = (node_to_ask.ip, node_to_ask.port) message = {'rpc_find_value': binascii.hexlify(node_to_find.id)} return dht.transmit(self.router, address, message)
def rpc_leaving(self, node): addr = self.get_address(node) return dht.transmit(self.router, addr, {"rpc_leaving":True})