Remove submodule, just put Dependencies in ./libs
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
'''
|
||||
An encryption plugin for Elixir utilizing the excellent PyCrypto library, which
|
||||
can be downloaded here: http://www.amk.ca/python/code/crypto
|
||||
|
||||
Values for columns that are specified to be encrypted will be transparently
|
||||
encrypted and safely encoded for storage in a unicode column using the powerful
|
||||
and secure Blowfish Cipher using a specified "secret" which can be passed into
|
||||
the plugin at class declaration time.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
from elixir import *
|
||||
from elixir.ext.encrypted import acts_as_encrypted
|
||||
|
||||
class Person(Entity):
|
||||
name = Field(Unicode)
|
||||
password = Field(Unicode)
|
||||
ssn = Field(Unicode)
|
||||
acts_as_encrypted(for_fields=['password', 'ssn'],
|
||||
with_secret='secret')
|
||||
|
||||
The above Person entity will automatically encrypt and decrypt the password and
|
||||
ssn columns on save, update, and load. Different secrets can be specified on
|
||||
an entity by entity basis, for added security.
|
||||
|
||||
**Important note**: instance attributes are encrypted in-place. This means that
|
||||
if one of the encrypted attributes of an instance is accessed after the
|
||||
instance has been flushed to the database (and thus encrypted), the value for
|
||||
that attribute will be crypted in the in-memory object in addition to the
|
||||
database row.
|
||||
'''
|
||||
|
||||
from Crypto.Cipher import Blowfish
|
||||
from elixir.statements import Statement
|
||||
from sqlalchemy.orm import MapperExtension, EXT_CONTINUE, EXT_STOP
|
||||
|
||||
try:
|
||||
from sqlalchemy.orm import EXT_PASS
|
||||
SA05orlater = False
|
||||
except ImportError:
|
||||
SA05orlater = True
|
||||
|
||||
__all__ = ['acts_as_encrypted']
|
||||
__doc_all__ = []
|
||||
|
||||
|
||||
#
|
||||
# encryption and decryption functions
|
||||
#
|
||||
|
||||
def encrypt_value(value, secret):
|
||||
return Blowfish.new(secret, Blowfish.MODE_CFB) \
|
||||
.encrypt(value).encode('string_escape')
|
||||
|
||||
def decrypt_value(value, secret):
|
||||
return Blowfish.new(secret, Blowfish.MODE_CFB) \
|
||||
.decrypt(value.decode('string_escape'))
|
||||
|
||||
|
||||
#
|
||||
# acts_as_encrypted statement
|
||||
#
|
||||
|
||||
class ActsAsEncrypted(object):
|
||||
|
||||
def __init__(self, entity, for_fields=[], with_secret='abcdef'):
|
||||
|
||||
def perform_encryption(instance, encrypt=True):
|
||||
encrypted = getattr(instance, '_elixir_encrypted', None)
|
||||
if encrypted is encrypt:
|
||||
# skipping encryption or decryption, as it is already done
|
||||
return
|
||||
else:
|
||||
# marking instance as already encrypted/decrypted
|
||||
instance._elixir_encrypted = encrypt
|
||||
|
||||
if encrypt:
|
||||
func = encrypt_value
|
||||
else:
|
||||
func = decrypt_value
|
||||
|
||||
for column_name in for_fields:
|
||||
current_value = getattr(instance, column_name)
|
||||
if current_value:
|
||||
setattr(instance, column_name,
|
||||
func(current_value, with_secret))
|
||||
|
||||
def perform_decryption(instance):
|
||||
perform_encryption(instance, encrypt=False)
|
||||
|
||||
class EncryptedMapperExtension(MapperExtension):
|
||||
|
||||
def before_insert(self, mapper, connection, instance):
|
||||
perform_encryption(instance)
|
||||
return EXT_CONTINUE
|
||||
|
||||
def before_update(self, mapper, connection, instance):
|
||||
perform_encryption(instance)
|
||||
return EXT_CONTINUE
|
||||
|
||||
if SA05orlater:
|
||||
def reconstruct_instance(self, mapper, instance):
|
||||
perform_decryption(instance)
|
||||
# no special return value is required for
|
||||
# reconstruct_instance, but you never know...
|
||||
return EXT_CONTINUE
|
||||
else:
|
||||
def populate_instance(self, mapper, selectcontext, row,
|
||||
instance, *args, **kwargs):
|
||||
mapper.populate_instance(selectcontext, instance, row,
|
||||
*args, **kwargs)
|
||||
perform_decryption(instance)
|
||||
# EXT_STOP because we already did populate the instance and
|
||||
# the normal processing should not happen
|
||||
return EXT_STOP
|
||||
|
||||
# make sure that the entity's mapper has our mapper extension
|
||||
entity._descriptor.add_mapper_extension(EncryptedMapperExtension())
|
||||
|
||||
|
||||
acts_as_encrypted = Statement(ActsAsEncrypted)
|
||||
|
||||
Reference in New Issue
Block a user