Skip to content

Commit 3e99cfb

Browse files
authored
Move users menu into authentication submenu (#3678)
* Move users menu into authentication submenu * Tests * Update * Update
1 parent 725c3fe commit 3e99cfb

8 files changed

Lines changed: 72 additions & 68 deletions

File tree

archinstall/default_profiles/servers/docker.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ def services(self) -> list[str]:
2727
def post_install(self, install_session: 'Installer') -> None:
2828
from archinstall.lib.args import arch_config_handler
2929

30-
for user in arch_config_handler.config.users:
31-
install_session.arch_chroot(f'usermod -a -G docker {user.username}')
30+
if auth_config := arch_config_handler.config.auth_config:
31+
for user in auth_config.users:
32+
install_session.arch_chroot(f'usermod -a -G docker {user.username}')

archinstall/lib/args.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,15 @@ class ArchConfig:
7676
services: list[str] = field(default_factory=list)
7777
custom_commands: list[str] = field(default_factory=list)
7878

79-
# Special fields that should be handle with care due to security implications
80-
users: list[User] = field(default_factory=list)
81-
8279
def unsafe_json(self) -> dict[str, Any]:
83-
config: dict[str, list[UserSerialization] | str | None] = {
84-
'users': [user.json() for user in self.users],
85-
}
80+
config: dict[str, list[UserSerialization] | str | None] = {}
81+
82+
if self.auth_config:
83+
if self.auth_config.users:
84+
config['users'] = [user.json() for user in self.auth_config.users]
8685

87-
if self.auth_config and self.auth_config.root_enc_password:
88-
config['root_enc_password'] = self.auth_config.root_enc_password.enc_password
86+
if self.auth_config.root_enc_password:
87+
config['root_enc_password'] = self.auth_config.root_enc_password.enc_password
8988

9089
if self.disk_config:
9190
disk_encryption = self.disk_config.disk_encryption
@@ -177,13 +176,6 @@ def from_config(cls, args_config: dict[str, Any]) -> 'ArchConfig':
177176
if net_config := args_config.get('network_config', None):
178177
arch_config.network_config = NetworkConfiguration.parse_arg(net_config)
179178

180-
# DEPRECATED: backwards copatibility
181-
if users := args_config.get('!users', None):
182-
arch_config.users = User.parse_arguments(users)
183-
184-
if users := args_config.get('users', None):
185-
arch_config.users = User.parse_arguments(users)
186-
187179
if bootloader_config := args_config.get('bootloader', None):
188180
arch_config.bootloader = Bootloader.from_arg(bootloader_config)
189181

@@ -235,6 +227,19 @@ def from_config(cls, args_config: dict[str, Any]) -> 'ArchConfig':
235227
arch_config.auth_config = AuthenticationConfiguration()
236228
arch_config.auth_config.root_enc_password = root_password
237229

230+
# DEPRECATED: backwards copatibility
231+
users: list[User] = []
232+
if args_users := args_config.get('!users', None):
233+
users = User.parse_arguments(args_users)
234+
235+
if args_users := args_config.get('users', None):
236+
users = User.parse_arguments(args_users)
237+
238+
if users:
239+
if arch_config.auth_config is None:
240+
arch_config.auth_config = AuthenticationConfiguration()
241+
arch_config.auth_config.users = users
242+
238243
if custom_commands := args_config.get('custom_commands', []):
239244
arch_config.custom_commands = custom_commands
240245

archinstall/lib/authentication/authentication_handler.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,10 @@ def setup_auth(
1818
self,
1919
install_session: 'Installer',
2020
auth_config: AuthenticationConfiguration,
21-
users: list['User'],
2221
hostname: str,
2322
) -> None:
24-
if auth_config.u2f_config and users is not None:
25-
self._setup_u2f_login(install_session, auth_config.u2f_config, users, hostname)
23+
if auth_config.u2f_config and auth_config.users is not None:
24+
self._setup_u2f_login(install_session, auth_config.u2f_config, auth_config.users, hostname)
2625

2726
def _setup_u2f_login(self, install_session: 'Installer', u2f_config: U2FLoginConfiguration, users: list[User], hostname: str) -> None:
2827
self._configure_u2f_mapping(install_session, u2f_config, users, hostname)

archinstall/lib/authentication/authentication_menu.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from typing import override
22

33
from archinstall.lib.disk.fido import Fido2
4+
from archinstall.lib.interactions.manage_users_conf import ask_for_additional_users
45
from archinstall.lib.menu.abstract_menu import AbstractSubMenu
56
from archinstall.lib.models.authentication import AuthenticationConfiguration, U2FLoginConfiguration, U2FLoginMethod
6-
from archinstall.lib.models.users import Password
7+
from archinstall.lib.models.users import Password, User
8+
from archinstall.lib.output import FormattedOutput
79
from archinstall.lib.translationhandler import tr
810
from archinstall.lib.utils.util import get_password
911
from archinstall.tui.curses_menu import SelectMenu
@@ -41,6 +43,12 @@ def _define_menu_options(self) -> list[MenuItem]:
4143
preview_action=self._prev_root_pwd,
4244
key='root_enc_password',
4345
),
46+
MenuItem(
47+
text=tr('User account'),
48+
action=self._create_user_account,
49+
preview_action=self._prev_users,
50+
key='users',
51+
),
4452
MenuItem(
4553
text=tr('U2F login setup'),
4654
action=select_u2f_login,
@@ -50,6 +58,18 @@ def _define_menu_options(self) -> list[MenuItem]:
5058
),
5159
]
5260

61+
def _create_user_account(self, preset: list[User] | None = None) -> list[User]:
62+
preset = [] if preset is None else preset
63+
users = ask_for_additional_users(defined_users=preset)
64+
return users
65+
66+
def _prev_users(self, item: MenuItem) -> str | None:
67+
users: list[User] | None = item.value
68+
69+
if users:
70+
return FormattedOutput.as_table(users)
71+
return None
72+
5373
def _prev_root_pwd(self, item: MenuItem) -> str | None:
5474
if item.value is not None:
5575
password: Password = item.value

archinstall/lib/global_menu.py

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
ask_hostname,
2222
ask_ntp,
2323
)
24-
from .interactions.manage_users_conf import ask_for_additional_users
2524
from .interactions.network_menu import ask_to_configure_network
2625
from .interactions.system_conf import ask_for_bootloader, ask_for_swap, ask_for_uki, select_kernel
2726
from .locale.locale_menu import LocaleMenu
@@ -33,7 +32,6 @@
3332
from .models.network import NetworkConfiguration, NicType
3433
from .models.packages import Repository
3534
from .models.profile import ProfileConfiguration
36-
from .models.users import User
3735
from .output import FormattedOutput
3836
from .pacman.config import PacmanConfig
3937
from .translationhandler import Language, tr, translation_handler
@@ -115,12 +113,6 @@ def _get_menu_options(self) -> list[MenuItem]:
115113
preview_action=self._prev_authentication,
116114
key='auth_config',
117115
),
118-
MenuItem(
119-
text=tr('User account'),
120-
action=self._create_user_account,
121-
preview_action=self._prev_users,
122-
key='users',
123-
),
124116
MenuItem(
125117
text=tr('Profile'),
126118
action=self._select_profile,
@@ -207,24 +199,20 @@ def _safe_config(self) -> None:
207199
save_config(self._arch_config)
208200

209201
def _missing_configs(self) -> list[str]:
202+
item: MenuItem = self._item_group.find_by_key('auth_config')
203+
auth_config: AuthenticationConfiguration | None = item.value
204+
210205
def check(s: str) -> bool:
211206
item = self._item_group.find_by_key(s)
212207
return item.has_value()
213208

214209
def has_superuser() -> bool:
215-
item = self._item_group.find_by_key('users')
216-
217-
if item.has_value():
218-
users = item.value
219-
if users:
220-
return any([u.sudo for u in users])
210+
if auth_config and auth_config.users:
211+
return any([u.sudo for u in auth_config.users])
221212
return False
222213

223214
missing = set()
224215

225-
item: MenuItem = self._item_group.find_by_key('auth_config')
226-
auth_config: AuthenticationConfiguration | None = item.value
227-
228216
if (auth_config is None or auth_config.root_enc_password is None) and not has_superuser():
229217
missing.add(
230218
tr('Either root-password or at least 1 user with sudo privileges must be specified'),
@@ -312,6 +300,9 @@ def _prev_authentication(self, item: MenuItem) -> str | None:
312300
if auth_config.root_enc_password:
313301
output += f'{tr("Root password")}: {auth_config.root_enc_password.hidden()}\n'
314302

303+
if auth_config.users:
304+
output += FormattedOutput.as_table(auth_config.users) + '\n'
305+
315306
if auth_config.u2f_config:
316307
u2f_config = auth_config.u2f_config
317308
login_method = u2f_config.u2f_login_method.display_value()
@@ -475,13 +466,6 @@ def _prev_install_invalid_config(self, item: MenuItem) -> str | None:
475466

476467
return None
477468

478-
def _prev_users(self, item: MenuItem) -> str | None:
479-
users: list[User] | None = item.value
480-
481-
if users:
482-
return FormattedOutput.as_table(users)
483-
return None
484-
485469
def _prev_profile(self, item: MenuItem) -> str | None:
486470
profile_config: ProfileConfiguration | None = item.value
487471

@@ -543,11 +527,6 @@ def _select_additional_packages(self, preset: list[str]) -> list[str]:
543527

544528
return packages
545529

546-
def _create_user_account(self, preset: list[User] | None = None) -> list[User]:
547-
preset = [] if preset is None else preset
548-
users = ask_for_additional_users(defined_users=preset)
549-
return users
550-
551530
def _mirror_configuration(self, preset: MirrorConfiguration | None = None) -> MirrorConfiguration:
552531
mirror_configuration = MirrorMenu(preset=preset).run()
553532

archinstall/lib/models/authentication.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from dataclasses import dataclass
1+
from dataclasses import dataclass, field
22
from enum import Enum
33
from typing import Any, NotRequired, TypedDict
44

5-
from archinstall.lib.models.users import Password
5+
from archinstall.lib.models.users import Password, User
66
from archinstall.lib.translationhandler import tr
77

88

@@ -60,6 +60,7 @@ def parse_arg(args: U2FLoginConfigSerialization) -> 'U2FLoginConfiguration | Non
6060
@dataclass
6161
class AuthenticationConfiguration:
6262
root_enc_password: Password | None = None
63+
users: list[User] = field(default_factory=list)
6364
u2f_config: U2FLoginConfiguration | None = None
6465

6566
@staticmethod

archinstall/scripts/guided.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,10 @@ def perform_installation(mountpoint: Path) -> None:
114114
config.profile_config,
115115
)
116116

117-
if users := config.users:
118-
installation.create_users(users)
119-
120-
if config.auth_config and config.users:
121-
auth_handler.setup_auth(installation, config.auth_config, config.users, config.hostname)
117+
if config.auth_config:
118+
if config.auth_config.users:
119+
installation.create_users(config.auth_config.users)
120+
auth_handler.setup_auth(installation, config.auth_config, config.hostname)
122121

123122
if config.packages and config.packages[0] != '':
124123
installation.add_additional_packages(config.packages)

tests/test_args.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ def test_config_file_parsing(
135135
),
136136
auth_config=AuthenticationConfiguration(
137137
root_enc_password=Password(enc_password='password_hash'),
138+
users=[
139+
User(
140+
username='user_name',
141+
password=Password(enc_password='password_hash'),
142+
sudo=True,
143+
groups=['wheel'],
144+
),
145+
],
138146
u2f_config=U2FLoginConfiguration(
139147
u2f_login_method=U2FLoginMethod.Passwordless,
140148
passwordless_sudo=True,
@@ -215,14 +223,6 @@ def test_config_file_parsing(
215223
parallel_downloads=66,
216224
swap=False,
217225
timezone='UTC',
218-
users=[
219-
User(
220-
username='user_name',
221-
password=Password(enc_password='password_hash'),
222-
sudo=True,
223-
groups=['wheel'],
224-
),
225-
],
226226
services=['service_1', 'service_2'],
227227
custom_commands=["echo 'Hello, World!'"],
228228
)
@@ -283,7 +283,7 @@ def test_deprecated_creds_config_parsing(
283283
assert arch_config.auth_config is not None
284284
assert arch_config.auth_config.root_enc_password == Password(plaintext='rootPwd')
285285

286-
assert arch_config.users == [
286+
assert arch_config.auth_config.users == [
287287
User(
288288
username='user_name',
289289
password=Password(plaintext='userPwd'),
@@ -334,7 +334,7 @@ def test_encrypted_creds_with_arg(
334334

335335
assert arch_config.auth_config is not None
336336
assert arch_config.auth_config.root_enc_password == Password(enc_password='$y$j9T$FWCInXmSsS.8KV4i7O50H.$Hb6/g.Sw1ry888iXgkVgc93YNuVk/Rw94knDKdPVQw7')
337-
assert arch_config.users == [
337+
assert arch_config.auth_config.users == [
338338
User(
339339
username='t',
340340
password=Password(enc_password='$y$j9T$3KxMigAEnjtzbjalhLewE.$gmuoQtc9RNY/PmO/GxHHYvkZNO86Eeftg1Oc7L.QSO/'),
@@ -363,7 +363,7 @@ def test_encrypted_creds_with_env_var(
363363

364364
assert arch_config.auth_config is not None
365365
assert arch_config.auth_config.root_enc_password == Password(enc_password='$y$j9T$FWCInXmSsS.8KV4i7O50H.$Hb6/g.Sw1ry888iXgkVgc93YNuVk/Rw94knDKdPVQw7')
366-
assert arch_config.users == [
366+
assert arch_config.auth_config.users == [
367367
User(
368368
username='t',
369369
password=Password(enc_password='$y$j9T$3KxMigAEnjtzbjalhLewE.$gmuoQtc9RNY/PmO/GxHHYvkZNO86Eeftg1Oc7L.QSO/'),

0 commit comments

Comments
 (0)