167 lines
4.8 KiB
Python
167 lines
4.8 KiB
Python
import json
|
|
import requests
|
|
|
|
from django.conf import settings
|
|
|
|
from funkwhale_api.common import session
|
|
|
|
from . import actors
|
|
from . import models
|
|
from . import serializers
|
|
from . import signing
|
|
from . import webfinger
|
|
|
|
|
|
def scan_from_account_name(account_name):
|
|
"""
|
|
Given an account name such as library@test.library, will:
|
|
|
|
1. Perform the webfinger lookup
|
|
2. Perform the actor lookup
|
|
3. Perform the library's collection lookup
|
|
|
|
and return corresponding data in a dictionary.
|
|
"""
|
|
data = {}
|
|
try:
|
|
username, domain = webfinger.clean_acct(
|
|
account_name, ensure_local=False)
|
|
except serializers.ValidationError:
|
|
return {
|
|
'webfinger': {
|
|
'errors': ['Invalid account string']
|
|
}
|
|
}
|
|
system_library = actors.SYSTEM_ACTORS['library'].get_actor_instance()
|
|
library = models.Library.objects.filter(
|
|
actor__domain=domain,
|
|
actor__preferred_username=username
|
|
).select_related('actor').first()
|
|
data['local'] = {
|
|
'following': False,
|
|
'awaiting_approval': False,
|
|
}
|
|
try:
|
|
follow = models.Follow.objects.get(
|
|
target__preferred_username=username,
|
|
target__domain=username,
|
|
actor=system_library,
|
|
)
|
|
data['local']['awaiting_approval'] = not bool(follow.approved)
|
|
data['local']['following'] = True
|
|
except models.Follow.DoesNotExist:
|
|
pass
|
|
|
|
try:
|
|
data['webfinger'] = webfinger.get_resource(
|
|
'acct:{}'.format(account_name))
|
|
except requests.ConnectionError:
|
|
return {
|
|
'webfinger': {
|
|
'errors': ['This webfinger resource is not reachable']
|
|
}
|
|
}
|
|
except requests.HTTPError as e:
|
|
return {
|
|
'webfinger': {
|
|
'errors': [
|
|
'Error {} during webfinger request'.format(
|
|
e.response.status_code)]
|
|
}
|
|
}
|
|
except json.JSONDecodeError as e:
|
|
return {
|
|
'webfinger': {
|
|
'errors': ['Could not process webfinger response']
|
|
}
|
|
}
|
|
|
|
try:
|
|
data['actor'] = actors.get_actor_data(data['webfinger']['actor_url'])
|
|
except requests.ConnectionError:
|
|
data['actor'] = {
|
|
'errors': ['This actor is not reachable']
|
|
}
|
|
return data
|
|
except requests.HTTPError as e:
|
|
data['actor'] = {
|
|
'errors': [
|
|
'Error {} during actor request'.format(
|
|
e.response.status_code)]
|
|
}
|
|
return data
|
|
|
|
serializer = serializers.LibraryActorSerializer(data=data['actor'])
|
|
if not serializer.is_valid():
|
|
data['actor'] = {
|
|
'errors': ['Invalid ActivityPub actor']
|
|
}
|
|
return data
|
|
data['library'] = get_library_data(
|
|
serializer.validated_data['library_url'])
|
|
|
|
return data
|
|
|
|
|
|
def get_library_data(library_url):
|
|
actor = actors.SYSTEM_ACTORS['library'].get_actor_instance()
|
|
auth = signing.get_auth(actor.private_key, actor.private_key_id)
|
|
try:
|
|
response = session.get_session().get(
|
|
library_url,
|
|
auth=auth,
|
|
timeout=5,
|
|
verify=settings.EXTERNAL_REQUESTS_VERIFY_SSL,
|
|
headers={
|
|
'Content-Type': 'application/activity+json'
|
|
}
|
|
)
|
|
except requests.ConnectionError:
|
|
return {
|
|
'errors': ['This library is not reachable']
|
|
}
|
|
scode = response.status_code
|
|
if scode == 401:
|
|
return {
|
|
'errors': ['This library requires authentication']
|
|
}
|
|
elif scode == 403:
|
|
return {
|
|
'errors': ['Permission denied while scanning library']
|
|
}
|
|
elif scode >= 400:
|
|
return {
|
|
'errors': ['Error {} while fetching the library'.format(scode)]
|
|
}
|
|
serializer = serializers.PaginatedCollectionSerializer(
|
|
data=response.json(),
|
|
)
|
|
if not serializer.is_valid():
|
|
return {
|
|
'errors': [
|
|
'Invalid ActivityPub response from remote library']
|
|
}
|
|
|
|
return serializer.validated_data
|
|
|
|
|
|
def get_library_page(library, page_url):
|
|
actor = actors.SYSTEM_ACTORS['library'].get_actor_instance()
|
|
auth = signing.get_auth(actor.private_key, actor.private_key_id)
|
|
response = session.get_session().get(
|
|
page_url,
|
|
auth=auth,
|
|
timeout=5,
|
|
verify=settings.EXTERNAL_REQUESTS_VERIFY_SSL,
|
|
headers={
|
|
'Content-Type': 'application/activity+json'
|
|
}
|
|
)
|
|
serializer = serializers.CollectionPageSerializer(
|
|
data=response.json(),
|
|
context={
|
|
'library': library,
|
|
'item_serializer': serializers.AudioSerializer})
|
|
serializer.is_valid(raise_exception=True)
|
|
return serializer.validated_data
|