Merge pull request #174 from mouse-reeve/remote-user

Fixes remote user code
This commit is contained in:
Mouse Reeve 2020-05-18 18:29:37 -07:00 committed by GitHub
commit b54c6f7855
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 101 additions and 13 deletions

View file

@ -90,6 +90,7 @@ def shared_inbox(request):
def get_public_key(key_actor):
''' try a stored key or load it from remote '''
try:
user = models.User.objects.get(remote_id=key_actor)
public_key = user.public_key

View file

@ -4,6 +4,7 @@ from uuid import uuid4
import requests
from django.core.files.base import ContentFile
from django.db import transaction
from fedireads import models
from fedireads.status import create_review_from_activity
@ -12,7 +13,7 @@ from fedireads.status import create_review_from_activity
def get_or_create_remote_user(actor):
''' look up a remote user or add them '''
try:
return models.User.objects.get(actor=actor)
return models.User.objects.get(remote_id=actor)
except models.User.DoesNotExist:
pass
@ -25,37 +26,50 @@ def get_or_create_remote_user(actor):
response.raise_for_status()
data = response.json()
# the webfinger format for the username.
# make sure our actor is who they say they are
assert actor == data['id']
actor_parts = urlparse(actor)
with transaction.atomic():
user = create_remote_user(data)
user.federated_server = get_or_create_remote_server(actor_parts.netloc)
user.save()
avatar = get_avatar(data)
user.avatar.save(*avatar)
if user.fedireads_user:
get_remote_reviews(user)
return user
def create_remote_user(data):
''' parse the activitypub actor data into a user '''
actor = data['id']
actor_parts = urlparse(actor)
# the webfinger format for the username.
username = '%s@%s' % (actor_parts.path.split('/')[-1], actor_parts.netloc)
shared_inbox = data.get('endpoints').get('sharedInbox') if \
data.get('endpoints') else None
server = get_or_create_remote_server(actor_parts.netloc)
avatar = get_avatar(data)
# throws a key error if it can't find any of these fields
user = models.User.objects.create_user(
return models.User.objects.create_user(
username,
'', '', # email and passwords are left blank
actor=actor,
remote_id=actor,
name=data.get('name'),
summary=data.get('summary'),
inbox=data['inbox'], #fail if there's no inbox
outbox=data['outbox'], # fail if there's no outbox
shared_inbox=shared_inbox,
# TODO: I'm never actually using this for remote users
public_key=data.get('publicKey').get('publicKeyPem'),
local=False,
fedireads_user=data.get('fedireadsUser', False),
manually_approves_followers=data.get(
'manuallyApprovesFollowers', False),
federated_server=server,
)
user.avatar.save(*avatar)
if user.fedireads_user:
get_remote_reviews(user)
return user
def get_avatar(data):

View file

@ -0,0 +1,36 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"schema": "http://schema.org#",
"PropertyValue": "schema:PropertyValue",
"value": "schema:value"
}
],
"id": "https://example.com/user/mouse",
"type": "Person",
"preferredUsername": "mouse",
"name": "MOUSE?? MOUSE!!",
"inbox": "https://example.com/user/mouse/inbox",
"outbox": "https://example.com/user/mouse/outbox",
"followers": "https://example.com/user/mouse/followers",
"following": "https://example.com/user/mouse/following",
"summary": "",
"publicKey": {
"id": "https://example.com/user/mouse/#main-key",
"owner": "https://example.com/user/mouse",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6QisDrjOQvkRo/MqNmSYPwqtt\nCxg/8rCW+9jKbFUKvqjTeKVotEE85122v/DCvobCCdfQuYIFdVMk+dB1xJ0iPGPg\nyU79QHY22NdV9mFKA2qtXVVxb5cxpA4PlwOHM6PM/k8B+H09OUrop2aPUAYwy+vg\n+MXyz8bAXrIS1kq6fQIDAQAB\n-----END PUBLIC KEY-----"
},
"endpoints": {
"sharedInbox": "https://example.com/inbox"
},
"fedireadsUser": true,
"manuallyApprovesFollowers": false,
"icon": {
"type": "Image",
"mediaType": "image/png",
"url": "https://example.com/images/avatars/AL-2-crop-50.png"
}
}

View file

@ -0,0 +1,37 @@
from django.test import TestCase
import json
import pathlib
from fedireads import models, remote_user
class RemoteUser(TestCase):
''' not too much going on in the books model but here we are '''
def setUp(self):
self.remote_user = models.User.objects.create_user(
'mouse', 'mouse@mouse.com', 'mouseword',
local=False,
remote_id='https://example.com/users/mouse',
inbox='https://example.com/users/mouse/inbox',
outbox='https://example.com/users/mouse/outbox',
)
def test_get_remote_user(self):
actor = 'https://example.com/users/mouse'
user = remote_user.get_or_create_remote_user(actor)
self.assertEqual(user, self.remote_user)
def test_create_remote_user(self):
datafile = pathlib.Path(__file__).parent.joinpath('data/ap_user.json')
data = json.loads(datafile.read_bytes())
user = remote_user.create_remote_user(data)
self.assertEqual(user.username, 'mouse@example.com')
self.assertEqual(user.name, 'MOUSE?? MOUSE!!')
self.assertEqual(user.inbox, 'https://example.com/user/mouse/inbox')
self.assertEqual(user.outbox, 'https://example.com/user/mouse/outbox')
self.assertEqual(user.shared_inbox, 'https://example.com/inbox')
self.assertEqual(user.public_key, data['publicKey']['publicKeyPem'])
self.assertEqual(user.local, False)
self.assertEqual(user.fedireads_user, True)
self.assertEqual(user.manually_approves_followers, False)