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'],
 | 
			
		||||
                                                        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
 | 
			
		||||
    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):
 | 
			
		||||
    """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:
 | 
			
		||||
      fn (callable): :func:`util.requests_get` or  :func:`util.requests_post`
 | 
			
		||||
      url (str):
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
| 
						 | 
				
			
			@ -539,7 +539,9 @@ def signed_request(fn, url, data=None, headers=None, from_user=None, **kwargs):
 | 
			
		|||
    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.
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
| 
						 | 
				
			
			@ -596,8 +598,8 @@ def postprocess_as2(activity, orig_obj=None, wrap=True):
 | 
			
		|||
        obj['id'] = util.get_first(obj, 'url') or orig_id
 | 
			
		||||
 | 
			
		||||
    # for Accepts
 | 
			
		||||
    if g.user and g.user.is_web_url(as1.get_object(obj).get('id')):
 | 
			
		||||
        obj['object'] = g.user.ap_actor()
 | 
			
		||||
    if from_user and from_user.is_web_url(as1.get_object(obj).get('id')):
 | 
			
		||||
        obj['object'] = from_user.ap_actor()
 | 
			
		||||
 | 
			
		||||
    # id is required for most things. default to url if it's not set.
 | 
			
		||||
    if not activity.get('id'):
 | 
			
		||||
| 
						 | 
				
			
			@ -675,7 +677,9 @@ def postprocess_as2(activity, orig_obj=None, wrap=True):
 | 
			
		|||
 | 
			
		||||
    activity['object'] = [
 | 
			
		||||
        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)]
 | 
			
		||||
    if len(activity['object']) == 1:
 | 
			
		||||
        activity['object'] = activity['object'][0]
 | 
			
		||||
| 
						 | 
				
			
			@ -950,16 +954,16 @@ def outbox(id):
 | 
			
		|||
    if not protocol:
 | 
			
		||||
        error(f"Couldn't determine protocol", status=404)
 | 
			
		||||
 | 
			
		||||
    g.user = protocol.get_by_id(id)
 | 
			
		||||
    if not g.user:
 | 
			
		||||
    user = protocol.get_by_id(id)
 | 
			
		||||
    if not user:
 | 
			
		||||
        error(f'User {id} not found', status=404)
 | 
			
		||||
 | 
			
		||||
    if request.method == 'HEAD':
 | 
			
		||||
        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,
 | 
			
		||||
                                                   user=g.user)
 | 
			
		||||
                                                   user=user)
 | 
			
		||||
 | 
			
		||||
    # page
 | 
			
		||||
    page = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -470,9 +470,6 @@ def poll_notifications():
 | 
			
		|||
 | 
			
		||||
            common.create_task(queue='receive', obj=obj.key.urlsafe(),
 | 
			
		||||
                               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'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -529,8 +526,5 @@ def poll_posts():
 | 
			
		|||
            obj.put()
 | 
			
		||||
 | 
			
		||||
            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'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -130,7 +130,6 @@ class FollowCallback(indieauth.Callback):
 | 
			
		|||
        follow_obj = Object(id=follow_id, users=[user.key, followee_user.key],
 | 
			
		||||
                            labels=['user'], source_protocol='ui', status='complete',
 | 
			
		||||
                            as2=follow_as2)
 | 
			
		||||
        g.user = user
 | 
			
		||||
        ActivityPub.send(follow_obj, inbox, from_user=user)
 | 
			
		||||
 | 
			
		||||
        Follower.get_or_create(from_=user, to=followee_user, status='active',
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +217,6 @@ class UnfollowCallback(indieauth.Callback):
 | 
			
		|||
        # network etiquette.)
 | 
			
		||||
        obj = Object(id=unfollow_id, users=[user.key], labels=['user'],
 | 
			
		||||
                     source_protocol='ui', status='complete', as2=unfollow_as2)
 | 
			
		||||
        g.user = user
 | 
			
		||||
        ActivityPub.send(obj, inbox, from_user=user)
 | 
			
		||||
 | 
			
		||||
        follower.status = 'inactive'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								protocol.py
								
								
								
								
							
							
						
						
									
										22
									
								
								protocol.py
								
								
								
								
							| 
						 | 
				
			
			@ -600,8 +600,6 @@ class Protocol:
 | 
			
		|||
        from_user = from_cls.get_or_create(id=actor)
 | 
			
		||||
        if from_user.status == 'opt-out':
 | 
			
		||||
            error(r'Actor {actor} is opted out', status=204)
 | 
			
		||||
        if not g.user:
 | 
			
		||||
            g.user = from_user
 | 
			
		||||
 | 
			
		||||
        # update copy ids to originals
 | 
			
		||||
        obj.resolve_ids()
 | 
			
		||||
| 
						 | 
				
			
			@ -811,14 +809,7 @@ class Protocol:
 | 
			
		|||
                '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)
 | 
			
		||||
            g.user = orig_g_user
 | 
			
		||||
 | 
			
		||||
            if sent:
 | 
			
		||||
                accept.populate(
 | 
			
		||||
                    delivered=[Target(protocol=from_cls.LABEL, uri=from_target)],
 | 
			
		||||
| 
						 | 
				
			
			@ -1165,16 +1156,13 @@ def receive_task():
 | 
			
		|||
 | 
			
		||||
    Parameters:
 | 
			
		||||
      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`
 | 
			
		||||
 | 
			
		||||
    TODO: migrate incoming webmentions and AP inbox deliveries to this. The
 | 
			
		||||
    difficulty is that parts of :meth:`protocol.Protocol.receive` depend on
 | 
			
		||||
    setup in :func:`web.webmention` and :func:`activitypub.inbox`, eg
 | 
			
		||||
    :class:`models.Object` with ``new`` and ``changed``, ``g.user`` (which
 | 
			
		||||
    :meth:`Protocol.receive` now loads), HTTP request details, etc. See stash
 | 
			
		||||
    for attempt at this for :class:`web.Web`.
 | 
			
		||||
    :class:`models.Object` with ``new`` and ``changed``, HTTP request details,
 | 
			
		||||
    etc. See stash for attempt at this for :class:`web.Web`.
 | 
			
		||||
    """
 | 
			
		||||
    form = request.form.to_dict()
 | 
			
		||||
    logger.info(f'Params: {list(form.items())}')
 | 
			
		||||
| 
						 | 
				
			
			@ -1183,10 +1171,6 @@ def receive_task():
 | 
			
		|||
    assert obj
 | 
			
		||||
    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')
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
| 
						 | 
				
			
			@ -1231,7 +1215,7 @@ def send_task():
 | 
			
		|||
 | 
			
		||||
    user = None
 | 
			
		||||
    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()
 | 
			
		||||
                if form.get('orig_obj') else None)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,8 +100,8 @@ def redir(to):
 | 
			
		|||
        if not obj or obj.deleted:
 | 
			
		||||
            return f'Object not found: {to}', 404
 | 
			
		||||
 | 
			
		||||
        g.user = Web.get_or_create(util.domain_from_link(to), direct=False, obj=obj)
 | 
			
		||||
        ret = ActivityPub.convert(obj, from_user=g.user)
 | 
			
		||||
        user = Web.get_or_create(util.domain_from_link(to), direct=False, obj=obj)
 | 
			
		||||
        ret = ActivityPub.convert(obj, from_user=user)
 | 
			
		||||
        logger.info(f'Returning: {json_dumps(ret, indent=2)}')
 | 
			
		||||
        return ret, {
 | 
			
		||||
            'Content-Type': accept_type,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1834,7 +1834,6 @@ class ActivityPubUtilsTest(TestCase):
 | 
			
		|||
        # preferredUsername stays y.z despite user's username. since Mastodon
 | 
			
		||||
        # queries Webfinger for preferredUsername@fed.brid.gy
 | 
			
		||||
        # https://github.com/snarfed/bridgy-fed/issues/77#issuecomment-949955109
 | 
			
		||||
        g.user = self.user
 | 
			
		||||
        self.assertEqual('user.com', postprocess_as2_actor({
 | 
			
		||||
            'type': 'Person',
 | 
			
		||||
            'url': 'https://user.com/about-me',
 | 
			
		||||
| 
						 | 
				
			
			@ -2008,7 +2007,6 @@ class ActivityPubUtilsTest(TestCase):
 | 
			
		|||
            'actor': 'fake:user',
 | 
			
		||||
            'object': 'https://mas.to/thing',
 | 
			
		||||
        }
 | 
			
		||||
        g.user = self.user
 | 
			
		||||
        self.assertEqual({
 | 
			
		||||
            '@context': 'https://www.w3.org/ns/activitystreams',
 | 
			
		||||
            'id': 'https://fa.brid.gy/convert/ap/fake:like',
 | 
			
		||||
| 
						 | 
				
			
			@ -2031,8 +2029,6 @@ class ActivityPubUtilsTest(TestCase):
 | 
			
		|||
        }, ActivityPub.convert(obj), ignore=['to'])
 | 
			
		||||
 | 
			
		||||
    def test_postprocess_as2_idempotent(self):
 | 
			
		||||
        g.user = self.user
 | 
			
		||||
 | 
			
		||||
        for obj in (ACTOR, REPLY_OBJECT, REPLY_OBJECT_WRAPPED, REPLY,
 | 
			
		||||
                    NOTE_OBJECT, NOTE, MENTION_OBJECT, MENTION, LIKE,
 | 
			
		||||
                    LIKE_WRAPPED, REPOST, FOLLOW, FOLLOW_WRAPPED, ACCEPT,
 | 
			
		||||
| 
						 | 
				
			
			@ -2156,7 +2152,6 @@ class ActivityPubUtilsTest(TestCase):
 | 
			
		|||
            'author': 'http://the/author',
 | 
			
		||||
        })
 | 
			
		||||
        # test is that we short circuit out instead of infinite recursion
 | 
			
		||||
        g.user = self.user
 | 
			
		||||
        self.assertIsNone(ActivityPub.target_for(obj))
 | 
			
		||||
 | 
			
		||||
    @patch('requests.post')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue