[docs]defbuild_uri(secret:str,name:str,initial_count:Optional[int]=None,issuer:Optional[str]=None,algorithm:Optional[str]=None,digits:Optional[int]=None,period:Optional[int]=None,**kwargs,)->str:""" Returns the provisioning URI for the OTP; works for either TOTP or HOTP. This can then be encoded in a QR Code and used to provision the Google Authenticator app. For module-internal use. See also: https://github.com/google/google-authenticator/wiki/Key-Uri-Format :param secret: the hotp/totp secret used to generate the URI :param name: name of the account :param initial_count: starting counter value, defaults to None. If none, the OTP type will be assumed as TOTP. :param issuer: the name of the OTP issuer; this will be the organization title of the OTP entry in Authenticator :param algorithm: the algorithm used in the OTP generation. :param digits: the length of the OTP generated code. :param period: the number of seconds the OTP generator is set to expire every code. :param kwargs: other query string parameters to include in the URI :returns: provisioning uri """# initial_count may be 0 as a valid paramis_initial_count_present=initial_countisnotNone# Handling values different from defaultsis_algorithm_set=algorithmisnotNoneandalgorithm!="sha1"is_digits_set=digitsisnotNoneanddigits!=6is_period_set=periodisnotNoneandperiod!=30otp_type="hotp"ifis_initial_count_presentelse"totp"base_uri="otpauth://{0}/{1}?{2}"url_args:Dict[str,Union[None,int,str]]={"secret":secret}label=quote(name)ifissuerisnotNone:label=quote(issuer)+":"+labelurl_args["issuer"]=issuerifis_initial_count_present:url_args["counter"]=initial_countifis_algorithm_set:url_args["algorithm"]=algorithm.upper()# type: ignoreifis_digits_set:url_args["digits"]=digitsifis_period_set:url_args["period"]=periodfork,vinkwargs.items():ifnotisinstance(v,str):raiseValueError("All otpauth uri parameters must be strings")ifk=="image":image_uri=urlparse(v)ifimage_uri.scheme!="https"ornotimage_uri.netlocornotimage_uri.path:raiseValueError("{} is not a valid url".format(image_uri))url_args[k]=vuri=base_uri.format(otp_type,label,urlencode(url_args).replace("+","%20"))returnuri
[docs]defstrings_equal(s1:str,s2:str)->bool:""" Timing-attack resistant string comparison. Normal comparison using == will short-circuit on the first mismatching character. This avoids that by scanning the whole string, though we still reveal to a timing attack whether the strings are the same length. """s1=unicodedata.normalize("NFKC",s1)s2=unicodedata.normalize("NFKC",s2)returncompare_digest(s1.encode("utf-8"),s2.encode("utf-8"))