feat/build http signature

This commit is contained in:
SouthFox 2023-03-18 01:07:07 +08:00
parent 54eddbcf23
commit 1389ba47fb

View file

@ -1,11 +1,14 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import base64 import base64
from urllib.request import HTTPSHandler
import httpx import httpx
import json import json
import fastapi import fastapi
import hashlib
from datetime import datetime
from typing import Literal, TypedDict, cast, Any from typing import Literal, TypedDict, cast, Any
from typing import Optional from typing import Optional
from app.config import AP_CONTENT_TYPE, USER_AGENT from app.config import AP_CONTENT_TYPE, USER_AGENT, KEY_PATH, ID
from loguru import logger from loguru import logger
@ -118,8 +121,8 @@ class HttpSignature:
cls, cls,
method : str, method : str,
path : str, path : str,
signed_headers : dict, signed_headers : list,
body_digest : str, body_digest : str | None,
headers, headers,
) -> str : ) -> str :
signed_string = [] signed_string = []
@ -131,3 +134,47 @@ class HttpSignature:
else: else:
signed_string.append(signed_header + ": " + headers[signed_header]) signed_string.append(signed_header + ": " + headers[signed_header])
return "\n".join(signed_string) return "\n".join(signed_string)
class HTTPXSigAuth(httpx.Auth):
def __init__(self, key) -> None:
self.key = key
def auth_flow(
self, r: httpx.Request
):
bodydigest = None
if r.content:
bh = hashlib.new("sha256")
bh.update(r.content)
bodydigest = "SHA-256=" + base64.b64encode(bh.digest()).decode("utf-8")
date = datetime.utcnow().strftime("%Y %m %d %H:%M:%S GMT")
r.headers["Date"] = date
sigheaders = {}
if bodydigest:
r.headers["digest"] = bodydigest
sigheaders = "(request-target) user-agent host date digest content-type"
else:
sigheaders = "(request-target) user-agent host date accept"
logger.warning(r.headers)
to_be_signed = HttpSignature.build_signature_string(
r.method, r.url.path, sigheaders.split(), bodydigest, r.headers
)
if not self.key:
raise ValueError("Should never happen")
signer = PKCS1_v1_5.new(self.key)
digest = SHA256.new()
digest.update(to_be_signed.encode("utf-8"))
sig = base64.b64encode(signer.sign(digest)).decode()
key_id = f"{ID}#main-key"
sig_value = f'keyId="{key_id}",algorithm="rsa-sha256",headers="{sigheaders}",signature="{sig}"' # noqa: E501
logger.debug(f"signed request {sig_value=}")
r.headers["signature"] = sig_value
yield r
k = KEY_PATH.read_text()
k = RSA.importKey(k)
auth = HTTPXSigAuth(k)