From 08769f3107120d16b36baa0ac9bd0ced3ea91915 Mon Sep 17 00:00:00 2001 From: Himadri Bhattacharjee <107522312+lavafroth@users.noreply.github.com> Date: Tue, 28 Feb 2023 18:49:59 +0000 Subject: Fixes mypy errors. (#1658) --- archinstall/lib/menu/abstract_menu.py | 20 ++++++++++---------- archinstall/lib/menu/global_menu.py | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'archinstall/lib/menu') diff --git a/archinstall/lib/menu/abstract_menu.py b/archinstall/lib/menu/abstract_menu.py index 5a7ca03a..d659d709 100644 --- a/archinstall/lib/menu/abstract_menu.py +++ b/archinstall/lib/menu/abstract_menu.py @@ -17,14 +17,14 @@ class Selector: def __init__( self, description :str, - func :Callable = None, - display_func :Callable = None, + func :Optional[Callable] = None, + display_func :Optional[Callable] = None, default :Any = None, enabled :bool = False, dependencies :List = [], dependencies_not :List = [], - exec_func :Callable = None, - preview_func :Callable = None, + exec_func :Optional[Callable] = None, + preview_func :Optional[Callable] = None, mandatory :bool = False, no_store :bool = False ): @@ -165,7 +165,7 @@ class Selector: class AbstractMenu: - def __init__(self, data_store: Dict[str, Any] = None, auto_cursor=False, preview_size :float = 0.2): + def __init__(self, data_store: Optional[Dict[str, Any]] = None, auto_cursor=False, preview_size :float = 0.2): """ Create a new selection menu. @@ -226,7 +226,7 @@ class AbstractMenu: """ will be called before each action in the menu """ return - def post_callback(self, selection_name: str = None, value: Any = None): + def post_callback(self, selection_name: Optional[str] = None, value: Any = None): """ will be called after each action in the menu """ return True @@ -356,7 +356,7 @@ class AbstractMenu: config_name, selector = self._find_selection(selection_name) return self.exec_option(config_name, selector) - def exec_option(self, config_name :str, p_selector :Selector = None) -> bool: + def exec_option(self, config_name :str, p_selector :Optional[Selector] = None) -> bool: """ processes the execution of a given menu entry - pre process callback - selection function @@ -372,13 +372,13 @@ class AbstractMenu: self.pre_callback(config_name) result = None - if selector.func: + if selector.func is not None: presel_val = self.option(config_name).get_selection() result = selector.func(presel_val) self._menu_options[config_name].set_current_selection(result) if selector.do_store(): self._data_store[config_name] = result - exec_ret_val = selector.exec_func(config_name,result) if selector.exec_func else False + exec_ret_val = selector.exec_func(config_name,result) if selector.exec_func is not None else False self.post_callback(config_name,result) if exec_ret_val and self._check_mandatory_status(): @@ -478,7 +478,7 @@ class AbstractMenu: class AbstractSubMenu(AbstractMenu): - def __init__(self, data_store: Dict[str, Any] = None): + def __init__(self, data_store: Optional[Dict[str, Any]] = None): super().__init__(data_store=data_store) self._menu_options['__separator__'] = Selector('') diff --git a/archinstall/lib/menu/global_menu.py b/archinstall/lib/menu/global_menu.py index 0d348227..f0062b4c 100644 --- a/archinstall/lib/menu/global_menu.py +++ b/archinstall/lib/menu/global_menu.py @@ -197,11 +197,11 @@ class GlobalMenu(AbstractMenu): self._menu_options['abort'] = Selector(_('Abort'), exec_func=lambda n,v:exit(1)) - def _update_install_text(self, name :str = None, result :Any = None): + def _update_install_text(self, name :Optional[str] = None, result :Any = None): text = self._install_text() self._menu_options['install'].update_description(text) - def post_callback(self,name :str = None ,result :Any = None): + def post_callback(self,name :Optional[str] = None ,result :Any = None): self._update_install_text(name, result) def _install_text(self): @@ -377,9 +377,9 @@ class GlobalMenu(AbstractMenu): return harddrives - def _select_profile(self, preset): + def _select_profile(self, preset) -> Optional[Profile]: + ret: Optional[Profile] = None profile = select_profile(preset) - ret = None if profile is None: if any([ @@ -403,7 +403,7 @@ class GlobalMenu(AbstractMenu): namespace = f'{profile.namespace}.py' with profile.load_instructions(namespace=namespace) as imported: if imported._prep_function(servers=servers, desktop=desktop, desktop_env=desktop_env, gfx_driver=gfx_driver): - ret: Profile = profile + ret = profile match ret.name: case 'minimal': -- cgit v1.2.3-70-g09d2 From 83f4b4178fae83f9fae3dd0a7ac333957acd0c3f Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Wed, 29 Mar 2023 21:48:11 +1100 Subject: Save encryption configuration (#1672) * Save encryption configuration * Fix deserialization problem * Added .part_uuid to MapperDev --------- Co-authored-by: Daniel Girtler Co-authored-by: Anton Hvornum Co-authored-by: Anton Hvornum --- archinstall/__init__.py | 8 ++++ archinstall/lib/configuration.py | 5 ++- archinstall/lib/disk/encryption.py | 26 ++++++++--- archinstall/lib/disk/filesystem.py | 2 +- archinstall/lib/hsm/fido.py | 19 +++++++- archinstall/lib/installer.py | 6 +-- archinstall/lib/menu/global_menu.py | 4 +- archinstall/lib/models/disk_encryption.py | 59 ++++++++++++++++++++++--- archinstall/lib/user_interaction/system_conf.py | 1 - 9 files changed, 108 insertions(+), 22 deletions(-) (limited to 'archinstall/lib/menu') diff --git a/archinstall/__init__.py b/archinstall/__init__.py index b22b4663..9664c507 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -240,6 +240,14 @@ def load_config(): superusers = arguments.get('!superusers', None) arguments['!users'] = User.parse_arguments(users, superusers) + if arguments.get('disk_encryption', None) is not None and arguments.get('disk_layouts', None) is not None: + password = arguments.get('encryption_password', '') + arguments['disk_encryption'] = DiskEncryption.parse_arg( + arguments['disk_layouts'], + arguments['disk_encryption'], + password + ) + def post_process_arguments(arguments): storage['arguments'] = arguments diff --git a/archinstall/lib/configuration.py b/archinstall/lib/configuration.py index ad537b21..e0b5a143 100644 --- a/archinstall/lib/configuration.py +++ b/archinstall/lib/configuration.py @@ -44,7 +44,7 @@ class ConfigurationOutput: self._disk_layout_file = "user_disk_layout.json" self._sensitive = ['!users'] - self._ignore = ['abort', 'install', 'config', 'creds', 'dry_run', 'disk_encryption'] + self._ignore = ['abort', 'install', 'config', 'creds', 'dry_run'] self._process_config() @@ -71,6 +71,9 @@ class ConfigurationOutput: else: self._user_config[key] = self._config[key] + if key == 'disk_encryption': # special handling for encryption password + self._user_credentials['encryption_password'] = self._config[key].encryption_password + def user_config_to_json(self) -> str: return json.dumps({ 'config_version': storage['__version__'], # Tells us what version was used to generate the config diff --git a/archinstall/lib/disk/encryption.py b/archinstall/lib/disk/encryption.py index 67f656c8..c7496bfa 100644 --- a/archinstall/lib/disk/encryption.py +++ b/archinstall/lib/disk/encryption.py @@ -46,7 +46,7 @@ class DiskEncryptionMenu(AbstractSubMenu): Selector( _('Partitions'), func=lambda preset: select_partitions_to_encrypt(self._disk_layouts, preset), - display_func=lambda x: f'{len(x)} {_("Partitions")}' if x else None, + display_func=lambda x: f'{sum([len(y) for y in x.values()])} {_("Partitions")}' if x else None, dependencies=['encryption_password'], default=self._preset.partitions, preview_func=self._prev_disk_layouts, @@ -86,9 +86,14 @@ class DiskEncryptionMenu(AbstractSubMenu): def _prev_disk_layouts(self) -> Optional[str]: selector = self._menu_options['partitions'] if selector.has_selection(): - partitions: List[Any] = selector.current_selection + partitions: Dict[str, Any] = selector.current_selection + + all_partitions = [] + for parts in partitions.values(): + all_partitions += parts + output = str(_('Partitions to be encrypted')) + '\n' - output += current_partition_layout(partitions, with_title=False) + output += current_partition_layout(all_partitions, with_title=False) return output.rstrip() return None @@ -132,7 +137,7 @@ def select_hsm(preset: Optional[Fido2Device] = None) -> Optional[Fido2Device]: return None -def select_partitions_to_encrypt(disk_layouts: Dict[str, Any], preset: List[Any]) -> List[Any]: +def select_partitions_to_encrypt(disk_layouts: Dict[str, Any], preset: Dict[str, Any]) -> Dict[str, Any]: # If no partitions was marked as encrypted, but a password was supplied and we have some disks to format.. # Then we need to identify which partitions to encrypt. This will default to / (root). all_partitions = [] @@ -153,10 +158,17 @@ def select_partitions_to_encrypt(disk_layouts: Dict[str, Any], preset: List[Any] match choice.type_: case MenuSelectionType.Reset: - return [] + return {} case MenuSelectionType.Skip: return preset case MenuSelectionType.Selection: - return choice.value # type: ignore + selections: List[Any] = choice.value # type: ignore + partitions = {} + + for path, device in disk_layouts.items(): + for part in selections: + if part in device.get('partitions', []): + partitions.setdefault(path, []).append(part) - return [] + return partitions + return {} diff --git a/archinstall/lib/disk/filesystem.py b/archinstall/lib/disk/filesystem.py index 1e722ce5..1083df53 100644 --- a/archinstall/lib/disk/filesystem.py +++ b/archinstall/lib/disk/filesystem.py @@ -113,7 +113,7 @@ class Filesystem: format_options = partition.get('options',[]) + partition.get('filesystem',{}).get('format_options',[]) disk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption') - if disk_encryption and partition in disk_encryption.partitions: + if disk_encryption and partition in disk_encryption.all_partitions: if not partition['device_instance']: raise DiskError(f"Internal error caused us to loose the partition. Please report this issue upstream!") diff --git a/archinstall/lib/hsm/fido.py b/archinstall/lib/hsm/fido.py index 758a2548..1c226322 100644 --- a/archinstall/lib/hsm/fido.py +++ b/archinstall/lib/hsm/fido.py @@ -1,9 +1,11 @@ +from __future__ import annotations + import getpass import logging from dataclasses import dataclass from pathlib import Path -from typing import List +from typing import List, Dict from ..general import SysCommand, SysCommandWorker, clear_vt100_escape_codes from ..disk.partition import Partition @@ -16,6 +18,21 @@ class Fido2Device: manufacturer: str product: str + def json(self) -> Dict[str, str]: + return { + 'path': str(self.path), + 'manufacturer': self.manufacturer, + 'product': self.product + } + + @classmethod + def parse_arg(cls, arg: Dict[str, str]) -> 'Fido2Device': + return Fido2Device( + Path(arg['path']), + arg['manufacturer'], + arg['product'] + ) + class Fido2: _loaded: bool = False diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 8c6a8367..0e9f0662 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -248,7 +248,7 @@ class Installer: # we manage the encrypted partititons if self._disk_encryption: - for partition in self._disk_encryption.partitions: + for partition in self._disk_encryption.all_partitions: # open the luks device and all associate stuff loopdev = f"{storage.get('ENC_IDENTIFIER', 'ai')}{pathlib.Path(partition['device_instance'].path).name}" @@ -324,7 +324,7 @@ class Installer: file = f"/{file}" if len(file.strip()) <= 0 or file == '/': raise ValueError(f"The filename for the swap file has to be a valid path, not: {self.target}{file}") - + SysCommand(f'dd if=/dev/zero of={self.target}{file} bs={size} count=1') SysCommand(f'chmod 0600 {self.target}{file}') SysCommand(f'mkswap {self.target}{file}') @@ -452,7 +452,7 @@ class Installer: if hasattr(plugin, 'on_genfstab'): if plugin.on_genfstab(self) is True: break - + with open(f"{self.target}/etc/fstab", 'a') as fstab_fh: for entry in self.FSTAB_ENTRIES: fstab_fh.write(f'{entry}\n') diff --git a/archinstall/lib/menu/global_menu.py b/archinstall/lib/menu/global_menu.py index f0062b4c..7c5b153e 100644 --- a/archinstall/lib/menu/global_menu.py +++ b/archinstall/lib/menu/global_menu.py @@ -279,8 +279,8 @@ class GlobalMenu(AbstractMenu): output = str(_('Encryption type')) + f': {enc_type}\n' output += str(_('Password')) + f': {secret(encryption.encryption_password)}\n' - if encryption.partitions: - output += 'Partitions: {} selected'.format(len(encryption.partitions)) + '\n' + if encryption.all_partitions: + output += 'Partitions: {} selected'.format(len(encryption.all_partitions)) + '\n' if encryption.hsm_device: output += f'HSM: {encryption.hsm_device.manufacturer}' diff --git a/archinstall/lib/models/disk_encryption.py b/archinstall/lib/models/disk_encryption.py index 3edab93e..a4a501d9 100644 --- a/archinstall/lib/models/disk_encryption.py +++ b/archinstall/lib/models/disk_encryption.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from dataclasses import dataclass, field -from enum import Enum, auto +from enum import Enum from typing import Optional, List, Dict, TYPE_CHECKING, Any from ..hsm.fido import Fido2Device @@ -9,8 +11,7 @@ if TYPE_CHECKING: class EncryptionType(Enum): - Partition = auto() - # FullDiskEncryption = auto() + Partition = 'partition' @classmethod def _encryption_type_mapper(cls) -> Dict[str, 'EncryptionType']: @@ -35,9 +36,55 @@ class EncryptionType(Enum): class DiskEncryption: encryption_type: EncryptionType = EncryptionType.Partition encryption_password: str = '' - partitions: List[str] = field(default_factory=list) + partitions: Dict[str, List[Dict[str, Any]]] = field(default_factory=dict) hsm_device: Optional[Fido2Device] = None + @property + def all_partitions(self) -> List[Dict[str, Any]]: + _all: List[Dict[str, Any]] = [] + for parts in self.partitions.values(): + _all += parts + return _all + def generate_encryption_file(self, partition) -> bool: - return partition in self.partitions and partition['mountpoint'] != '/' - + return partition in self.all_partitions and partition['mountpoint'] != '/' + + def json(self) -> Dict[str, Any]: + obj = { + 'encryption_type': self.encryption_type.value, + 'partitions': self.partitions + } + + if self.hsm_device: + obj['hsm_device'] = self.hsm_device.json() + + return obj + + @classmethod + def parse_arg( + cls, + disk_layout: Dict[str, Any], + arg: Dict[str, Any], + password: str = '' + ) -> 'DiskEncryption': + # we have to map the enc partition config to the disk layout objects + # they both need to point to the same object as it will get modified + # during the installation process + enc_partitions: Dict[str, List[Dict[str, Any]]] = {} + + for path, partitions in disk_layout.items(): + conf_partitions = arg['partitions'].get(path, []) + for part in partitions['partitions']: + if part in conf_partitions: + enc_partitions.setdefault(path, []).append(part) + + enc = DiskEncryption( + EncryptionType(arg['encryption_type']), + password, + enc_partitions + ) + + if hsm := arg.get('hsm_device', None): + enc.hsm_device = Fido2Device.parse_arg(hsm) + + return enc diff --git a/archinstall/lib/user_interaction/system_conf.py b/archinstall/lib/user_interaction/system_conf.py index 42a6cec7..e1581677 100644 --- a/archinstall/lib/user_interaction/system_conf.py +++ b/archinstall/lib/user_interaction/system_conf.py @@ -60,7 +60,6 @@ def select_harddrives(preset: List[str] = []) -> List[str]: selected_harddrive = Menu( title, list(options.keys()), - preset_values=preset, multi=True, allow_reset=True, allow_reset_warning_msg=warning -- cgit v1.2.3-70-g09d2