feat/add deletc activiyt precheck
&& refactor precheck
This commit is contained in:
parent
dcd862180e
commit
a03ecede17
4 changed files with 100 additions and 62 deletions
|
@ -1,74 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
import base64
|
||||
import httpx
|
||||
import json
|
||||
import fastapi
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
from app.config import AP_CONTENT_TYPE, USER_AGENT, KEY_PATH, ID
|
||||
|
||||
from datetime import datetime
|
||||
from app.config import KEY_PATH, ID
|
||||
from loguru import logger
|
||||
|
||||
from Crypto.Hash import SHA256
|
||||
from Crypto.Signature import PKCS1_v1_5
|
||||
from Crypto.PublicKey import RSA
|
||||
|
||||
async def httpsig_checker(
|
||||
request : fastapi.Request,
|
||||
) -> bool :
|
||||
"""
|
||||
Check http signature
|
||||
"""
|
||||
payload = await request.json()
|
||||
|
||||
try:
|
||||
logger.info(f"headers={request.headers}")
|
||||
logger.info(f"{payload=}")
|
||||
|
||||
parsec_signature = HttpSignature.parse_signature(
|
||||
request.headers.get("signature")
|
||||
)
|
||||
except KeyError:
|
||||
logger.warning("Not signature headers")
|
||||
raise KeyError
|
||||
|
||||
actor_url = payload["actor"]
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(
|
||||
actor_url,
|
||||
headers={
|
||||
"User-Agent": USER_AGENT,
|
||||
"Accept": AP_CONTENT_TYPE,
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
try:
|
||||
_actor = resp.json()
|
||||
pubkey = _actor["publicKey"]["publicKeyPem"]
|
||||
except json.JSONDecodeError:
|
||||
raise ValueError
|
||||
except KeyError:
|
||||
logger.warning("actor gone? ")
|
||||
raise KeyError
|
||||
|
||||
body = await request.body()
|
||||
signture_string = HttpSignature.build_signature_string(
|
||||
request.method,
|
||||
request.url.path,
|
||||
parsec_signature["headers"],
|
||||
HttpSignature.calculation_digest(body),
|
||||
request.headers,
|
||||
)
|
||||
is_verify = HttpSignature.verify_signature(
|
||||
signture_string,
|
||||
parsec_signature["signature"],
|
||||
pubkey)
|
||||
|
||||
logger.info(signture_string)
|
||||
logger.info(f"verify? {is_verify}")
|
||||
|
||||
return is_verify
|
||||
|
||||
|
||||
class HttpSignature:
|
||||
|
|
|
@ -16,7 +16,7 @@ from typing import Any
|
|||
|
||||
from loguru import logger
|
||||
|
||||
from app import httpsig
|
||||
from app.utils import precheck
|
||||
from app.database import get_db_session
|
||||
from app.config import DEBUG
|
||||
from app.activitypub import ME
|
||||
|
@ -50,7 +50,7 @@ async def index():
|
|||
async def inbox(
|
||||
request: Request,
|
||||
db_session: AsyncSession = Depends(get_db_session),
|
||||
httpsig_checker = Depends(httpsig.httpsig_checker),
|
||||
httpsig_checker = Depends(precheck.inbox_prechecker),
|
||||
) -> Response:
|
||||
payload = await request.json()
|
||||
|
||||
|
|
1
app/utils/__init__.py
Normal file
1
app/utils/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
#!/usr/bin/env python3
|
95
app/utils/precheck.py
Normal file
95
app/utils/precheck.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/env python3
|
||||
import fastapi
|
||||
import json
|
||||
import httpx
|
||||
|
||||
from loguru import logger
|
||||
from app.httpsig import HttpSignature
|
||||
from app.config import AP_CONTENT_TYPE, USER_AGENT
|
||||
|
||||
from app.database import AsyncSession
|
||||
from app.database import get_db_session
|
||||
from sqlalchemy import select
|
||||
|
||||
|
||||
async def inbox_prechecker(
|
||||
request : fastapi.Request,
|
||||
db_session : AsyncSession = fastapi.Depends(get_db_session)
|
||||
) -> bool :
|
||||
"""
|
||||
Check http request
|
||||
"""
|
||||
payload = await request.json()
|
||||
|
||||
try:
|
||||
logger.info(f"headers={request.headers}")
|
||||
logger.info(f"{payload=}")
|
||||
|
||||
parsec_signature = HttpSignature.parse_signature(
|
||||
request.headers.get("signature")
|
||||
)
|
||||
except KeyError:
|
||||
logger.warning("Not signature headers")
|
||||
raise KeyError
|
||||
|
||||
try:
|
||||
if request.method == "POST" and request.url.path.endswith("/inbox"):
|
||||
from app import models
|
||||
|
||||
if (
|
||||
payload["type"] == "Delete"
|
||||
and payload["actor"] == payload["object"]
|
||||
and not (
|
||||
await db_session.scalars(
|
||||
select(models.Actor).where(
|
||||
models.Actor.ap_id == payload["id"],
|
||||
)
|
||||
)
|
||||
).one_or_none()
|
||||
):
|
||||
|
||||
logger.info(f"Dropping unnecessary delete activity {payload=}")
|
||||
raise fastapi.HTTPException(status_code=202)
|
||||
except fastapi.HTTPException as http_exc:
|
||||
raise http_exc
|
||||
except Exception:
|
||||
logger.exception("Failed to precheck delete activity")
|
||||
return False
|
||||
|
||||
actor_url = payload["actor"]
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(
|
||||
actor_url,
|
||||
headers={
|
||||
"User-Agent": USER_AGENT,
|
||||
"Accept": AP_CONTENT_TYPE,
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
try:
|
||||
_actor = resp.json()
|
||||
pubkey = _actor["publicKey"]["publicKeyPem"]
|
||||
except json.JSONDecodeError:
|
||||
raise ValueError
|
||||
except KeyError:
|
||||
logger.warning("actor gone? ")
|
||||
raise KeyError
|
||||
|
||||
body = await request.body()
|
||||
signture_string = HttpSignature.build_signature_string(
|
||||
request.method,
|
||||
request.url.path,
|
||||
parsec_signature["headers"],
|
||||
HttpSignature.calculation_digest(body),
|
||||
request.headers,
|
||||
)
|
||||
is_verify = HttpSignature.verify_signature(
|
||||
signture_string,
|
||||
parsec_signature["signature"],
|
||||
pubkey)
|
||||
|
||||
logger.info(signture_string)
|
||||
logger.info(f"verify? {is_verify}")
|
||||
|
||||
return is_verify
|
Loading…
Reference in a new issue