AP: switch default signing actor to real fed.brid.gy instance actor

https://seb.jambor.dev/posts/understanding-activitypub-part-4-threads/#the-instance-actor
pull/777/head
Ryan Barrett 2024-01-06 11:59:31 -10:00
rodzic 6025925c26
commit 26de4097ae
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
8 zmienionych plików z 73 dodań i 16 usunięć

Wyświetl plik

@ -45,14 +45,15 @@ CONNEG_HEADERS_AS2_HTML = {
HTTP_SIG_HEADERS = ('Date', 'Host', 'Digest', '(request-target)')
_DEFAULT_SIGNATURE_USER = None
# https://seb.jambor.dev/posts/understanding-activitypub-part-4-threads/#the-instance-actor
_INSTANCE_ACTOR = None
def default_signature_user():
global _DEFAULT_SIGNATURE_USER
if _DEFAULT_SIGNATURE_USER is None:
def instance_actor():
global _INSTANCE_ACTOR
if _INSTANCE_ACTOR is None:
import web
_DEFAULT_SIGNATURE_USER = web.Web.get_or_create('snarfed.org')
return _DEFAULT_SIGNATURE_USER
_INSTANCE_ACTOR = web.Web.get_or_create(PRIMARY_DOMAIN)
return _INSTANCE_ACTOR
class ActivityPub(User, Protocol):
@ -486,7 +487,7 @@ def signed_request(fn, url, data=None, headers=None, from_user=None, **kwargs):
# prepare HTTP Signature and headers
if not from_user or isinstance(from_user, ActivityPub):
# ActivityPub users are remote, so we don't have their keys
from_user = default_signature_user()
from_user = instance_actor()
if data:
logger.info(f'Sending AS2 object: {json_dumps(data, indent=2)}')

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 129 KiB

Wyświetl plik

@ -0,0 +1,24 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1"
],
"type": "Application",
"id": "https://fed.brid.gy/fed.brid.gy",
"url": "https://fed.brid.gy/",
"preferredUsername": "fed.brid.gy",
"summary": "Bridging the new social internet",
"updated": "2023-12-26T16:53:48.598945+00:00",
"name": "Ryan Barrett",
"attachment": [{
"name": "Web site",
"type": "PropertyValue",
"value": "<a rel=\"me\" href=\"https://fed.brid.gy\"><span class=\"invisible\">https://</span>fed.brid.gy</a>"
}],
"image": "https://fed.brid.gy/static/bridgy_logo_with_alpha_square_1024.png",
"icon": {
"name": "Bridgy Fed",
"type": "Image",
"url": "https://fed.brid.gy/static/favicon.ico"
}
}

Wyświetl plik

@ -6,6 +6,11 @@
<script src="/static/bootstrap.min.js"></script>
<script src="/static/index.js"></script>
<!-- For Mastodon profile link verification
https://fed.brid.gy/docs#mastodon-link-verification
-->
<a rel="me" href="https://fed.brid.gy/"></a>
<div id="front-form" class="row front-dark">
<div id="topology" style="position: absolute; top: 0; left: 0"></div>
<div id="front-tagline" class="row bigger">
@ -29,7 +34,7 @@
</div>
<div class="row big front-light">
<p>Bridgy Fed connects some of the most popular decentralized social networks. You can use it from one network to follow people on another, see their posts, and reply and like and repost them. All interactions work in both directions. <a href="/docs">See the docs for more info.</a></p>
<p>Bridgy Fed connects some of the most popular decentralized social networks. You can use it from one network to make your profile visible in another network, follow people there, see their posts, and reply and like and repost them. All interactions work in both directions. <a href="/docs">See the docs for more info.</a></p>
</div>
<div class="row big front-dark">

Wyświetl plik

@ -19,12 +19,13 @@ from urllib3.exceptions import ReadTimeoutError
from werkzeug.exceptions import BadGateway
# import first so that Fake is defined before URL routes are registered
from . import testutil
from .testutil import Fake, TestCase
import activitypub
from activitypub import (
ActivityPub,
default_signature_user,
instance_actor,
postprocess_as2,
postprocess_as2_actor,
)
@ -479,6 +480,23 @@ class ActivityPubTest(TestCase):
got = self.client.get('/user.com')
self.assertEqual(404, got.status_code)
def test_instance_actor_fetch(self, *_):
def reset_instance_actor():
activitypub._INSTANCE_ACTOR = testutil.global_user
self.addCleanup(reset_instance_actor)
actor_as2 = json_loads(util.read('static/instance-actor.as2.json'))
self.make_user(common.PRIMARY_DOMAIN, cls=Web, obj_as2=actor_as2)
activitypub._INSTANCE_ACTOR = None
got = self.client.get(f'/{common.PRIMARY_DOMAIN}')
self.assertEqual(200, got.status_code)
self.assert_equals({
**actor_as2,
'id': 'http://localhost/fed.brid.gy',
}, got.json, ignore=['inbox', 'outbox', 'endpoints', 'followers',
'following', 'publicKey', 'publicKeyPem'])
def test_individual_inbox_no_user(self, mock_head, mock_get, mock_post):
self.user.key.delete()
@ -1970,14 +1988,14 @@ class ActivityPubUtilsTest(TestCase):
second['auth'].header_signer.sign(second['headers'], method='GET', path='/'))
@patch('requests.post', return_value=requests_response(status=200))
def test_signed_post_from_user_is_activitypub_so_use_default_user(self, mock_post):
def test_signed_post_from_user_is_activitypub_use_instance_actor(self, mock_post):
activitypub.signed_post('https://url', from_user=ActivityPub(id='http://fed'))
self.assertEqual(1, len(mock_post.call_args_list))
args, kwargs = mock_post.call_args_list[0]
self.assertEqual(('https://url',), args)
rsa_key = kwargs['auth'].header_signer._rsa._key
self.assertEqual(default_signature_user().private_pem(), rsa_key.exportKey())
self.assertEqual(instance_actor().private_pem(), rsa_key.exportKey())
@patch('requests.post')
def test_signed_post_ignores_redirect(self, mock_post):

Wyświetl plik

@ -477,7 +477,6 @@ class WebTest(TestCase):
'acct:user.com',
'acct:@user.com@user.com',
'acc:me@user.com',
'fed.brid.gy',
'ap.brid.gy',
'localhost',
):
@ -2230,10 +2229,10 @@ http://this/404s
self.assertEqual(1, Web.query().count())
def test_check_web_site_bridgy_fed_domain(self, _, __):
got = self.post('/web-site', data={'url': 'https://fed.brid.gy/foo'})
got = self.post('/web-site', data={'url': 'https://web.brid.gy/foo'})
self.assert_equals(400, got.status_code)
self.assertEqual(
['https://fed.brid.gy/foo is not a valid or supported web site'],
['https://web.brid.gy/foo is not a valid or supported web site'],
get_flashed_messages())
self.assertEqual(1, Web.query().count())
@ -2515,6 +2514,12 @@ class WebUtilTest(TestCase):
self.assertFalse(Web.fetch(obj))
self.assertIsNone(obj.as1)
def test_fetch_instance_actor(self, _, __):
obj = Object(id=f'https://{common.PRIMARY_DOMAIN}/')
self.assertTrue(Web.fetch(obj))
self.assertEqual(obj.as2,
json_loads(util.read('static/instance-actor.as2.json')))
def test_fetch_resolves_relative_urls(self, mock_get, __):
mock_get.return_value = requests_response("""\
<html>

Wyświetl plik

@ -178,7 +178,7 @@ from flask_app import app, cache
# expensive to generate.
requests.post(f'http://{ndb_client.host}/reset')
with ndb_client.context():
global_user = activitypub._DEFAULT_SIGNATURE_USER = Fake.get_or_create('fake:user')
global_user = activitypub._INSTANCE_ACTOR = Fake.get_or_create('fake:user')
class TestCase(unittest.TestCase, testutil.Asserts):

6
web.py
Wyświetl plik

@ -73,7 +73,7 @@ def is_valid_domain(domain):
logger.debug(f"{domain} doesn't look like a domain")
return False
if Web.is_blocklisted(domain):
if Web.is_blocklisted(domain) and domain != common.PRIMARY_DOMAIN:
logger.debug(f'{domain} is blocklisted')
return False
@ -410,6 +410,10 @@ class Web(User, Protocol):
is_homepage = urlparse(url).path.strip('/') == ''
if is_homepage and util.domain_from_link(url) == common.PRIMARY_DOMAIN:
obj.as2 = json_loads(util.read('static/instance-actor.as2.json'))
return True
require_backlink = (common.host_url().rstrip('/')
if check_backlink and not is_homepage
else None)