PyOTP 2.7.0__tar.gz → 2.8.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyotp
3
- Version: 2.7.0
3
+ Version: 2.8.0
4
4
  Summary: Python One Time Password Library
5
5
  Home-page: https://github.com/pyotp/pyotp
6
6
  Author: PyOTP contributors
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.8
20
20
  Classifier: Programming Language :: Python :: 3.9
21
21
  Classifier: Programming Language :: Python :: 3.10
22
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
- Requires-Python: >=3.6
23
+ Requires-Python: >=3.7
24
24
  License-File: LICENSE
25
25
 
26
26
  PyOTP - The Python One-Time Password Library
@@ -45,7 +45,7 @@ minimum, application implementers should follow this checklist:
45
45
  - Ensure HOTP/TOTP secret confidentiality by storing secrets in a controlled access database
46
46
  - Deny replay attacks by rejecting one-time passwords that have been used by the client (this requires storing the most
47
47
  recently authenticated timestamp, OTP, or hash of the OTP in your database, and rejecting the OTP when a match is seen)
48
- - Throttle (rate limit) brute-force attacks against your application's login functionality
48
+ - Throttle (rate limit) brute-force attacks against your application's login functionality (see RFC 4226, section 7.3)
49
49
  - When implementing a "greenfield" application, consider supporting
50
50
  `FIDO U2F <https://en.wikipedia.org/wiki/Universal_2nd_Factor>`_/`WebAuthn <https://www.w3.org/TR/webauthn/>`_ in
51
51
  addition to HOTP/TOTP. U2F uses asymmetric cryptography to avoid using a shared secret design, which strengthens your
@@ -80,6 +80,9 @@ Time-based OTPs
80
80
  ~~~~~~~~~~~~~~~
81
81
  ::
82
82
 
83
+ import pyotp
84
+ import time
85
+
83
86
  totp = pyotp.TOTP('base32secret3232')
84
87
  totp.now() # => '492039'
85
88
 
@@ -92,6 +95,8 @@ Counter-based OTPs
92
95
  ~~~~~~~~~~~~~~~~~~
93
96
  ::
94
97
 
98
+ import pyotp
99
+
95
100
  hotp = pyotp.HOTP('base32secret3232')
96
101
  hotp.at(0) # => '260182'
97
102
  hotp.at(1) # => '055283'
@@ -20,7 +20,7 @@ minimum, application implementers should follow this checklist:
20
20
  - Ensure HOTP/TOTP secret confidentiality by storing secrets in a controlled access database
21
21
  - Deny replay attacks by rejecting one-time passwords that have been used by the client (this requires storing the most
22
22
  recently authenticated timestamp, OTP, or hash of the OTP in your database, and rejecting the OTP when a match is seen)
23
- - Throttle (rate limit) brute-force attacks against your application's login functionality
23
+ - Throttle (rate limit) brute-force attacks against your application's login functionality (see RFC 4226, section 7.3)
24
24
  - When implementing a "greenfield" application, consider supporting
25
25
  `FIDO U2F <https://en.wikipedia.org/wiki/Universal_2nd_Factor>`_/`WebAuthn <https://www.w3.org/TR/webauthn/>`_ in
26
26
  addition to HOTP/TOTP. U2F uses asymmetric cryptography to avoid using a shared secret design, which strengthens your
@@ -55,6 +55,9 @@ Time-based OTPs
55
55
  ~~~~~~~~~~~~~~~
56
56
  ::
57
57
 
58
+ import pyotp
59
+ import time
60
+
58
61
  totp = pyotp.TOTP('base32secret3232')
59
62
  totp.now() # => '492039'
60
63
 
@@ -67,6 +70,8 @@ Counter-based OTPs
67
70
  ~~~~~~~~~~~~~~~~~~
68
71
  ::
69
72
 
73
+ import pyotp
74
+
70
75
  hotp = pyotp.HOTP('base32secret3232')
71
76
  hotp.at(0) # => '260182'
72
77
  hotp.at(1) # => '055283'
@@ -4,14 +4,14 @@ from setuptools import setup
4
4
 
5
5
  setup(
6
6
  name="pyotp",
7
- version="2.7.0",
7
+ version="2.8.0",
8
8
  url="https://github.com/pyotp/pyotp",
9
9
  license="MIT License",
10
10
  author="PyOTP contributors",
11
11
  author_email="kislyuk@gmail.com",
12
12
  description="Python One Time Password Library",
13
13
  long_description=open("README.rst").read(),
14
- python_requires=">=3.6",
14
+ python_requires=">=3.7",
15
15
  install_requires=[],
16
16
  packages=["pyotp", "pyotp.contrib"],
17
17
  package_dir={"": "src"},
@@ -41,7 +41,7 @@ def parse_uri(uri: str) -> OTP:
41
41
  secret = None
42
42
 
43
43
  # Data we'll parse to the correct constructor
44
- otp_data = {} # type: Dict[str, Any]
44
+ otp_data: Dict[str, Any] = {}
45
45
 
46
46
  # Parse with URLlib
47
47
  parsed_uri = urlparse(unquote(uri))
@@ -14,7 +14,7 @@ class HOTP(OTP):
14
14
  self,
15
15
  s: str,
16
16
  digits: int = 6,
17
- digest: Any = hashlib.sha1,
17
+ digest: Any = None,
18
18
  name: Optional[str] = None,
19
19
  issuer: Optional[str] = None,
20
20
  initial_count: int = 0,
@@ -23,10 +23,13 @@ class HOTP(OTP):
23
23
  :param s: secret in base32 format
24
24
  :param initial_count: starting HMAC counter value, defaults to 0
25
25
  :param digits: number of integers in the OTP. Some apps expect this to be 6 digits, others support more.
26
- :param digest: digest function to use in the HMAC (expected to be sha1)
26
+ :param digest: digest function to use in the HMAC (expected to be SHA1)
27
27
  :param name: account name
28
28
  :param issuer: issuer
29
29
  """
30
+ if digest is None:
31
+ digest = hashlib.sha1
32
+
30
33
  self.initial_count = initial_count
31
34
  super().__init__(s=s, digits=digits, digest=digest, name=name, issuer=issuer)
32
35
 
@@ -18,6 +18,8 @@ class OTP(object):
18
18
  issuer: Optional[str] = None,
19
19
  ) -> None:
20
20
  self.digits = digits
21
+ if digits > 10:
22
+ raise ValueError("digits must be no greater than 10")
21
23
  self.digest = digest
22
24
  self.secret = s
23
25
  self.name = name or "Secret"
@@ -39,11 +41,8 @@ class OTP(object):
39
41
  | (hmac_hash[offset + 2] & 0xFF) << 8
40
42
  | (hmac_hash[offset + 3] & 0xFF)
41
43
  )
42
- str_code = str(code % 10**self.digits)
43
- while len(str_code) < self.digits:
44
- str_code = "0" + str_code
45
-
46
- return str_code
44
+ str_code = str(10_000_000_000 + (code % 10**self.digits))
45
+ return str_code[-self.digits :]
47
46
 
48
47
  def byte_secret(self) -> bytes:
49
48
  secret = self.secret
@@ -17,7 +17,7 @@ class TOTP(OTP):
17
17
  self,
18
18
  s: str,
19
19
  digits: int = 6,
20
- digest: Any = hashlib.sha1,
20
+ digest: Any = None,
21
21
  name: Optional[str] = None,
22
22
  issuer: Optional[str] = None,
23
23
  interval: int = 30,
@@ -26,10 +26,13 @@ class TOTP(OTP):
26
26
  :param s: secret in base32 format
27
27
  :param interval: the time interval in seconds for OTP. This defaults to 30.
28
28
  :param digits: number of integers in the OTP. Some apps expect this to be 6 digits, others support more.
29
- :param digest: digest function to use in the HMAC (expected to be sha1)
29
+ :param digest: digest function to use in the HMAC (expected to be SHA1)
30
30
  :param name: account name
31
31
  :param issuer: issuer
32
32
  """
33
+ if digest is None:
34
+ digest = hashlib.sha1
35
+
33
36
  self.interval = interval
34
37
  super().__init__(s=s, digits=digits, digest=digest, name=name, issuer=issuer)
35
38
 
@@ -37,7 +40,9 @@ class TOTP(OTP):
37
40
  """
38
41
  Accepts either a Unix timestamp integer or a datetime object.
39
42
 
40
- To get the time until the next timecode change (seconds until the current OTP expires), use this instead::
43
+ To get the time until the next timecode change (seconds until the current OTP expires), use this instead:
44
+
45
+ .. code:: python
41
46
 
42
47
  totp = pyotp.TOTP(...)
43
48
  time_remaining = totp.interval - datetime.datetime.now().timestamp() % totp.interval
@@ -49,7 +49,7 @@ def build_uri(
49
49
  otp_type = "hotp" if is_initial_count_present else "totp"
50
50
  base_uri = "otpauth://{0}/{1}?{2}"
51
51
 
52
- url_args = {"secret": secret} # type: Dict[str, Union[None, int, str]]
52
+ url_args: Dict[str, Union[None, int, str]] = {"secret": secret}
53
53
 
54
54
  label = quote(name)
55
55
  if issuer is not None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyotp
3
- Version: 2.7.0
3
+ Version: 2.8.0
4
4
  Summary: Python One Time Password Library
5
5
  Home-page: https://github.com/pyotp/pyotp
6
6
  Author: PyOTP contributors
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.8
20
20
  Classifier: Programming Language :: Python :: 3.9
21
21
  Classifier: Programming Language :: Python :: 3.10
22
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
- Requires-Python: >=3.6
23
+ Requires-Python: >=3.7
24
24
  License-File: LICENSE
25
25
 
26
26
  PyOTP - The Python One-Time Password Library
@@ -45,7 +45,7 @@ minimum, application implementers should follow this checklist:
45
45
  - Ensure HOTP/TOTP secret confidentiality by storing secrets in a controlled access database
46
46
  - Deny replay attacks by rejecting one-time passwords that have been used by the client (this requires storing the most
47
47
  recently authenticated timestamp, OTP, or hash of the OTP in your database, and rejecting the OTP when a match is seen)
48
- - Throttle (rate limit) brute-force attacks against your application's login functionality
48
+ - Throttle (rate limit) brute-force attacks against your application's login functionality (see RFC 4226, section 7.3)
49
49
  - When implementing a "greenfield" application, consider supporting
50
50
  `FIDO U2F <https://en.wikipedia.org/wiki/Universal_2nd_Factor>`_/`WebAuthn <https://www.w3.org/TR/webauthn/>`_ in
51
51
  addition to HOTP/TOTP. U2F uses asymmetric cryptography to avoid using a shared secret design, which strengthens your
@@ -80,6 +80,9 @@ Time-based OTPs
80
80
  ~~~~~~~~~~~~~~~
81
81
  ::
82
82
 
83
+ import pyotp
84
+ import time
85
+
83
86
  totp = pyotp.TOTP('base32secret3232')
84
87
  totp.now() # => '492039'
85
88
 
@@ -92,6 +95,8 @@ Counter-based OTPs
92
95
  ~~~~~~~~~~~~~~~~~~
93
96
  ::
94
97
 
98
+ import pyotp
99
+
95
100
  hotp = pyotp.HOTP('base32secret3232')
96
101
  hotp.at(0) # => '260182'
97
102
  hotp.at(1) # => '055283'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes