AP: add publicKey to actor object

needed for mastodon interop
pull/27/head
Ryan Barrett 2017-10-01 07:01:35 -07:00
rodzic 8e2406caa4
commit 71f0a4c8d4
4 zmienionych plików z 27 dodań i 10 usunięć

Wyświetl plik

@ -13,6 +13,7 @@ import webapp2
from webmentiontools import send
import common
import models
# https://www.w3.org/TR/activitypub/#retrieving-objects
@ -38,7 +39,9 @@ class ActorHandler(webapp2.RequestHandler):
Couldn't find a <a href="http://microformats.org/wiki/representative-hcard-parsing">\
representative h-card</a> on %s""" % resp.url)
obj = common.postprocess_as2(as2.from_as1(microformats2.json_to_object(hcard)))
key = models.MagicKey.get_or_create(domain)
obj = common.postprocess_as2(as2.from_as1(microformats2.json_to_object(hcard)),
key=key)
obj.update({
'inbox': '%s/%s/inbox' % (appengine_config.HOST_URL, domain),
})
@ -63,6 +66,8 @@ class InboxHandler(webapp2.RequestHandler):
logging.error(msg, exc_info=True)
self.abort(400, msg)
# TODO: verify signature if there is one
obj = obj.get('object') or obj
source = obj.get('url')
if not source:

Wyświetl plik

@ -58,8 +58,13 @@ def error(handler, msg, status=400):
handler.abort(status, msg)
def postprocess_as2(activity):
"""Prepare an AS2 object to be served or sent via ActivityPub."""
def postprocess_as2(activity, key=None):
"""Prepare an AS2 object to be served or sent via ActivityPub.
Args:
activity: dict, AS2 object or activity
key: MagicKey, optional. populated into publicKey field if provided.
"""
# for Mastodon
activity.update({
'type': activity.get('@type'),
@ -71,6 +76,14 @@ def postprocess_as2(activity):
obj['@id'] = obj.get('url')
obj['id'] = obj['@id']
if not activity.get('publicKey'):
# underspecified, inferred from this issue and Mastodon's implementation:
# https://github.com/w3c/activitypub/issues/203#issuecomment-297553229
# https://github.com/tootsuite/mastodon/blob/bc2c263504e584e154384ecc2d804aeb1afb1ba3/app/services/activitypub/process_account_service.rb#L77
activity['publicKey'] = {
'publicKeyPem': key.public_pem(),
}
in_reply_tos = activity.get('inReplyTo')
if isinstance(in_reply_tos, list):
if len(in_reply_tos) > 1:

Wyświetl plik

@ -27,15 +27,15 @@ class MagicKey(StringIdModel):
@staticmethod
@ndb.transactional
def get_or_create(uri):
def get_or_create(domain):
"""Loads and returns a MagicKey. Creates it if necessary."""
key = MagicKey.get_by_id(uri)
key = MagicKey.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=uri, mod=mod, public_exponent=pubexp,
key = MagicKey(id=domain, mod=mod, public_exponent=pubexp,
private_exponent=privexp)
key.put()

Wyświetl plik

@ -84,15 +84,14 @@ class WebmentionHandler(webapp2.RequestHandler):
return self.send_salmon(source_obj, target_url=target)
# convert to AS2
source_activity = common.postprocess_as2(as2.from_as1(source_obj))
source_domain = urlparse.urlparse(source).netloc
key = models.MagicKey.get_or_create(source_domain)
source_activity = common.postprocess_as2(as2.from_as1(source_obj), key=key)
# prepare HTTP Signature (required by Mastodon)
# https://w3c.github.io/activitypub/#authorization-lds
# https://tools.ietf.org/html/draft-cavage-http-signatures-07
# https://github.com/tootsuite/mastodon/issues/4906#issuecomment-328844846
source_domain = urlparse.urlparse(source).netloc
key = models.MagicKey.get_or_create(source_domain)
acct = 'acct:me@%s' % source_domain
auth = HTTPSignatureAuth(secret=key.private_pem(), key_id=acct,
algorithm='rsa-sha256')