|
from operator import or_ as bit_or |
|
from operator import xor as bit_xor |
|
from itertools import imap |
|
import hmac |
|
from pack.util import codec |
|
|
|
class CookieStore(object): |
|
def __init__(self, secret_key): |
|
if not secret_key: |
|
self.secret_key = secure_random_bytes(16) |
|
elif isinstance(secret_key, str): |
|
self.secret_key = get_bytes(secret_key) |
|
else: |
|
self.secret_key = secret_key |
|
def read_session(self, data): |
|
if data: |
|
return unseal(self.secret_key, data) |
|
else: |
|
return {} |
|
def write_session(self, _, data): |
|
return seal(self.secret_key, data) |
|
def delete_session(self, _): |
|
return seal(self.secret_key, {}) |
|
|
|
def seal(key, data): |
|
data = encrypt(key, get_bytes(repr(data))) |
|
return "%s--%s" % (codec.base64_encode(data), hmac(key, data)) |
|
|
|
def unseal(key, string): |
|
"Restore a sealed object from a string." |
|
data, mac = string.split("--") |
|
data = codec.base64_decode(data) |
|
if secure_compare(mac, hmac(key, data)): |
|
return read_string(decrypt(key, data)) |
|
|
|
def encrypt(key, data): |
|
cipher = |
|
|
|
def decrypt(key, data): |
|
cipher = |
|
|
|
def hmac(key, data): |
|
return codec.base64_encode(hmac.new(key, data, hashlib.sha256).digest()) |
|
|
|
def secure_compare(a, b): |
|
if a and b and len(a) == len(b): |
|
return 0 == reduce(bit_or, |
|
imap(bit_xor, get_bytes(a), get_bytes(b))) |
|
else: |
|
return False |
|
|
|
def secure_random_bytes(size): |
|
seed = bytearray |
|
|
|
def get_bytes(string): |
|
return [ord(x) for x in string] |