[feat] add post sign flow
This commit is contained in:
parent
38b2e7f917
commit
6b27db30b2
1 changed files with 60 additions and 1 deletions
|
@ -3,12 +3,19 @@
|
||||||
Verify and build HTTP signatures
|
Verify and build HTTP signatures
|
||||||
"""
|
"""
|
||||||
import base64
|
import base64
|
||||||
|
import httpx
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from app import logger
|
||||||
|
from demo.config import ID
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from Crypto.Hash import SHA256
|
from Crypto.Hash import SHA256
|
||||||
from Crypto.Signature import PKCS1_v1_5
|
from Crypto.Signature import PKCS1_v1_5
|
||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
from werkzeug.datastructures import Headers
|
from werkzeug.datastructures import Headers
|
||||||
|
from httpx import Headers as Httpx_headers
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -20,7 +27,7 @@ class SignedData:
|
||||||
path: str
|
path: str
|
||||||
signed_list: list
|
signed_list: list
|
||||||
body_digest: str | None
|
body_digest: str | None
|
||||||
headers: Headers
|
headers: Headers | Httpx_headers
|
||||||
|
|
||||||
|
|
||||||
class HttpSignature:
|
class HttpSignature:
|
||||||
|
@ -103,3 +110,55 @@ class HttpSignature:
|
||||||
+ signed_data.headers[signed_str])
|
+ signed_data.headers[signed_str])
|
||||||
|
|
||||||
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("%a, %d %b %Y %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)
|
||||||
|
|
||||||
|
sigdate = SignedData(
|
||||||
|
method = r.method,
|
||||||
|
path = r.url.path,
|
||||||
|
signed_list = sigheaders.split(),
|
||||||
|
body_digest = bodydigest,
|
||||||
|
headers = r.headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
to_be_signed = HttpSignature.build_signature_string(
|
||||||
|
sigdate
|
||||||
|
)
|
||||||
|
|
||||||
|
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))
|
||||||
|
logger.debug(f"{sig=}")
|
||||||
|
|
||||||
|
|
||||||
|
key_id = f"{ID}#main-key"
|
||||||
|
sig_value = f'keyId="{key_id}",algorithm="rsa-sha256",headers="{sigheaders}",signature="{sig.decode()}"' # noqa: E501
|
||||||
|
logger.debug(f"signed request {sig_value=}")
|
||||||
|
r.headers["signature"] = sig_value
|
||||||
|
yield r
|
||||||
|
|
Loading…
Reference in a new issue