2019-03-14 20:06:39 +00:00
|
|
|
import json
|
2018-10-28 21:31:33 +00:00
|
|
|
import logging
|
|
|
|
from typing import Optional, Any
|
|
|
|
|
|
|
|
from federation.entities.activitypub.entities import ActivitypubProfile
|
2022-08-19 17:01:44 +00:00
|
|
|
from federation.protocols.activitypub.signing import get_http_authentication
|
2019-11-02 23:02:03 +00:00
|
|
|
from federation.utils.network import fetch_document, try_retrieve_webfinger_document
|
|
|
|
from federation.utils.text import decode_if_bytes, validate_handle
|
2018-10-28 21:31:33 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger('federation')
|
|
|
|
|
2022-08-19 17:01:44 +00:00
|
|
|
try:
|
|
|
|
from federation.utils.django import get_federation_user
|
|
|
|
federation_user = get_federation_user()
|
|
|
|
except (ImportError, AttributeError):
|
|
|
|
federation_user = None
|
|
|
|
logger.warning("django is required for get requests signing")
|
2018-10-28 21:31:33 +00:00
|
|
|
|
2019-11-02 23:02:03 +00:00
|
|
|
def get_profile_id_from_webfinger(handle: str) -> Optional[str]:
|
|
|
|
"""
|
|
|
|
Fetch remote webfinger, if any, and try to parse an AS2 profile ID.
|
|
|
|
"""
|
|
|
|
document = try_retrieve_webfinger_document(handle)
|
|
|
|
if not document:
|
|
|
|
return
|
|
|
|
|
|
|
|
try:
|
|
|
|
doc = json.loads(document)
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
return
|
|
|
|
for link in doc.get("links", []):
|
|
|
|
if link.get("rel") == "self" and link.get("type") == "application/activity+json":
|
|
|
|
return link["href"]
|
|
|
|
logger.debug("get_profile_id_from_webfinger: found webfinger but it has no as2 self href")
|
|
|
|
|
|
|
|
|
2019-08-05 20:58:08 +00:00
|
|
|
def retrieve_and_parse_content(**kwargs) -> Optional[Any]:
|
|
|
|
return retrieve_and_parse_document(kwargs.get("id"))
|
|
|
|
|
|
|
|
|
2019-03-14 20:06:39 +00:00
|
|
|
def retrieve_and_parse_document(fid: str) -> Optional[Any]:
|
2018-10-28 21:31:33 +00:00
|
|
|
"""
|
|
|
|
Retrieve remote document by ID and return the entity.
|
|
|
|
"""
|
2022-08-19 17:01:44 +00:00
|
|
|
from federation.entities.activitypub.models import element_to_objects # Circulars
|
|
|
|
document, status_code, ex = fetch_document(fid, extra_headers={'accept': 'application/activity+json'},
|
|
|
|
auth=get_http_authentication(federation_user.rsa_private_key,f'{federation_user.id}#main-key') if federation_user else None)
|
2018-10-28 21:31:33 +00:00
|
|
|
if document:
|
2019-03-14 20:06:39 +00:00
|
|
|
document = json.loads(decode_if_bytes(document))
|
2022-08-19 17:01:44 +00:00
|
|
|
entities = element_to_objects(document)
|
2018-10-28 21:31:33 +00:00
|
|
|
if entities:
|
2019-08-05 20:58:08 +00:00
|
|
|
logger.info("retrieve_and_parse_document - using first entity: %s", entities[0])
|
2018-10-28 21:31:33 +00:00
|
|
|
return entities[0]
|
|
|
|
|
|
|
|
|
2019-03-14 20:06:39 +00:00
|
|
|
def retrieve_and_parse_profile(fid: str) -> Optional[ActivitypubProfile]:
|
2018-10-28 21:31:33 +00:00
|
|
|
"""
|
2019-03-14 20:06:39 +00:00
|
|
|
Retrieve the remote fid and return a Profile object.
|
2018-10-28 21:31:33 +00:00
|
|
|
"""
|
2019-11-02 23:02:03 +00:00
|
|
|
if validate_handle(fid):
|
|
|
|
profile_id = get_profile_id_from_webfinger(fid)
|
|
|
|
if not profile_id:
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
profile_id = fid
|
|
|
|
profile = retrieve_and_parse_document(profile_id)
|
2018-10-28 21:31:33 +00:00
|
|
|
if not profile:
|
|
|
|
return
|
|
|
|
try:
|
|
|
|
profile.validate()
|
|
|
|
except ValueError as ex:
|
|
|
|
logger.warning("retrieve_and_parse_profile - found profile %s but it didn't validate: %s",
|
|
|
|
profile, ex)
|
|
|
|
return
|
|
|
|
return profile
|
2022-08-19 17:01:44 +00:00
|
|
|
|