[docs]classTOTP(OTP):""" Handler for time-based OTP counters. """def__init__(self,s:str,digits:int=6,digest:Any=None,name:Optional[str]=None,issuer:Optional[str]=None,interval:int=30,)->None:""" :param s: secret in base32 format :param digits: number of integers in the OTP. Some apps expect this to be 6 digits, others support more. :param digest: digest function to use in the HMAC (expected to be SHA1) :param name: account name :param issuer: issuer :param interval: the time interval in seconds for OTP. This defaults to 30. """ifdigestisNone:digest=hashlib.sha1self.interval=intervalsuper().__init__(s=s,digits=digits,digest=digest,name=name,issuer=issuer)
[docs]defat(self,for_time:Union[int,datetime.datetime],counter_offset:int=0)->str:""" Accepts either a Unix timestamp integer or a datetime object. To get the time until the next timecode change (seconds until the current OTP expires), use this instead: .. code:: python totp = pyotp.TOTP(...) time_remaining = totp.interval - datetime.datetime.now().timestamp() % totp.interval :param for_time: the time to generate an OTP for :param counter_offset: the amount of ticks to add to the time counter :returns: OTP value """ifnotisinstance(for_time,datetime.datetime):for_time=datetime.datetime.fromtimestamp(int(for_time))returnself.generate_otp(self.timecode(for_time)+counter_offset)
[docs]defnow(self)->str:""" Generate the current time OTP :returns: OTP value """returnself.generate_otp(self.timecode(datetime.datetime.now()))
[docs]defverify(self,otp:str,for_time:Optional[datetime.datetime]=None,valid_window:int=0)->bool:""" Verifies the OTP passed in against the current time OTP. :param otp: the OTP to check against :param for_time: Time to check OTP at (defaults to now) :param valid_window: extends the validity to this many counter ticks before and after the current one :returns: True if verification succeeded, False otherwise """iffor_timeisNone:for_time=datetime.datetime.now()ifvalid_window:foriinrange(-valid_window,valid_window+1):ifutils.strings_equal(str(otp),str(self.at(for_time,i))):returnTruereturnFalsereturnutils.strings_equal(str(otp),str(self.at(for_time)))
[docs]defprovisioning_uri(self,name:Optional[str]=None,issuer_name:Optional[str]=None,**kwargs)->str:""" Returns the provisioning URI for the OTP. This can then be encoded in a QR Code and used to provision an OTP app like Google Authenticator. See also: https://github.com/google/google-authenticator/wiki/Key-Uri-Format """returnutils.build_uri(self.secret,nameifnameelseself.name,issuer=issuer_nameifissuer_nameelseself.issuer,algorithm=self.digest().name,digits=self.digits,period=self.interval,**kwargs,)
[docs]deftimecode(self,for_time:datetime.datetime)->int:""" Accepts either a timezone naive (`for_time.tzinfo is None`) or a timezone aware datetime as argument and returns the corresponding counter value (timecode). """iffor_time.tzinfo:returnint(calendar.timegm(for_time.utctimetuple())/self.interval)else:returnint(time.mktime(for_time.timetuple())/self.interval)