feat/add deletc activiyt precheck

&& refactor precheck
This commit is contained in:
SouthFox 2023-03-19 12:51:20 +08:00
parent dcd862180e
commit a03ecede17
4 changed files with 100 additions and 62 deletions

View file

@ -1,74 +1,16 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import base64 import base64
import httpx import httpx
import json
import fastapi
import hashlib 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 loguru import logger
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
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: class HttpSignature:

View file

@ -16,7 +16,7 @@ from typing import Any
from loguru import logger from loguru import logger
from app import httpsig from app.utils import precheck
from app.database import get_db_session from app.database import get_db_session
from app.config import DEBUG from app.config import DEBUG
from app.activitypub import ME from app.activitypub import ME
@ -50,7 +50,7 @@ async def index():
async def inbox( async def inbox(
request: Request, request: Request,
db_session: AsyncSession = Depends(get_db_session), db_session: AsyncSession = Depends(get_db_session),
httpsig_checker = Depends(httpsig.httpsig_checker), httpsig_checker = Depends(precheck.inbox_prechecker),
) -> Response: ) -> Response:
payload = await request.json() payload = await request.json()

1
app/utils/__init__.py Normal file
View file

@ -0,0 +1 @@
#!/usr/bin/env python3

95
app/utils/precheck.py Normal file
View 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