lib.itmens/mastodon/auth.py

103 lines
3.5 KiB
Python
Raw Normal View History

2020-05-05 23:50:48 +08:00
from django.contrib.auth.backends import ModelBackend, UserModel
from django.shortcuts import reverse
from .api import *
2020-10-22 21:45:05 +02:00
from .models import MastodonApplication
from django.conf import settings
2020-05-05 23:50:48 +08:00
2020-10-22 21:45:05 +02:00
def obtain_token(site, request, code):
2020-05-05 23:50:48 +08:00
""" Returns token if success else None. """
2020-10-22 21:45:05 +02:00
mast_app = MastodonApplication.objects.get(domain_name=site)
2020-05-05 23:50:48 +08:00
payload = {
2020-10-22 21:45:05 +02:00
'client_id': mast_app.client_id,
'client_secret': mast_app.client_secret,
2020-05-07 01:10:08 +08:00
'redirect_uri': f"https://{request.get_host()}{reverse('users:OAuth2_login')}",
2020-05-05 23:50:48 +08:00
'grant_type': 'authorization_code',
'code': code,
'scope': 'read write'
}
if settings.DEBUG:
payload['redirect_uri'] = f"http://{request.get_host()}{reverse('users:OAuth2_login')}",
2020-10-22 21:45:05 +02:00
if mast_app.is_proxy:
url = 'https://' + mast_app.proxy_to + API_OBTAIN_TOKEN
else:
url = 'https://' + mast_app.domain_name + API_OBTAIN_TOKEN
response = post(url, data=payload, headers={'User-Agent': 'NeoDB/1.0'})
2020-05-05 23:50:48 +08:00
if response.status_code != 200:
return
data = response.json()
return data.get('access_token')
2020-10-22 21:45:05 +02:00
def get_user_data(site, token):
url = 'https://' + site + API_VERIFY_ACCOUNT
2020-05-05 23:50:48 +08:00
headers = {
'User-Agent': 'NeoDB/1.0',
2020-05-05 23:50:48 +08:00
'Authorization': f'Bearer {token}'
}
response = get(url, headers=headers)
if response.status_code != 200:
return None
return response.json()
2020-10-22 21:45:05 +02:00
def revoke_token(site, token):
mast_app = MastodonApplication.objects.get(domain_name=site)
2020-05-05 23:50:48 +08:00
payload = {
2020-10-22 21:45:05 +02:00
'client_id': mast_app.client_id,
'client_secret': mast_app.client_secret,
2020-05-05 23:50:48 +08:00
'scope': token
}
2020-10-22 21:45:05 +02:00
if mast_app.is_proxy:
url = 'https://' + mast_app.proxy_to + API_REVOKE_TOKEN
else:
url = 'https://' + site + API_REVOKE_TOKEN
response = post(url, data=payload, headers={'User-Agent': 'NeoDB/1.0'})
2020-05-05 23:50:48 +08:00
2020-10-22 21:45:05 +02:00
def verify_token(site, token):
2020-05-05 23:50:48 +08:00
""" Check if the token is valid and is of local instance. """
2020-10-22 21:45:05 +02:00
url = 'https://' + site + API_VERIFY_ACCOUNT
2020-05-05 23:50:48 +08:00
headers = {
'User-Agent': 'NeoDB/1.0',
2020-05-05 23:50:48 +08:00
'Authorization': f'Bearer {token}'
}
response = get(url, headers=headers)
if response.status_code == 200:
res_data = response.json()
# check if is local instance user
if res_data['acct'] == res_data['username']:
return True
return False
class OAuth2Backend(ModelBackend):
""" Used to glue OAuth2 and Django User model """
# "authenticate() should check the credentials it gets and returns
# a user object that matches those credentials."
# arg request is an interface specification, not used in this implementation
2020-10-22 21:45:05 +02:00
def authenticate(self, request, token=None, username=None, site=None, **kwargs):
2020-05-05 23:50:48 +08:00
""" when username is provided, assume that token is newly obtained and valid """
2020-10-22 21:45:05 +02:00
if token is None or site is None:
2020-05-05 23:50:48 +08:00
return
if username is None:
2020-10-22 21:45:05 +02:00
user_data = get_user_data(site, token)
2020-05-05 23:50:48 +08:00
if user_data:
username = user_data['username']
else:
# aquiring user data fail means token is invalid thus auth fail
return None
# when username is provided, assume that token is newly obtained and valid
try:
2021-09-15 14:21:29 -04:00
user = UserModel._default_manager.get(username=username, mastodon_site=site)
2020-05-05 23:50:48 +08:00
except UserModel.DoesNotExist:
return None
else:
if self.user_can_authenticate(user):
return user
return None