# coding=utf-8
"""Unit tests for webfinger.py.
to test:
* user URL that redirects
* error handling
"""
import html
from unittest import mock
import urllib.parse
from oauth_dropins.webutil import util
from oauth_dropins.webutil.testutil import requests_response
from oauth_dropins.webutil.util import json_loads
import requests
import common
import models
from . import testutil
class WebfingerTest(testutil.TestCase):
def setUp(self):
super().setUp()
self.html = """
Mrs. ☕ Foo
"""
self.key = models.User.get_or_create('foo.com')
self.expected_webfinger = {
'subject': 'acct:foo.com@foo.com',
'aliases': [
'https://foo.com/about-me',
'https://foo.com/',
],
'magic_keys': [{'value': self.key.href()}],
'links': [{
'rel': 'http://webfinger.net/rel/profile-page',
'type': 'text/html',
'href': 'https://foo.com/about-me'
}, {
'rel': 'http://webfinger.net/rel/profile-page',
'type': 'text/html',
'href': 'https://foo.com/'
}, {
'rel': 'http://webfinger.net/rel/avatar',
'href': 'https://foo.com/me.jpg'
}, {
'rel': 'canonical_uri',
'type': 'text/html',
'href': 'https://foo.com/about-me'
}, {
'rel': 'self',
'type': 'application/activity+json',
'href': 'http://localhost/foo.com'
}, {
'rel': 'inbox',
'type': 'application/activity+json',
'href': 'http://localhost/foo.com/inbox'
}, {
'rel': 'sharedInbox',
'type': 'application/activity+json',
'href': 'http://localhost/inbox'
}, {
'rel': 'http://schemas.google.com/g/2010#updates-from',
'type': 'application/atom+xml',
'href': 'https://granary.io/url?input=html&output=atom&url=https%3A%2F%2Ffoo.com%2F&hub=https%3A%2F%2Ffoo.com%2F',
}, {
'rel': 'hub',
'href': 'https://bridgy-fed.superfeedr.com/'
}, {
'rel': 'magic-public-key',
'href': self.key.href(),
}, {
'rel': 'salmon',
'href': 'http://localhost/foo.com/salmon'
}]
}
def test_host_meta_handler_xrd(self):
got = self.client.get('/.well-known/host-meta')
self.assertEqual(200, got.status_code)
self.assertEqual('application/xrd+xml; charset=utf-8',
got.headers['Content-Type'])
body = got.get_data(as_text=True)
self.assertTrue(body.startswith('
""" + self.html
mock_get.return_value = requests_response(html, url = 'https://foo.com/')
got = self.client.get('/acct:foo.com', headers={'Accept': 'application/json'})
self.assertEqual(200, got.status_code)
self.assertIn({
'rel': 'http://schemas.google.com/g/2010#updates-from',
'type': 'application/atom+xml',
'href': 'https://foo.com/use-this',
}, got.json['links'])
@mock.patch('requests.get')
def test_user_handler_with_push_header(self, mock_get):
mock_get.return_value = requests_response(
self.html, url = 'https://foo.com/', headers={
'Link': 'badly formatted, '
"; rel='foo',"
' ; rel="hub"',
})
got = self.client.get('/acct:foo.com', headers={'Accept': 'application/json'})
self.assertEqual(200, got.status_code)
self.assertIn({
'rel': 'hub',
'href': 'http://a.custom.hub/',
}, got.json['links'])
@mock.patch('requests.get')
def test_user_handler_no_hcard(self, mock_get):
mock_get.return_value = requests_response("""
""")
got = self.client.get('/acct:foo.com')
self.assert_req(mock_get, 'https://foo.com/')
self.assertEqual(400, got.status_code)
self.assertIn('representative h-card', got.get_data(as_text=True))
def test_user_handler_bad_tld(self):
got = self.client.get('/acct:foo.json')
self.assertEqual(404, got.status_code)
self.assertIn("doesn't look like a domain",
html.unescape(got.get_data(as_text=True)))
@mock.patch('requests.get')
def test_webfinger_handler(self, mock_get):
mock_get.return_value = requests_response(self.html, url='https://foo.com/')
for resource in ('foo.com@foo.com', 'acct:foo.com@foo.com', 'xyz@foo.com',
'foo.com', 'http://foo.com/', 'https://foo.com/',
'http://localhost/foo.com'):
url = '/.well-known/webfinger?%s' % urllib.parse.urlencode(
{'resource': resource})
got = self.client.get(url, headers={'Accept': 'application/json'})
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
self.assertEqual('application/jrd+json', got.headers['Content-Type'])
self.assertEqual(self.expected_webfinger, got.json)
@mock.patch('requests.get')
def test_webfinger_handler_custom_username(self, mock_get):
self.html = """
Mrs. ☕ Foo
"""
self.expected_webfinger.update({
'subject': 'acct:customuser@foo.com',
'aliases': [
'https://foo.com/about-me',
'acct:notthisuser@boop.org',
'acct:customuser@foo.com',
'https://foo.com/',
],
})
mock_get.return_value = requests_response(self.html, url='https://foo.com/')
for resource in (
'customuser@foo.com',
'acct:customuser@foo.com',
'foo.com',
'http://foo.com/',
'https://foo.com/',
# Mastodon requires this as of 3.3.0
# https://github.com/snarfed/bridgy-fed/issues/73
# 'acct:foo.com@fed.brid.gy',
'acct:foo.com@fed.brid.gy',
'acct:foo.com@bridgy-federated.appspot.com',
'acct:foo.com@localhost',
):
url = '/.well-known/webfinger?%s' % urllib.parse.urlencode(
{'resource': resource})
got = self.client.get(url, headers={'Accept': 'application/json'})
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
self.assertEqual('application/jrd+json', got.headers['Content-Type'])
self.assertEqual(self.expected_webfinger, got.json)