PyOTP 2.4.0__tar.gz → 2.4.1__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: 1.1
2
2
  Name: pyotp
3
- Version: 2.4.0
3
+ Version: 2.4.1
4
4
  Summary: Python One Time Password Library
5
5
  Home-page: https://github.com/pyotp/pyotp
6
6
  Author: PyOTP contributors
@@ -7,7 +7,7 @@ install_requires = [line.rstrip() for line in open(os.path.join(os.path.dirname(
7
7
 
8
8
  setup(
9
9
  name="pyotp",
10
- version="2.4.0",
10
+ version="2.4.1",
11
11
  url="https://github.com/pyotp/pyotp",
12
12
  license="MIT License",
13
13
  author="PyOTP contributors",
@@ -84,9 +84,9 @@ def parse_uri(uri: str) -> OTP:
84
84
  raise ValueError('Digits may only be 6 or 8')
85
85
  otp_data['digits'] = digits
86
86
  elif key == 'period':
87
- otp_data['interval'] = value
87
+ otp_data['interval'] = int(value)
88
88
  elif key == 'counter':
89
- otp_data['initial_count'] = value
89
+ otp_data['initial_count'] = int(value)
90
90
  else:
91
91
  raise ValueError('{} is not a valid parameter'.format(key))
92
92
 
@@ -22,7 +22,7 @@ class HOTP(OTP):
22
22
  :param count: the OTP HMAC counter
23
23
  :returns: OTP
24
24
  """
25
- return self.generate_otp(count)
25
+ return self.generate_otp(self.initial_count + count)
26
26
 
27
27
  def verify(self, otp: str, counter: int) -> bool:
28
28
  """
@@ -1,5 +1,6 @@
1
1
  from typing import Any, Union, Optional
2
2
 
3
+ import calendar
3
4
  import datetime
4
5
  import time
5
6
 
@@ -80,5 +81,13 @@ class TOTP(OTP):
80
81
  digits=self.digits, period=self.interval)
81
82
 
82
83
  def timecode(self, for_time: datetime.datetime) -> int:
83
- i = time.mktime(for_time.timetuple())
84
- return int(i / self.interval)
84
+ """
85
+ Accepts either a timezone naive (`for_time.tzinfo is None`) or
86
+ a timezone aware datetime as argument and returns the
87
+ corresponding counter value (timecode).
88
+
89
+ """
90
+ if for_time.tzinfo:
91
+ return int(calendar.timegm(for_time.utctimetuple()) / self.interval)
92
+ else:
93
+ return int(time.mktime(for_time.timetuple()) / self.interval)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: pyotp
3
- Version: 2.4.0
3
+ Version: 2.4.1
4
4
  Summary: Python One Time Password Library
5
5
  Home-page: https://github.com/pyotp/pyotp
6
6
  Author: PyOTP contributors
@@ -339,6 +339,7 @@ class ValidWindowTest(unittest.TestCase):
339
339
  self.assertTrue(totp.verify("681610", 200, 1))
340
340
  self.assertFalse(totp.verify("195979", 200, 1))
341
341
 
342
+
342
343
  class ParseUriTest(unittest.TestCase):
343
344
  def test_invalids(self):
344
345
  with self.assertRaises(ValueError) as cm:
@@ -369,15 +370,48 @@ class ParseUriTest(unittest.TestCase):
369
370
  pyotp.parse_uri('otpauth://totp?algorithm=aes')
370
371
  self.assertEqual('Invalid value for algorithm, must be SHA1, SHA256 or SHA512', str(cm.exception))
371
372
 
373
+ @unittest.skipIf(sys.version_info < (3, 6), "Skipping test that requires deterministic dict key enumeration")
372
374
  def test_algorithms(self):
373
- otp = pyotp.parse_uri('otpauth://totp?algorithm=SHA1&secret=123456&algorithm=SHA1')
375
+ otp = pyotp.parse_uri('otpauth://totp?algorithm=SHA1&secret=GEZDGNBV&algorithm=SHA1')
376
+ self.assertEqual(hashlib.sha1, otp.digest)
377
+ self.assertEqual(otp.at(0), '734055')
378
+ self.assertEqual(otp.at(30), '662488')
379
+ self.assertEqual(otp.at(60), '289363')
380
+ self.assertEqual(otp.provisioning_uri(), 'otpauth://totp/Secret?secret=GEZDGNBV')
381
+ self.assertEqual(otp.provisioning_uri(name='n', issuer_name='i'), 'otpauth://totp/i:n?secret=GEZDGNBV&issuer=i')
382
+
383
+ otp = pyotp.parse_uri('otpauth://totp?algorithm=SHA1&secret=GEZDGNBV&algorithm=SHA1&period=60')
384
+ self.assertEqual(hashlib.sha1, otp.digest)
385
+ self.assertEqual(otp.at(30), '734055')
386
+ self.assertEqual(otp.at(60), '662488')
387
+ self.assertEqual(otp.provisioning_uri(name='n', issuer_name='i'),
388
+ 'otpauth://totp/i:n?secret=GEZDGNBV&issuer=i&period=60')
389
+
390
+ otp = pyotp.parse_uri('otpauth://hotp?algorithm=SHA1&secret=GEZDGNBV&algorithm=SHA1')
391
+ self.assertEqual(hashlib.sha1, otp.digest)
392
+ self.assertEqual(otp.at(0), '734055')
393
+ self.assertEqual(otp.at(1), '662488')
394
+ self.assertEqual(otp.at(2), '289363')
395
+ self.assertEqual(otp.provisioning_uri(name='n', issuer_name='i'),
396
+ 'otpauth://hotp/i:n?secret=GEZDGNBV&issuer=i&counter=0')
397
+
398
+ otp = pyotp.parse_uri('otpauth://hotp?algorithm=SHA1&secret=GEZDGNBV&algorithm=SHA1&counter=1')
374
399
  self.assertEqual(hashlib.sha1, otp.digest)
400
+ self.assertEqual(otp.at(0), '662488')
401
+ self.assertEqual(otp.at(1), '289363')
402
+ self.assertEqual(otp.provisioning_uri(name='n', issuer_name='i'),
403
+ 'otpauth://hotp/i:n?secret=GEZDGNBV&issuer=i&counter=1')
375
404
 
376
- otp = pyotp.parse_uri('otpauth://totp?algorithm=SHA1&secret=123456&algorithm=SHA256')
405
+ otp = pyotp.parse_uri('otpauth://totp?algorithm=SHA1&secret=GEZDGNBV&algorithm=SHA256')
377
406
  self.assertEqual(hashlib.sha256, otp.digest)
407
+ self.assertEqual(otp.at(0), '918961')
408
+ self.assertEqual(otp.at(9000), '934470')
378
409
 
379
- otp = pyotp.parse_uri('otpauth://totp?algorithm=SHA1&secret=123456&algorithm=SHA512')
410
+ otp = pyotp.parse_uri('otpauth://totp?algorithm=SHA1&secret=GEZDGNBV&algorithm=SHA512')
380
411
  self.assertEqual(hashlib.sha512, otp.digest)
412
+ self.assertEqual(otp.at(0), '816660')
413
+ self.assertEqual(otp.at(9000), '524153')
414
+
381
415
 
382
416
  class Timecop(object):
383
417
  """
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes