kopia lustrzana https://gitlab.com/jaywink/federation
Fixes to address the reviewer's comments. Where appropriate, align with existing code structure.
rodzic
26f93ec1be
commit
e7d954b788
|
@ -2,10 +2,12 @@ import json
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from pyld import jsonld
|
from pyld import jsonld
|
||||||
|
|
||||||
from federation.utils.django import get_redis
|
try:
|
||||||
|
from federation.utils.django import get_redis
|
||||||
cache = get_redis() or {}
|
cache = get_redis() or {}
|
||||||
EXPIRATION = int(timedelta(weeks=4).total_seconds())
|
EXPIRATION = int(timedelta(weeks=4).total_seconds())
|
||||||
|
except:
|
||||||
|
cache = {}
|
||||||
|
|
||||||
|
|
||||||
# This is required to workaround a bug in pyld that has the Accept header
|
# This is required to workaround a bug in pyld that has the Accept header
|
||||||
|
@ -24,9 +26,9 @@ def get_loader(*args, **kwargs):
|
||||||
options['headers']['Accept'] = 'application/ld+json'
|
options['headers']['Accept'] = 'application/ld+json'
|
||||||
doc = requests_loader(url, options)
|
doc = requests_loader(url, options)
|
||||||
if isinstance(cache, dict):
|
if isinstance(cache, dict):
|
||||||
cache[url] = json.dumps(doc)
|
cache[key] = json.dumps(doc)
|
||||||
else:
|
else:
|
||||||
cache.set(f'ld_cache:{url}', json.dumps(doc), ex=EXPIRATION)
|
cache.set(key, json.dumps(doc), ex=EXPIRATION)
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
return loader
|
return loader
|
||||||
|
|
|
@ -6,6 +6,7 @@ from pyld import jsonld
|
||||||
|
|
||||||
from federation.entities.activitypub.constants import CONTEXT_ACTIVITYSTREAMS, CONTEXT_SECURITY, NAMESPACE_PUBLIC
|
from federation.entities.activitypub.constants import CONTEXT_ACTIVITYSTREAMS, CONTEXT_SECURITY, NAMESPACE_PUBLIC
|
||||||
|
|
||||||
|
|
||||||
# Extract context information from the metadata parameter defined for fields
|
# Extract context information from the metadata parameter defined for fields
|
||||||
# that are not part of the official AP spec. Use the same extended context for
|
# that are not part of the official AP spec. Use the same extended context for
|
||||||
# inbound payload. For outbound payload, build a context with only the required
|
# inbound payload. For outbound payload, build a context with only the required
|
||||||
|
@ -22,16 +23,16 @@ class LdContextManager:
|
||||||
self._extensions[klass] = {}
|
self._extensions[klass] = {}
|
||||||
ctx = getattr(klass, 'ctx', [])
|
ctx = getattr(klass, 'ctx', [])
|
||||||
if ctx:
|
if ctx:
|
||||||
self._extensions[klass].update({klass.__name__:ctx})
|
self._extensions[klass].update({klass.__name__: ctx})
|
||||||
for name, value in klass.schema().declared_fields.items():
|
for name, value in klass.schema().declared_fields.items():
|
||||||
ctx = value.metadata.get('ctx') or []
|
ctx = value.metadata.get('ctx') or []
|
||||||
if ctx:
|
if ctx:
|
||||||
self._extensions[klass].update({name:ctx})
|
self._extensions[klass].update({name: ctx})
|
||||||
merged = {}
|
merged = {}
|
||||||
for field in self._extensions.values():
|
for field in self._extensions.values():
|
||||||
for ctx in field.values():
|
for ctx in field.values():
|
||||||
self._add_extensions(ctx, self._named, merged)
|
self._add_extensions(ctx, self._named, merged)
|
||||||
self._merged = copy.copy(self._named)
|
self._merged = copy.copy(self._named)
|
||||||
self._merged.append(merged)
|
self._merged.append(merged)
|
||||||
|
|
||||||
def _add_extensions(self, field, named, extensions):
|
def _add_extensions(self, field, named, extensions):
|
||||||
|
@ -41,7 +42,6 @@ class LdContextManager:
|
||||||
elif isinstance(item, dict):
|
elif isinstance(item, dict):
|
||||||
extensions.update(item)
|
extensions.update(item)
|
||||||
|
|
||||||
|
|
||||||
def _get_fields(self, obj):
|
def _get_fields(self, obj):
|
||||||
for klass in self._extensions.keys():
|
for klass in self._extensions.keys():
|
||||||
if issubclass(type(obj), klass):
|
if issubclass(type(obj), klass):
|
||||||
|
@ -58,14 +58,16 @@ class LdContextManager:
|
||||||
def patch_payload(payload, patched):
|
def patch_payload(payload, patched):
|
||||||
for field in ('attachment', 'cc', 'tag', 'to'):
|
for field in ('attachment', 'cc', 'tag', 'to'):
|
||||||
value = payload.get(field)
|
value = payload.get(field)
|
||||||
if value and not isinstance(value, list):
|
if not value:
|
||||||
|
continue
|
||||||
|
if not isinstance(value, list):
|
||||||
value = [value]
|
value = [value]
|
||||||
patched[field] = value
|
patched[field] = value
|
||||||
if field in ('cc', 'to'):
|
if field in ('cc', 'to'):
|
||||||
try:
|
try:
|
||||||
idx = value.index('as:Public')
|
idx = value.index('as:Public')
|
||||||
patched[field][idx] = value[idx].replace('as:Public', NAMESPACE_PUBLIC)
|
patched[field][idx] = value[idx].replace('as:Public', NAMESPACE_PUBLIC)
|
||||||
except:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
if isinstance(payload.get('object'), dict):
|
if isinstance(payload.get('object'), dict):
|
||||||
patch_payload(payload['object'], patched['object'])
|
patch_payload(payload['object'], patched['object'])
|
||||||
|
@ -88,22 +90,25 @@ class LdContextManager:
|
||||||
if field in to_add.keys():
|
if field in to_add.keys():
|
||||||
if field_value is not missing or obj.signable and field == 'signature':
|
if field_value is not missing or obj.signable and field == 'signature':
|
||||||
self._add_extensions(to_add[field], final, extensions)
|
self._add_extensions(to_add[field], final, extensions)
|
||||||
if not isinstance(field_value, list): field_value = [field_value]
|
if not isinstance(field_value, list):
|
||||||
|
field_value = [field_value]
|
||||||
for value in field_value:
|
for value in field_value:
|
||||||
if issubclass(type(value), (Object, Link)):
|
if issubclass(type(value), (Object, Link)):
|
||||||
walk_object(value)
|
walk_object(value)
|
||||||
|
|
||||||
walk_object(obj)
|
walk_object(obj)
|
||||||
if extensions: final.append(extensions)
|
if extensions:
|
||||||
|
final.append(extensions)
|
||||||
# compact the array if len == 1 to minimize test changes
|
# compact the array if len == 1 to minimize test changes
|
||||||
return final if len(final) > 1 else final[0]
|
return final if len(final) > 1 else final[0]
|
||||||
|
|
||||||
def merge_context(self, ctx):
|
def merge_context(self, ctx):
|
||||||
# One platform sends a single string context
|
# One platform sends a single string context
|
||||||
if isinstance(ctx, str): ctx = [ctx]
|
if isinstance(ctx, str):
|
||||||
|
ctx = [ctx]
|
||||||
|
|
||||||
# add a # at the end of the python-federation string
|
# add a # at the end of the python-federation string
|
||||||
# for socialhome payloads
|
# for legacy socialhome payloads
|
||||||
s = json.dumps(ctx)
|
s = json.dumps(ctx)
|
||||||
if 'python-federation"' in s:
|
if 'python-federation"' in s:
|
||||||
ctx = json.loads(s.replace('python-federation', 'python-federation#', 1))
|
ctx = json.loads(s.replace('python-federation', 'python-federation#', 1))
|
||||||
|
@ -112,7 +117,7 @@ class LdContextManager:
|
||||||
# is not a json-ld document.
|
# is not a json-ld document.
|
||||||
try:
|
try:
|
||||||
ctx.pop(ctx.index('http://joinmastodon.org/ns'))
|
ctx.pop(ctx.index('http://joinmastodon.org/ns'))
|
||||||
except:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# remove @language in context since this directive is not
|
# remove @language in context since this directive is not
|
||||||
|
@ -124,13 +129,12 @@ class LdContextManager:
|
||||||
for i, v in enumerate(ctx):
|
for i, v in enumerate(ctx):
|
||||||
if isinstance(v, dict):
|
if isinstance(v, dict):
|
||||||
v.pop('@language', None)
|
v.pop('@language', None)
|
||||||
if len(v) == 0: idx.insert(0, i)
|
if len(v) == 0:
|
||||||
for i in idx: ctx.pop(i)
|
idx.insert(0, i)
|
||||||
|
for i in idx:
|
||||||
|
ctx.pop(i)
|
||||||
|
|
||||||
# AP activities may be signed, but most platforms don't
|
# Merge all defined AP extensions to the inbound context
|
||||||
# define RsaSignature2017. add it to the context
|
|
||||||
# hubzilla doesn't define the discoverable property in its context
|
|
||||||
# include all Mastodon extensions for platforms that only define http://joinmastodon.org/ns in their context
|
|
||||||
uris = []
|
uris = []
|
||||||
defs = {}
|
defs = {}
|
||||||
# Merge original context dicts in one dict
|
# Merge original context dicts in one dict
|
||||||
|
|
|
@ -3,7 +3,7 @@ import logging
|
||||||
import math
|
import math
|
||||||
import re
|
import re
|
||||||
from base64 import b64encode, b64decode
|
from base64 import b64encode, b64decode
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from funcy import omit
|
from funcy import omit
|
||||||
from pyld import jsonld
|
from pyld import jsonld
|
||||||
|
|
||||||
|
@ -22,13 +22,13 @@ def create_ld_signature(obj, author):
|
||||||
sig = {
|
sig = {
|
||||||
'created': datetime.datetime.now(tz=datetime.timezone.utc).isoformat(timespec='seconds'),
|
'created': datetime.datetime.now(tz=datetime.timezone.utc).isoformat(timespec='seconds'),
|
||||||
'creator': f'{author.id}#main-key',
|
'creator': f'{author.id}#main-key',
|
||||||
'@context':'https://w3id.org/security/v1'
|
'@context': 'https://w3id.org/security/v1'
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
private_key = import_key(author.private_key)
|
private_key = import_key(author.private_key)
|
||||||
except (ValueError, TypeError) as exc:
|
except (ValueError, TypeError) as exc:
|
||||||
logger.warning(f'ld_signature - {exc}')
|
logger.warning('ld_signature - %s', exc)
|
||||||
return None
|
return None
|
||||||
signer = pkcs1_15.new(private_key)
|
signer = pkcs1_15.new(private_key)
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ def create_ld_signature(obj, author):
|
||||||
sig.update({'type': 'RsaSignature2017', 'signatureValue': b64encode(signature).decode()})
|
sig.update({'type': 'RsaSignature2017', 'signatureValue': b64encode(signature).decode()})
|
||||||
sig.pop('@context')
|
sig.pop('@context')
|
||||||
|
|
||||||
obj.update({'signature':sig})
|
obj.update({'signature': sig})
|
||||||
|
|
||||||
|
|
||||||
def verify_ld_signature(payload):
|
def verify_ld_signature(payload):
|
||||||
|
@ -49,24 +49,25 @@ def verify_ld_signature(payload):
|
||||||
"""
|
"""
|
||||||
signature = copy(payload.get('signature', None))
|
signature = copy(payload.get('signature', None))
|
||||||
if not signature:
|
if not signature:
|
||||||
logger.warning(f'ld_signature - No signature in {payload.get("id", "the payload")}')
|
logger.warning('ld_signature - No signature in %s', payload.get("id", "the payload"))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# retrieve the author's public key
|
# retrieve the author's public key
|
||||||
profile = retrieve_and_parse_document(signature.get('creator'))
|
profile = retrieve_and_parse_document(signature.get('creator'))
|
||||||
if not profile:
|
if not profile:
|
||||||
logger.warning(f'ld_signature - Failed to retrieve profile for {signature.get("creator")}')
|
|
||||||
|
logger.warning('ld_signature - Failed to retrieve profile for %s', signature.get("creator"))
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
pkey = import_key(profile.public_key)
|
pkey = import_key(profile.public_key)
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
logger.warning(f'ld_signature - {exc}')
|
logger.warning('ld_signature - %s', exc)
|
||||||
return None
|
return None
|
||||||
verifier = pkcs1_15.new(pkey)
|
verifier = pkcs1_15.new(pkey)
|
||||||
|
|
||||||
# Compute digests and verify signature
|
# Compute digests and verify signature
|
||||||
sig = omit(signature, ('type', 'signatureValue'))
|
sig = omit(signature, ('type', 'signatureValue'))
|
||||||
sig.update({'@context':'https://w3id.org/security/v1'})
|
sig.update({'@context': 'https://w3id.org/security/v1'})
|
||||||
sig_digest = hash(sig)
|
sig_digest = hash(sig)
|
||||||
obj = omit(payload, 'signature')
|
obj = omit(payload, 'signature')
|
||||||
obj_digest = hash(obj)
|
obj_digest = hash(obj)
|
||||||
|
@ -75,15 +76,15 @@ def verify_ld_signature(payload):
|
||||||
sig_value = b64decode(signature.get('signatureValue'))
|
sig_value = b64decode(signature.get('signatureValue'))
|
||||||
try:
|
try:
|
||||||
verifier.verify(SHA256.new(digest), sig_value)
|
verifier.verify(SHA256.new(digest), sig_value)
|
||||||
logger.debug(f'ld_signature - {payload.get("id")} has a valid signature')
|
logger.debug('ld_signature - %s has a valid signature', payload.get("id"))
|
||||||
return profile.id
|
return profile.id
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.warning(f'ld_signature - Invalid signature for {payload.get("id")}')
|
logger.warning('ld_signature - Invalid signature for %s', payload.get("id"))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def hash(obj):
|
def hash(obj):
|
||||||
nquads = NormalizedDoubles().normalize(obj, options={'format':'application/nquads','algorithm':'URDNA2015'})
|
nquads = NormalizedDoubles().normalize(obj, options={'format': 'application/nquads', 'algorithm': 'URDNA2015'})
|
||||||
return SHA256.new(nquads.encode('utf-8')).hexdigest()
|
return SHA256.new(nquads.encode('utf-8')).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import bleach
|
||||||
from calamus import fields
|
from calamus import fields
|
||||||
from calamus.schema import JsonLDAnnotation, JsonLDSchema, JsonLDSchemaOpts
|
from calamus.schema import JsonLDAnnotation, JsonLDSchema, JsonLDSchemaOpts
|
||||||
from calamus.utils import normalize_value
|
from calamus.utils import normalize_value
|
||||||
|
from cryptography.exceptions import InvalidSignature
|
||||||
from marshmallow import exceptions, pre_load, post_load, post_dump
|
from marshmallow import exceptions, pre_load, post_load, post_dump
|
||||||
from marshmallow.fields import Integer
|
from marshmallow.fields import Integer
|
||||||
from marshmallow.utils import EXCLUDE, missing
|
from marshmallow.utils import EXCLUDE, missing
|
||||||
|
@ -25,7 +26,6 @@ from federation.outbound import handle_send
|
||||||
from federation.types import UserType, ReceiverVariant
|
from federation.types import UserType, ReceiverVariant
|
||||||
from federation.utils.activitypub import retrieve_and_parse_document, retrieve_and_parse_profile, \
|
from federation.utils.activitypub import retrieve_and_parse_document, retrieve_and_parse_profile, \
|
||||||
get_profile_id_from_webfinger
|
get_profile_id_from_webfinger
|
||||||
from federation.utils.django import get_configuration
|
|
||||||
from federation.utils.text import with_slash, validate_handle
|
from federation.utils.text import with_slash, validate_handle
|
||||||
|
|
||||||
logger = logging.getLogger("federation")
|
logger = logging.getLogger("federation")
|
||||||
|
@ -297,12 +297,23 @@ class Object(BaseEntity, metaclass=JsonLDAnnotation):
|
||||||
# TODO: rework validation
|
# TODO: rework validation
|
||||||
def validate(self, direction='inbound'):
|
def validate(self, direction='inbound'):
|
||||||
if direction == 'inbound':
|
if direction == 'inbound':
|
||||||
|
# ensure marshmallow.missing is not sent to the client app
|
||||||
for attr in type(self).schema().load_fields.keys():
|
for attr in type(self).schema().load_fields.keys():
|
||||||
if getattr(self, attr) is missing:
|
if getattr(self, attr) is missing:
|
||||||
setattr(self, attr, None)
|
setattr(self, attr, None)
|
||||||
|
|
||||||
super().validate(direction)
|
super().validate(direction)
|
||||||
|
|
||||||
|
def _validate_signatures(self):
|
||||||
|
# Always verify the inbound LD signature, for monitoring purposes
|
||||||
|
actor = verify_ld_signature(self._source_object)
|
||||||
|
if not self._sender:
|
||||||
|
return
|
||||||
|
if self.signable and self._sender not in (self.id, getattr(self, 'actor_id', None)):
|
||||||
|
# Relayed payload
|
||||||
|
if not actor:
|
||||||
|
raise InvalidSignature('no or invalid signature for %s, a relayed payload', self.id)
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self):
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
return str(self.to_as2())
|
return str(self.to_as2())
|
||||||
|
@ -457,6 +468,7 @@ class Link(metaclass=JsonLDAnnotation):
|
||||||
|
|
||||||
class Hashtag(Link):
|
class Hashtag(Link):
|
||||||
ctx = [{'Hashtag': 'as:Hashtag'}]
|
ctx = [{'Hashtag': 'as:Hashtag'}]
|
||||||
|
id = fields.Id() # Hubzilla uses id instead of href
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
rdf_type = as2.Hashtag
|
rdf_type = as2.Hashtag
|
||||||
|
@ -702,7 +714,7 @@ class Note(Object, RawContentMixin):
|
||||||
self._allowed_children += (base.Audio, base.Video)
|
self._allowed_children += (base.Audio, base.Video)
|
||||||
|
|
||||||
def to_as2(self):
|
def to_as2(self):
|
||||||
#self.sensitive = 'nsfw' in self.tags
|
self.sensitive = 'nsfw' in self.tags
|
||||||
self.url = self.id
|
self.url = self.id
|
||||||
|
|
||||||
edited = False
|
edited = False
|
||||||
|
@ -768,7 +780,13 @@ class Note(Object, RawContentMixin):
|
||||||
# Skip when markdown
|
# Skip when markdown
|
||||||
return
|
return
|
||||||
|
|
||||||
hrefs = [tag.href.lower() for tag in self.tag_objects if isinstance(tag, Hashtag)]
|
hrefs = []
|
||||||
|
for tag in self.tag_objects:
|
||||||
|
if isinstance(tag, Hashtag):
|
||||||
|
if tag.href is not missing:
|
||||||
|
hrefs.append(tag.href.lower())
|
||||||
|
elif tag.id is not missing:
|
||||||
|
hrefs.append(tag.id.lower())
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
def remove_tag_links(attrs, new=False):
|
def remove_tag_links(attrs, new=False):
|
||||||
# Hashtag object hrefs
|
# Hashtag object hrefs
|
||||||
|
@ -807,6 +825,7 @@ class Note(Object, RawContentMixin):
|
||||||
Populate tags to the object.tag list.
|
Populate tags to the object.tag list.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
from federation.utils.django import get_configuration
|
||||||
config = get_configuration()
|
config = get_configuration()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
tags_path = None
|
tags_path = None
|
||||||
|
@ -1321,6 +1340,7 @@ def element_to_objects(element: Union[Dict, Object], sender: str = "") -> List:
|
||||||
entity = model_to_objects(element) if not isinstance(element, Object) else element
|
entity = model_to_objects(element) if not isinstance(element, Object) else element
|
||||||
if entity and hasattr(entity, 'to_base'):
|
if entity and hasattr(entity, 'to_base'):
|
||||||
entity = entity.to_base()
|
entity = entity.to_base()
|
||||||
|
entity._sender = sender
|
||||||
if isinstance(entity, (
|
if isinstance(entity, (
|
||||||
base.Post, base.Comment, base.Profile, base.Share, base.Follow,
|
base.Post, base.Comment, base.Profile, base.Share, base.Follow,
|
||||||
base.Retraction, base.Accept,)
|
base.Retraction, base.Accept,)
|
||||||
|
@ -1330,13 +1350,11 @@ def element_to_objects(element: Union[Dict, Object], sender: str = "") -> List:
|
||||||
except ValueError as ex:
|
except ValueError as ex:
|
||||||
logger.error("Failed to validate entity %s: %s", entity, ex)
|
logger.error("Failed to validate entity %s: %s", entity, ex)
|
||||||
return []
|
return []
|
||||||
# Always verify the LD signature, for monitoring purposes
|
except InvalidSignature as exc:
|
||||||
actor = verify_ld_signature(entity._source_object)
|
logger.info('%s, fetching from remote', exc)
|
||||||
if entity.signable and sender not in (entity.id, getattr(entity, 'actor_id', None), ''):
|
entity = retrieve_and_parse_document(entity.id)
|
||||||
# Relayed payload
|
if not entity:
|
||||||
if not actor:
|
return []
|
||||||
logger.warning(f'no or invalid signature for a relayed payload, fetching {entity.id}')
|
|
||||||
entity = retrieve_and_parse_document(entity.id)
|
|
||||||
logger.info('Entity type "%s" was handled through the json-ld processor', entity.__class__.__name__)
|
logger.info('Entity type "%s" was handled through the json-ld processor', entity.__class__.__name__)
|
||||||
return [entity]
|
return [entity]
|
||||||
elif entity:
|
elif entity:
|
||||||
|
@ -1355,7 +1373,7 @@ def model_to_objects(payload):
|
||||||
try:
|
try:
|
||||||
entity = model.schema().load(payload)
|
entity = model.schema().load(payload)
|
||||||
except (KeyError, jsonld.JsonLdError, exceptions.ValidationError) as exc : # Just give up for now. This must be made robust
|
except (KeyError, jsonld.JsonLdError, exceptions.ValidationError) as exc : # Just give up for now. This must be made robust
|
||||||
logger.error(f"Error parsing jsonld payload ({exc})")
|
logger.error("Error parsing jsonld payload (%s)", exc)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if isinstance(getattr(entity, 'object_', None), Object):
|
if isinstance(getattr(entity, 'object_', None), Object):
|
||||||
|
|
|
@ -20,6 +20,7 @@ class BaseEntity:
|
||||||
_source_protocol: str = ""
|
_source_protocol: str = ""
|
||||||
# Contains the original object from payload as a string
|
# Contains the original object from payload as a string
|
||||||
_source_object: Union[str, Dict] = None
|
_source_object: Union[str, Dict] = None
|
||||||
|
_sender: str = ""
|
||||||
_sender_key: str = ""
|
_sender_key: str = ""
|
||||||
# ActivityType
|
# ActivityType
|
||||||
activity: ActivityType = None
|
activity: ActivityType = None
|
||||||
|
@ -231,8 +232,8 @@ class RawContentMixin(BaseEntity):
|
||||||
@property
|
@property
|
||||||
def rendered_content(self) -> str:
|
def rendered_content(self) -> str:
|
||||||
"""Returns the rendered version of raw_content, or just raw_content."""
|
"""Returns the rendered version of raw_content, or just raw_content."""
|
||||||
from federation.utils.django import get_configuration
|
|
||||||
try:
|
try:
|
||||||
|
from federation.utils.django import get_configuration
|
||||||
config = get_configuration()
|
config = get_configuration()
|
||||||
if config["tags_path"]:
|
if config["tags_path"]:
|
||||||
def linkifier(tag: str) -> str:
|
def linkifier(tag: str) -> str:
|
||||||
|
|
|
@ -60,7 +60,7 @@ def rfc7033_webfinger_view(request, *args, **kwargs):
|
||||||
if not resource.startswith("acct:"):
|
if not resource.startswith("acct:"):
|
||||||
return HttpResponseBadRequest("Invalid resource")
|
return HttpResponseBadRequest("Invalid resource")
|
||||||
handle = resource.replace("acct:", "").lower()
|
handle = resource.replace("acct:", "").lower()
|
||||||
logger.debug(f"{handle} requested with {request}")
|
logger.debug("%s requested with %s", handle, request)
|
||||||
profile_func = get_function_from_config("get_profile_function")
|
profile_func = get_function_from_config("get_profile_function")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -90,6 +90,6 @@ class Protocol:
|
||||||
# Verify the HTTP signature
|
# Verify the HTTP signature
|
||||||
self.sender = verify_request_signature(self.request)
|
self.sender = verify_request_signature(self.request)
|
||||||
except (ValueError, KeyError, InvalidSignature) as exc:
|
except (ValueError, KeyError, InvalidSignature) as exc:
|
||||||
logger.warning(f'HTTP signature verification failed: {exc}')
|
logger.warning('HTTP signature verification failed: %s', exc)
|
||||||
return self.actor, {}
|
return self.actor, {}
|
||||||
return self.sender, self.payload
|
return self.sender, self.payload
|
||||||
|
|
|
@ -79,9 +79,3 @@ def verify_request_signature(request: RequestType, required: bool=True):
|
||||||
raise ValueError("Invalid signature")
|
raise ValueError("Invalid signature")
|
||||||
|
|
||||||
return signer.id
|
return signer.id
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,17 @@ import logging
|
||||||
from typing import Optional, Any
|
from typing import Optional, Any
|
||||||
|
|
||||||
from federation.protocols.activitypub.signing import get_http_authentication
|
from federation.protocols.activitypub.signing import get_http_authentication
|
||||||
from federation.utils.django import get_federation_user
|
|
||||||
from federation.utils.network import fetch_document, try_retrieve_webfinger_document
|
from federation.utils.network import fetch_document, try_retrieve_webfinger_document
|
||||||
from federation.utils.text import decode_if_bytes, validate_handle
|
from federation.utils.text import decode_if_bytes, validate_handle
|
||||||
|
|
||||||
logger = logging.getLogger('federation')
|
logger = logging.getLogger('federation')
|
||||||
|
|
||||||
federation_user = get_federation_user()
|
try:
|
||||||
if not federation_user: logger.warning("django is required for get requests signing")
|
from federation.utils.django import get_federation_user
|
||||||
|
federation_user = get_federation_user()
|
||||||
|
except ImportError:
|
||||||
|
federation_user = None
|
||||||
|
logger.warning("django is required for get requests signing")
|
||||||
|
|
||||||
|
|
||||||
def get_profile_id_from_webfinger(handle: str) -> Optional[str]:
|
def get_profile_id_from_webfinger(handle: str) -> Optional[str]:
|
||||||
|
|
Ładowanie…
Reference in New Issue