Fixed many instances where the curses menus could break the terminal session

Former-commit-id: df73403b4a8bc3ffb238486516d0f1e5a1f601c6
Former-commit-id: 649503907f391ff318fc0d3247b965ed3b2aacba
This commit is contained in:
2023-07-07 15:06:57 -04:00
parent 4ad516e156
commit ee56a7a919
3 changed files with 154 additions and 169 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ from os import listdir, remove, walk
from os.path import expanduser, isdir, isfile, getmtime, join from os.path import expanduser, isdir, isfile, getmtime, join
from subprocess import CalledProcessError, PIPE, run from subprocess import CalledProcessError, PIPE, run
from sys import exit as s_exit from sys import exit as s_exit
home = expanduser("~") home = expanduser('~')
# PORT START SSHYNC-REMOTE # PORT START SSHYNC-REMOTE
+7 -7
View File
@@ -10,7 +10,7 @@ from sys import argv, exit as s_exit
# PORT START UNAME-IMPORT-SSHYP # PORT START UNAME-IMPORT-SSHYP
from os import uname from os import uname
# PORT END UNAME-IMPORT-SSHYP # PORT END UNAME-IMPORT-SSHYP
home = expanduser("~") home = expanduser('~')
# UTILITY FUNCTIONS # UTILITY FUNCTIONS
@@ -652,8 +652,8 @@ if __name__ == "__main__":
print(f"{73*'!'}\n") print(f"{73*'!'}\n")
s_exit(1) s_exit(1)
else: else:
from stweak import initial_setup from stweak import wrapped_entry
initial_setup() wrapped_entry(False)
s_exit() s_exit()
# run function based on arguments # run function based on arguments
@@ -702,8 +702,8 @@ if __name__ == "__main__":
read_shortcut() read_shortcut()
elif arguments[0] == 'tweak': elif arguments[0] == 'tweak':
success_flag = True success_flag = True
from stweak import global_menu from stweak import wrapped_entry
global_menu('client', 'configuration options:') wrapped_entry(device_type)
# PORT START ARGS-SERVER # PORT START ARGS-SERVER
# server arguments # server arguments
@@ -713,8 +713,8 @@ if __name__ == "__main__":
print_info() print_info()
elif arg_count == 1 and arguments[0] == 'tweak': elif arg_count == 1 and arguments[0] == 'tweak':
success_flag = True success_flag = True
from stweak import global_menu from stweak import wrapped_entry
global_menu('server', 'configuration options:') wrapped_entry(device_type)
# PORT END ARGS-SERVER # PORT END ARGS-SERVER
if arg_count > 0 and success_flag == 0 and arguments[0] != 'sync': if arg_count > 0 and success_flag == 0 and arguments[0] != 'sync':
+45 -60
View File
@@ -10,7 +10,7 @@ from subprocess import PIPE, run
# PORT START UNAME-IMPORT-STWEAK # PORT START UNAME-IMPORT-STWEAK
from os import uname from os import uname
# PORT END UNAME-IMPORT-STWEAK # PORT END UNAME-IMPORT-STWEAK
home, stdscr, sshyp_data = expanduser("~"), initscr(), ConfigParser() home, sshyp_data, stdscr, term_messages = expanduser('~'), ConfigParser(), None, []
if isfile(f"{home}/.config/sshyp/sshyp.ini"): if isfile(f"{home}/.config/sshyp/sshyp.ini"):
_exists_flag = True _exists_flag = True
sshyp_data.read(f"{home}/.config/sshyp/sshyp.ini") sshyp_data.read(f"{home}/.config/sshyp/sshyp.ini")
@@ -66,15 +66,6 @@ def curses_text(_pretext):
return _box.gather().strip() return _box.gather().strip()
# cleanly exit curses and optionally prints an exit message
def curses_terminate(_term_message):
nocbreak()
echo()
endwin()
if _term_message:
print(_term_message)
# device+sync type selection # device+sync type selection
def install_type(): def install_type():
_offline_mode = 'false' _offline_mode = 'false'
@@ -86,7 +77,7 @@ def install_type():
_dev_type = 'server' _dev_type = 'server'
Path(f"{home}/.config/sshyp/deleted").mkdir(mode=0o700, exist_ok=True) Path(f"{home}/.config/sshyp/deleted").mkdir(mode=0o700, exist_ok=True)
Path(f"{home}/.config/sshyp/whitelist").mkdir(mode=0o700, exist_ok=True) Path(f"{home}/.config/sshyp/whitelist").mkdir(mode=0o700, exist_ok=True)
curses_terminate('\nmake sure the ssh service is running and properly configured\n') term_messages.append('make sure the ssh service is running and properly configured')
else: else:
_dev_type = 'client' _dev_type = 'client'
if _install_type == 1: if _install_type == 1:
@@ -260,7 +251,6 @@ def refresh_encryption():
# decrypt, optimize, and re-encrypt each entry with the newly selected key # decrypt, optimize, and re-encrypt each entry with the newly selected key
if isdir(_directory): if isdir(_directory):
curses_terminate('\noptimizing and re-encrypting entries... please wait - do not terminate this process')
_gpg_id = sshyp_data.get('CLIENT-GENERAL', 'gpg_id') _gpg_id = sshyp_data.get('CLIENT-GENERAL', 'gpg_id')
for _root, _dirs, _files in sorted(walk(_directory, topdown=True)): for _root, _dirs, _files in sorted(walk(_directory, topdown=True)):
for _filename in _files: for _filename in _files:
@@ -369,7 +359,7 @@ def extension_downloader():
_extensions.append('CANCEL') _extensions.append('CANCEL')
_choice = curses_radio(_extensions, 'select an extension for more info') _choice = curses_radio(_extensions, 'select an extension for more info')
if _choice == len(_extensions)-1: if _choice == len(_extensions)-1:
return False, False return False
_selected = _extensions[_choice] _selected = _extensions[_choice]
_choice = curses_radio(('no', 'yes'), f"install {_selected}?\n\n\n\n\ndescription: " _choice = curses_radio(('no', 'yes'), f"install {_selected}?\n\n\n\n\ndescription: "
f"{_pointer.get(_selected, 'desc')}\n\nusage: " f"{_pointer.get(_selected, 'desc')}\n\nusage: "
@@ -383,8 +373,8 @@ def extension_downloader():
# set permissions under active user # set permissions under active user
chmod(_exe_dir, 0o755) chmod(_exe_dir, 0o755)
chmod(_ini_dir, 0o644) chmod(_ini_dir, 0o644)
return False, _selected return _selected
return False, False return False
# uninstalls/deletes selected extensions # uninstalls/deletes selected extensions
@@ -395,16 +385,16 @@ def extension_remover():
_installed.append('CANCEL') _installed.append('CANCEL')
_choice = curses_radio(_installed, 'select an extension to uninstall') _choice = curses_radio(_installed, 'select an extension to uninstall')
if _choice == len(_installed)-1: if _choice == len(_installed)-1:
return False, False return False
_sure = curses_radio(('no', 'yes'), f"are you sure you want to remove {_installed[_choice]}?") _sure = curses_radio(('no', 'yes'), f"are you sure you want to remove {_installed[_choice]}?")
if _sure == 0: if _sure == 0:
return False, False return False
return False, _installed[_choice] return _installed[_choice]
# provides options for managing extensions # provides options for managing extensions
def extension_menu(): def extension_menu():
_term_message, _ext_name, _action = False, False, False _ext_name, _action = False, False
# determine which of the supported privilege escalation utilities is installed # determine which of the supported privilege escalation utilities is installed
if which('doas') is not None: if which('doas') is not None:
_escalator = 'doas' _escalator = 'doas'
@@ -417,30 +407,29 @@ def extension_menu():
while True: while True:
_choice = curses_radio(('download/update extensions', 'remove extensions', 'BACK'), 'extension management') _choice = curses_radio(('download/update extensions', 'remove extensions', 'BACK'), 'extension management')
if _choice == 0: if _choice == 0:
_term_message, _ext_name = extension_downloader() _ext_name = extension_downloader()
if _ext_name: if _ext_name:
# True represents installation # True represents installation
_action = True _action = True
break break
elif _choice == 1: elif _choice == 1:
_term_message, _ext_name = extension_remover() _ext_name = extension_remover()
if _ext_name: if _ext_name:
break break
else: else:
break break
return _term_message, _ext_name, _escalator, _action return _ext_name, _escalator, _action
# runs secondary configuration menu # runs secondary configuration menu
def global_menu(_device_type, _top_message): def global_menu(_scr, _device_type, _top_message):
while True: global stdscr
# curses initialization # only set global stdscr if running as entry point
noecho() if not isinstance(_scr, bool):
cbreak() stdscr = _scr
stdscr.keypad(True)
_options, _choice, _term_message, _exit_signal = ['change device/synchronization types'], 0, False, False while True:
try: _options, _choice, _exit_signal = ['change device/synchronization types'], 0, False
if _device_type == 'client': if _device_type == 'client':
_options.extend(['change gpg key', 're-configure ssh(ync)', 'change device name', _options.extend(['change gpg key', 're-configure ssh(ync)', 'change device name',
'[OPTIONAL, RECOMMENDED] set custom text editor', '[OPTIONAL, RECOMMENDED] set custom text editor',
@@ -498,23 +487,22 @@ def global_menu(_device_type, _top_message):
elif _choice == 5: elif _choice == 5:
_enabled = quick_unlock_config(False) _enabled = quick_unlock_config(False)
if _enabled == 'true': if _enabled == 'true':
_term_message = ('\nquick-unlock has been enabled client-side - in order for this feature to ' term_messages.append('quick-unlock has been enabled client-side - in order for this feature to '
'function,\nyou must first log in to the sshyp server and run:\n\nsshyp tweak\n\n' 'function,\nyou must first log in to the sshyp server and run:\n\nsshyp tweak\n\n'
'from there you can create a quick-unlock pin and add this device to the ' 'from there you can create a quick-unlock pin and add this device to the '
'whitelist\n') 'whitelist')
elif _choice == 6: elif _choice == 6:
_success = refresh_encryption() _success = refresh_encryption()
if _success == 1: if _success == 1:
_term_message = "\na backup of your previous entry directory has been created:\n\n" \ term_messages.append("a backup of your previous entry directory has been created:\n\n"
f"{home}/.local/share/sshyp.old\n" f"{home}/.local/share/sshyp.old")
elif _success == 2: elif _success == 2:
_term_message = '\n\u001b[38;5;9merror: re-encryption failed: ' \ term_messages.append('\u001b[38;5;9merror: re-encryption failed: '
'entry directory not found\u001b[0m\n' 'entry directory not found\u001b[0m')
elif _choice == 7: elif _choice == 7:
_term_message, _ext_name, _escalator, _action = extension_menu() _ext_name, _escalator, _action = extension_menu()
else: else:
_exit_signal = True _exit_signal = True
curses_terminate(_term_message)
# if root is needed for extension management... # if root is needed for extension management...
if _choice == 7 and _ext_name: if _choice == 7 and _ext_name:
if _action: if _action:
@@ -528,15 +516,15 @@ def global_menu(_device_type, _top_message):
# uninstall with privilege escalation (outside of curses) # uninstall with privilege escalation (outside of curses)
run((_escalator, 'rm', '-I', f"/usr/lib/sshyp/{_ext_name}", f"/usr/lib/sshyp/extensions/{_ext_name}.ini")) run((_escalator, 'rm', '-I', f"/usr/lib/sshyp/{_ext_name}", f"/usr/lib/sshyp/extensions/{_ext_name}.ini"))
break break
except KeyboardInterrupt:
curses_terminate(False)
_exit_signal = True
if _exit_signal: if _exit_signal:
break break
# runs initial configuration wizard # runs initial configuration wizard
def initial_setup(): def initial_setup(_scr):
global stdscr
stdscr = _scr
# required directory creation # required directory creation
Path(f"{home}/.config/sshyp/devices").mkdir(mode=0o700, parents=True, exist_ok=True) Path(f"{home}/.config/sshyp/devices").mkdir(mode=0o700, parents=True, exist_ok=True)
Path(f"{home}/.local/share/sshyp").mkdir(mode=0o700, parents=True, exist_ok=True) Path(f"{home}/.local/share/sshyp").mkdir(mode=0o700, parents=True, exist_ok=True)
@@ -545,13 +533,7 @@ def initial_setup():
if _exists_flag: if _exists_flag:
sshyp_data.clear() sshyp_data.clear()
# curses initialization
noecho()
cbreak()
stdscr.keypad(True)
# curses menu tree # curses menu tree
try:
# device+sync type selection # device+sync type selection
_dev_sync_types = install_type() _dev_sync_types = install_type()
@@ -575,14 +557,7 @@ def initial_setup():
# device id configuration # device id configuration
dev_id_config(_ip, _username_ssh, _port) dev_id_config(_ip, _username_ssh, _port)
# cleanly exit curses # PORT START CLIPTOOL TODO fix printing with new curses wrapper
curses_terminate(False)
else:
# cleanly exit curses
curses_terminate(False)
# PORT START CLIPTOOL
# check for clipboard tool and display warning if missing # check for clipboard tool and display warning if missing
if uname()[0] in ('Linux', 'FreeBSD') and 'WSL_DISTRO_NAME' not in environ \ if uname()[0] in ('Linux', 'FreeBSD') and 'WSL_DISTRO_NAME' not in environ \
and not exists("/data/data/com.termux"): and not exists("/data/data/com.termux"):
@@ -597,8 +572,18 @@ def initial_setup():
f'"{_clipboard_package}" is installed\u001b[0m') f'"{_clipboard_package}" is installed\u001b[0m')
# PORT END CLIPTOOL # PORT END CLIPTOOL
global_menu(_dev_sync_types[0], 'additional configuration options:') # run optional configuration menu
wrapped_entry(_dev_sync_types[0], 'additional configuration options:')
except KeyboardInterrupt:
# cleanly exit curses # runs the specified entry function (menu start point) within a curses wrapper
curses_terminate(False) def wrapped_entry(_gm_device_type, _gm_top_message='configuration options:'):
from curses import wrapper, use_default_colors
# a boolean value represents init
if isinstance(_gm_device_type, bool):
wrapper(lambda _wrap_stdscr: (use_default_colors(), initial_setup(_wrap_stdscr)))
# any other vlaue will be provided as the global menu device type
else:
wrapper(lambda _wrap_stdscr: (use_default_colors(), global_menu(_wrap_stdscr, _gm_device_type, _gm_top_message)))
for _message in term_messages:
print(f"\n{_message}\n")