User Management via lists (#1008)
* Fix user/superuser config * Fix flake8 * Remove timezone check since we have a default value now * Remove unused * add new widget ListManager * flake8 complains * Null_action appears now in the main list (to simplify additions to the list) Formatted data are now at the from to the actions submenu * Manage users thru a ListManagers * Define a default action in the menu, potentially independent of a null_action Both default and null actions don't have to be part of the element's action list Some cleanup Co-authored-by: Daniel Girtler <girtler.daniel@gmail.com> Co-authored-by: Anton Hvornum <anton.feeds@gmail.com> Co-authored-by: Anton Hvornum <anton@hvornum.se>
This commit is contained in:
parent
76a6c37893
commit
86d991f442
|
|
@ -497,6 +497,7 @@ class GlobalMenu(GeneralMenu):
|
||||||
Selector(
|
Selector(
|
||||||
_('Specify superuser account'),
|
_('Specify superuser account'),
|
||||||
lambda preset: self._create_superuser_account(),
|
lambda preset: self._create_superuser_account(),
|
||||||
|
exec_func=lambda n,v:self._users_resynch(),
|
||||||
dependencies_not=['!root-password'],
|
dependencies_not=['!root-password'],
|
||||||
display_func=lambda x: self._display_superusers())
|
display_func=lambda x: self._display_superusers())
|
||||||
self._menu_options['!users'] = \
|
self._menu_options['!users'] = \
|
||||||
|
|
@ -504,6 +505,7 @@ class GlobalMenu(GeneralMenu):
|
||||||
_('Specify user account'),
|
_('Specify user account'),
|
||||||
lambda x: self._create_user_account(),
|
lambda x: self._create_user_account(),
|
||||||
default={},
|
default={},
|
||||||
|
exec_func=lambda n,v:self._users_resynch(),
|
||||||
display_func=lambda x: list(x.keys()) if x else '[]')
|
display_func=lambda x: list(x.keys()) if x else '[]')
|
||||||
self._menu_options['profile'] = \
|
self._menu_options['profile'] = \
|
||||||
Selector(
|
Selector(
|
||||||
|
|
@ -668,11 +670,11 @@ class GlobalMenu(GeneralMenu):
|
||||||
return profile
|
return profile
|
||||||
|
|
||||||
def _create_superuser_account(self):
|
def _create_superuser_account(self):
|
||||||
superusers = ask_for_superuser_account(str(_('Enter a username to create an additional superuser (leave blank to skip): ')))
|
superusers = ask_for_superuser_account(str(_('Manage superuser accounts: ')))
|
||||||
return superusers if superusers else None
|
return superusers if superusers else None
|
||||||
|
|
||||||
def _create_user_account(self):
|
def _create_user_account(self):
|
||||||
users = ask_for_additional_users(str(_('Enter a username to create an additional user (leave blank to skip): ')))
|
users = ask_for_additional_users(str(_('Manage ordinary user accounts: ')))
|
||||||
return users
|
return users
|
||||||
|
|
||||||
def _display_superusers(self):
|
def _display_superusers(self):
|
||||||
|
|
@ -682,3 +684,8 @@ class GlobalMenu(GeneralMenu):
|
||||||
return list(superusers.keys()) if superusers else '[]'
|
return list(superusers.keys()) if superusers else '[]'
|
||||||
else:
|
else:
|
||||||
return list(superusers.keys()) if superusers else ''
|
return list(superusers.keys()) if superusers else ''
|
||||||
|
|
||||||
|
def _users_resynch(self):
|
||||||
|
self.synch('!superusers')
|
||||||
|
self.synch('!users')
|
||||||
|
return False
|
||||||
|
|
@ -28,6 +28,7 @@ from .hardware import AVAILABLE_GFX_DRIVERS, has_uefi, has_amd_graphics, has_int
|
||||||
from .locale_helpers import list_keyboard_languages, list_timezones, list_locales
|
from .locale_helpers import list_keyboard_languages, list_timezones, list_locales
|
||||||
from .networking import list_interfaces
|
from .networking import list_interfaces
|
||||||
from .menu import Menu
|
from .menu import Menu
|
||||||
|
from .menu.list_manager import ListManager
|
||||||
from .output import log
|
from .output import log
|
||||||
from .profiles import Profile, list_profiles
|
from .profiles import Profile, list_profiles
|
||||||
from .storage import storage
|
from .storage import storage
|
||||||
|
|
@ -336,26 +337,14 @@ def ask_hostname(preset :str = None) -> str :
|
||||||
|
|
||||||
|
|
||||||
def ask_for_superuser_account(prompt: str) -> Dict[str, Dict[str, str]]:
|
def ask_for_superuser_account(prompt: str) -> Dict[str, Dict[str, str]]:
|
||||||
prompt = prompt if prompt else str(_('Enter username for superuser with sudo privileges (leave blank for no superusers): '))
|
prompt = prompt if prompt else str(_('Define users with sudo privilege: '))
|
||||||
superusers = ask_for_additional_users(prompt)
|
superusers,dummy = manage_users(prompt,sudo=True)
|
||||||
return superusers
|
return superusers
|
||||||
|
|
||||||
|
|
||||||
def ask_for_additional_users(prompt :str = '') -> Dict[str, Dict[str, str | None]]:
|
def ask_for_additional_users(prompt :str = '') -> Dict[str, Dict[str, str | None]]:
|
||||||
prompt = prompt if prompt else _('Any additional users to install (leave blank for no users): ')
|
prompt = prompt if prompt else _('Any additional users to install (leave blank for no users): ')
|
||||||
users = {}
|
dummy,users = manage_users(prompt,sudo=False)
|
||||||
|
|
||||||
while 1:
|
|
||||||
new_user = input(prompt).strip(' ')
|
|
||||||
if not new_user:
|
|
||||||
break
|
|
||||||
if not check_for_correct_username(new_user):
|
|
||||||
continue
|
|
||||||
|
|
||||||
password_prompt = str(_('Password for user "{}": ').format(new_user))
|
|
||||||
password = get_password(prompt=password_prompt)
|
|
||||||
users[new_user] = {"!password": password}
|
|
||||||
|
|
||||||
return users
|
return users
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1174,6 +1163,124 @@ def generic_multi_select(p_options :Union[list,dict],
|
||||||
default=default)
|
default=default)
|
||||||
|
|
||||||
|
|
||||||
|
class UserList(ListManager):
|
||||||
|
"""
|
||||||
|
subclass of ListManager for the managing of user accounts
|
||||||
|
"""
|
||||||
|
def __init__(self,prompt :str, lusers :dict, sudo :bool = None):
|
||||||
|
"""
|
||||||
|
param: prompt
|
||||||
|
type: str
|
||||||
|
param: lusers dict with the users already defined for the system
|
||||||
|
type: Dict
|
||||||
|
param: sudo. boolean to determine if we handle superusers or users. If None handles both types
|
||||||
|
"""
|
||||||
|
self.sudo = sudo
|
||||||
|
self.actions = [
|
||||||
|
str(_('Add an user')),
|
||||||
|
str(_('Change password')),
|
||||||
|
str(_('Promote/Demote user')),
|
||||||
|
str(_('Delete User'))
|
||||||
|
]
|
||||||
|
self.default_action = self.actions[0]
|
||||||
|
super().__init__(prompt,lusers,self.actions,self.default_action)
|
||||||
|
|
||||||
|
def reformat(self):
|
||||||
|
def format_element(elem):
|
||||||
|
# secret gives away the length of the password
|
||||||
|
if self.data[elem].get('!password'):
|
||||||
|
pwd = '*' * 16
|
||||||
|
# pwd = archinstall.secret(self.data[elem]['!password'])
|
||||||
|
else:
|
||||||
|
pwd = ''
|
||||||
|
if self.data[elem].get('sudoer'):
|
||||||
|
super = 'Superuser'
|
||||||
|
else:
|
||||||
|
super = ' '
|
||||||
|
return f"{elem:16}: password {pwd:16} {super}"
|
||||||
|
return list(map(lambda x:format_element(x),self.data))
|
||||||
|
|
||||||
|
def action_list(self):
|
||||||
|
if self.target:
|
||||||
|
active_user = list(self.target.keys())[0]
|
||||||
|
else:
|
||||||
|
active_user = None
|
||||||
|
sudoer = self.target[active_user].get('sudoer',False)
|
||||||
|
if self.sudo is None:
|
||||||
|
return self.actions
|
||||||
|
if self.sudo and sudoer:
|
||||||
|
return self.actions
|
||||||
|
elif self.sudo and not sudoer:
|
||||||
|
return [self.actions[2]]
|
||||||
|
elif not self.sudo and sudoer:
|
||||||
|
return [self.actions[2]]
|
||||||
|
else:
|
||||||
|
return self.actions
|
||||||
|
|
||||||
|
def exec_action(self):
|
||||||
|
if self.target:
|
||||||
|
active_user = list(self.target.keys())[0]
|
||||||
|
else:
|
||||||
|
active_user = None
|
||||||
|
|
||||||
|
if self.action == self.actions[0]: # add
|
||||||
|
new_user = self.add_user()
|
||||||
|
# no unicity check, if exists will be replaced
|
||||||
|
self.data.update(new_user)
|
||||||
|
elif self.action == self.actions[1]: # change password
|
||||||
|
self.data[active_user]['!password'] = get_password(prompt=str(_('Password for user "{}": ').format(active_user)))
|
||||||
|
elif self.action == self.actions[2]: # promote/demote
|
||||||
|
self.data[active_user]['sudoer'] = not self.data[active_user]['sudoer']
|
||||||
|
elif self.action == self.actions[3]: # delete
|
||||||
|
del self.data[active_user]
|
||||||
|
|
||||||
|
def add_user(self):
|
||||||
|
print(_('\nDefine a new user\n'))
|
||||||
|
prompt = str(_("User Name : "))
|
||||||
|
while True:
|
||||||
|
userid = input(prompt).strip(' ')
|
||||||
|
if not userid:
|
||||||
|
return {} # end
|
||||||
|
if not check_for_correct_username(userid):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if self.sudo:
|
||||||
|
sudoer = True
|
||||||
|
elif self.sudo is not None and not self.sudo:
|
||||||
|
sudoer = False
|
||||||
|
else:
|
||||||
|
sudoer = False
|
||||||
|
sudo_choice = Menu(
|
||||||
|
str(_('Should {} be a superuser (sudoer)?')).format(userid),
|
||||||
|
['yes', 'no'],
|
||||||
|
skip=False,
|
||||||
|
preset_values='yes' if sudoer else 'no',
|
||||||
|
default_option='no'
|
||||||
|
).run()
|
||||||
|
sudoer = True if sudo_choice == 'yes' else False
|
||||||
|
|
||||||
|
password = get_password(prompt=str(_('Password for user "{}": ').format(userid)))
|
||||||
|
|
||||||
|
return {userid :{"!password":password, "sudoer":sudoer}}
|
||||||
|
|
||||||
|
def manage_users(prompt :str, sudo :bool) -> tuple[dict, dict]:
|
||||||
|
|
||||||
|
# TODO Filtering and some kind of simpler code
|
||||||
|
lusers = {}
|
||||||
|
if storage['arguments'].get('!superusers',{}):
|
||||||
|
lusers.update({uid: {'!password':storage['arguments']['!superusers'][uid].get('!password'), 'sudoer':True} for uid in storage['arguments'].get('!superusers',{})})
|
||||||
|
if storage['arguments'].get('!users',{}):
|
||||||
|
lusers.update({uid: {'!password':storage['arguments']['!users'][uid].get('!password'), 'sudoer':False} for uid in storage['arguments'].get('!users',{})})
|
||||||
|
# processing
|
||||||
|
lusers = UserList(prompt,lusers,sudo).run()
|
||||||
|
# return data
|
||||||
|
superusers = {uid: {'!password':lusers[uid].get('!password')} for uid in lusers if lusers[uid].get('sudoer',False)}
|
||||||
|
users = {uid: {'!password':lusers[uid].get('!password')} for uid in lusers if not lusers[uid].get('sudoer',False)}
|
||||||
|
storage['arguments']['!superusers'] = superusers
|
||||||
|
storage['arguments']['!users'] = users
|
||||||
|
return superusers,users
|
||||||
|
|
||||||
def save_config(config: Dict):
|
def save_config(config: Dict):
|
||||||
def preview(selection: str):
|
def preview(selection: str):
|
||||||
if options['user_config'] == selection:
|
if options['user_config'] == selection:
|
||||||
|
|
@ -1235,4 +1342,4 @@ def save_config(config: Dict):
|
||||||
elif options['all'] == selection:
|
elif options['all'] == selection:
|
||||||
config_output.save_user_config(dest_path)
|
config_output.save_user_config(dest_path)
|
||||||
config_output.save_user_creds(dest_path)
|
config_output.save_user_creds(dest_path)
|
||||||
config_output.save_disk_layout(dest_path)
|
config_output.save_disk_layout
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue