Snapshot: alpha-2026-9
This commit is contained in:
parent
9acf5a97e2
commit
d00b5c7961
241 changed files with 85546 additions and 2409 deletions
|
|
@ -2,7 +2,7 @@ from nacl.exceptions import BadSignatureError
|
|||
from nacl.signing import VerifyKey
|
||||
from rest_framework import authentication
|
||||
|
||||
from authentication.models import KnownIdentity, ToolshedUser
|
||||
from authentication.models import Group, KnownIdentity, ToolshedUser
|
||||
|
||||
|
||||
def split_userhandle_or_throw(userhandle):
|
||||
|
|
@ -16,6 +16,27 @@ def split_userhandle_or_throw(userhandle):
|
|||
return username, domain
|
||||
|
||||
|
||||
def split_grouphandle_or_throw(grouphandle):
|
||||
if not grouphandle.startswith('#'):
|
||||
raise ValueError('Group handle must be in the format #name@domain')
|
||||
return split_userhandle_or_throw(grouphandle[1:])
|
||||
|
||||
|
||||
def resolve_owner_handle(handle):
|
||||
"""Resolves a "user@domain" or "+name@domain" handle to (owner_user, owner_group), exactly one set. Raises ValueError if the handle doesn't parse at all (no '@'); returns (None, None) if it parses but names nothing that exists."""
|
||||
is_group = handle.startswith('+')
|
||||
name, domain = split_userhandle_or_throw(handle[1:] if is_group else handle)
|
||||
if is_group:
|
||||
try:
|
||||
return None, Group.objects.get(name=name, domain=domain)
|
||||
except Group.DoesNotExist:
|
||||
return None, None
|
||||
try:
|
||||
return ToolshedUser.objects.get(username=name, domain=domain), None
|
||||
except ToolshedUser.DoesNotExist:
|
||||
return None, None
|
||||
|
||||
|
||||
def verify_request(request, raw_request_body):
|
||||
authentication_header = request.META.get('HTTP_AUTHORIZATION')
|
||||
|
||||
|
|
@ -74,6 +95,32 @@ def verify_incoming_friend_request(request, raw_request_body):
|
|||
return False
|
||||
|
||||
|
||||
def verify_incoming_group_invite(request, raw_request_body, handle_field, key_field):
|
||||
"""Self-certifying verifier for the group invite/accept dance. See
|
||||
docs/implementation.md#group-invite-and-accept-self-certifying-verification."""
|
||||
try:
|
||||
username, domain, signed_data, signature_bytes_hex = verify_request(request, raw_request_body)
|
||||
except ValueError:
|
||||
return False
|
||||
try:
|
||||
claimed_handle = request.data[handle_field]
|
||||
claimed_key = request.data[key_field]
|
||||
except KeyError:
|
||||
return False
|
||||
if not claimed_handle or not claimed_key:
|
||||
return False
|
||||
if username + "@" + domain != claimed_handle:
|
||||
return False
|
||||
if len(claimed_key) != 64:
|
||||
return False
|
||||
verify_key = VerifyKey(bytes.fromhex(claimed_key))
|
||||
try:
|
||||
verify_key.verify(signed_data.encode('utf-8'), bytes.fromhex(signature_bytes_hex))
|
||||
return True
|
||||
except BadSignatureError:
|
||||
return False
|
||||
|
||||
|
||||
def authenticate_request_against_known_identities(request, raw_request_body):
|
||||
try:
|
||||
username, domain, signed_data, signature_bytes_hex = verify_request(request, raw_request_body)
|
||||
|
|
@ -106,11 +153,17 @@ def authenticate_request_against_local_users(request, raw_request_body):
|
|||
|
||||
class SignatureAuthentication(authentication.BaseAuthentication):
|
||||
def authenticate(self, request):
|
||||
return authenticate_request_against_known_identities(
|
||||
request, request.body.decode('utf-8')), None
|
||||
identity = authenticate_request_against_known_identities(request, request.body.decode('utf-8'))
|
||||
# Bare None (not a (None, None) tuple) tells DRF to try the next authenticator, instead
|
||||
# of treating the request as authenticated with an empty user.
|
||||
if identity is None:
|
||||
return None
|
||||
return identity, None
|
||||
|
||||
|
||||
class SignatureAuthenticationLocal(authentication.BaseAuthentication):
|
||||
def authenticate(self, request):
|
||||
return authenticate_request_against_local_users(
|
||||
request, request.body.decode('utf-8')), None
|
||||
user = authenticate_request_against_local_users(request, request.body.decode('utf-8'))
|
||||
if user is None:
|
||||
return None
|
||||
return user, None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue