132 lines
3.5 KiB
Python
132 lines
3.5 KiB
Python
# (c) Copyright 2021 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
|
#
|
|
# countdowns.py - various details and chooser menus for setting/showing countdown times
|
|
#
|
|
from glob import settings
|
|
from nvstore import SettingsObject
|
|
from menu import MenuItem
|
|
from ux import ux_show_story, ux_dramatic_pause
|
|
|
|
# Login countdown length, stored in minutes
|
|
#
|
|
lgto_map = {
|
|
0: 'Disabled',
|
|
5: ' 5 minutes',
|
|
15: '15 minutes',
|
|
30: '30 minutes',
|
|
60: ' 1 hour',
|
|
2*60: ' 2 hours',
|
|
4*60: ' 4 hours',
|
|
8*60: ' 8 hours',
|
|
12*60: '12 hours',
|
|
24*60: '24 hours',
|
|
48*60: '48 hours',
|
|
3*24*60: ' 3 days',
|
|
7*24*60: ' 1 week',
|
|
28*24*60: '28 days later' }
|
|
lgto_va = list(lgto_map.keys())
|
|
lgto_ch = list(lgto_map.values())
|
|
|
|
def real_countdown_chooser(tag, offset, def_to):
|
|
|
|
# 'disabled' choice not appropriate for cd_lgto case
|
|
ch = lgto_ch[offset:]
|
|
va = lgto_va[offset:]
|
|
|
|
s = SettingsObject()
|
|
timeout = s.get(tag, def_to) # in minutes
|
|
try:
|
|
which = va.index(timeout)
|
|
except ValueError:
|
|
which = 0
|
|
|
|
def set_it(idx, text):
|
|
# save on key0, not normal settings
|
|
s = SettingsObject()
|
|
s.set(tag, va[idx])
|
|
s.save()
|
|
del s
|
|
|
|
return which, ch, set_it
|
|
|
|
def countdown_chooser():
|
|
return real_countdown_chooser('lgto', 0, 0)
|
|
def cd_countdown_chooser():
|
|
return real_countdown_chooser('cd_lgto', 1, 60)
|
|
|
|
# Mk3 only
|
|
async def set_countdown_pin(_1, _2, menu_item):
|
|
# Accept a new PIN to be used to enable this feature
|
|
from login import LoginUX
|
|
|
|
lll = LoginUX()
|
|
lll.reset()
|
|
lll.subtitle = "Countdown PIN"
|
|
|
|
pin = await lll.get_new_pin(None, allow_clear=True) # a string
|
|
|
|
s = SettingsObject()
|
|
|
|
from pincodes import pa
|
|
if pin == pa.pin.decode():
|
|
# can't compare to others like duress/brickme but will override them
|
|
await ux_show_story("Must be a unique PIN value!")
|
|
return
|
|
elif not pin:
|
|
# X on first screen does this (better than CLEAR_PIN thing)
|
|
s.remove_key('cd_pin')
|
|
msg = 'PIN Cleared.'
|
|
menu_item.label = "Enable Feature"
|
|
else:
|
|
s.set('cd_pin', pin)
|
|
msg = 'PIN Set.'
|
|
menu_item.label = "PIN is Set!"
|
|
|
|
s.save()
|
|
|
|
await ux_dramatic_pause(msg, 3)
|
|
|
|
# Mk3 only
|
|
def set_countdown_pin_mode():
|
|
# cd_mode = various harm levels
|
|
s = SettingsObject()
|
|
which = s.get('cd_mode', 0) # default is brick
|
|
del s
|
|
|
|
ch = ['Brick', 'Final PIN', 'Test Mode']
|
|
|
|
def set(idx, text):
|
|
# save it, but "outside" of login PIN
|
|
s = SettingsObject()
|
|
s.set('cd_mode', idx)
|
|
s.save()
|
|
del s
|
|
|
|
return which, ch, set
|
|
|
|
# Mk3 only
|
|
async def countdown_pin_submenu(*a):
|
|
# Background and settings for duress-countdown pin
|
|
s = SettingsObject()
|
|
pin_set = bool(s.get('cd_pin', 0))
|
|
|
|
if not pin_set:
|
|
ok = await ux_show_story('''\
|
|
This special PIN will immediately and silently brick the Coldcard, \
|
|
but as it does that, it shows a normal-looking countdown timer for login. \
|
|
At the end of the countdown, the Coldcard crashes with a vague error. \
|
|
|
|
Instead of complete brick, you may select a test mode (no harm done) or \
|
|
to consume all but the final PIN attempt.\
|
|
''')
|
|
if not ok: return
|
|
|
|
|
|
return [
|
|
MenuItem('PIN is Set!' if pin_set else 'Enable Feature', f=set_countdown_pin),
|
|
MenuItem('Countdown Time', chooser=cd_countdown_chooser),
|
|
MenuItem('Brick Mode', chooser=set_countdown_pin_mode),
|
|
]
|
|
|
|
# EOF
|