aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar jesopo2019-09-10 18:08:58 +0100
committerGravatar jesopo2019-09-10 18:08:58 +0100
commit8726bd9717d7cf85028bdd7c4c8a67f45f1758bf (patch)
tree0d83c084da61d801246cd1c3915cc39e16ee7738
parentreturn error codes from webfinger (diff)
signature
implement first draft of fediverse outbox
-rw-r--r--modules/fediverse_server.py90
1 files changed, 85 insertions, 5 deletions
diff --git a/modules/fediverse_server.py b/modules/fediverse_server.py
index b24db75e..5e93e45d 100644
--- a/modules/fediverse_server.py
+++ b/modules/fediverse_server.py
@@ -1,6 +1,6 @@
#--require-config tls-certificate
-import urllib.parse
+import binascii, os, urllib.parse
from src import ModuleManager, utils
ACTIVITY_TYPE = "application/activity+json"
@@ -8,6 +8,7 @@ ACTIVITY_TYPE = ("application/ld+json; "
"profile=\"https://www.w3.org/ns/activitystreams\"")
WEBFINGER_TYPE = "application/jrd+json"
+ACTIVITY_SETTING_PREFIX = "ap-activity-"
def _parse_username(s):
username, _, instance = s.rpartition("@")
@@ -30,12 +31,39 @@ def _setting_parse(s):
class Module(ModuleManager.BaseModule):
_name = "Fedi"
+ def _random_id(self):
+ return binascii.hexlify(os.urandom(3)).decode("ascii")
+
+ def _get_activities(self):
+ activities = []
+ for setting, (content, timestamp) in self.bot.find_settings_prefix(
+ ACTIVITY_SETTING_PREFIX):
+ activities[setting.replace(ACTIVITY_SETTING_PREFIX, "", 1)
+ ] = [content, timestamp]
+ return activities
+ def _make_activity(self, content):
+ timestamp = utils.iso8601_format_now()
+ activity_id = self._random_id()
+ self.bot.set_setting("ap-activity-%s" % activity_id,
+ [content, timestamp])
+ return activity_id
+
+ @utils.hook("received.command.toot")
+ @utils.kwarg("min_args", 1)
+ @utils.kwarg("permission", "toot")
+ def toot(self, event):
+ activity_id = self._make_activity(event["args"])
+ event["stdout"].write("Sent toot %s" % activity_id)
+
def _ap_self(self):
our_username = self.bot.get_setting("fediverse", None)
return _parse_username(our_username)
- def _ap_self_id(self, url_for, our_username):
+ def _ap_self_url(self, url_for, our_username):
return "https://%s" % url_for("api", "ap-user", {"u": our_username})
-
+ def _ap_outbox_url(self, url_for, our_username):
+ return "https://%s" % url_for("api", "ap-outbox", {"u": our_username})
+ def _ap_activity_url(self, url_for, activity_id):
+ return "https://%s" % url_for("api", "ap-activity", {"a": activity_id})
@utils.hook("api.get.ap-webfinger")
@utils.kwarg("authenticated", False)
@@ -52,7 +80,7 @@ class Module(ModuleManager.BaseModule):
if (requested_username == our_username and
requested_instance == our_instance):
- self_id = self._ap_self_id(event["url_for"], our_username)
+ self_id = self._ap_self_url(event["url_for"], our_username)
event["response"].content_type = WEBFINGER_TYPE
event["response"].write_json({
@@ -75,8 +103,9 @@ class Module(ModuleManager.BaseModule):
our_username, our_instance = self._ap_self()
username = event["params"].get("u", None)
if username and username == our_username:
- self_id = self._ap_self_id(event["url_for"], our_username)
+ self_id = self._ap_self_url(event["url_for"], our_username)
inbox = event["url_for"]("api", "ap-inbox", {"u": our_username})
+ outbox = self._ap_outbox_url(event["url_for"], our_username)
cert_filename = self.bot.config["tls-certificate"]
with open(cert_filename) as cert_file:
@@ -92,9 +121,60 @@ class Module(ModuleManager.BaseModule):
"type": "Person",
"preferredUsername": our_username,
"inbox": inbox,
+ "outbox": outbox,
"publicKey": {
"id": "%s#key" % self_id,
"owner": self_id,
"publicKeyPem": cert
}
})
+ else:
+ event["response"].code = 404
+
+ def _prepare_activity(self, url_for, self_id, activity_id, content,
+ timestamp):
+ activity_url = self._ap_activity_url(url_for, activity_id)
+ return activity_url, {
+ "attributedTo": self_id,
+ "content": content,
+ "conversation": activity_id, "context": activity_id,
+ "id": activity_url, "url": activity_url,
+ "published": timestamp,
+ "summary": "", # content warning here
+ "to": "https://www.w3.org/ns/activitystreams#Public",
+ "type": "Note",
+ }
+
+ @utils.hook("api.get.ap-outbox")
+ @utils.kwarg("authenticated", False)
+ def ap_outbox(self, event):
+ our_username, our_instance = self._ap_self()
+ username = event["params"].get("u", None)
+ if username and username == our_username:
+ self_id = self._ap_self_url(event["url_for"], our_username)
+ outbox = self._ap_outbox_url(event["url_for"], our_username)
+
+ activities = []
+ for activity_id, (content, timestamp) in self._get_activities():
+ activity_url, activity_object = self._prepare_actitivy(
+ event["url_for"], self_id, activity_id, content, timestamp)
+ activities.append({
+ "actor": self_id,
+ "id": activity_url,
+ "object": activity_object,
+ "published": timestamp,
+ "to": ["https://www.w3.org/ns/activitystreams#Public"],
+ "type": "Create"
+ })
+
+ event["response"].write_json({
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "id": outbox,
+ "orderedItems": activities,
+ "totalItems": len(activities),
+ "type": "OrderedCollection"
+ })
+
+ else:
+ event["response"].code = 404
+