mirror of
https://github.com/avatao-content/baseimage-tutorial-framework
synced 2025-06-28 13:15:13 +00:00
Implement reference counting mechanism
This commit is contained in:
committed by
therealkrispet
parent
911831fdb1
commit
25bd9aa0f3
2
tfw/internals/crypto/__init__.py
Normal file
2
tfw/internals/crypto/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
from .authentication import sign_message, verify_message
|
||||
from .key_manager import KeyManager
|
71
tfw/internals/crypto/authentication.py
Normal file
71
tfw/internals/crypto/authentication.py
Normal file
@ -0,0 +1,71 @@
|
||||
from functools import wraps
|
||||
from base64 import b64encode, b64decode
|
||||
from copy import deepcopy
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.hashes import SHA256
|
||||
from cryptography.hazmat.primitives.hmac import HMAC as _HMAC
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
|
||||
from tfw.internals.networking import message_bytes
|
||||
|
||||
|
||||
def sign_message(key, message):
|
||||
message.pop('scope', None)
|
||||
message.pop('signature', None)
|
||||
signature = message_signature(key, message)
|
||||
message['signature'] = b64encode(signature).decode()
|
||||
|
||||
|
||||
def message_signature(key, message):
|
||||
return HMAC(key, message_bytes(message)).signature
|
||||
|
||||
|
||||
def verify_message(key, message):
|
||||
message.pop('scope', None)
|
||||
message = deepcopy(message)
|
||||
try:
|
||||
signature_b64 = message.pop('signature')
|
||||
signature = b64decode(signature_b64)
|
||||
actual_signature = message_signature(key, message)
|
||||
return signature == actual_signature
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
class HMAC:
|
||||
def __init__(self, key, message):
|
||||
self.key = key
|
||||
self.message = message
|
||||
self._hmac = _HMAC(
|
||||
key=key,
|
||||
algorithm=SHA256(),
|
||||
backend=default_backend()
|
||||
)
|
||||
|
||||
def _reload_if_finalized(f):
|
||||
# pylint: disable=no-self-argument,not-callable
|
||||
@wraps(f)
|
||||
def wrapped(instance, *args, **kwargs):
|
||||
if getattr(instance, '_finalized', False):
|
||||
instance.__init__(instance.key, instance.message)
|
||||
ret_val = f(instance, *args, **kwargs)
|
||||
setattr(instance, '_finalized', True)
|
||||
return ret_val
|
||||
return wrapped
|
||||
|
||||
@property
|
||||
@_reload_if_finalized
|
||||
def signature(self):
|
||||
self._hmac.update(self.message)
|
||||
signature = self._hmac.finalize()
|
||||
return signature
|
||||
|
||||
@_reload_if_finalized
|
||||
def verify(self, signature):
|
||||
self._hmac.update(self.message)
|
||||
try:
|
||||
self._hmac.verify(signature)
|
||||
return True
|
||||
except InvalidSignature:
|
||||
return False
|
48
tfw/internals/crypto/key_manager.py
Normal file
48
tfw/internals/crypto/key_manager.py
Normal file
@ -0,0 +1,48 @@
|
||||
from atexit import register
|
||||
from tempfile import gettempdir
|
||||
from os import urandom, chmod, remove
|
||||
from os.path import exists, join
|
||||
from stat import S_IRUSR, S_IWUSR, S_IXUSR
|
||||
|
||||
from tfw.internals.lazy import lazy_property
|
||||
from tfw.internals.ref_counter import RefCounter
|
||||
|
||||
|
||||
KEYFILE = join(gettempdir(), 'tfw-auth.key')
|
||||
LOCKFILE = join(gettempdir(), 'tfw-auth.lock')
|
||||
|
||||
|
||||
class KeyManagerRefCounter(RefCounter):
|
||||
def deallocate(self):
|
||||
if exists(KEYFILE):
|
||||
remove(KEYFILE)
|
||||
|
||||
|
||||
class KeyManager:
|
||||
keyfile = KEYFILE
|
||||
refcounter = KeyManagerRefCounter(LOCKFILE)
|
||||
|
||||
def __init__(self):
|
||||
if not exists(self.keyfile):
|
||||
self._init_auth_key()
|
||||
|
||||
@lazy_property
|
||||
def auth_key(self):
|
||||
with open(self.keyfile, 'rb') as ifile:
|
||||
return ifile.read()
|
||||
|
||||
def _init_auth_key(self):
|
||||
key = self.generate_key()
|
||||
with open(self.keyfile, 'wb') as ofile:
|
||||
ofile.write(key)
|
||||
self._chmod_700_keyfile()
|
||||
return key
|
||||
|
||||
@staticmethod
|
||||
def generate_key():
|
||||
return urandom(32)
|
||||
|
||||
def _chmod_700_keyfile(self):
|
||||
chmod(self.keyfile, S_IRUSR | S_IWUSR | S_IXUSR)
|
||||
|
||||
register(KeyManager.refcounter.teardown_instance)
|
Reference in New Issue
Block a user