diff --git a/activitypub.py b/activitypub.py index b413c022..4eb56249 100644 --- a/activitypub.py +++ b/activitypub.py @@ -1,4 +1,3 @@ -# coding=utf-8 """Handles requests for ActivityPub endpoints: actors, inbox, etc. """ import json @@ -14,21 +13,25 @@ import requests import webapp2 from webmentiontools import send +import common + # https://www.w3.org/TR/activitypub/#retrieving-objects -CONTENT_TYPE = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' -USER_AGENT = 'bridgy-federated (https://fed.brid.gy/)' +CONTENT_TYPE_AS2 = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' +CONTENT_TYPE_AS = 'application/activity+json' +CONNEG_HEADER = { + 'Accept': '%s; q=0.9, %s; q=0.8' % (CONTENT_TYPE_AS2, CONTENT_TYPE_AS), +} + DOMAIN_RE = r'([^/]+\.[^/]+)' + class ActorHandler(webapp2.RequestHandler): """Serves /[DOMAIN], fetches its mf2, converts to AS Actor, and serves it.""" def get(self, domain): url = 'https://%s/' % domain - resp = requests.get(url=url, headers={ - 'User-Agent': USER_AGENT, - }) - resp.raise_for_status() + resp = common.requests_get(url) mf2 = mf2py.parse(resp.text, url=resp.url) logging.info('Parsed mf2 for %s: %s', resp.url, json.dumps(mf2, indent=2)) @@ -42,7 +45,7 @@ class ActorHandler(webapp2.RequestHandler): logging.info('Returning: %s', json.dumps(obj, indent=2)) self.response.headers.update({ - 'Content-Type': CONTENT_TYPE, + 'Content-Type': CONTENT_TYPE_AS2, 'Access-Control-Allow-Origin': '*', }) self.response.write(json.dumps(obj, indent=2)) @@ -73,7 +76,7 @@ class InboxHandler(webapp2.RequestHandler): for target in targets: logging.info('Sending webmention from %s to %s', source, target) wm = send.WebmentionSend(source, target) - if wm.send(headers={'User-Agent': USER_AGENT}): + if wm.send(headers=common.HEADERS): logging.info('Success: %s', wm.response) else: logging.warning('Failed: %s', wm.error) diff --git a/app.yaml b/app.yaml index 6f168639..906b55c2 100644 --- a/app.yaml +++ b/app.yaml @@ -35,9 +35,14 @@ handlers: upload: static/index.html # dynamic -- url: /[^/]+/? +- url: /[^/]+/?(inbox)? script: activitypub.app - secure: always + # TODO + # secure: always + +- url: /webmention + script: webmention.app + # secure: always skip_files: - ^(.*/)?.*\.py[co] diff --git a/common.py b/common.py new file mode 100644 index 00000000..d8b44d2d --- /dev/null +++ b/common.py @@ -0,0 +1,33 @@ +"""Misc common utilities. +""" +import json +import logging + +import mf2py +import requests + +HEADERS = { + 'User-Agent': 'bridgy-federated (https://fed.brid.gy/)', +} + + +def requests_get(url, **kwargs): + kwargs.setdefault('headers', {}).update(HEADERS) + resp = requests.get(url, **kwargs) + resp.raise_for_status() + return resp + + +# def fetch_mf2(url): +# """Fetches a URL and parses and returns its mf2. + +# Args: +# url: string + +# Returns: dict, parsed mf2 +# """ +# resp = requests.get(url=url, headers={'User-Agent': USER_AGENT}) +# resp.raise_for_status() +# mf2 = mf2py.parse(resp.text, url=resp.url) +# logging.info('Parsed mf2 for %s: %s', resp.url, json.dumps(mf2, indent=2)) +# return mf2 diff --git a/test/test_activitypub.py b/test/test_activitypub.py index b77ecc99..67846315 100644 --- a/test/test_activitypub.py +++ b/test/test_activitypub.py @@ -12,6 +12,7 @@ import requests import activitypub from activitypub import app +import common @mock.patch('requests.post') @@ -34,7 +35,7 @@ class ActivityPubTest(unittest.TestCase): got = app.get_response('/foo.com') self.assertEquals(200, got.status_int) - self.assertEquals(activitypub.CONTENT_TYPE, got.headers['Content-Type']) + self.assertEquals(activitypub.CONTENT_TYPE_AS2, got.headers['Content-Type']) self.assertEquals({ 'objectType' : 'person', 'displayName': u'Mrs. ☕ Foo', @@ -73,5 +74,5 @@ class ActivityPubTest(unittest.TestCase): 'target': 'http://orig/post', }, allow_redirects=False, - headers={'User-Agent': activitypub.USER_AGENT}, + headers=common.HEADERS, verify=False)