def read_envelope(self, data): """ Take an incoming message and either update the last_seen time for the sender or add the sender as a new contact. peers.py should also call this method once it's determined the network a message is for. That way we can inspect the 'peers' attribute and use read_envelope to also learn of new peers. """ # Validate the senders' node ID seed = "%s:%i:%s" % (data['node'][1],data['node'][2],data['pubkey']) if data['node'][0] != long(utils.generate_node_id(seed).encode('hex'), 16): dht.log("\"%s\" is using an incorrect node ID." % data['node'][1], "warning") return # Learn of peers # TODO: Spawn green threads to ping these nodes. # NOTE: Don't permit a spammer to abuse the routing topology. # This can include decrementing the senders trust rating for # referring us to dead nodes. if 'peers' in data: for peer in data['peers']: node = dht.Node(*peer['node'], pubkey=peer['pubkey'], router=self.router) if node != self.source_node and self.router.is_new_node(node): self.router.add_contact(node) # Update last_seen times for contacts or add if new node = dht.Node(*data['node'], pubkey=data['pubkey'], router=self.router) existing_node = self.router.get_existing_node(node) if existing_node: existing_node.last_seen = time.time() return existing_node elif node != self.source_node: self.router.add_contact(node) return node
def post(self): """ Unserialise the data and accept the following calls: PING CHAT EDIT APPEND LEAVING FIND_NODE FIND_VALUE APPEND signifies the requesting host has data for the given hash. """ parser = restful.reqparse.RequestParser() parser.add_argument("data", type=str, help="The RPC body.", default=None) # parser.add_argument("signature", type=str, help="Signature.", default=None) # parser.add_argument("pubkey", type=str, help="Public key.", default=None) args = parser.parse_args() if not args.data: log("Received request from %s with no data." % request.remote_addr, "warning") return {}, 400 response = [] data = json.loads(args.data) if not validate_signature(data): log("Received message from %s with an invalid signature." % request.remote_addr, "warning") return "Invalid message signature.", 400 if not 'node' in data: log("%s didn't provide useable information about themselves." % request.remote_addr, "warning") return {}, 400 # Validate the node field for internet hosts if not any([request.remote_addr.startswith(subnet) for subnet in local_subnets]): stated_addr = data['node'][1] if stated_addr != request.remote_addr: log("Request made from %s stated it originated from %s" % (request.remote_addr, stated_addr), "warning") return "sicillian shrug", 418 # Ensure this peer is using the node ID that corresponds to their ip, port and public key seed = "%s:%i:%s" % (data['node'][1], data['node'][2], data['pubkey']) expected_id = long(generate_node_id(seed).encode('hex'), 16) if data['node'][0] != expected_id: log("%s is using an incorrect node ID." % request.remote_addr, "warning") log("Expecting %s but received %s" % (str(expected_id), str(data['node'][0])), "warning") return {}, 400 # Determine which overlay network this request is concerned with if not 'network' in data: return {}, 400 router = app.routes.get(data['network'], None) if router is None: return {}, 404 # Execute the corresponding RPC handler for field in data.keys(): if field.startswith('rpc_'): rpc_name = 'handle_%s' % field.replace('rpc_', '') # data[rpc_name] = data[field] # del data[field] rpc_method = getattr(router.protocol, rpc_name, None) if not rpc_method: log("%s tried to call unknown procedure %s." % (request.remote_addr, rpc_name), "warning") return {}, 400 response = rpc_method(data) break return response