<s> from base64 import b32encode <EOL> from binascii import unhexlify <EOL> from random import SystemRandom <EOL> from modularodm . fields import BooleanField , StringField , IntegerField <EOL> from oath import accept_totp <EOL> from website . addons . base import AddonUserSettingsBase <EOL> class TwoFactorUserSettings ( AddonUserSettingsBase ) : <EOL> totp_secret = StringField ( ) <EOL> totp_drift = IntegerField ( ) <EOL> is_confirmed = BooleanField ( default = False ) <EOL> @ property <EOL> def totp_secret_b32 ( self ) : <EOL> return b32encode ( unhexlify ( self . totp_secret ) ) <EOL> @ property <EOL> def otpauth_url ( self ) : <EOL> return '<STR_LIT>' . format ( self . owner . username , <EOL> self . totp_secret_b32 ) <EOL> def to_json ( self , user ) : <EOL> rv = super ( TwoFactorUserSettings , self ) . to_json ( user ) <EOL> rv . update ( { <EOL> '<STR_LIT>' : True , <EOL> '<STR_LIT>' : self . is_confirmed , <EOL> '<STR_LIT>' : self . totp_secret_b32 , <EOL> '<STR_LIT>' : self . totp_drift , <EOL> } ) <EOL> return rv <EOL> def verify_code ( self , code ) : <EOL> accepted , drift = accept_totp ( key = self . totp_secret , <EOL> response = code , <EOL> drift = self . totp_drift ) <EOL> if accepted : <EOL> self . totp_drift = drift <EOL> return True <EOL> return False <EOL> def on_add ( self ) : <EOL> super ( TwoFactorUserSettings , self ) . on_add ( ) <EOL> self . totp_secret = _generate_seed ( ) <EOL> self . totp_drift = <NUM_LIT:0> <EOL> self . is_confirmed = False <EOL> def on_delete ( self ) : <EOL> super ( TwoFactorUserSettings , self ) . on_delete ( ) <EOL> self . totp_secret = None <EOL> self . totp_drift = <NUM_LIT:0> <EOL> self . is_confirmed = False <EOL> def _generate_seed ( ) : <EOL> """<STR_LIT>""" <EOL> x = SystemRandom ( ) . randint ( <NUM_LIT:0> , <NUM_LIT:32> ** <NUM_LIT:16> - <NUM_LIT:1> ) <EOL> h = hex ( x ) . strip ( '<STR_LIT:L>' ) [ <NUM_LIT:2> : ] <EOL> if len ( h ) % <NUM_LIT:2> : <EOL> h = '<STR_LIT:0>' + h <EOL> return h </s>
