kopia lustrzana https://github.com/snarfed/bridgy-fed
rodzic
1591dfb641
commit
03315891aa
|
|
@ -358,7 +358,9 @@ class ActivityPub(User, Protocol):
|
||||||
converted['object'] = postprocess_as2_actor(converted['object'],
|
converted['object'] = postprocess_as2_actor(converted['object'],
|
||||||
user=from_user)
|
user=from_user)
|
||||||
|
|
||||||
return postprocess_as2(converted, orig_obj=orig_obj)
|
return postprocess_as2(converted, orig_obj=orig_obj,
|
||||||
|
# TODO: remove
|
||||||
|
from_user=from_user)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def verify_signature(cls, activity):
|
def verify_signature(cls, activity):
|
||||||
|
|
@ -469,14 +471,12 @@ def signed_post(url, from_user, **kwargs):
|
||||||
def signed_request(fn, url, data=None, headers=None, from_user=None, **kwargs):
|
def signed_request(fn, url, data=None, headers=None, from_user=None, **kwargs):
|
||||||
"""Wraps ``requests.*`` and adds HTTP Signature.
|
"""Wraps ``requests.*`` and adds HTTP Signature.
|
||||||
|
|
||||||
If the current session has a user (ie in ``g.user``), signs with that user's
|
|
||||||
key. Otherwise, uses the default user snarfed.org.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
fn (callable): :func:`util.requests_get` or :func:`util.requests_post`
|
fn (callable): :func:`util.requests_get` or :func:`util.requests_post`
|
||||||
url (str):
|
url (str):
|
||||||
data (dict): optional AS2 object
|
data (dict): optional AS2 object
|
||||||
from_user (models.User): user to sign request as; optional
|
from_user (models.User): user to sign request as; optional. If not
|
||||||
|
provided, uses the default user ``@snarfed.org@snarfed.org``.
|
||||||
kwargs: passed through to requests
|
kwargs: passed through to requests
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -539,7 +539,9 @@ def signed_request(fn, url, data=None, headers=None, from_user=None, **kwargs):
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
def postprocess_as2(activity, orig_obj=None, wrap=True):
|
def postprocess_as2(activity, orig_obj=None, wrap=True,
|
||||||
|
# TODO: remove
|
||||||
|
from_user=None):
|
||||||
"""Prepare an AS2 object to be served or sent via ActivityPub.
|
"""Prepare an AS2 object to be served or sent via ActivityPub.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -596,8 +598,8 @@ def postprocess_as2(activity, orig_obj=None, wrap=True):
|
||||||
obj['id'] = util.get_first(obj, 'url') or orig_id
|
obj['id'] = util.get_first(obj, 'url') or orig_id
|
||||||
|
|
||||||
# for Accepts
|
# for Accepts
|
||||||
if g.user and g.user.is_web_url(as1.get_object(obj).get('id')):
|
if from_user and from_user.is_web_url(as1.get_object(obj).get('id')):
|
||||||
obj['object'] = g.user.ap_actor()
|
obj['object'] = from_user.ap_actor()
|
||||||
|
|
||||||
# id is required for most things. default to url if it's not set.
|
# id is required for most things. default to url if it's not set.
|
||||||
if not activity.get('id'):
|
if not activity.get('id'):
|
||||||
|
|
@ -675,7 +677,9 @@ def postprocess_as2(activity, orig_obj=None, wrap=True):
|
||||||
|
|
||||||
activity['object'] = [
|
activity['object'] = [
|
||||||
postprocess_as2(o, orig_obj=orig_obj,
|
postprocess_as2(o, orig_obj=orig_obj,
|
||||||
wrap=wrap and type in ('Create', 'Update', 'Delete'))
|
wrap=wrap and type in ('Create', 'Update', 'Delete'),
|
||||||
|
# TODO: remove
|
||||||
|
from_user=from_user)
|
||||||
for o in as1.get_objects(activity)]
|
for o in as1.get_objects(activity)]
|
||||||
if len(activity['object']) == 1:
|
if len(activity['object']) == 1:
|
||||||
activity['object'] = activity['object'][0]
|
activity['object'] = activity['object'][0]
|
||||||
|
|
@ -950,16 +954,16 @@ def outbox(id):
|
||||||
if not protocol:
|
if not protocol:
|
||||||
error(f"Couldn't determine protocol", status=404)
|
error(f"Couldn't determine protocol", status=404)
|
||||||
|
|
||||||
g.user = protocol.get_by_id(id)
|
user = protocol.get_by_id(id)
|
||||||
if not g.user:
|
if not user:
|
||||||
error(f'User {id} not found', status=404)
|
error(f'User {id} not found', status=404)
|
||||||
|
|
||||||
if request.method == 'HEAD':
|
if request.method == 'HEAD':
|
||||||
return '', {'Content-Type': as2.CONTENT_TYPE}
|
return '', {'Content-Type': as2.CONTENT_TYPE}
|
||||||
|
|
||||||
query = Object.query(Object.users == g.user.key)
|
query = Object.query(Object.users == user.key)
|
||||||
objects, new_before, new_after = fetch_objects(query, by=Object.updated,
|
objects, new_before, new_after = fetch_objects(query, by=Object.updated,
|
||||||
user=g.user)
|
user=user)
|
||||||
|
|
||||||
# page
|
# page
|
||||||
page = {
|
page = {
|
||||||
|
|
|
||||||
|
|
@ -470,9 +470,6 @@ def poll_notifications():
|
||||||
|
|
||||||
common.create_task(queue='receive', obj=obj.key.urlsafe(),
|
common.create_task(queue='receive', obj=obj.key.urlsafe(),
|
||||||
authed_as=notif['author']['did'])
|
authed_as=notif['author']['did'])
|
||||||
# note that we don't pass a user param above. it's the acting user,
|
|
||||||
# which is different for every notif, and may not actually have a BF
|
|
||||||
# User yet.
|
|
||||||
|
|
||||||
return 'OK'
|
return 'OK'
|
||||||
|
|
||||||
|
|
@ -529,8 +526,5 @@ def poll_posts():
|
||||||
obj.put()
|
obj.put()
|
||||||
|
|
||||||
common.create_task(queue='receive', obj=obj.key.urlsafe(), authed_as=did)
|
common.create_task(queue='receive', obj=obj.key.urlsafe(), authed_as=did)
|
||||||
# note that we don't pass a user param above. it's the acting user,
|
|
||||||
# which is different for every notif, and may not actually have a BF
|
|
||||||
# User yet.
|
|
||||||
|
|
||||||
return 'OK'
|
return 'OK'
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,6 @@ class FollowCallback(indieauth.Callback):
|
||||||
follow_obj = Object(id=follow_id, users=[user.key, followee_user.key],
|
follow_obj = Object(id=follow_id, users=[user.key, followee_user.key],
|
||||||
labels=['user'], source_protocol='ui', status='complete',
|
labels=['user'], source_protocol='ui', status='complete',
|
||||||
as2=follow_as2)
|
as2=follow_as2)
|
||||||
g.user = user
|
|
||||||
ActivityPub.send(follow_obj, inbox, from_user=user)
|
ActivityPub.send(follow_obj, inbox, from_user=user)
|
||||||
|
|
||||||
Follower.get_or_create(from_=user, to=followee_user, status='active',
|
Follower.get_or_create(from_=user, to=followee_user, status='active',
|
||||||
|
|
@ -218,7 +217,6 @@ class UnfollowCallback(indieauth.Callback):
|
||||||
# network etiquette.)
|
# network etiquette.)
|
||||||
obj = Object(id=unfollow_id, users=[user.key], labels=['user'],
|
obj = Object(id=unfollow_id, users=[user.key], labels=['user'],
|
||||||
source_protocol='ui', status='complete', as2=unfollow_as2)
|
source_protocol='ui', status='complete', as2=unfollow_as2)
|
||||||
g.user = user
|
|
||||||
ActivityPub.send(obj, inbox, from_user=user)
|
ActivityPub.send(obj, inbox, from_user=user)
|
||||||
|
|
||||||
follower.status = 'inactive'
|
follower.status = 'inactive'
|
||||||
|
|
|
||||||
22
protocol.py
22
protocol.py
|
|
@ -600,8 +600,6 @@ class Protocol:
|
||||||
from_user = from_cls.get_or_create(id=actor)
|
from_user = from_cls.get_or_create(id=actor)
|
||||||
if from_user.status == 'opt-out':
|
if from_user.status == 'opt-out':
|
||||||
error(r'Actor {actor} is opted out', status=204)
|
error(r'Actor {actor} is opted out', status=204)
|
||||||
if not g.user:
|
|
||||||
g.user = from_user
|
|
||||||
|
|
||||||
# update copy ids to originals
|
# update copy ids to originals
|
||||||
obj.resolve_ids()
|
obj.resolve_ids()
|
||||||
|
|
@ -811,14 +809,7 @@ class Protocol:
|
||||||
'object': obj.as1,
|
'object': obj.as1,
|
||||||
})
|
})
|
||||||
|
|
||||||
# TODO: ugly, brittle. dangerous. remove once postprocess_as2 no
|
|
||||||
# longer depends on g.user!
|
|
||||||
# https://github.com/snarfed/bridgy-fed/issues/690
|
|
||||||
orig_g_user = g.user
|
|
||||||
g.user = to_user
|
|
||||||
sent = from_cls.send(accept, from_target, from_user=to_user)
|
sent = from_cls.send(accept, from_target, from_user=to_user)
|
||||||
g.user = orig_g_user
|
|
||||||
|
|
||||||
if sent:
|
if sent:
|
||||||
accept.populate(
|
accept.populate(
|
||||||
delivered=[Target(protocol=from_cls.LABEL, uri=from_target)],
|
delivered=[Target(protocol=from_cls.LABEL, uri=from_target)],
|
||||||
|
|
@ -1165,16 +1156,13 @@ def receive_task():
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
obj (url-safe google.cloud.ndb.key.Key): :class:`models.Object` to handle
|
obj (url-safe google.cloud.ndb.key.Key): :class:`models.Object` to handle
|
||||||
user (url-safe google.cloud.ndb.key.Key): :class:`models.User` this
|
|
||||||
activity is on behalf of. This user will be loaded into ``g.user``
|
|
||||||
authed_as (str): passed to :meth:`Protocol.receive`
|
authed_as (str): passed to :meth:`Protocol.receive`
|
||||||
|
|
||||||
TODO: migrate incoming webmentions and AP inbox deliveries to this. The
|
TODO: migrate incoming webmentions and AP inbox deliveries to this. The
|
||||||
difficulty is that parts of :meth:`protocol.Protocol.receive` depend on
|
difficulty is that parts of :meth:`protocol.Protocol.receive` depend on
|
||||||
setup in :func:`web.webmention` and :func:`activitypub.inbox`, eg
|
setup in :func:`web.webmention` and :func:`activitypub.inbox`, eg
|
||||||
:class:`models.Object` with ``new`` and ``changed``, ``g.user`` (which
|
:class:`models.Object` with ``new`` and ``changed``, HTTP request details,
|
||||||
:meth:`Protocol.receive` now loads), HTTP request details, etc. See stash
|
etc. See stash for attempt at this for :class:`web.Web`.
|
||||||
for attempt at this for :class:`web.Web`.
|
|
||||||
"""
|
"""
|
||||||
form = request.form.to_dict()
|
form = request.form.to_dict()
|
||||||
logger.info(f'Params: {list(form.items())}')
|
logger.info(f'Params: {list(form.items())}')
|
||||||
|
|
@ -1183,10 +1171,6 @@ def receive_task():
|
||||||
assert obj
|
assert obj
|
||||||
obj.new = True
|
obj.new = True
|
||||||
|
|
||||||
if user_key := form.get('user'):
|
|
||||||
g.user = ndb.Key(urlsafe=user_key).get()
|
|
||||||
logger.info(f'setting g.user to {g.user.key}')
|
|
||||||
|
|
||||||
authed_as = form.get('authed_as')
|
authed_as = form.get('authed_as')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -1231,7 +1215,7 @@ def send_task():
|
||||||
|
|
||||||
user = None
|
user = None
|
||||||
if user_key := form.get('user'):
|
if user_key := form.get('user'):
|
||||||
g.user = user = ndb.Key(urlsafe=user_key).get()
|
user = ndb.Key(urlsafe=user_key).get()
|
||||||
orig_obj = (ndb.Key(urlsafe=form['orig_obj']).get()
|
orig_obj = (ndb.Key(urlsafe=form['orig_obj']).get()
|
||||||
if form.get('orig_obj') else None)
|
if form.get('orig_obj') else None)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,8 @@ def redir(to):
|
||||||
if not obj or obj.deleted:
|
if not obj or obj.deleted:
|
||||||
return f'Object not found: {to}', 404
|
return f'Object not found: {to}', 404
|
||||||
|
|
||||||
g.user = Web.get_or_create(util.domain_from_link(to), direct=False, obj=obj)
|
user = Web.get_or_create(util.domain_from_link(to), direct=False, obj=obj)
|
||||||
ret = ActivityPub.convert(obj, from_user=g.user)
|
ret = ActivityPub.convert(obj, from_user=user)
|
||||||
logger.info(f'Returning: {json_dumps(ret, indent=2)}')
|
logger.info(f'Returning: {json_dumps(ret, indent=2)}')
|
||||||
return ret, {
|
return ret, {
|
||||||
'Content-Type': accept_type,
|
'Content-Type': accept_type,
|
||||||
|
|
|
||||||
|
|
@ -1834,7 +1834,6 @@ class ActivityPubUtilsTest(TestCase):
|
||||||
# preferredUsername stays y.z despite user's username. since Mastodon
|
# preferredUsername stays y.z despite user's username. since Mastodon
|
||||||
# queries Webfinger for preferredUsername@fed.brid.gy
|
# queries Webfinger for preferredUsername@fed.brid.gy
|
||||||
# https://github.com/snarfed/bridgy-fed/issues/77#issuecomment-949955109
|
# https://github.com/snarfed/bridgy-fed/issues/77#issuecomment-949955109
|
||||||
g.user = self.user
|
|
||||||
self.assertEqual('user.com', postprocess_as2_actor({
|
self.assertEqual('user.com', postprocess_as2_actor({
|
||||||
'type': 'Person',
|
'type': 'Person',
|
||||||
'url': 'https://user.com/about-me',
|
'url': 'https://user.com/about-me',
|
||||||
|
|
@ -2008,7 +2007,6 @@ class ActivityPubUtilsTest(TestCase):
|
||||||
'actor': 'fake:user',
|
'actor': 'fake:user',
|
||||||
'object': 'https://mas.to/thing',
|
'object': 'https://mas.to/thing',
|
||||||
}
|
}
|
||||||
g.user = self.user
|
|
||||||
self.assertEqual({
|
self.assertEqual({
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
'id': 'https://fa.brid.gy/convert/ap/fake:like',
|
'id': 'https://fa.brid.gy/convert/ap/fake:like',
|
||||||
|
|
@ -2031,8 +2029,6 @@ class ActivityPubUtilsTest(TestCase):
|
||||||
}, ActivityPub.convert(obj), ignore=['to'])
|
}, ActivityPub.convert(obj), ignore=['to'])
|
||||||
|
|
||||||
def test_postprocess_as2_idempotent(self):
|
def test_postprocess_as2_idempotent(self):
|
||||||
g.user = self.user
|
|
||||||
|
|
||||||
for obj in (ACTOR, REPLY_OBJECT, REPLY_OBJECT_WRAPPED, REPLY,
|
for obj in (ACTOR, REPLY_OBJECT, REPLY_OBJECT_WRAPPED, REPLY,
|
||||||
NOTE_OBJECT, NOTE, MENTION_OBJECT, MENTION, LIKE,
|
NOTE_OBJECT, NOTE, MENTION_OBJECT, MENTION, LIKE,
|
||||||
LIKE_WRAPPED, REPOST, FOLLOW, FOLLOW_WRAPPED, ACCEPT,
|
LIKE_WRAPPED, REPOST, FOLLOW, FOLLOW_WRAPPED, ACCEPT,
|
||||||
|
|
@ -2156,7 +2152,6 @@ class ActivityPubUtilsTest(TestCase):
|
||||||
'author': 'http://the/author',
|
'author': 'http://the/author',
|
||||||
})
|
})
|
||||||
# test is that we short circuit out instead of infinite recursion
|
# test is that we short circuit out instead of infinite recursion
|
||||||
g.user = self.user
|
|
||||||
self.assertIsNone(ActivityPub.target_for(obj))
|
self.assertIsNone(ActivityPub.target_for(obj))
|
||||||
|
|
||||||
@patch('requests.post')
|
@patch('requests.post')
|
||||||
|
|
|
||||||
Ładowanie…
Reference in New Issue