From 33f9218a8de8d47b39d7469319fb03cab626525a Mon Sep 17 00:00:00 2001 From: SouthFox Date: Fri, 14 Jul 2023 02:04:41 +0800 Subject: [PATCH] [doc] show done? --- docs/show.org | 185 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 174 insertions(+), 11 deletions(-) diff --git a/docs/show.org b/docs/show.org index 11357fe..4cef3ea 100644 --- a/docs/show.org +++ b/docs/show.org @@ -88,7 +88,7 @@ ME = { "sharedInbox": config.BASE_URL + "/inbox", }, "url": config.ID + "/", # Important for Mastodon - "manuallyApprovesFollowers": False, + "manuallyApprovesFollowers": config.MANUALLY_APPROVES_FOLLOWERS, "attachment": [], "icon": { "mediaType": "image/png", @@ -118,7 +118,6 @@ def locate_user() -> Response: GET http://coscup.localhost/user/show #+end_src - ** WebFinger #+begin_src python from flask import Flask, abort, request, Response, jsonify @@ -163,9 +162,7 @@ def wellknown_webfinger() -> Response: GET http://coscup.localhost/.well-known/webfinger?resource=acct:show@coscup.localhost #+end_src - ** HTTP Signature - other.localhost --Follow-> coscup.localhost #+begin_src json @@ -174,7 +171,7 @@ other.localhost --Follow-> coscup.localhost "@context": "https://www.w3.org/ns/activitystreams", "id": "http://other.localhost/9ef8847d72434cff82254f36ff88e710", "type": "Follow", - "actor": "http://other.localhost", + "actor": "http://other.localhost/accounts/other", "object": "http://coscup.localhost/meow/show" } @@ -205,15 +202,14 @@ def parse_signature( detail[name.lower()] = value signature_details = { "headers": detail["headers"].split(), - "signature": (detail["signature"]), + "signature": detail["signature"], "algorithm": detail["algorithm"], "keyid": detail["keyid"], } return signature_details #+end_src - -parse_signature(headers["signature"]) +parsed_signature = parse_signature(headers["signature"]) #+begin_src json {"algorithm": "rsa-sha256", "headers": ["(request-target)", "user-agent", "host", "date", "digest", "content-type"], @@ -221,7 +217,6 @@ parse_signature(headers["signature"]) "signature": "irioDQuhYstSvafpl6DW4d31wDPRiTv7MZGyBo3j4kkc2TrfOweH3WRMMnoaWwl4LAI2WYLoKefeQpOg7Rm7ZEffsoLOzZvgdWJBm8lnOEgieyy5l2Vq1mlcS2PRJCisYGdzAwFOBkcHk0WKAZXvs1ieRV34NHfM8JF+DjrCBTZ/U9LyxULBwC6tPQTh9tflCOwXZOzXUq17C+2Uzsr8h4tDHjbmrG7OAcvYiPeOUKaP+InoE6j9ViHllhidNCPL0y8b1c7c72ruN48kF42OfyfUeiuCcuLwdp8eYBlTdG/ZsT2YXyKruwim3tTD1TtyW4Vfll+F/4/1RfWHsc9LrQ=="} #+end_src - #+begin_src python import base64 from Crypto.Hash import SHA256 @@ -254,16 +249,17 @@ def build_signature_string( return "\n".join(sign_str) -build_signature_string( +signature_string = build_signature_string( request.method # "post" request.path # "/inbox" - parse_signature(headers["signature"])["headers"], # ["(request-target)", "user-agent", "host", "date", "digest", "content-type"] + parsed_signature["headers"], # ["(request-target)", "user-agent", "host", "date", "digest", "content-type"] calculate_digest(request.data), headers, ) #+end_src +signature_string #+begin_quote (request-target): post /inbox user-agent: something/fediverse+app @@ -272,3 +268,170 @@ date: Tue, 11 Jul 2023 04:21:11 GMT digest: SHA-256=WzNniTyRBcZpgK7a6zYJBgsdKIQmFEPPfysh/ZzKb2o= content-type: application/activity+json #+end_quote + +#+begin_src python +from Crypto.Hash import SHA256 +from Crypto.Signature import PKCS1_v1_5 +from Crypto.PublicKey import RSA + +def verify_signature( + signature_string: str, + signature: bytes, # base64.b64decode(parsed_signature["signature"]) + pubkey: str, +) -> bool : + pubkey = RSA.importKey(pubkey) + signer = PKCS1_v1_5.new(pubkey) + digest = SHA256.new() + digest.update(signature_string.encode("utf-8")) + return signer.verify(digest, signature) +#+end_src + +** Activity! +*** Follow / Accept +other.localhost --Follow-> coscup.localhost +#+begin_src json +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "http://other.localhost/9ef8847d72434cff82254f36ff88e710", + "type": "Follow", + "actor": "http://other.localhost/accounts/other", + "object": "http://coscup.localhost/meow/show" +} +#+end_src + +#+begin_src python +def _process_inbox_request(...): + ... + actor = feact_actor(ap_object["actor"]) + ... + if "Follow" == ap_object["type"]: + if _handle_follow(actor, ap_object): + ... + elif "Create" == ap_object["type"]: + if _handle_create(ap_object): + ... + + +def _handle_follow(...): + if ME["id"] != ap_object["object"]: + logger.warning("wrong follow object!" + .ap_object["id"]) + return False + + if MANUALLY_APPROVES_FOLLOWERS: + save_follow_request(ap_object) + return True + + _send_accept(actor, ap_object) + save_follower() + return True + + +async def _send_accept(...) -> None : + reply_id = BASE_URL + str(uuid.uuid4()) + + actor_url = actor["inbox"] + payload = { + "@context": AS_CTX, + "id": reply_id, + "type": "Accept", + "actor": ID, # http://coscup.localhost/user/show + "object": ap_object["id"], # http://other.localhost/9ef8847d72434cff82254f36ff88e710 + } + + post(actor_url, payload) +#+end_src + +*** Creat! +#+begin_src json +{ + "@context" : [ + "https://www.w3.org/ns/activitystreams", + { + "Emoji" : "toot:Emoji", + "atomUri" : "ostatus:atomUri", + "conversation" : "ostatus:conversation", + "focalPoint" : { + "@container" : "@list", + "@id" : "toot:focalPoint" + }, + "inReplyToAtomUri" : "ostatus:inReplyToAtomUri", + "ostatus" : "http://ostatus.org#", + "sensitive" : "as:sensitive", + "toot" : "http://joinmastodon.org/ns#", + "votersCount" : "toot:votersCount" + } + ], + "type":"Create", + "published" : "2023-07-13T16:04:57Z", + "cc" : ["http://coscup.localhost/users/show/followers"], + "to" : ["https://www.w3.org/ns/activitystreams#Public"], + "id" : "http://coscup.localhost/79d42b46-aa2f-4837-835a-5f75ce9a253f", + "object": { + "attributedTo" : "http://coscup.localhost/user/show", + "cc" : ["http://coscup.localhost/users/show/followers"], + "to" : ["https://www.w3.org/ns/activitystreams#Public"], + "id" : "http://coscup.localhost/79d42b46-aa2f-4837-835a-5f75ce9a253f", + "content" : "

Hello World!

", + "inReplyTo" : null, + "published" : "2023-07-13T16:04:57Z", + "sensitive" : false, + "summary" : null, + "tag" : [], + "type" : "Note", + "url" : "http://coscup.localhost/79d42b46-aa2f-4837-835a-5f75ce9a253f" + }, +} +#+end_src + +#+begin_src python +def _send_create(...): + object_id = BASE_URL + str(uuid.uuid4()) + to = [] + cc = [] + if visibility == "public": + to = [ap.AS_PUBLIC] + cc = [f"{BASE_URL}/followers"] + else: + raise ValueError(f"Unsupport visibility {visibility}") + + ap_object = { + "type": "Note", + "id": object_id, + "attributedTo": ID, + "content": content, + "to": to, + "cc": cc, + "published": published, + "url": object_id, + "tag": [], + "content": content, #

Hello World!

+ "summary": summary, + "inReplyTo": reply_id, + "sensitive": sensitive, + "attachment": [], + } + + recipients = set() + for actor in get_followers(): + recipients.add(actor.sharedInbox or actor.inbox_url) + + ap_object = wrap_ap_object(ap_object) + + for inbox_url in recipients: + post(inbox_url, ap_object,) + + return True + + +def wrap_ap_object(...): + return { + "@context": AS_EXTENDED_CTX, + "actor": config.ID, + "to": ap_object.get("to", []), + "cc": ap_object.get("cc", []), + "id": ap_object["id"], + "object": ap_object, + "published": now() + "type": "Create", + } +#+end_src