-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
284 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import logging | ||
import time | ||
from abc import abstractmethod | ||
|
||
import redis | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class KeyCache: | ||
@abstractmethod | ||
def get(self, key: str) -> bytes | None: | ||
return None | ||
|
||
@abstractmethod | ||
def set(self, key: str, value: bytes, ttl: int | None = None) -> None: | ||
pass | ||
|
||
|
||
class NoyKeyCache(KeyCache): | ||
def get(self, key: str) -> bytes | None: | ||
return None | ||
|
||
def set(self, key: str, value: bytes, ttl: int | None = None) -> None: | ||
pass | ||
|
||
|
||
class RedisKeyCache(KeyCache): | ||
def __init__(self, redis_client: redis.Redis, default_ttl: int | None = None): | ||
self.redis_client = redis_client | ||
self.default_ttl = default_ttl | ||
|
||
def get(self, key: str) -> bytes | None: | ||
res = self.redis_client.get(name=key) | ||
logger.debug("Cache GET %s (%s)", key, "hit" if res else "miss") | ||
return res | ||
|
||
def set(self, key: str, value: bytes, ttl: int | None = None) -> None: | ||
ttl = ttl if ttl is not None else self.default_ttl | ||
expires_at = int(time.time()) + ttl | ||
logger.debug("Cache SET %s with TTL %d EXAT %d", key, ttl, expires_at) | ||
self.redis_client.set(name=key, value=value, exat=expires_at) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from abc import abstractmethod | ||
from urllib.parse import urljoin | ||
|
||
import httpx | ||
from cryptography.hazmat.primitives.serialization import load_pem_public_key | ||
from http_message_signatures import HTTPSignatureKeyResolver | ||
from werkzeug.utils import safe_join | ||
|
||
from .key_cache import KeyCache | ||
|
||
|
||
class CacheKeyResolver(HTTPSignatureKeyResolver): | ||
def __init__(self, key_cache: KeyCache): | ||
self.key_cache = key_cache | ||
|
||
@abstractmethod | ||
def get_public_key_pem(self, key_id: str) -> bytes: | ||
pass | ||
|
||
def resolve_public_key(self, key_id: str): | ||
public_key_pem = self.key_cache.get(key_id) | ||
if not public_key_pem: | ||
public_key_pem = self.get_public_key_pem(key_id) | ||
self.key_cache.set(key_id, public_key_pem) | ||
return load_pem_public_key(public_key_pem) | ||
|
||
|
||
class FileKeyResolver(CacheKeyResolver): | ||
def __init__(self, client_database_directory: str, key_cache: KeyCache): | ||
super().__init__(key_cache=key_cache) | ||
self.client_database_directory = client_database_directory | ||
|
||
def get_public_key_pem(self, key_id: str) -> bytes: | ||
filename = safe_join(self.client_database_directory, f"{key_id}.pem") | ||
try: | ||
with open(filename, "rb") as fp: | ||
return fp.read() | ||
except FileNotFoundError as exc: | ||
raise KeyError(key_id) from exc | ||
|
||
|
||
class UrlKeyResolver(CacheKeyResolver): | ||
def __init__(self, client_database_base_url: str, key_cache: KeyCache): | ||
super().__init__(key_cache=key_cache) | ||
self.client_database_base_url = client_database_base_url | ||
self.httpx_client = httpx.Client() | ||
|
||
def get_public_key_pem(self, key_id: str) -> bytes: | ||
public_key_url = urljoin(self.client_database_base_url, f"{key_id}.pem") | ||
try: | ||
response = self.httpx_client.get(public_key_url) | ||
response.raise_for_status() | ||
return response.content | ||
except httpx.HTTPError as exc: | ||
raise KeyError(key_id) from exc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.