Skip to content

Commit 5d21652

Browse files
author
brentru
committed
5-button layout, customizable button colors
1 parent 031ac58 commit 5d21652

1 file changed

Lines changed: 59 additions & 46 deletions

File tree

PyPortal_TOTP_Friend/code.py

Lines changed: 59 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# PyPortal TOTP Authenticator
21
import time
32

4-
import adafruit_hashlib as hashlib
5-
import adafruit_imageload
6-
import adafruit_touchscreen
73
import board
84
import busio
5+
from digitalio import DigitalInOut
6+
7+
import adafruit_hashlib as hashlib
8+
import adafruit_touchscreen
99
import displayio
1010
import neopixel
1111
import terminalio
@@ -18,7 +18,6 @@
1818
from adafruit_esp32spi import adafruit_esp32spi
1919
from adafruit_ntp import NTP
2020
from adafruit_pyportal import PyPortal
21-
from digitalio import DigitalInOut
2221

2322
# Background/Images
2423
BACKGROUND = 0x059ACE
@@ -34,6 +33,7 @@
3433
print("WiFi secrets are kept in secrets.py, please add them there!")
3534
raise
3635

36+
3737
# Initialize PyPortal Display
3838
display = board.DISPLAY
3939

@@ -47,6 +47,7 @@
4747
),
4848
size=(WIDTH, HEIGHT))
4949

50+
5051
# Create a SHA1 Object
5152
SHA1 = hashlib.sha1
5253

@@ -59,6 +60,7 @@
5960
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
6061
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
6162

63+
6264
# HMAC implementation, as hashlib/hmac wouldn't fit
6365
# From https://en.wikipedia.org/wiki/Hash-based_message_authentication_code
6466
def HMAC(k, m):
@@ -114,6 +116,7 @@ def int_to_bytestring(i, padding=8):
114116

115117
# HMAC -> OTP generator, pretty much same as
116118
# https://github.com/pyotp/pyotp/blob/master/src/pyotp/otp.py
119+
117120
def generate_otp(int_input, secret_key, digits=6):
118121
if int_input < 0:
119122
raise ValueError('input must be positive integer')
@@ -129,6 +132,7 @@ def generate_otp(int_input, secret_key, digits=6):
129132
str_code = str(code % 10 ** digits)
130133
while len(str_code) < digits:
131134
str_code = '0' + str_code
135+
132136
return str_code
133137

134138

@@ -154,7 +158,7 @@ def generate_otp(int_input, secret_key, digits=6):
154158
bg_palette[0] = BACKGROUND
155159
background = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette)
156160

157-
# Text DisplayIO
161+
# Create a new DisplayIO group
158162
splash = displayio.Group(max_size=100)
159163

160164
splash.append(background)
@@ -163,20 +167,46 @@ def generate_otp(int_input, secret_key, digits=6):
163167
# We'll use a default text placeholder for this label
164168
label_key = Label(font, text="000 000")
165169
label_key.x = (display.width // 2) // 13
166-
label_key.y = 17
170+
label_key.y = 20
167171
key_group.append(label_key)
168172

169173
label_title = Label(font, max_glyphs=14)
170-
label_title.text = "loading.."
171-
label_title.x = (display.width // 2) // 13
174+
label_title.text = "loading..."
175+
label_title.x = (display.width // 2) // 10
172176
label_title.y = 5
173177
key_group.append(label_title)
174178

179+
# append key_group to splash
175180
splash.append(key_group)
176-
177181
# Show the group
178182
display.show(splash)
179183

184+
# Add buttons to the interface
185+
assert len(secrets['totp_keys']) < 6, "This code can only render 5 keys at a time"
186+
187+
# generate buttons
188+
buttons = []
189+
190+
btn_x = 5
191+
for i in secrets['totp_keys']:
192+
print(i)
193+
try:
194+
if i[2]:
195+
color = i[2]
196+
except IndexError:
197+
color = 0x00FF00
198+
button = Button(name=i[0], x=btn_x, y=175,
199+
width=60, height=60,
200+
label=i[0], label_font=font, label_color=0xFFFFFF,
201+
fill_color=color, style=Button.ROUNDRECT)
202+
buttons.append(button)
203+
btn_x+=63
204+
205+
# append buttons to splash group
206+
for b in buttons:
207+
splash.append(b.group)
208+
209+
180210
print("Connecting to AP...")
181211
while not esp.is_connected:
182212
try:
@@ -207,45 +237,28 @@ def generate_otp(int_input, secret_key, digits=6):
207237
print("Monotonic time", mono_time)
208238

209239

210-
def display_otp(unix_time, name, secret):
211-
"""Updates text objects to display the OTP and name.
212-
213-
:param int unix_time: Current unix time
214-
:param str name: OTP name
215-
:param str secret: OTP Secret
216-
"""
217-
otp = generate_otp(unix_time // 30, secret)
218-
print(name + " OTP output: ", otp)
219-
# display the key's name
220-
label_title.text = name
221-
# format and display the OTP
222-
label_key.text = "{} {}".format(str(otp)[0:3],str(otp)[3:6])
223-
224-
def get_unix_time():
225-
"""Calculate current time based on NTP + monotonic
226-
227-
"""
228-
unix_time = t - mono_time + int(time.monotonic())
229-
return unix_time
230-
231-
# how long to stay on if not in always_on mode
232-
countdown = ON_SECONDS
233-
cur_otp = 0
234-
max_otp = len(secrets['totp_keys'])
235-
236-
display_otp(get_unix_time(), secrets['totp_keys'][cur_otp][0],
237-
secrets['totp_keys'][cur_otp][1])
238-
240+
countdown = ON_SECONDS # how long to stay on if not in always_on mode
239241
while ALWAYS_ON or (countdown > 0):
242+
# Calculate current time based on NTP + monotonic
243+
unix_time = t - mono_time + int(time.monotonic())
240244
p = ts.touch_point
241245
if p:
242-
if cur_otp < max_otp:
243-
display_otp(get_unix_time(), secrets['totp_keys'][cur_otp][0],
244-
secrets['totp_keys'][cur_otp][1])
245-
cur_otp+=1
246-
else:
247-
# reset the current otp display
248-
cur_otp = 0
246+
for i, b in enumerate(buttons):
247+
if b.contains(p):
248+
b.selected = True
249+
for name, secret in secrets['totp_keys']:
250+
if b.name == name:
251+
# generate OTP
252+
#print('Background color: ', background_color)
253+
otp = generate_otp(unix_time // 30, secret)
254+
print('{} selected: '.format(name))
255+
print(name + " OTP output: ", otp)
256+
# display the key's name
257+
label_title.text = name
258+
# format and display the OTP
259+
label_key.text = "{} {}".format(str(otp)[0:3],str(otp)[3:6])
260+
else:
261+
b.selected = False
249262
# We'll update every 1/4 second, we can hash very fast so its no biggie!
250263
countdown -= 0.25
251264
time.sleep(0.25)

0 commit comments

Comments
 (0)