2019-08-02 15:21:11 +00:00
|
|
|
import urllib.parse
|
2019-09-12 20:58:26 +00:00
|
|
|
from src import IRCBot, ModuleManager, utils
|
2019-08-02 14:57:53 +00:00
|
|
|
|
2019-08-05 14:41:24 +00:00
|
|
|
HOSTMETA = "https://%s/.well-known/host-meta"
|
2019-09-07 20:49:22 +00:00
|
|
|
WEBFINGER_DEFAULT = "https://%s/.well-known/webfinger?resource={uri}"
|
2019-08-02 14:57:53 +00:00
|
|
|
WEBFINGER_HEADERS = {"Accept": "application/jrd+json"}
|
|
|
|
|
|
|
|
ACTIVITY_TYPE = "application/activity+json"
|
|
|
|
ACTIVITY_HEADERS = {"Accept": ("application/ld+json; "
|
|
|
|
'profile="https://www.w3.org/ns/activitystreams"')}
|
|
|
|
|
2019-09-12 20:58:26 +00:00
|
|
|
USERAGENT = "BitBot (%s) Fediverse" % IRCBot.VERSION
|
|
|
|
|
2019-09-02 07:51:56 +00:00
|
|
|
def _parse_username(s):
|
2019-09-09 20:35:54 +00:00
|
|
|
username, _, instance = s.rpartition("@")
|
2019-09-07 16:44:20 +00:00
|
|
|
if username.startswith("@"):
|
|
|
|
username = username[1:]
|
2019-09-02 07:51:56 +00:00
|
|
|
if username and instance:
|
2019-09-10 14:40:01 +00:00
|
|
|
return username, instance
|
|
|
|
return None, None
|
|
|
|
def _format_username(username, instance):
|
|
|
|
return "@%s@%s" % (username, instance)
|
|
|
|
def _setting_parse(s):
|
|
|
|
username, instance = _parse_username(s)
|
|
|
|
if username and instance:
|
|
|
|
return _format_username(username, instance)
|
2019-09-02 07:51:56 +00:00
|
|
|
return None
|
|
|
|
|
2019-09-10 14:40:01 +00:00
|
|
|
@utils.export("set", utils.FunctionSetting(_setting_parse, "fediverse",
|
2019-09-02 07:51:56 +00:00
|
|
|
help="Set your fediverse account", example="@gargron@mastodon.social"))
|
2019-08-02 14:57:53 +00:00
|
|
|
class Module(ModuleManager.BaseModule):
|
|
|
|
_name = "Fedi"
|
|
|
|
|
|
|
|
@utils.hook("received.command.fediverse")
|
|
|
|
@utils.hook("received.command.fedi", alias_of="fediverse")
|
|
|
|
@utils.kwarg("help", "Get someone's latest toot")
|
|
|
|
@utils.kwarg("usage", "@<user>@<instance>")
|
|
|
|
def fedi(self, event):
|
2019-09-02 07:51:56 +00:00
|
|
|
account = None
|
|
|
|
if not event["args"]:
|
|
|
|
account = event["user"].get_setting("fediverse", None)
|
|
|
|
elif not "@" in event["args"]:
|
|
|
|
target = event["args_split"][0]
|
|
|
|
if event["server"].has_user_id(target):
|
|
|
|
target_user = event["server"].get_user(target)
|
|
|
|
account = target_user.get_setting("fediverse", None)
|
|
|
|
else:
|
|
|
|
account = event["args_split"][0]
|
|
|
|
|
|
|
|
username = None
|
|
|
|
instance = None
|
|
|
|
if account:
|
2019-09-10 14:40:01 +00:00
|
|
|
username, instance = _parse_username(account)
|
2019-09-02 07:51:56 +00:00
|
|
|
|
2019-08-02 14:57:53 +00:00
|
|
|
if not username or not instance:
|
|
|
|
raise utils.EventError("Please provide @<user>@<instance>")
|
|
|
|
|
2019-08-05 14:41:24 +00:00
|
|
|
hostmeta = utils.http.request(HOSTMETA % instance,
|
2019-09-12 20:58:26 +00:00
|
|
|
parse=True, check_content_type=False, useragent=USERAGENT)
|
2019-08-05 14:41:24 +00:00
|
|
|
webfinger_url = None
|
|
|
|
for item in hostmeta.data.find_all("link"):
|
|
|
|
if item["rel"] and item["rel"][0] == "lrdd":
|
|
|
|
webfinger_url = item["template"]
|
|
|
|
break
|
|
|
|
|
|
|
|
if webfinger_url == None:
|
2019-09-07 20:49:22 +00:00
|
|
|
self.log.debug("host-meta lookup failed for %s" % instance)
|
|
|
|
webfinger_url = WEBFINGER_DEFAULT % instance
|
2019-09-10 14:46:25 +00:00
|
|
|
webfinger_url = webfinger_url.replace("{uri}",
|
|
|
|
"acct:%s@%s" % (username, instance))
|
2019-08-05 14:41:24 +00:00
|
|
|
|
|
|
|
webfinger = utils.http.request(webfinger_url,
|
2019-09-12 20:58:26 +00:00
|
|
|
headers=WEBFINGER_HEADERS, json=True, useragent=USERAGENT)
|
2019-08-02 14:57:53 +00:00
|
|
|
|
2019-08-05 14:41:24 +00:00
|
|
|
activity_url = None
|
|
|
|
for link in webfinger.data["links"]:
|
|
|
|
if link["type"] == ACTIVITY_TYPE:
|
|
|
|
activity_url = link["href"]
|
|
|
|
break
|
2019-08-02 14:57:53 +00:00
|
|
|
|
2019-08-05 14:41:24 +00:00
|
|
|
if not activity_url:
|
|
|
|
raise utils.EventError("Failed to find user activity feed")
|
2019-08-02 14:57:53 +00:00
|
|
|
|
2019-08-05 14:41:24 +00:00
|
|
|
activity = utils.http.request(activity_url,
|
2019-09-12 20:58:26 +00:00
|
|
|
headers=ACTIVITY_HEADERS, json=True, useragent=USERAGENT)
|
2019-08-05 14:41:24 +00:00
|
|
|
preferred_username = activity.data["preferredUsername"]
|
|
|
|
outbox_url = activity.data["outbox"]
|
|
|
|
|
|
|
|
outbox = utils.http.request(outbox_url, headers=ACTIVITY_HEADERS,
|
2019-09-12 20:58:26 +00:00
|
|
|
json=True, useragent=USERAGENT)
|
2019-08-05 14:41:24 +00:00
|
|
|
items = None
|
|
|
|
|
|
|
|
if "first" in outbox.data:
|
|
|
|
if type(outbox.data["first"]) == dict:
|
2019-09-02 07:51:56 +00:00
|
|
|
# pleroma
|
2019-08-05 14:41:24 +00:00
|
|
|
items = outbox.data["first"]["orderedItems"]
|
2019-08-02 16:15:16 +00:00
|
|
|
else:
|
2019-09-02 07:51:56 +00:00
|
|
|
# mastodon
|
2019-08-05 14:41:24 +00:00
|
|
|
first = utils.http.request(outbox.data["first"],
|
2019-09-12 20:58:26 +00:00
|
|
|
headers=ACTIVITY_HEADERS, json=True, useragent=USERAGENT)
|
2019-08-05 14:41:24 +00:00
|
|
|
items = first.data["orderedItems"]
|
2019-08-02 16:15:29 +00:00
|
|
|
else:
|
2019-08-05 14:41:24 +00:00
|
|
|
items = outbox.data["orderedItems"]
|
|
|
|
|
|
|
|
if not items:
|
|
|
|
raise utils.EventError("No toots found")
|
|
|
|
|
|
|
|
first_item = items[0]
|
|
|
|
if first_item["type"] == "Announce":
|
|
|
|
retoot_url = first_item["object"]
|
|
|
|
retoot_instance = urllib.parse.urlparse(retoot_url).hostname
|
|
|
|
retoot = utils.http.request(retoot_url,
|
2019-09-12 20:58:26 +00:00
|
|
|
headers=ACTIVITY_HEADERS, json=True, useragent=USERAGENT)
|
2019-08-05 14:41:24 +00:00
|
|
|
|
|
|
|
original_tooter_url = retoot.data["attributedTo"]
|
|
|
|
original_tooter = utils.http.request(original_tooter_url,
|
2019-09-12 20:58:26 +00:00
|
|
|
headers=ACTIVITY_HEADERS, json=True, useragent=USERAGENT)
|
2019-08-05 14:41:24 +00:00
|
|
|
|
|
|
|
retooted_user = "@%s@%s" % (
|
|
|
|
original_tooter.data["preferredUsername"],
|
|
|
|
retoot_instance)
|
|
|
|
|
|
|
|
shorturl = self.exports.get_one("shorturl")(
|
|
|
|
event["server"], retoot_url)
|
|
|
|
retoot_content = utils.http.strip_html(
|
|
|
|
retoot.data["content"])
|
|
|
|
|
|
|
|
event["stdout"].write("%s (boost %s): %s - %s" % (
|
|
|
|
preferred_username, retooted_user, retoot_content,
|
|
|
|
shorturl))
|
|
|
|
|
|
|
|
elif first_item["type"] == "Create":
|
|
|
|
content = utils.http.strip_html(
|
|
|
|
first_item["object"]["content"])
|
|
|
|
url = first_item["object"]["id"]
|
|
|
|
shorturl = self.exports.get_one("shorturl")(
|
|
|
|
event["server"], url)
|
|
|
|
|
|
|
|
event["stdout"].write("%s: %s - %s" % (preferred_username,
|
|
|
|
content, shorturl))
|