def create_actor(user): """ :param user: an User object :return: an Actor object """ actor = Actor() # Init a new Keypair for this user key = LittleBoxesKey(owner=user.name) key.new() actor.preferred_username = user.name actor.domain = current_app.config["AP_DOMAIN"] actor.type = "Person" actor.name = user.display_name actor.manually_approves_followers = False actor.url = ap_url("url", user.name) actor.shared_inbox_url = ap_url("shared_inbox", user.name) actor.inbox_url = ap_url("inbox", user.name) actor.outbox_url = ap_url("outbox", user.name) actor.private_key = key.privkey_pem actor.public_key = key.pubkey_pem actor.followers_url = ap_url("followers", user.name) actor.following_url = ap_url("followings", user.name) return actor
def test_httpsig(): back = InMemBackend() ap.use_backend(back) k = Key("https://lol.com") k.new() back.FETCH_MOCK["https://lol.com#main-key"] = { "publicKey": k.to_dict(), "id": "https://lol.com", } httpretty.register_uri(httpretty.POST, "https://remote-instance.com", body="ok") auth = httpsig.HTTPSigAuth(k) resp = requests.post("https://remote-instance.com", json={"ok": 1}, auth=auth) assert httpsig.verify_request( resp.request.method, resp.request.path_url, resp.request.headers, resp.request.body, )
def test_linked_data_sig(): doc = json.loads(DOC) k = Key("https://lol.com") k.new() linked_data_sig.generate_signature(doc, k) assert linked_data_sig.verify_signature(doc, k)
def post_to_remote_inbox(self, payload: str, to: str) -> None: if not current_app.config["AP_ENABLED"]: return # not federating if not enabled current_app.logger.debug(f"post_to_remote_inbox {payload}") ap_actor = json.loads(payload)["actor"] actor = Actor.query.filter(Actor.url == ap_actor).first() if not actor: current_app.logger.exception("no actor found") return key = Key(owner=actor.url) key.load(actor.private_key) signature_auth = HTTPSigAuth(key) # current_app.logger.debug(f"key=={key.__dict__}") try: current_app.logger.info("payload=%s", payload) current_app.logger.info("generating sig") signed_payload = json.loads(payload) backend = ap.get_backend() # Don't overwrite the signature if we're forwarding an activity if "signature" not in signed_payload: generate_signature(signed_payload, key) current_app.logger.info("to=%s", to) resp = requests.post( to, data=json.dumps(signed_payload), auth=signature_auth, headers={ "Content-Type": HEADERS[1], "Accept": HEADERS[1], "User-Agent": backend.user_agent() }, ) current_app.logger.info("resp=%s", resp) current_app.logger.info("resp_body=%s", resp.text) resp.raise_for_status() except HTTPError as err: current_app.logger.exception("request failed") if 400 >= err.response.status_code >= 499: current_app.logger.info("client error, no retry") return
def get_key(owner: str, _id: str, user: str, domain: str) -> Key: """"Loads or generates an RSA key.""" k = Key(owner, _id) user = user.replace(".", "_") domain = domain.replace(".", "_") key_path = os.path.join(KEY_DIR, f"key_{user}_{domain}.pem") if os.path.isfile(key_path): with open(key_path) as f: privkey_pem = f.read() k.load(privkey_pem) else: k.new() with open(key_path, "w") as f: f.write(k.privkey_pem) return k
def test_key_new_load(): owner = "http://lol.com" k = Key(owner) k.new() assert k.to_dict() == { "id": f"{owner}#main-key", "owner": owner, "publicKeyPem": k.pubkey_pem, } k2 = Key(owner) k2.load(k.privkey_pem) assert k2.to_dict() == k.to_dict()