# HG changeset patch # User Goffi # Date 1656497181 -7200 # Node ID 0b1c30ff2cbb9d018f0555ff702164d5e288fefe # Parent 88e332cec47b644e02d9ef4cfa2df581b6bb1336 component AP: XMPP identity => AP actor data converstion: XMPP identity data (coming from various XEPs, notably XEP-0292 (vCard4) and XEP-0084 (User Avatar)) are now used to complete actor data. Avatar files can now be delivered with the `avatar` type in URL. rel 368 diff -r 88e332cec47b -r 0b1c30ff2cbb sat/plugins/plugin_comp_ap_gateway/__init__.py --- a/sat/plugins/plugin_comp_ap_gateway/__init__.py Wed Jun 29 11:59:07 2022 +0200 +++ b/sat/plugins/plugin_comp_ap_gateway/__init__.py Wed Jun 29 12:06:21 2022 +0200 @@ -87,8 +87,8 @@ C.PI_TYPE: C.PLUG_TYPE_ENTRY_POINT, C.PI_PROTOCOLS: [], C.PI_DEPENDENCIES: [ - "XEP-0060", "XEP-0106", "XEP-0277", "XEP-0329", "XEP-0424", "XEP-0465", - "PUBSUB_CACHE", "TEXT_SYNTAXES" + "XEP-0060", "XEP-0084", "XEP-0106", "XEP-0277", "XEP-0292", "XEP-0329", + "XEP-0424", "XEP-0465", "PUBSUB_CACHE", "TEXT_SYNTAXES", "IDENTITY", "XEP-0054" ], C.PI_RECOMMENDATIONS: [], C.PI_MAIN: "APGateway", diff -r 88e332cec47b -r 0b1c30ff2cbb sat/plugins/plugin_comp_ap_gateway/http_server.py --- a/sat/plugins/plugin_comp_ap_gateway/http_server.py Wed Jun 29 11:59:07 2022 +0200 +++ b/sat/plugins/plugin_comp_ap_gateway/http_server.py Wed Jun 29 12:06:21 2022 +0200 @@ -17,14 +17,17 @@ # along with this program. If not, see . import time +import html from typing import Optional, Dict, List, Any import json from urllib import parse from collections import deque import unicodedata +from pathlib import Path from pprint import pformat from twisted.web import http, resource as web_resource, server +from twisted.web import static from twisted.python import failure from twisted.internet import reactor, defer from twisted.words.protocols.jabber import jid, error @@ -300,7 +303,10 @@ # we have to use AP account as preferredUsername because it is used to retrieve # actor handle (see https://socialhub.activitypub.rocks/t/how-to-retrieve-user-server-tld-handle-from-actors-url/2196) preferred_username = ap_account.split("@", 1)[0] - return { + + identity_data = await self.apg._i.getIdentity(self.apg.client, account_jid) + + actor_data = { "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1" @@ -323,6 +329,28 @@ }, } + if identity_data.get("nicknames"): + actor_data["name"] = identity_data["nicknames"][0] + if identity_data.get("description"): + # description is plain text while summary expects HTML + actor_data["summary"] = html.escape(identity_data["description"]) + if identity_data.get("avatar"): + avatar_data = identity_data["avatar"] + try: + filename = avatar_data["filename"] + media_type = avatar_data["media_type"] + except KeyError: + log.error(f"incomplete avatar data: {identity_data!r}") + else: + avatar_url = self.apg.buildAPURL("avatar", filename) + actor_data["icon"] = { + "type": "Image", + "url": avatar_url, + "mediaType": media_type + } + + return actor_data + def getCanonicalURL(self, request: "HTTPRequest") -> str: return parse.urljoin( f"https://{self.apg.public_url}", @@ -618,6 +646,12 @@ ret_data = await self.APInboxRequest( request, None, None, None, ap_url, signing_actor ) + elif request_type == "avatar": + if len(extra_args) != 1: + raise exceptions.DataError("avatar argument expected in URL") + avatar_filename = extra_args[0] + avatar_path = self.apg.host.common_cache.getPath(avatar_filename) + return static.File(str(avatar_path)).render(request) else: if len(extra_args) > 1: log.warning(f"unexpected extra arguments: {extra_args!r}")