kopia lustrzana https://github.com/snarfed/bridgy-fed
AP: switch default signing actor to real fed.brid.gy instance actor
https://seb.jambor.dev/posts/understanding-activitypub-part-4-threads/#the-instance-actorpull/777/head
rodzic
6025925c26
commit
26de4097ae
|
@ -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 |
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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">
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
6
web.py
|
@ -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)
|
||||
|
|
Ładowanie…
Reference in New Issue