mastodon interop: salmon + activitypub + webfinger cleanup, tests

mastodon
Ryan Barrett 2017-09-03 12:54:10 -07:00
rodzic b975d68a72
commit 4dd8f7e1a7
7 zmienionych plików z 29 dodań i 27 usunięć

Wyświetl plik

@ -89,6 +89,6 @@ class InboxHandler(webapp2.RequestHandler):
app = webapp2.WSGIApplication([
(r'/(%s)/?' % common.DOMAIN_RE, ActorHandler),
(r'/(%s)/inbox' % common.DOMAIN_RE, InboxHandler),
(r'/%s/?' % common.DOMAIN_RE, ActorHandler),
(r'/%s/inbox' % common.DOMAIN_RE, InboxHandler),
], debug=appengine_config.DEBUG)

Wyświetl plik

@ -74,7 +74,7 @@ handlers:
script: salmon.app
secure: always
- url: /(acct:)?@[^/]+/?
- url: /(acct:)?([^@]+)@@[^/]+/?
script: webfinger.app
secure: always

Wyświetl plik

@ -6,7 +6,8 @@ from oauth_dropins.webutil import util
import requests
from webob import exc
DOMAIN_RE = r'[^/]+\.[^/]+'
DOMAIN_RE = r'([^/]+\.[^/]+)'
ACCT_RE = r'(?:acct:)?([^@]+)@' + DOMAIN_RE
HEADERS = {
'User-Agent': 'Bridgy Fed (https://fed.brid.gy/)',
}

Wyświetl plik

@ -21,10 +21,10 @@ ATOM_THREADING_NS = 'http://purl.org/syndication/thread/1.0'
class SlapHandler(webapp2.RequestHandler):
"""Accepts POSTs to /[DOMAIN]/salmon and converts to outbound webmentions."""
"""Accepts POSTs to /[ACCT]/salmon and converts to outbound webmentions."""
# TODO: unify with activitypub
def post(self, domain):
def post(self, username, domain):
logging.info('Got: %s', self.request.body)
parsed = utils.parse_magic_envelope(self.request.body)
@ -39,12 +39,14 @@ class SlapHandler(webapp2.RequestHandler):
common.error(self, 'Author URI %s has unsupported scheme; expected acct:' % author)
logging.info('Fetching Salmon key for %s' % author)
if not magicsigs.verify(data, parsed['sig'], author_uri=author):
if not magicsigs.verify(author, data, parsed['sig']):
common.error(self, 'Could not verify magic signature.')
logging.info('Verified magic signature.')
# Mastodon doesn't do this! so screw it.
# # verify that the timestamp is recent (required by spec)
# Verify that the timestamp is recent. Required by spec.
# I get that this helps prevent spam, but in practice it's a bit silly,
# and other major implementations don't (e.g. Mastodon), so forget it.
#
# updated = utils.parse_updated_from_atom(data)
# if not utils.verify_timestamp(updated):
# common.error(self, 'Timestamp is more than 1h old.')
@ -82,5 +84,5 @@ class SlapHandler(webapp2.RequestHandler):
app = webapp2.WSGIApplication([
(r'/(?:acct:)?@%s/salmon' % common.DOMAIN_RE, SlapHandler),
(r'/%s/salmon' % common.ACCT_RE, SlapHandler),
], debug=appengine_config.DEBUG)

Wyświetl plik

@ -64,8 +64,8 @@ class SalmonTest(testutil.TestCase):
<title>My Reply</title>
<updated>%s</updated>
</entry>""" % datetime.datetime.now().isoformat(b'T')
slap = magicsigs.magic_envelope(atom_reply, 'application/atom+xml', key)
got = app.get_response('/@foo.com/salmon', method='POST', body=slap)
slap = magicsigs.magic_envelope(atom_reply, common.ATOM_CONTENT_TYPE, key)
got = app.get_response('/me@foo.com/salmon', method='POST', body=slap)
self.assertEquals(200, got.status_int)
# check salmon magic key discovery

Wyświetl plik

@ -51,17 +51,17 @@ class WebFingerTest(testutil.TestCase):
</body>
""", url = 'https://foo.com/')
got = app.get_response('/@foo.com', headers={'Accept': 'application/json'})
mock_get.assert_called_once_with('http://foo.com/', headers=common.HEADERS,
timeout=util.HTTP_TIMEOUT)
got = app.get_response(u'/me@foo.com', headers={'Accept': 'application/json'})
self.assertEquals(200, got.status_int)
self.assertEquals('application/json; charset=utf-8',
got.headers['Content-Type'])
mock_get.assert_called_once_with('http://foo.com/', headers=common.HEADERS,
timeout=util.HTTP_TIMEOUT)
key = models.MagicKey.get_by_id('@foo.com')
key = models.MagicKey.get_by_id('me@foo.com')
self.assertEquals({
'subject': 'acct:@foo.com',
'subject': 'acct:me@foo.com',
'aliases': [
'https://foo.com/about-me',
'https://foo.com/',
@ -91,7 +91,7 @@ class WebFingerTest(testutil.TestCase):
'href': key.href(),
}, {
'rel': 'salmon',
'href': 'http://localhost/@foo.com/salmon'
'href': 'http://localhost/me@foo.com/salmon'
# TODO
# }, {
# 'rel': 'self',
@ -105,7 +105,7 @@ class WebFingerTest(testutil.TestCase):
# check that magic key is persistent
again = json.loads(app.get_response(
'/@foo.com', headers={'Accept': 'application/json'}).body)
'/me@foo.com', headers={'Accept': 'application/json'}).body)
self.assertEquals(key.href(), again['magic_keys'][0]['value'])
links = {l['rel']: l['href'] for l in again['links']}
@ -120,7 +120,7 @@ class WebFingerTest(testutil.TestCase):
</div>
</body>
""")
got = app.get_response('/@foo.com')
got = app.get_response('/me@foo.com')
mock_get.assert_called_once_with('http://foo.com/', headers=common.HEADERS,
timeout=util.HTTP_TIMEOUT)
self.assertEquals(400, got.status_int)

Wyświetl plik

@ -33,8 +33,7 @@ class UserHandler(handlers.XrdOrJrdHandler):
def template_prefix(self):
return 'templates/webfinger_user'
def template_vars(self, acct):
username, domain = util.parse_acct_uri(acct)
def template_vars(self, username, domain):
url = 'http://%s/' % domain
# TODO: unify with activitypub
@ -49,14 +48,14 @@ class UserHandler(handlers.XrdOrJrdHandler):
Couldn't find a <a href="http://microformats.org/wiki/representative-hcard-parsing">\
representative h-card</a> on %s""" % resp.url)
uri = '%s@%s' % (username, domain)
key = models.MagicKey.get_or_create(uri)
acct = '%s@%s' % (username, domain)
key = models.MagicKey.get_or_create(acct)
props = hcard.get('properties', {})
urls = util.dedupe_urls(props.get('url', []) + [resp.url])
canonical_url = urls[0]
data = util.trim_nulls({
'subject': 'acct:' + uri,
'subject': 'acct:' + acct,
'aliases': urls,
'magic_keys': [{'value': key.href()}],
'links': sum(([{
@ -81,7 +80,7 @@ representative h-card</a> on %s""" % resp.url)
'href': key.href(),
}, {
'rel': 'salmon',
'href': '%s/@%s/salmon' % (self.request.host_url, domain),
'href': '%s/%s/salmon' % (self.request.host_url, acct),
}]
})
logging.info('Returning WebFinger data: %s', json.dumps(data, indent=2))
@ -99,6 +98,6 @@ class WebfingerHandler(UserHandler):
app = webapp2.WSGIApplication([
(r'/(?:acct)?(@%s)/?' % common.DOMAIN_RE, UserHandler),
(r'/%s/?' % common.ACCT_RE, UserHandler),
('/.well-known/webfinger', WebfingerHandler),
] + handlers.HOST_META_ROUTES, debug=appengine_config.DEBUG)