Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ repos:
- pydantic
- pydantic-settings
- pytest
- bcrypt
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.2
hooks:
Expand Down
1 change: 1 addition & 0 deletions PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ depends=(
'pciutils'
'procps-ng'
'python'
'python-bcrypt'
'python-pydantic'
'python-pyparted'
'systemd'
Expand Down
30 changes: 18 additions & 12 deletions archinstall/lib/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from archinstall.lib.models.mirrors import MirrorConfiguration
from archinstall.lib.models.network_configuration import NetworkConfiguration
from archinstall.lib.models.profile_model import ProfileConfiguration
from archinstall.lib.models.users import User
from archinstall.lib.models.users import Password, User
from archinstall.lib.output import error, warn
from archinstall.lib.plugins import load_plugin
from archinstall.lib.storage import storage
Expand Down Expand Up @@ -71,16 +71,16 @@ class ArchConfig:
# Special fields that should be handle with care due to security implications
users: list[User] = field(default_factory=list)
disk_encryption: DiskEncryption | None = None
root_password: str | None = None
root_enc_password: Password | None = None

def unsafe_json(self) -> dict[str, Any]:
config = {
'!users': [user.json() for user in self.users],
'!root-password': self.root_password,
'users': [user.json() for user in self.users],
'root_enc_password': self.root_enc_password.enc_password if self.root_enc_password else None,
}

if self.disk_encryption:
config['encryption_password'] = self.disk_encryption.encryption_password
if self.disk_encryption and self.disk_encryption.encryption_password:
config['encryption_password'] = self.disk_encryption.encryption_password.plaintext

return config

Expand Down Expand Up @@ -149,10 +149,12 @@ def from_config(cls, args_config: dict[str, Any]) -> 'ArchConfig':
if net_config := args_config.get('network_config', None):
arch_config.network_config = NetworkConfiguration.parse_arg(net_config)

users = args_config.get('!users', None)
superusers = args_config.get('!superusers', None)
if users is not None or superusers is not None:
arch_config.users = User.parse_arguments(users, superusers)
# DEPRECATED: backwards copatibility
if users := args_config.get('!users', None):
arch_config.users = User.parse_arguments(users)

if users := args_config.get('users', None):
arch_config.users = User.parse_arguments(users)

if bootloader_config := args_config.get('bootloader', None):
arch_config.bootloader = Bootloader.from_arg(bootloader_config)
Expand All @@ -167,7 +169,7 @@ def from_config(cls, args_config: dict[str, Any]) -> 'ArchConfig':
arch_config.disk_encryption = DiskEncryption.parse_arg(
arch_config.disk_config,
args_config['disk_encryption'],
args_config.get('encryption_password', '')
Password(plaintext=args_config.get('encryption_password', ''))
)

if hostname := args_config.get('hostname', ''):
Expand All @@ -193,8 +195,12 @@ def from_config(cls, args_config: dict[str, Any]) -> 'ArchConfig':
if services := args_config.get('services', []):
arch_config.services = services

# DEPRECATED: backwards compatibility
if root_password := args_config.get('!root-password', None):
arch_config.root_password = root_password
arch_config.root_enc_password = Password(plaintext=root_password)

if enc_password := args_config.get('root_enc_password', None):
arch_config.root_enc_password = Password(enc_password=enc_password)

if custom_commands := args_config.get('custom_commands', []):
arch_config.custom_commands = custom_commands
Expand Down
13 changes: 11 additions & 2 deletions archinstall/lib/disk/device_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
_DeviceInfo,
_PartitionInfo,
)
from ..models.users import Password
from ..output import debug, error, info, log
from ..utils.util import is_subpath
from .utils import (
Expand Down Expand Up @@ -307,7 +308,7 @@ def encrypt(
self,
dev_path: Path,
mapper_name: str | None,
enc_password: str,
enc_password: Password | None,
lock_after_create: bool = True
) -> Luks2:
luks_handler = Luks2(
Expand Down Expand Up @@ -338,6 +339,9 @@ def format_encrypted(
fs_type: FilesystemType,
enc_conf: DiskEncryption
) -> None:
if not enc_conf.encryption_password:
raise ValueError('No encryption password provided')

luks_handler = Luks2(
dev_path,
mapper_name=mapper_name,
Expand Down Expand Up @@ -678,7 +682,12 @@ def create_btrfs_volumes(
if luks_handler is not None and luks_handler.mapper_dev is not None:
luks_handler.lock()

def unlock_luks2_dev(self, dev_path: Path, mapper_name: str, enc_password: str) -> Luks2:
def unlock_luks2_dev(
self,
dev_path: Path,
mapper_name: str,
enc_password: Password | None
) -> Luks2:
luks_handler = Luks2(dev_path, mapper_name=mapper_name, password=enc_password)

if not luks_handler.is_unlocked():
Expand Down
8 changes: 4 additions & 4 deletions archinstall/lib/disk/encryption_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from ..menu.abstract_menu import AbstractSubMenu
from ..models.device_model import Fido2Device
from ..models.users import Password
from ..output import FormattedOutput
from ..utils.util import get_password
from .fido import Fido2
Expand Down Expand Up @@ -122,7 +123,7 @@ def run(self) -> DiskEncryption | None:
super().run()

enc_type: EncryptionType | None = self._item_group.find_by_key('encryption_type').value
enc_password: str | None = self._item_group.find_by_key('encryption_password').value
enc_password: Password | None = self._item_group.find_by_key('encryption_password').value
enc_partitions = self._item_group.find_by_key('partitions').value
enc_lvm_vols = self._item_group.find_by_key('lvm_volumes').value

Expand Down Expand Up @@ -183,8 +184,7 @@ def _prev_password(self) -> str | None:
enc_pwd = self._item_group.find_by_key('encryption_password').value

if enc_pwd:
pwd_text = '*' * len(enc_pwd)
return f'{_("Encryption password")}: {pwd_text}'
return f'{_("Encryption password")}: {enc_pwd.hidden()}'

return None

Expand Down Expand Up @@ -249,7 +249,7 @@ def select_encryption_type(disk_config: DiskLayoutConfiguration, preset: Encrypt
return result.get_value()


def select_encrypted_password() -> str | None:
def select_encrypted_password() -> Password | None:
header = str(_('Enter disk encryption password (leave blank for no encryption)')) + '\n'
password = get_password(
text=str(_('Disk encryption password')),
Expand Down
5 changes: 3 additions & 2 deletions archinstall/lib/disk/fido.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from ..exceptions import SysCallError
from ..general import SysCommand, SysCommandWorker, clear_vt100_escape_codes_from_str
from ..models.users import Password
from ..output import error, info


Expand Down Expand Up @@ -74,7 +75,7 @@ def fido2_enroll(
cls,
hsm_device: Fido2Device,
dev_path: Path,
password: str
password: Password
) -> None:
worker = SysCommandWorker(f"systemd-cryptenroll --fido2-device={hsm_device.path} {dev_path}", peek_output=True)
pw_inputted = False
Expand All @@ -83,7 +84,7 @@ def fido2_enroll(
while worker.is_alive():
if pw_inputted is False:
if bytes(f"please enter current passphrase for disk {dev_path}", 'UTF-8') in worker._trace_log.lower():
worker.write(bytes(password, 'UTF-8'))
worker.write(bytes(password.plaintext, 'UTF-8'))
pw_inputted = True
elif pin_inputted is False:
if bytes("please enter security token pin", 'UTF-8') in worker._trace_log.lower():
Expand Down
5 changes: 0 additions & 5 deletions archinstall/lib/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,8 +533,3 @@ def json_stream_to_structure(configuration_identifier: str, stream: str, target:
return False
target.update(structure)
return True


def secret(x: str) -> str:
""" return * with len equal to to the input string """
return '*' * len(x)
20 changes: 11 additions & 9 deletions archinstall/lib/global_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from .args import ArchConfig
from .configuration import save_config
from .general import secret
from .hardware import SysInfo
from .interactions.general_conf import (
add_number_of_parallel_downloads,
Expand All @@ -31,7 +30,7 @@
from .models.mirrors import MirrorConfiguration
from .models.network_configuration import NetworkConfiguration, NicType
from .models.profile_model import ProfileConfiguration
from .models.users import User
from .models.users import Password, User
from .output import FormattedOutput
from .translationhandler import Language, translation_handler
from .utils.util import get_password
Expand Down Expand Up @@ -125,7 +124,7 @@ def _get_menu_options(self) -> list[MenuItem]:
text=str(_('Root password')),
action=self._set_root_password,
preview_action=self._prev_root_pwd,
key='root_password',
key='root_enc_password',
),
MenuItem(
text=str(_('User account')),
Expand Down Expand Up @@ -223,7 +222,7 @@ def check(s) -> bool:
return item.has_value()

def has_superuser() -> bool:
item = self._item_group.find_by_key('!users')
item = self._item_group.find_by_key('users')

if item.has_value():
users = item.value
Expand All @@ -234,8 +233,8 @@ def has_superuser() -> bool:
missing = set()

for item in self._item_group.items:
if item.key in ['!root-password', '!users']:
if not check('!root-password') and not has_superuser():
if item.key in ['root_enc_password', 'users']:
if not check('root_enc_password') and not has_superuser():
missing.add(
str(_('Either root-password or at least 1 user with sudo privileges must be specified'))
)
Expand Down Expand Up @@ -363,7 +362,8 @@ def _prev_hostname(self, item: MenuItem) -> str | None:

def _prev_root_pwd(self, item: MenuItem) -> str | None:
if item.value is not None:
return f'{_("Root password")}: {secret(item.value)}'
password: Password = item.value
return f'{_("Root password")}: {password.hidden()}'
return None

def _prev_audio(self, item: MenuItem) -> str | None:
Expand Down Expand Up @@ -398,7 +398,9 @@ def _prev_disk_encryption(self, item: MenuItem) -> str | None:
if enc_config:
enc_type = EncryptionType.type_to_text(enc_config.encryption_type)
output = str(_('Encryption type')) + f': {enc_type}\n'
output += str(_('Password')) + f': {secret(enc_config.encryption_password)}\n'

if enc_config.encryption_password:
output += str(_('Password')) + f': {enc_config.encryption_password.hidden()}\n'

if enc_config.partitions:
output += f'Partitions: {len(enc_config.partitions)} selected\n'
Expand Down Expand Up @@ -481,7 +483,7 @@ def _prev_profile(self, item: MenuItem) -> str | None:

return None

def _set_root_password(self, preset: str | None = None) -> str | None:
def _set_root_password(self, preset: str | None = None) -> Password | None:
password = get_password(text=str(_('Root password')), allow_skip=True)
return password

Expand Down
Loading
Loading