2019-03-03 01:09:25 +00:00
|
|
|
"""
|
|
|
|
Thank you Funkwhale for inspiration on the HTTP signatures parts <3
|
|
|
|
|
|
|
|
https://funkwhale.audio/
|
|
|
|
"""
|
|
|
|
import datetime
|
|
|
|
import logging
|
|
|
|
from typing import Union
|
|
|
|
|
|
|
|
import pytz
|
2019-03-17 01:13:47 +00:00
|
|
|
from Crypto.PublicKey.RSA import RsaKey
|
2019-03-03 01:09:25 +00:00
|
|
|
from requests_http_signature import HTTPSignatureHeaderAuth
|
|
|
|
|
|
|
|
from federation.types import RequestType
|
|
|
|
from federation.utils.network import parse_http_date
|
2019-03-17 01:13:47 +00:00
|
|
|
from federation.utils.text import encode_if_text
|
2019-03-03 01:09:25 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger("federation")
|
|
|
|
|
|
|
|
|
2019-03-17 01:13:47 +00:00
|
|
|
def get_http_authentication(private_key: RsaKey, private_key_id: str) -> HTTPSignatureHeaderAuth:
|
2019-03-03 01:09:25 +00:00
|
|
|
"""
|
|
|
|
Get HTTP signature authentication for a request.
|
|
|
|
"""
|
2019-03-17 01:13:47 +00:00
|
|
|
key = private_key.exportKey()
|
2019-03-03 01:09:25 +00:00
|
|
|
return HTTPSignatureHeaderAuth(
|
|
|
|
headers=["(request-target)", "user-agent", "host", "date"],
|
|
|
|
algorithm="rsa-sha256",
|
2019-03-17 01:13:47 +00:00
|
|
|
key=key,
|
2019-03-03 01:09:25 +00:00
|
|
|
key_id=private_key_id,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def verify_request_signature(request: RequestType, public_key: Union[str, bytes]):
|
|
|
|
"""
|
|
|
|
Verify HTTP signature in request against a public key.
|
|
|
|
"""
|
2019-03-16 01:21:07 +00:00
|
|
|
key = encode_if_text(public_key)
|
2019-03-03 01:09:25 +00:00
|
|
|
date_header = request.headers.get("Date")
|
|
|
|
if not date_header:
|
|
|
|
raise ValueError("Rquest Date header is missing")
|
|
|
|
|
|
|
|
ts = parse_http_date(date_header)
|
|
|
|
dt = datetime.datetime.utcfromtimestamp(ts).replace(tzinfo=pytz.utc)
|
|
|
|
delta = datetime.timedelta(seconds=30)
|
|
|
|
now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
|
|
|
|
if dt < now - delta or dt > now + delta:
|
|
|
|
raise ValueError("Request Date is too far in future or past")
|
|
|
|
|
|
|
|
HTTPSignatureHeaderAuth.verify(request, key_resolver=lambda **kwargs: key)
|