#!/usr/bin/python # -*- coding: UTF-8 -*- import base64 import cPickle from cStringIO import StringIO import functools import hashlib import json import smtplib import time from flask.globals import session from PIL import Image, ImageDraw, ImageFont import config import utils ################################################################################ # DEK def get_dek_from_submissionid( submission_id ): """ Get the Data Encryption Key related to a submission id folder. """ try: sql = """ SELECT donor_dek.dek FROM donor_dek LEFT JOIN users ON users.username = donor_dek.donor_name LEFT JOIN submissions ON submissions.donor_id = users.id WHERE submissions.uuid = %s LIMIT 1 """ dek = config.db.query_fetchone( sql, ( submission_id, ) )[ "dek" ] if dek == None: raise else: return dek except: try: return session[ "dek_{}".format( submission_id ) ] except: return None def do_decrypt_dek( data, submission_id ): """ AES encrypt the data with the Data Encryption Key related to the donor. """ dek = get_dek_from_submissionid( submission_id ) return utils.aes.do_decrypt( data, dek ) def do_encrypt_dek( data, submission_id ): """ AES decrypt the data with the Data Encryption Key related to the donor. """ dek = get_dek_from_submissionid( submission_id ) return utils.aes.do_encrypt( data, dek ) def dek_check( submission_id ): if dek_exists( submission_id ): return True else: try: return dek_submitte_recreate_session( submission_id ) except: return False def dek_exists( submission_id ): if get_dek_from_submissionid( submission_id ) == None: return False else: return True def dek_submitte_recreate_session( submission_id ): sql = """ SELECT donor_dek.salt, donor_dek.dek_check, donor_dek.donor_name as username, submissions.email_aes as email FROM donor_dek LEFT JOIN users ON users.username = donor_dek.donor_name LEFT JOIN submissions ON submissions.donor_id = users.id WHERE submissions.uuid = %s LIMIT 1 """ user = config.db.query_fetchone( sql, ( submission_id, ) ) username = user[ "username" ] email = do_decrypt_user_session( user[ "email" ] ) dek_salt = user[ "salt" ] _, dek, _ = dek_generate( username = username, email = email, salt = dek_salt ) to_check = utils.aes.do_decrypt( user[ "dek_check" ], dek ) to_check = json.loads( to_check ) if to_check[ "value" ] == "ok": session[ "dek_{}".format( submission_id ) ] = dek return True else: return False def dek_generate( **kwargs ): if "email" in kwargs: email = kwargs[ "email" ] email = utils.hash.pbkdf2( email, "icnml_user_DEK" ).hash( True ) elif "email_hash" in kwargs: email = kwargs[ "email_hash" ] else: raise Exception( "need the email or hashed_email" ) if "username" in kwargs: username = kwargs[ "username" ] else: raise Exception( "need the username" ) dek_salt = kwargs.get( "salt", utils.rand.random_data( config.DEK_SALT_LENGTH ) ) dek = utils.hash.pbkdf2( "{}:{}".format( username, email, ), dek_salt, iterations = config.DEK_NB_ITERATIONS, hash_name = "sha512" ).hash( True ) check = { "value": "ok", "time": int( time.time() * 1000 ), "random": utils.rand.random_data( config.DEK_CHECK_SALT_LENGTH ) } check = json.dumps( check ) check = utils.aes.do_encrypt( check, dek ) return dek_salt, dek, check ################################################################################ # Decrypt/Encrypt user session def do_decrypt_user_session( data ): return utils.aes.do_decrypt( data, session[ "password" ] ) def do_encrypt_user_session( data ): return utils.aes.do_encrypt( data, session[ "password" ] ) ################################################################################ # Redis Cache def redis_cache( ttl = 3600 ): def decorator( func ): @functools.wraps( func ) def wrapper_cache( *args, **kwargs ): lst = [] lst.append( func.__name__ ) lst.extend( args ) lst = map( str, lst ) index = "_".join( lst ) index = hashlib.sha256( index ).hexdigest() d = config.redis_shared.get( index ) if d != None: config.redis_shared.expire( index, ttl ) buff = StringIO() buff.write( base64.b64decode( d ) ) buff.seek( 0 ) return cPickle.load( buff ) else: d = func( *args, **kwargs ) buff = StringIO() cPickle.dump( d, buff ) buff.seek( 0 ) d_cached = base64.b64encode( buff.getvalue() ) config.redis_shared.set( index, d_cached, ex = ttl ) return d return wrapper_cache return decorator ################################################################################ # No preview image def no_preview_image(): img = Image.new( "L", ( 210, 297 ), 255 ) draw = ImageDraw.Draw( img ) font = ImageFont.truetype( "arial.ttf", 18 ) draw.text( ( 0, 0 ), "No preview", 0, font = font ) buff = utils.images.pil2buffer( img, "PNG" ) return buff ################################################################################ # SMTP context manager class mySMTP( object ): def __init__( self ): self.host = config.smtpserver self.port = config.smtpport self.username = config.smtpuser self.password = config.smtppassword self.sender = config.sender def __enter__( self ): self.s = smtplib.SMTP( self.host, self.port ) self.s.starttls() self.s.login( self.username, self.password ) return self.s def __exit__( self, ty, value, traceback ): self.s.quit()