[PATCH numberstation] Update TOTP codes when they are expired
Export this patch
From: Andrey Skvortsov <andrej.skvortzov@gmail.com>
If system is suspended, then after resume TOTP are not updated until
'period' seconds are left in the wakeup state. During this time shown
TOTP codes are wrong, because they are calculated base on the
timestamp before system was suspended.
---
numberstation/otpurl.py | 15 ++++++++++++++-
numberstation/window.py | 24 +++++++++++-------------
2 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/numberstation/otpurl.py b/numberstation/otpurl.py
index 628e3f0..701d100 100644
--- a/numberstation/otpurl.py
+++ b/numberstation/otpurl.py
@@ -46,7 +46,9 @@ class OTPUrl:
def get_token(self):
if self.type == 'totp':
totp = pyotp.TOTP(self.secret, interval=self.period, digits=self.digits, digest=self.digest)
- return totp.now(), totp.interval - datetime.now().timestamp() % totp.interval
+ base_timestamp = totp.interval * int(datetime.now().timestamp() / totp.interval)
+ valid_until = datetime.fromtimestamp(base_timestamp + totp.interval)
+ return totp.now(), valid_until
elif self.type == 'hotp':
hotp = pyotp.HOTP(self.secret, digits=self.digits, digest=self.digest, initial_count=self.initial_count)
return hotp.at(0), None
@@ -54,6 +56,17 @@ class OTPUrl:
sys.stderr.write("Unknown key format '{}'\n".format(self.type))
return None, None
+ def get_validity(self):
+ """Returns floating value in the range 0.0-1.0
+ described how long generated code will be valid
+ relative to update period
+ """
+ if self.type == 'totp':
+ secs_left = self.period - datetime.now().timestamp() % self.period
+ return 1.0 * secs_left / self.period
+ else:
+ return None
+
def get_url(self):
properties = {
'secret': self.secret,
diff --git a/numberstation/window.py b/numberstation/window.py
index 5dda4c9..eb14310 100644
--- a/numberstation/window.py
+++ b/numberstation/window.py
@@ -1,4 +1,5 @@
from base64 import b32decode
+from datetime import datetime
from collections import namedtuple
import keyring
@@ -128,7 +129,7 @@ class NumberstationWindow:
self.save_keyring()
def update_code_label(self, label, progressbar, token):
- code, validity = token.get_token()
+ code, valid_until = token.get_token()
if code is None:
return
user_code = code
@@ -144,23 +145,20 @@ class NumberstationWindow:
else:
label.set_label(user_code)
label.paste_code = paste_code
- if validity:
- progressbar.validity = int(validity)
+ if valid_until:
+ progressbar.valid_until = valid_until
else:
if progressbar:
- progressbar.validity = None
+ progressbar.valid_until = None
def update_codes(self):
GLib.timeout_add(1000, self.update_codes)
for timer in self.timers:
- if timer.validity is None:
+ if timer.valid_until is None:
continue
- timer.validity -= 1
- if timer.validity < 1:
- timer.validity = int(timer.period)
+ if timer.valid_until < datetime.now():
self.update_code_label(timer.display, timer, timer.token)
-
- timer.set_fraction(1.0 / timer.period * timer.validity)
+ timer.set_fraction(timer.token.get_validity())
def on_long_press(self, gesture, x, y, *args):
eb = gesture.eb
@@ -249,12 +247,12 @@ class NumberstationWindow:
timer.token = token
timer.display = code
- if not hasattr(timer, 'validity'):
+ if not hasattr(timer, 'valid_until'):
continue
- if timer.validity is not None:
+ if timer.valid_until is not None:
timer.show()
timer.set_no_show_all(False)
- timer.set_fraction(1.0 / token.period * timer.validity)
+ timer.set_fraction(token.get_validity())
else:
timer.hide()
timer.set_no_show_all(True)
--
2.34.7
Hi Martijn,
do you have any feedback on the patch? Is there anything I could
possibly do to get it merged?