def rpc_unfollow(self, sender, signature): self.log.info("Unfollow request from %s" % sender.id.encode("hex")) self.router.addContact(sender) try: verify_key = nacl.signing.VerifyKey(sender.signed_pubkey[64:]) verify_key.verify("unfollow:" + self.proto.guid, signature) f = FollowData() f.delete_follower(sender.id) return ["True"] except Exception: self.log.warning("Failed to validate follower signature") return ["False"]
def rpc_follow(self, sender, proto, signature): self.log.info("Follow request from %s" % sender.id.encode("hex")) self.router.addContact(sender) try: verify_key = nacl.signing.VerifyKey(sender.signed_pubkey[64:]) verify_key.verify(proto, signature) f = Followers.Follower() f.ParseFromString(proto) if f.guid != sender.id: raise Exception('GUID does not match sending node') if f.following != self.proto.guid: raise Exception('Following wrong node') f.signature = signature FollowData().set_follower(f) proto = Profile().get(False) m = Metadata() m.name = proto.name m.handle = proto.handle m.avatar_hash = proto.avatar_hash m.nsfw = proto.nsfw return [ "True", m.SerializeToString(), self.signing_key.sign(m.SerializeToString())[:64] ] except Exception: self.log.warning("Failed to validate follower") return ["False"]
def send_notification(self, message): """ Sends a notification message to all online followers. It will resolve each guid before sending the notification. Messages must be less than 140 characters. Returns the number of followers the notification reached. """ if len(message) > 140: return defer.succeed(0) def send(nodes): def how_many_reached(responses): count = 0 for resp in responses: if resp[1][0] and resp[1][1][0] == "True": count += 1 return count ds = [] signature = self.signing_key.sign(str(message))[:64] for n in nodes: if n[1] is not None: ds.append(self.protocol.callNotify(n[1], message, signature)) return defer.DeferredList(ds).addCallback(how_many_reached) dl = [] f = objects.Followers() f.ParseFromString(FollowData().get_followers()) for follower in f.followers: dl.append(self.kserver.resolve(follower.guid)) return defer.DeferredList(dl).addCallback(send)
def rpc_get_following(self, sender): self.log.info("Fetching following list from db") self.router.addContact(sender) ser = FollowData().get_following() if ser is None: return ["None"] else: return [ser, self.signing_key.sign(ser)[:64]]
def rpc_notify(self, sender, message, signature): if len(message) <= 140 and FollowData().is_following(sender.id): try: verify_key = nacl.signing.VerifyKey(sender.signed_pubkey[64:]) verify_key.verify(message, signature) except Exception: return ["False"] self.log.info("Received a notification from %s" % sender) self.router.addContact(sender) for listener in self.listeners: try: verifyObject(NotificationListener, listener) listener.notify(sender.id, message) except DoesNotImplement: pass return ["True"] else: return ["False"]
def save_to_db(result): if result[0] and result[1][0] == "True": try: u = objects.Following.User() u.guid = node_to_follow.id u.signed_pubkey = node_to_follow.signed_pubkey m = objects.Metadata() m.ParseFromString(result[1][1]) u.metadata.MergeFrom(m) u.signature = result[1][2] pubkey = node_to_follow.signed_pubkey[64:] verify_key = nacl.signing.VerifyKey(pubkey) verify_key.verify(result[1][1], result[1][2]) FollowData().follow(u) return True except Exception: return False else: return False
def get_following(self, request): def parse_following(following): if following is not None: response = {"following": []} for f in following.users: user_json = { "guid": f.guid.encode("hex"), "handle": f.metadata.handle, "name": f.metadata.name, "avatar_hash": f.metadata.avatar_hash.encode("hex"), "nsfw": f.metadata.nsfw } response["following"].append(user_json) request.setHeader('content-type', "application/json") request.write(json.dumps(response, indent=4)) request.finish() else: request.write(NoResource().render(request)) request.finish() if "guid" in request.args: def get_node(node): if node is not None: self.mserver.get_following(node).addCallback( parse_following) else: request.write(NoResource().render(request)) request.finish() self.kserver.resolve(unhexlify( request.args["guid"][0])).addCallback(get_node) else: ser = FollowData().get_following() if ser is not None: f = objects.Following() f.ParseFromString(ser) parse_following(f) else: parse_following(None) return server.NOT_DONE_YET
def notify(self, guid, message): # pull the metadata for this node from the db f = Following() ser = FollowData().get_following() if ser is not None: f.ParseFromString(ser) for user in f.users: if user.guid == guid: avatar_hash = user.metadata.avatar_hash handle = user.metadata.handle timestamp = int(time.time()) NotificationStore().save_notification(guid, handle, message, timestamp, avatar_hash) notification_json = { "notification": { "guid": guid.encode("hex"), "message": message, "timestamp": timestamp, "avatar_hash": avatar_hash.encode("hex") } } if handle: notification_json["notification"]["handle"] = handle self.ws.push(json.dumps(notification_json, indent=4))
def save_to_db(result): if result[0] and result[1][0] == "True": FollowData().unfollow(node_to_unfollow.id) return True else: return False