Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall
diff options
context:
space:
mode:
authorWerner Llácer <wllacer@gmail.com>2022-02-28 23:11:25 +0100
committerGitHub <noreply@github.com>2022-02-28 23:11:25 +0100
commit86d991f4422d920ca714f459be3be4352d1c40a1 (patch)
tree256ec13a6e92c8e1fbf0aeee718ca3e0ef8533b0 /archinstall
parent76a6c378936afd9e68f9a39246480d7f8d2b75be (diff)
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>
Diffstat (limited to 'archinstall')
-rw-r--r--archinstall/lib/menu/selection_menu.py11
-rw-r--r--archinstall/lib/user_interaction.py139
2 files changed, 132 insertions, 18 deletions
diff --git a/archinstall/lib/menu/selection_menu.py b/archinstall/lib/menu/selection_menu.py
index 99015fad..8ac7dc99 100644
--- a/archinstall/lib/menu/selection_menu.py
+++ b/archinstall/lib/menu/selection_menu.py
@@ -497,6 +497,7 @@ class GlobalMenu(GeneralMenu):
Selector(
_('Specify superuser account'),
lambda preset: self._create_superuser_account(),
+ exec_func=lambda n,v:self._users_resynch(),
dependencies_not=['!root-password'],
display_func=lambda x: self._display_superusers())
self._menu_options['!users'] = \
@@ -504,6 +505,7 @@ class GlobalMenu(GeneralMenu):
_('Specify user account'),
lambda x: self._create_user_account(),
default={},
+ exec_func=lambda n,v:self._users_resynch(),
display_func=lambda x: list(x.keys()) if x else '[]')
self._menu_options['profile'] = \
Selector(
@@ -668,11 +670,11 @@ class GlobalMenu(GeneralMenu):
return profile
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
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
def _display_superusers(self):
@@ -682,3 +684,8 @@ class GlobalMenu(GeneralMenu):
return list(superusers.keys()) if superusers else '[]'
else:
return list(superusers.keys()) if superusers else ''
+
+ def _users_resynch(self):
+ self.synch('!superusers')
+ self.synch('!users')
+ return False \ No newline at end of file
diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py
index f0260488..c6f3eef7 100644
--- a/archinstall/lib/user_interaction.py
+++ b/archinstall/lib/user_interaction.py
@@ -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 .networking import list_interfaces
from .menu import Menu
+from .menu.list_manager import ListManager
from .output import log
from .profiles import Profile, list_profiles
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]]:
- prompt = prompt if prompt else str(_('Enter username for superuser with sudo privileges (leave blank for no superusers): '))
- superusers = ask_for_additional_users(prompt)
+ prompt = prompt if prompt else str(_('Define users with sudo privilege: '))
+ superusers,dummy = manage_users(prompt,sudo=True)
return superusers
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): ')
- users = {}
-
- 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}
-
+ dummy,users = manage_users(prompt,sudo=False)
return users
@@ -1174,6 +1163,124 @@ def generic_multi_select(p_options :Union[list,dict],
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 preview(selection: str):
if options['user_config'] == selection:
@@ -1235,4 +1342,4 @@ def save_config(config: Dict):
elif options['all'] == selection:
config_output.save_user_config(dest_path)
config_output.save_user_creds(dest_path)
- config_output.save_disk_layout(dest_path)
+ config_output.save_disk_layout