Support actor refresh while checking HTTP sig
parent
f6cfe06f66
commit
602da69083
|
@ -88,8 +88,12 @@ def _body_digest(body: bytes) -> str:
|
||||||
return "SHA-256=" + base64.b64encode(h.digest()).decode("utf-8")
|
return "SHA-256=" + base64.b64encode(h.digest()).decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
async def _get_public_key(db_session: AsyncSession, key_id: str) -> Key:
|
async def _get_public_key(
|
||||||
if cached_key := _KEY_CACHE.get(key_id):
|
db_session: AsyncSession,
|
||||||
|
key_id: str,
|
||||||
|
should_skip_cache: bool = False,
|
||||||
|
) -> Key:
|
||||||
|
if not should_skip_cache and (cached_key := _KEY_CACHE.get(key_id)):
|
||||||
logger.info(f"Key {key_id} found in cache")
|
logger.info(f"Key {key_id} found in cache")
|
||||||
return cached_key
|
return cached_key
|
||||||
|
|
||||||
|
@ -101,12 +105,13 @@ async def _get_public_key(db_session: AsyncSession, key_id: str) -> Key:
|
||||||
select(models.Actor).where(models.Actor.ap_id == key_id.split("#")[0])
|
select(models.Actor).where(models.Actor.ap_id == key_id.split("#")[0])
|
||||||
)
|
)
|
||||||
).one_or_none()
|
).one_or_none()
|
||||||
if existing_actor and existing_actor.public_key_id == key_id:
|
if not should_skip_cache:
|
||||||
k = Key(existing_actor.ap_id, key_id)
|
if existing_actor and existing_actor.public_key_id == key_id:
|
||||||
k.load_pub(existing_actor.public_key_as_pem)
|
k = Key(existing_actor.ap_id, key_id)
|
||||||
logger.info(f"Found {key_id} on an existing actor")
|
k.load_pub(existing_actor.public_key_as_pem)
|
||||||
_KEY_CACHE[key_id] = k
|
logger.info(f"Found {key_id} on an existing actor")
|
||||||
return k
|
_KEY_CACHE[key_id] = k
|
||||||
|
return k
|
||||||
|
|
||||||
# Fetch it
|
# Fetch it
|
||||||
from app import activitypub as ap
|
from app import activitypub as ap
|
||||||
|
@ -133,6 +138,13 @@ async def _get_public_key(db_session: AsyncSession, key_id: str) -> Key:
|
||||||
f"failed to fetch requested key {key_id}: got {actor['publicKey']}"
|
f"failed to fetch requested key {key_id}: got {actor['publicKey']}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if should_skip_cache and actor["type"] != "Key" and existing_actor:
|
||||||
|
# We had to skip the cache, which means the actor key probably changed
|
||||||
|
# and we want to update our cached version
|
||||||
|
existing_actor.ap_actor = actor
|
||||||
|
existing_actor.updated_at = now()
|
||||||
|
await db_session.commit()
|
||||||
|
|
||||||
_KEY_CACHE[key_id] = k
|
_KEY_CACHE[key_id] = k
|
||||||
return k
|
return k
|
||||||
|
|
||||||
|
@ -216,7 +228,17 @@ async def httpsig_checker(
|
||||||
has_valid_signature = _verify_h(
|
has_valid_signature = _verify_h(
|
||||||
signed_string, base64.b64decode(hsig["signature"]), k.pubkey
|
signed_string, base64.b64decode(hsig["signature"]), k.pubkey
|
||||||
)
|
)
|
||||||
# FIXME: fetch/update the user if the signature is wrong
|
|
||||||
|
# If the signature is not valid, we may have to update the cached actor
|
||||||
|
if not has_valid_signature:
|
||||||
|
logger.info("Invalid signature, trying to refresh actor")
|
||||||
|
try:
|
||||||
|
k = await _get_public_key(db_session, hsig["keyId"], should_skip_cache=True)
|
||||||
|
has_valid_signature = _verify_h(
|
||||||
|
signed_string, base64.b64decode(hsig["signature"]), k.pubkey
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to refresh actor")
|
||||||
|
|
||||||
httpsig_info = HTTPSigInfo(
|
httpsig_info = HTTPSigInfo(
|
||||||
has_valid_signature=has_valid_signature,
|
has_valid_signature=has_valid_signature,
|
||||||
|
|
Loading…
Reference in New Issue