rename MagicKey => Domain, Response => Activity

the Python classes, but not (yet) the kinds in the datastore. maybe eventually.
pull/280/head
Ryan Barrett 2022-11-12 15:27:59 -08:00
rodzic 53a133d554
commit 4f3dc03a3e
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
21 zmienionych plików z 155 dodań i 144 usunięć

Wyświetl plik

@ -17,7 +17,7 @@ from oauth_dropins.webutil.util import json_dumps, json_loads
from app import app, cache
import common
from common import redirect_unwrap, redirect_wrap
from models import Follower, MagicKey
from models import Follower, Domain
from httpsig.requests_auth import HTTPSignatureAuth
logger = logging.getLogger(__name__)
@ -58,7 +58,7 @@ def send(activity, inbox_url, user_domain):
# https://tools.ietf.org/html/draft-cavage-http-signatures-07
# https://github.com/tootsuite/mastodon/issues/4906#issuecomment-328844846
key_id = request.host_url + user_domain
key = MagicKey.get_or_create(user_domain)
key = Domain.get_or_create(user_domain)
auth = HTTPSignatureAuth(secret=key.private_pem(), key_id=key_id,
algorithm='rsa-sha256', sign_header='signature',
headers=('Date', 'Digest', 'Host'))
@ -94,7 +94,7 @@ def actor(domain):
if not hcard:
error(f"Couldn't find a representative h-card (http://microformats.org/wiki/representative-hcard-parsing) on {mf2['url']}")
key = MagicKey.get_or_create(domain)
key = Domain.get_or_create(domain)
obj = common.postprocess_as2(
as2.from_as1(microformats2.json_to_object(hcard)), key=key)
obj.update({

Wyświetl plik

@ -14,7 +14,7 @@ from oauth_dropins.webutil.flask_util import error
import requests
from werkzeug.exceptions import BadGateway
from models import Response
from models import Activity
logger = logging.getLogger(__name__)
@ -144,11 +144,11 @@ def content_type(resp):
return type.split(';')[0]
def send_webmentions(activity_wrapped, proxy=None, **response_props):
def send_webmentions(activity_wrapped, proxy=None, **activity_props):
"""Sends webmentions for an incoming Salmon slap or ActivityPub inbox delivery.
Args:
activity_wrapped: dict, AS1 activity
response_props: passed through to the newly created Responses
activity_props: passed through to the newly created Activity entities
"""
activity = redirect_unwrap(activity_wrapped)
@ -186,7 +186,7 @@ def send_webmentions(activity_wrapped, proxy=None, **response_props):
if not targets:
error("Couldn't find any target URLs in inReplyTo, object, or mention tags")
# send webmentions and store Responses
# send webmentions and store Activitys
errors = [] # stores (code, body) tuples
for target in targets:
domain = util.domain_from_link(target, minimize=False)
@ -194,10 +194,10 @@ def send_webmentions(activity_wrapped, proxy=None, **response_props):
logger.info(f'Skipping same-domain webmention from {source} to {target}')
continue
response = Response(source=source, target=target, direction='in',
domain=domain, **response_props)
response.put()
wm_source = (response.proxy_url()
activity = Activity(source=source, target=target, direction='in',
domain=domain, **activity_props)
activity.put()
wm_source = (activity.proxy_url()
if verb in ('follow', 'like', 'share') or proxy
else source)
logger.info(f'Sending webmention from {wm_source} to {target}')
@ -206,14 +206,14 @@ def send_webmentions(activity_wrapped, proxy=None, **response_props):
endpoint = webmention.discover(target).endpoint
if endpoint:
webmention.send(endpoint, wm_source, target)
response.status = 'complete'
activity.status = 'complete'
logger.info('Success!')
else:
response.status = 'ignored'
activity.status = 'ignored'
logger.info('Ignoring.')
except BaseException as e:
errors.append(util.interpret_http_exception(e))
response.put()
activity.put()
if errors:
msg = 'Errors: ' + ', '.join(f'{code} {body}' for code, body in errors)
@ -227,7 +227,7 @@ def postprocess_as2(activity, target=None, key=None):
activity: dict, AS2 object or activity
target: dict, AS2 object, optional. The target of activity's inReplyTo or
Like/Announce/etc object, if any.
key: :class:`models.MagicKey`, optional. populated into publicKey field
key: :class:`models.Domain`, optional. populated into publicKey field
if provided.
"""
type = activity.get('type')

Wyświetl plik

@ -11,7 +11,7 @@ from oauth_dropins.webutil.models import StringIdModel
logger = logging.getLogger(__name__)
class MagicKey(StringIdModel):
class Domain(StringIdModel):
"""Stores a user's public/private key pair used for Magic Signatures.
The key name is the domain.
@ -28,17 +28,21 @@ class MagicKey(StringIdModel):
public_exponent = ndb.StringProperty(required=True)
private_exponent = ndb.StringProperty(required=True)
@classmethod
def _get_kind(cls):
return 'MagicKey'
@staticmethod
@ndb.transactional()
def get_or_create(domain):
"""Loads and returns a MagicKey. Creates it if necessary."""
key = MagicKey.get_by_id(domain)
"""Loads and returns a Domain. Creates it if necessary."""
key = Domain.get_by_id(domain)
if not key:
# this uses urandom(), and does nontrivial math, so it can take a
# while depending on the amount of randomness available.
pubexp, mod, privexp = magicsigs.generate()
key = MagicKey(id=domain, mod=mod, public_exponent=pubexp,
key = Domain(id=domain, mod=mod, public_exponent=pubexp,
private_exponent=privexp)
key.put()
@ -62,7 +66,7 @@ class MagicKey(StringIdModel):
return rsa.exportKey(format='PEM')
class Response(StringIdModel):
class Activity(StringIdModel):
"""A reply, like, repost, or other interaction that we've relayed.
Key name is 'SOURCE_URL TARGET_URL', e.g. 'http://a/reply http://orig/post'.
@ -86,16 +90,20 @@ class Response(StringIdModel):
created = ndb.DateTimeProperty(auto_now_add=True)
updated = ndb.DateTimeProperty(auto_now=True)
@classmethod
def _get_kind(cls):
return 'Response'
def __init__(self, source=None, target=None, **kwargs):
if source and target:
assert 'id' not in kwargs
kwargs['id'] = self._id(source, target)
logger.info(f"Response id (source target): {kwargs['id']}")
super(Response, self).__init__(**kwargs)
logger.info(f"Activity id (source target): {kwargs['id']}")
super(Activity, self).__init__(**kwargs)
@classmethod
def get_or_create(cls, source=None, target=None, **kwargs):
logger.info(f'Response source target: {source} {target}')
logger.info(f'Activity source target: {source} {target}')
return cls.get_or_insert(cls._id(source, target), **kwargs)
def source(self):
@ -105,7 +113,7 @@ class Response(StringIdModel):
return self.key.id().split()[1]
def proxy_url(self):
"""Returns the Bridgy Fed proxy URL to render this response as HTML."""
"""Returns the Bridgy Fed proxy URL to render this post as HTML."""
if self.source_mf2 or self.source_as2 or self.source_atom:
source, target = self.key.id().split(' ')
return f'{request.host_url}render?' + urllib.parse.urlencode({

Wyświetl plik

@ -1,4 +1,4 @@
"""Render recent responses and logs."""
"""UI pages."""
import calendar
import datetime
from itertools import islice
@ -12,7 +12,7 @@ from oauth_dropins.webutil.flask_util import error
from app import app, cache
import common
from models import Follower, MagicKey, Response
from models import Follower, Domain, Activity
PAGE_SIZE = 20
FOLLOWERS_UI_LIMIT = 999
@ -28,14 +28,14 @@ def front_page():
@app.get(f'/user/<regex("{common.DOMAIN_RE}"):domain>')
@app.get(f'/responses/<regex("{common.DOMAIN_RE}"):domain>') # deprecated
def user(domain):
if not MagicKey.get_by_id(domain):
if not Domain.get_by_id(domain):
return render_template('user_not_found.html', domain=domain), 404
query = Response.query(
Response.status.IN(('new', 'complete', 'error')),
Response.domain == domain,
query = Activity.query(
Activity.status.IN(('new', 'complete', 'error')),
Activity.domain == domain,
)
responses, before, after = fetch_page(query, Response)
activities, before, after = fetch_page(query, Activity)
followers = Follower.query(Follower.dest == domain)\
.count(limit=FOLLOWERS_UI_LIMIT)
@ -54,7 +54,10 @@ def user(domain):
@app.get(f'/user/<regex("{common.DOMAIN_RE}"):domain>/followers')
def followers(domain):
if not MagicKey.get_by_id(domain):
# TODO:
# pull more info from last_follow, eg name, profile picture, url
# unify with following
if not Domain.get_by_id(domain):
return render_template('user_not_found.html', domain=domain), 404
query = Follower.query(
@ -79,7 +82,7 @@ def followers(domain):
@app.get(f'/user/<regex("{common.DOMAIN_RE}"):domain>/following')
def following(domain):
if not MagicKey.get_by_id(domain):
if not Domain.get_by_id(domain):
return render_template('user_not_found.html', domain=domain), 404
query = Follower.query(
@ -105,9 +108,9 @@ def following(domain):
@app.get('/recent')
@app.get('/responses') # deprecated
def recent():
"""Renders recent Responses, with links to logs."""
query = Response.query(Response.status.IN(('new', 'complete', 'error')))
responses, before, after = fetch_page(query, Response)
"""Renders recent activities, with links to logs."""
query = Activity.query(Activity.status.IN(('new', 'complete', 'error')))
activities, before, after = fetch_page(query, Activity)
return render_template(
'recent.html',
util=util,
@ -186,8 +189,8 @@ def fetch_page(query, model_class):
def stats():
return render_template(
'stats.html',
users=KindStat.query(KindStat.kind_name == 'MagicKey').get().count,
responses=KindStat.query(KindStat.kind_name == 'Response').get().count,
users=KindStat.query(KindStat.kind_name == 'Domain').get().count,
activities=KindStat.query(KindStat.kind_name == 'Activity').get().count,
followers=KindStat.query(KindStat.kind_name == 'Follower').get().count,
)

Wyświetl plik

@ -23,7 +23,7 @@ from werkzeug.exceptions import abort
from app import app, cache
import common
from models import MagicKey
from models import Domain
logger = logging.getLogger(__name__)
@ -51,8 +51,8 @@ def redir(to):
util.domain_from_link(to, minimize=False),
urllib.parse.urlparse(to).hostname))
for domain in domains:
if domain and MagicKey.get_by_id(domain):
logger.info(f'Found MagicKey for domain {domain}')
if domain and Domain.get_by_id(domain):
logger.info(f'Found Domain for domain {domain}')
break
else:
logger.info(f'No user found for any of {domains}; returning 404')

Wyświetl plik

@ -1,5 +1,5 @@
# coding=utf-8
"""Renders mf2 proxy pages based on stored Responses."""
"""Renders mf2 proxy pages based on stored Activity entities."""
import datetime
from flask import request
@ -10,7 +10,7 @@ from oauth_dropins.webutil.util import json_loads
from app import app, cache
import common
from models import Response
from models import Activity
CACHE_TIME = datetime.timedelta(minutes=15)
@ -18,23 +18,23 @@ CACHE_TIME = datetime.timedelta(minutes=15)
@app.get('/render')
@flask_util.cached(cache, CACHE_TIME)
def render():
"""Fetches a stored Response and renders it as HTML."""
"""Fetches a stored Activity and renders it as HTML."""
source = flask_util.get_required_param('source')
target = flask_util.get_required_param('target')
id = f'{source} {target}'
resp = Response.get_by_id(id)
if not resp:
error(f'No stored response for {id}', status=404)
activity = Activity.get_by_id(id)
if not activity:
error(f'No stored activity for {id}', status=404)
if resp.source_mf2:
as1 = microformats2.json_to_object(json_loads(resp.source_mf2))
elif resp.source_as2:
as1 = as2.to_as1(json_loads(resp.source_as2))
elif resp.source_atom:
as1 = atom.atom_to_activity(resp.source_atom)
if activity.source_mf2:
as1 = microformats2.json_to_object(json_loads(activity.source_mf2))
elif activity.source_as2:
as1 = as2.to_as1(json_loads(activity.source_as2))
elif activity.source_atom:
as1 = atom.atom_to_activity(activity.source_atom)
else:
error(f'Stored response for {id} has no data', status=404)
error(f'Stored activity for {id} has no data', status=404)
# add HTML meta redirect to source page. should trigger for end users in
# browsers but not for webmention receivers (hopefully).

Wyświetl plik

@ -0,0 +1,23 @@
<!-- <table> -->
<!-- <tr><th>Source</th> <th>Target</th> <th>Protocol</th> <th>Status</th> <th>Time (click for log)</th></tr> -->
<br>
{% for a in activities %}
<div class="row">
<div class="col-sm-3">{{ util.pretty_link(a.source())|safe }}</div>
<div class="col-sm-3">{{ util.pretty_link(a.target())|safe }}</div>
<div class="col-sm-2">{{ a.protocol }}</div>
<div class="col-sm-2">{{ a.status }}</div>
<div class="col-sm-2">
{% if a.log_url_path %}<a href="{{ a.log_url_path }}">{% endif %}
{{ a.updated.replace(microsecond=0) }}
{% if a.log_url_path %}</a>{% endif %}
</div>
</div>
{% else %}
<div class="row">None</div>
{% endfor %}
<!-- </table> -->
{% include "paging.html" %}

Wyświetl plik

@ -1,13 +1,13 @@
<div class="row">
<div class="col-sm-3">
{% if after %}
<a href="?after={{ after }}#responses">&larr; Newer</a>
<a href="?after={{ after }}">&larr; Newer</a>
{% endif %}
</div>
<div class="col-sm-3 col-sm-offset-6">
{% if before %}
<a href="?before={{ before }}#responses">Older &rarr;</a>
<a href="?before={{ before }}">Older &rarr;</a>
{% endif %}
</div>
</div>

Wyświetl plik

@ -6,6 +6,6 @@
<h2 class="row">Recent activity</h3>
{% include "responses.html" %}
{% include "activities.html" %}
{% endblock %}

Wyświetl plik

@ -1,23 +0,0 @@
<!-- <table> -->
<!-- <tr><th>Source</th> <th>Target</th> <th>Protocol</th> <th>Status</th> <th>Time (click for log)</th></tr> -->
<br>
{% for r in responses %}
<div class="row">
<div class="col-sm-3">{{ util.pretty_link(r.source())|safe }}</div>
<div class="col-sm-3">{{ util.pretty_link(r.target())|safe }}</div>
<div class="col-sm-2">{{ r.protocol }}</div>
<div class="col-sm-2">{{ r.status }}</div>
<div class="col-sm-2">
{% if r.log_url_path %}<a href="{{ r.log_url_path }}">{% endif %}
{{ r.updated.replace(microsecond=0) }}
{% if r.log_url_path %}</a>{% endif %}
</div>
</div>
{% else %}
<div class="row">None</div>
{% endfor %}
<!-- </table> -->
{% include "paging.html" %}

Wyświetl plik

@ -12,7 +12,7 @@
<li><a href="https://snarfed.org/2017-10-22_bridgy-fed">Launched Octover 17, 2022</a>
<li>{{ users }} users</li>
<li>{{ followers }} fediverse followers</li>
<li>{{ responses }} activities handled</li>
<li>{{ activities }} activities handled</li>
</ul>
</main>
</body>

Wyświetl plik

@ -16,6 +16,6 @@
<h3 class="row">Recent activity</h3>
{% include "responses.html" %}
{% include "activities.html" %}
{% endblock %}

Wyświetl plik

@ -14,7 +14,7 @@ from urllib3.exceptions import ReadTimeoutError
import activitypub
import common
from models import Follower, MagicKey, Response
from models import Follower, Domain, Activity
from . import testutil
REPLY_OBJECT = {
@ -173,7 +173,7 @@ class ActivityPubTest(testutil.TestCase):
'publicKey': {
'id': 'http://localhost/foo.com',
'owner': 'http://localhost/foo.com',
'publicKeyPem': MagicKey.get_by_id('foo.com').public_pem().decode(),
'publicKeyPem': Domain.get_by_id('foo.com').public_pem().decode(),
},
}, got.json)
@ -237,7 +237,7 @@ class ActivityPubTest(testutil.TestCase):
},
)
resp = Response.get_by_id('http://this/reply http://orig/post')
resp = Activity.get_by_id('http://this/reply http://orig/post')
self.assertEqual('orig', resp.domain)
self.assertEqual('in', resp.direction)
self.assertEqual('activitypub', resp.protocol)
@ -257,7 +257,7 @@ class ActivityPubTest(testutil.TestCase):
self.assert_req(mock_head, 'http://this', allow_redirects=True)
mock_get.assert_not_called()
mock_post.assert_not_called()
self.assertEqual(0, Response.query().count())
self.assertEqual(0, Activity.query().count())
def test_inbox_mention_object(self, *mocks):
self._test_inbox_mention(MENTION_OBJECT, *mocks)
@ -286,7 +286,7 @@ class ActivityPubTest(testutil.TestCase):
},
)
resp = Response.get_by_id('http://this/mention http://target/')
resp = Activity.get_by_id('http://this/mention http://target/')
self.assertEqual('target', resp.domain)
self.assertEqual('in', resp.direction)
self.assertEqual('activitypub', resp.protocol)
@ -319,7 +319,7 @@ class ActivityPubTest(testutil.TestCase):
'target': 'http://orig/post',
}, kwargs['data'])
resp = Response.get_by_id('http://this/like__ok http://orig/post')
resp = Activity.get_by_id('http://this/like__ok http://orig/post')
self.assertEqual('orig', resp.domain)
self.assertEqual('in', resp.direction)
self.assertEqual('activitypub', resp.protocol)
@ -358,7 +358,7 @@ class ActivityPubTest(testutil.TestCase):
'target': 'https://www.realize.be/',
}, kwargs['data'])
resp = Response.get_by_id('https://mastodon.social/6d1a https://www.realize.be/')
resp = Activity.get_by_id('https://mastodon.social/6d1a https://www.realize.be/')
self.assertEqual('www.realize.be', resp.domain)
self.assertEqual('in', resp.direction)
self.assertEqual('activitypub', resp.protocol)
@ -443,7 +443,7 @@ class ActivityPubTest(testutil.TestCase):
got = self.client.post('/foo.com/inbox', json=LIKE)
self.assertEqual(200, got.status_code)
resp = Response.get_by_id('http://this/like__ok http://orig/post')
resp = Activity.get_by_id('http://this/like__ok http://orig/post')
self.assertEqual('orig', resp.domain)
self.assertEqual('in', resp.direction)
self.assertEqual('activitypub', resp.protocol)

Wyświetl plik

@ -1,22 +1,22 @@
# coding=utf-8
"""Unit tests for models.py."""
from app import app
from models import MagicKey, Response
from models import Domain, Activity
from . import testutil
class MagicKeyTest(testutil.TestCase):
class DomainTest(testutil.TestCase):
def setUp(self):
super(MagicKeyTest, self).setUp()
self.key = MagicKey.get_or_create('y.z')
super(DomainTest, self).setUp()
self.key = Domain.get_or_create('y.z')
def test_magic_key_get_or_create(self):
assert self.key.mod
assert self.key.public_exponent
assert self.key.private_exponent
same = MagicKey.get_or_create('y.z')
same = Domain.get_or_create('y.z')
self.assertEqual(same, self.key)
def test_href(self):
@ -36,25 +36,25 @@ class MagicKeyTest(testutil.TestCase):
self.assertTrue(pem.decode().endswith('-----END RSA PRIVATE KEY-----'), pem)
class ResponseTest(testutil.TestCase):
class ActivityTest(testutil.TestCase):
def test_constructor(self):
resp = Response('abc', 'xyz')
resp = Activity('abc', 'xyz')
self.assertEqual('abc xyz', resp.key.id())
resp = Response('abc#1', 'xyz#Z')
resp = Activity('abc#1', 'xyz#Z')
self.assertEqual('abc__1 xyz__Z', resp.key.id())
def test_get_or_create(self):
resp = Response.get_or_create('abc', 'xyz')
resp = Activity.get_or_create('abc', 'xyz')
self.assertEqual('abc xyz', resp.key.id())
resp = Response.get_or_create('abc#1', 'xyz#Z')
resp = Activity.get_or_create('abc#1', 'xyz#Z')
self.assertEqual('abc__1 xyz__Z', resp.key.id())
def test_proxy_url(self):
with app.test_request_context('/'):
resp = Response.get_or_create('abc', 'xyz')
resp = Activity.get_or_create('abc', 'xyz')
self.assertIsNone(resp.proxy_url())
resp.source_as2 = 'as2'

Wyświetl plik

@ -6,7 +6,7 @@ from unittest.mock import patch
from oauth_dropins.webutil.testutil import requests_response
import common
from models import MagicKey
from models import Domain
from .test_webmention import REPOST_HTML, REPOST_AS2
from . import testutil
@ -15,7 +15,7 @@ class RedirectTest(testutil.TestCase):
def setUp(self):
super().setUp()
MagicKey.get_or_create('foo.com')
Domain.get_or_create('foo.com')
def test_redirect(self):
got = self.client.get('/r/https://foo.com/bar?baz=baj&biff')

Wyświetl plik

@ -2,7 +2,7 @@
"""Unit tests for render.py."""
from oauth_dropins.webutil.util import json_dumps
from models import Response
from models import Activity
import render
from . import testutil
@ -61,31 +61,31 @@ class RenderTest(testutil.TestCase):
resp = self.client.get(f'/render?source={source}&target={target}')
self.assertEqual(400, resp.status_code, resp.get_data(as_text=True))
# no Response
# no Activity
resp = self.client.get('/render?source=abc&target=xyz')
self.assertEqual(404, resp.status_code)
# no source data
Response(id='abc xyz').put()
Activity(id='abc xyz').put()
resp = self.client.get('/render?source=abc&target=xyz')
self.assertEqual(404, resp.status_code)
def test_render_as2(self):
Response(id='abc xyz', source_as2=json_dumps(self.as2)).put()
Activity(id='abc xyz', source_as2=json_dumps(self.as2)).put()
resp = self.client.get('/render?source=abc&target=xyz')
self.assertEqual(200, resp.status_code)
self.assert_multiline_equals(self.html, resp.get_data(as_text=True),
ignore_blanks=True)
def test_render_mf2(self):
Response(id='abc xyz', source_mf2=json_dumps(self.mf2)).put()
Activity(id='abc xyz', source_mf2=json_dumps(self.mf2)).put()
resp = self.client.get('/render?source=abc&target=xyz')
self.assertEqual(200, resp.status_code)
self.assert_multiline_equals(self.html, resp.get_data(as_text=True),
ignore_blanks=True)
def test_render_atom(self):
Response(id='abc xyz', source_atom=self.atom).put()
Activity(id='abc xyz', source_atom=self.atom).put()
resp = self.client.get('/render?source=abc&target=xyz')
self.assertEqual(200, resp.status_code)
self.assert_multiline_equals(self.html, resp.get_data(as_text=True),

Wyświetl plik

@ -12,7 +12,7 @@ from oauth_dropins.webutil.testutil import requests_response, UrlopenResult
import requests
import common
from models import MagicKey, Response
from models import Domain, Activity
from . import testutil
@ -24,7 +24,7 @@ class SalmonTest(testutil.TestCase):
def setUp(self):
super().setUp()
self.key = MagicKey.get_or_create('alice')
self.key = Domain.get_or_create('alice')
def send_slap(self, mock_urlopen, mock_head, mock_get, mock_post, atom_slap):
# salmon magic key discovery. first host-meta, then webfinger
@ -89,8 +89,8 @@ class SalmonTest(testutil.TestCase):
allow_redirects=False,
headers={'Accept': '*/*'})
# check stored response
resp = Response.get_by_id('https://my/reply http://orig/post')
# check stored post
resp = Activity.get_by_id('https://my/reply http://orig/post')
self.assertEqual('orig', resp.domain)
self.assertEqual('in', resp.direction)
self.assertEqual('ostatus', resp.protocol)
@ -124,8 +124,8 @@ class SalmonTest(testutil.TestCase):
allow_redirects=False,
headers={'Accept': '*/*'})
# check stored response
resp = Response.get_by_id('https://my/like http://orig/post')
# check stored post
resp = Activity.get_by_id('https://my/like http://orig/post')
self.assertEqual('orig', resp.domain)
self.assertEqual('in', resp.direction)
self.assertEqual('ostatus', resp.protocol)

Wyświetl plik

@ -32,7 +32,7 @@ class WebfingerTest(testutil.TestCase):
</a>
</body>
"""
self.key = models.MagicKey.get_or_create('foo.com')
self.key = models.Domain.get_or_create('foo.com')
self.expected_webfinger = {
'subject': 'acct:foo.com@foo.com',
'aliases': [

Wyświetl plik

@ -26,7 +26,7 @@ from common import (
CONTENT_TYPE_HTML,
CONTENT_TYPE_MAGIC_ENVELOPE,
)
from models import Follower, MagicKey, Response
from models import Follower, Domain, Activity
import webmention
from . import testutil
@ -68,7 +68,7 @@ REPOST_AS2 = {
class WebmentionTest(testutil.TestCase):
def setUp(self):
super().setUp()
self.key = MagicKey.get_or_create('a')
self.key = Domain.get_or_create('a')
self.orig_html_as2 = requests_response("""\
<html>
@ -284,7 +284,7 @@ class WebmentionTest(testutil.TestCase):
mock_get.side_effect = ValueError('foo bar')
got = self.client.post('/webmention', data={'source': 'bad'})
self.assertEqual(400, got.status_code)
self.assertEqual(0, Response.query().count())
self.assertEqual(0, Activity.query().count())
def test_no_source_entry(self, mock_get, mock_post):
mock_get.return_value = requests_response("""
@ -299,7 +299,7 @@ class WebmentionTest(testutil.TestCase):
'target': 'https://fed.brid.gy/',
})
self.assertEqual(400, got.status_code)
self.assertEqual(0, Response.query().count())
self.assertEqual(0, Activity.query().count())
mock_get.assert_has_calls((self.req('http://a/post'),))
@ -316,7 +316,7 @@ class WebmentionTest(testutil.TestCase):
'target': 'https://fed.brid.gy/',
})
self.assertEqual(200, got.status_code)
self.assertEqual(0, Response.query().count())
self.assertEqual(0, Activity.query().count())
mock_get.assert_has_calls((self.req('http://a/post'),))
@ -328,7 +328,7 @@ class WebmentionTest(testutil.TestCase):
got = self.client.post('/webmention', data={'source': 'http://a/post'})
self.assertEqual(400, got.status_code)
self.assertEqual(0, Response.query().count())
self.assertEqual(0, Activity.query().count())
def test_source_fetch_fails(self, mock_get, mock_post):
mock_get.side_effect = (
@ -350,7 +350,7 @@ class WebmentionTest(testutil.TestCase):
)
got = self.client.post('/webmention', data={'source': 'http://a/post'})
self.assertEqual(502, got.status_code)
self.assertEqual(0, Response.query().count())
self.assertEqual(0, Activity.query().count())
def test_no_backlink(self, mock_get, mock_post):
mock_get.return_value = requests_response(
@ -362,7 +362,7 @@ class WebmentionTest(testutil.TestCase):
'target': 'https://fed.brid.gy/',
})
self.assertEqual(400, got.status_code)
self.assertEqual(0, Response.query().count())
self.assertEqual(0, Activity.query().count())
mock_get.assert_has_calls((self.req('http://a/post'),))
@ -405,7 +405,7 @@ class WebmentionTest(testutil.TestCase):
rsa_key = kwargs['auth'].header_signer._rsa._key
self.assertEqual(self.key.private_pem(), rsa_key.exportKey())
resp = Response.get_by_id('http://a/reply http://orig/as2')
resp = Activity.get_by_id('http://a/reply http://orig/as2')
self.assertEqual('a', resp.domain)
self.assertEqual('out', resp.direction)
self.assertEqual('activitypub', resp.protocol)
@ -419,7 +419,7 @@ class WebmentionTest(testutil.TestCase):
# self.assertEqual(['abc xyz'], resp.responses)
def test_activitypub_update_reply(self, mock_get, mock_post):
Response(id='http://a/reply http://orig/as2', status='complete').put()
Activity(id='http://a/reply http://orig/as2', status='complete').put()
mock_get.side_effect = self.activitypub_gets
mock_post.return_value = requests_response('abc xyz')
@ -436,7 +436,7 @@ class WebmentionTest(testutil.TestCase):
def test_activitypub_skip_update_if_content_unchanged(self, mock_get, mock_post):
"""https://github.com/snarfed/bridgy-fed/issues/78"""
Response(id='http://a/reply http://orig/as2', status='complete',
Activity(id='http://a/reply http://orig/as2', status='complete',
source_mf2=json_dumps(self.reply_mf2)).put()
mock_get.side_effect = self.activitypub_gets
@ -508,7 +508,7 @@ class WebmentionTest(testutil.TestCase):
rsa_key = kwargs['auth'].header_signer._rsa._key
self.assertEqual(self.key.private_pem(), rsa_key.exportKey())
resp = Response.get_by_id('http://a/repost http://orig/as2')
resp = Activity.get_by_id('http://a/repost http://orig/as2')
self.assertEqual('a', resp.domain)
self.assertEqual('out', resp.direction)
self.assertEqual('activitypub', resp.protocol)
@ -605,12 +605,12 @@ class WebmentionTest(testutil.TestCase):
mock_get.side_effect = [self.create, self.actor]
mock_post.return_value = requests_response('abc xyz')
Response(id='http://orig/post https://skipped/inbox', domain='orig',
Activity(id='http://orig/post https://skipped/inbox', domain='orig',
status='complete', source_mf2=json_dumps(self.create_mf2)).put()
different_create_mf2 = copy.deepcopy(self.create_mf2)
different_create_mf2['items'][0]['properties']['content'][0]['value'] += ' different'
Response(id='http://orig/post https://updated/inbox', domain='orig',
Activity(id='http://orig/post https://updated/inbox', domain='orig',
status='complete', direction='out', protocol='activitypub',
source_mf2=json_dumps(different_create_mf2)).put()
@ -672,7 +672,7 @@ class WebmentionTest(testutil.TestCase):
self.update_as2 if inbox == 'https://updated/inbox' else self.create_as2,
json_loads(call[1]['data']))
resp = Response.get_by_id('http://orig/post %s' % inbox)
resp = Activity.get_by_id('http://orig/post %s' % inbox)
self.assertEqual('orig', resp.domain)
self.assertEqual('out', resp.direction, inbox)
self.assertEqual('activitypub', resp.protocol, inbox)
@ -733,7 +733,7 @@ class WebmentionTest(testutil.TestCase):
rsa_key = kwargs['auth'].header_signer._rsa._key
self.assertEqual(self.key.private_pem(), rsa_key.exportKey())
resp = Response.get_by_id('http://a/follow http://followee/')
resp = Activity.get_by_id('http://a/follow http://followee/')
self.assertEqual('a', resp.domain)
self.assertEqual('out', resp.direction)
self.assertEqual('activitypub', resp.protocol)
@ -776,7 +776,7 @@ class WebmentionTest(testutil.TestCase):
rsa_key = kwargs['auth'].header_signer._rsa._key
self.assertEqual(self.key.private_pem(), rsa_key.exportKey())
resp = Response.get_by_id('http://a/follow http://followee/')
resp = Activity.get_by_id('http://a/follow http://followee/')
self.assertEqual('a', resp.domain)
self.assertEqual('out', resp.direction)
self.assertEqual('activitypub', resp.protocol)
@ -821,7 +821,7 @@ class WebmentionTest(testutil.TestCase):
<a href="http://localhost/"></a>""",
entry.content[0]['value'])
resp = Response.get_by_id('http://a/reply http://orig/post')
resp = Activity.get_by_id('http://a/reply http://orig/post')
self.assertEqual('a', resp.domain)
self.assertEqual('out', resp.direction)
self.assertEqual('ostatus', resp.protocol)
@ -855,7 +855,7 @@ class WebmentionTest(testutil.TestCase):
}, entry['links'])
self.assertEqual('http://orig/post', entry['activity_object'])
resp = Response.get_by_id('http://a/like http://orig/post')
resp = Activity.get_by_id('http://a/like http://orig/post')
self.assertEqual('a', resp.domain)
self.assertEqual('out', resp.direction)
self.assertEqual('ostatus', resp.protocol)
@ -907,7 +907,7 @@ class WebmentionTest(testutil.TestCase):
self.assertIn('Target post http://orig/url has no Atom link',
got.get_data(as_text=True))
resp = Response.get_by_id('http://a/reply http://orig/url')
resp = Activity.get_by_id('http://a/reply http://orig/url')
self.assertEqual('a', resp.domain)
self.assertEqual('out', resp.direction)
self.assertEqual('ostatus', resp.protocol)

Wyświetl plik

@ -59,7 +59,7 @@ class User(flask_util.XrdOrJrd):
error(f"didn't find a representative h-card (http://microformats.org/wiki/representative-hcard-parsing) on {resp.url}")
logger.info(f'Generating WebFinger data for {domain}')
key = models.MagicKey.get_or_create(domain)
key = models.Domain.get_or_create(domain)
props = hcard.get('properties', {})
urls = util.dedupe_urls(props.get('url', []) + [resp.url])
canonical_url = urls[0]

Wyświetl plik

@ -25,7 +25,7 @@ from werkzeug.exceptions import BadGateway
import activitypub
from app import app
import common
from models import Follower, MagicKey, Response
from models import Follower, Domain, Activity
logger = logging.getLogger(__name__)
@ -91,7 +91,7 @@ class Webmention(View):
if not targets:
return None
key = MagicKey.get_or_create(self.source_domain)
key = Domain.get_or_create(self.source_domain)
error = None
last_success = None
@ -160,7 +160,7 @@ class Webmention(View):
def _activitypub_targets(self):
"""
Returns: list of (Response, string inbox URL)
Returns: list of (Activity, string inbox URL)
"""
# if there's in-reply-to, like-of, or repost-of, they're the targets.
# otherwise, it's all followers' inboxes.
@ -178,7 +178,7 @@ class Webmention(View):
inboxes.add(actor.get('endpoints', {}).get('sharedInbox') or
actor.get('publicInbox')or
actor.get('inbox'))
return [(Response.get_or_create(
return [(Activity.get_or_create(
source=self.source_url, target=inbox, domain=self.source_domain,
direction='out', protocol='activitypub',
source_mf2=json_dumps(self.source_mf2)),
@ -200,7 +200,7 @@ class Webmention(View):
raise
target_url = self.target_resp.url or target
resp = Response.get_or_create(
resp = Activity.get_or_create(
source=self.source_url, target=target_url, domain=self.source_domain,
direction='out', protocol='activitypub',
source_mf2=json_dumps(self.source_mf2))
@ -266,7 +266,7 @@ class Webmention(View):
raise
finally:
if status:
Response(source=self.source_url, target=target, status=status,
Activity(source=self.source_url, target=target, status=status,
domain=self.source_domain, direction='out',
protocol = 'ostatus',
source_mf2=json_dumps(self.source_mf2)).put()
@ -351,7 +351,7 @@ class Webmention(View):
# sign reply and wrap in magic envelope
domain = urllib.parse.urlparse(self.source_url).netloc
key = MagicKey.get_or_create(domain)
key = Domain.get_or_create(domain)
logger.info(f'Using key for {domain}: {key}')
magic_envelope = magicsigs.magic_envelope(
entry, common.CONTENT_TYPE_ATOM, key).decode()