On Dec 21, 2008, at 6:53 AM, Kless wrote:

>
> I'm trying to build a custom type [1] to manage the bcrypt hashes [2].
>
> ---------------
> from bcrypt_wrap import password
> from sqlalchemy import types
>
>
> class Bcrypt(types.TypeDecorator):
>  """Stores a bcrypt hash of a password."""
>  impl = types.String #(60)
>  hasher = password.Password()
>
>  def process_bind_param(self, value, dialect):
>    return hasher.create(value)
> ---------------
>
> And I've any doubts:
>
> 1) Since that the hash length is always 60, is there that use the
> next?
>  impl = types.String(60)
>
> 2) The bcryptWrap API [3] (line 53) lets call to 'create' with
> arguments 'cost' and 'admin' (boolean). Then,
>
>  a) I would that the cost could be passed from the column definition,
> i.e.
>      password = sqlalchemy.Column(types.Bcrypt, cost=12)
> or
>      password = sqlalchemy.Column(types.Bcrypt(cost=12))
>
>  b) This would be more hard, but I would to pass the 'admin' argument
> when an object is created
>
>    u = model.User()
>    u.login = u'foo'
>    u.password = u'bar'
>    u.admin = True
>
>    And sou could be call:
>        return hasher.create(value, admin=True)
>


the TypeDecorator's __init__ method just calls the impl class  
immediately, so the best approach is like:

class Bcrypt(types.TypeDecorator):
     """Stores a bcrypt hash of a password."""
     impl = types.String
     hasher = password.Password()

     def __init__(self, cost):
         self.cost = cost
         types.TypeDecorator.__init__(self, 60)

     def process_bind_param(self, value, dialect):
         return hasher.create(value)


then you can instantate like:

Column('foo', Bcrypt(cost=12))

For b, the type object and the ExecutionContext which ultimately calls  
its process_bind_param method are unaware of the ORM or the ORM- 
specific context in which its called during INSERT/UPDATE.   If you  
wanted to keep the logic within your type like that you'd have to  
integrate to a thread-local variable that is configured within an ORM  
plugin, something like:

hasher_status = threading.local()

class MyMapperExt(MapperExtension):
     def before_insert(self, ...):
         hasher_status.admin = instance.admin

     def after_insert(self, ...)
         del hasher_status.admin

mapper(MyClass, table, ext=MyMapperExt)

class Bcrypt(types.TypeDecorator):
     ...

     def process_bind_param(self, value, dialect):
         return hasher.create(value, getattr(hasher_status, 'admin',  
False))


Alternatively, you could keep the logic within the ORM using either a  
"valdiator" or a descriptor, as described at 
http://www.sqlalchemy.org/docs/05/mappers.html#changing-attribute-behavior 
  .  It depends on if you'd like your Bcrypt type to work with direct  
SQL expression language use or not.



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to