194 lines
7.7 KiB
Python

"""passlib.ifc - abstract interfaces used by Passlib"""
#=============================================================================
# imports
#=============================================================================
# core
import logging; log = logging.getLogger(__name__)
import sys
# site
# pkg
# local
__all__ = [
"PasswordHash",
]
#=============================================================================
# 2.5-3.2 compatibility helpers
#=============================================================================
if sys.version_info >= (2,6):
from abc import ABCMeta, abstractmethod, abstractproperty
else:
# create stub for python 2.5
ABCMeta = type
def abstractmethod(func):
return func
# def abstractproperty():
# return None
def create_with_metaclass(meta):
"class decorator that re-creates class using metaclass"
# have to do things this way since abc not present in py25,
# and py2/py3 have different ways of doing metaclasses.
def builder(cls):
if meta is type(cls):
return cls
return meta(cls.__name__, cls.__bases__, cls.__dict__.copy())
return builder
#=============================================================================
# PasswordHash interface
#=============================================================================
class PasswordHash(object):
"""This class describes an abstract interface which all password hashes
in Passlib adhere to. Under Python 2.6 and up, this is an actual
Abstract Base Class built using the :mod:`!abc` module.
See the Passlib docs for full documentation.
"""
#===================================================================
# class attributes
#===================================================================
#---------------------------------------------------------------
# general information
#---------------------------------------------------------------
##name
##setting_kwds
##context_kwds
#---------------------------------------------------------------
# salt information -- if 'salt' in setting_kwds
#---------------------------------------------------------------
##min_salt_size
##max_salt_size
##default_salt_size
##salt_chars
##default_salt_chars
#---------------------------------------------------------------
# rounds information -- if 'rounds' in setting_kwds
#---------------------------------------------------------------
##min_rounds
##max_rounds
##default_rounds
##rounds_cost
#---------------------------------------------------------------
# encoding info -- if 'encoding' in context_kwds
#---------------------------------------------------------------
##default_encoding
#===================================================================
# primary methods
#===================================================================
@classmethod
@abstractmethod
def encrypt(cls, secret, **setting_and_context_kwds): # pragma: no cover -- abstract method
"encrypt secret, returning resulting hash"
raise NotImplementedError("must be implemented by subclass")
@classmethod
@abstractmethod
def verify(cls, secret, hash, **context_kwds): # pragma: no cover -- abstract method
"verify secret against hash, returns True/False"
raise NotImplementedError("must be implemented by subclass")
#===================================================================
# additional methods
#===================================================================
@classmethod
@abstractmethod
def identify(cls, hash): # pragma: no cover -- abstract method
"check if hash belongs to this scheme, returns True/False"
raise NotImplementedError("must be implemented by subclass")
@classmethod
@abstractmethod
def genconfig(cls, **setting_kwds): # pragma: no cover -- abstract method
"compile settings into a configuration string for genhash()"
raise NotImplementedError("must be implemented by subclass")
@classmethod
@abstractmethod
def genhash(cls, secret, config, **context_kwds): # pragma: no cover -- abstract method
"generated hash for secret, using settings from config/hash string"
raise NotImplementedError("must be implemented by subclass")
#===================================================================
# undocumented methods / attributes
#===================================================================
# the following entry points are used internally by passlib,
# and aren't documented as part of the exposed interface.
# they are subject to change between releases,
# but are documented here so there's a list of them *somewhere*.
#---------------------------------------------------------------
# checksum information - defined for many hashes
#---------------------------------------------------------------
## checksum_chars
## checksum_size
#---------------------------------------------------------------
# CryptContext flags
#---------------------------------------------------------------
# hack for bsdi_crypt: if True, causes CryptContext to only generate
# odd rounds values. assumed False if not defined.
## _avoid_even_rounds = False
##@classmethod
##def _bind_needs_update(cls, **setting_kwds):
## """return helper to detect hashes that need updating.
##
## if this method is defined, the CryptContext constructor
## will invoke it with the settings specified for the context.
## this method should return either ``None``, or a callable
## with the signature ``needs_update(hash,secret)->bool``.
##
## this ``needs_update`` function should return True if the hash
## should be re-encrypted, whether due to internal
## issues or the specified settings.
##
## CryptContext will automatically take care of deprecating
## hashes with insufficient rounds for classes which define fromstring()
## and a rounds attribute - though the requirements for this last
## part may change at some point.
## """
#---------------------------------------------------------------
# experimental methods
#---------------------------------------------------------------
##@classmethod
##def normhash(cls, hash):
## """helper to clean up non-canonic instances of hash.
## currently only provided by bcrypt() to fix an historical passlib issue.
## """
# experimental helper to parse hash into components.
##@classmethod
##def parsehash(cls, hash, checksum=True, sanitize=False):
## """helper to parse hash into components, returns dict"""
# experiment helper to estimate bitsize of different hashes,
# implement for GenericHandler, but may be currently be off for some hashes.
# want to expand this into a way to programmatically compare
# "strengths" of different hashes and hash algorithms.
# still needs to have some factor for estimate relative cost per round,
# ala in the style of the scrypt whitepaper.
##@classmethod
##def bitsize(cls, **kwds):
## """returns dict mapping component -> bits contributed.
## components currently include checksum, salt, rounds.
## """
#===================================================================
# eoc
#===================================================================
PasswordHash = create_with_metaclass(ABCMeta)(PasswordHash)
#=============================================================================
# eof
#=============================================================================