Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Girtler <blackrabbit256@gmail.com>2022-11-11 19:40:05 +1100
committerGitHub <noreply@github.com>2022-11-11 09:40:05 +0100
commitc3862c5779194f5e93f9fd2518bb15706c93ad2b (patch)
treed369d5c9dbec14432e3ed42bf872f4b4e021278c
parentee1eea21307586c749c2734cff6440ff8f1c2806 (diff)
New encryption menu (#1520)
* New encryption menu Co-authored-by: Daniel Girtler <girtler.daniel@gmail.com> Co-authored-by: Anton Hvornum <anton@hvornum.se>
-rw-r--r--.github/workflows/mypy.yaml6
-rw-r--r--archinstall/__init__.py8
-rw-r--r--archinstall/lib/configuration.py14
-rw-r--r--archinstall/lib/disk/encryption.py162
-rw-r--r--archinstall/lib/disk/filesystem.py23
-rw-r--r--archinstall/lib/disk/helpers.py6
-rw-r--r--archinstall/lib/disk/partition.py1
-rw-r--r--archinstall/lib/hsm/__init__.py5
-rw-r--r--archinstall/lib/hsm/fido.py137
-rw-r--r--archinstall/lib/installer.py36
-rw-r--r--archinstall/lib/menu/abstract_menu.py (renamed from archinstall/lib/menu/selection_menu.py)92
-rw-r--r--archinstall/lib/menu/global_menu.py94
-rw-r--r--archinstall/lib/menu/list_manager.py2
-rw-r--r--archinstall/lib/menu/menu.py43
-rw-r--r--archinstall/lib/menu/table_selection_menu.py107
-rw-r--r--archinstall/lib/models/disk_encryption.py43
-rw-r--r--archinstall/lib/user_interaction/__init__.py2
-rw-r--r--archinstall/lib/user_interaction/disk_conf.py10
-rw-r--r--archinstall/lib/user_interaction/general_conf.py26
-rw-r--r--archinstall/lib/user_interaction/locale_conf.py4
-rw-r--r--archinstall/lib/user_interaction/network_conf.py10
-rw-r--r--archinstall/lib/user_interaction/partitioning_conf.py42
-rw-r--r--archinstall/lib/user_interaction/save_conf.py2
-rw-r--r--archinstall/lib/user_interaction/system_conf.py22
-rw-r--r--archinstall/locales/ar/LC_MESSAGES/base.po2
-rw-r--r--archinstall/locales/base.pot2
-rw-r--r--archinstall/locales/cs/LC_MESSAGES/base.po4
-rw-r--r--archinstall/locales/de/LC_MESSAGES/base.po7
-rw-r--r--archinstall/locales/el/LC_MESSAGES/base.po2
-rw-r--r--archinstall/locales/en/LC_MESSAGES/base.po2
-rw-r--r--archinstall/locales/es/LC_MESSAGES/base.po4
-rw-r--r--archinstall/locales/fr/LC_MESSAGES/base.po7
-rw-r--r--archinstall/locales/id/LC_MESSAGES/base.po4
-rw-r--r--archinstall/locales/it/LC_MESSAGES/base.po4
-rw-r--r--archinstall/locales/nl/LC_MESSAGES/base.po7
-rw-r--r--archinstall/locales/pl/LC_MESSAGES/base.po8
-rw-r--r--archinstall/locales/pt/LC_MESSAGES/base.po7
-rw-r--r--archinstall/locales/pt_BR/LC_MESSAGES/base.po4
-rw-r--r--archinstall/locales/ru/LC_MESSAGES/base.po4
-rw-r--r--archinstall/locales/sv/LC_MESSAGES/base.po7
-rw-r--r--archinstall/locales/ta/LC_MESSAGES/base.po4
-rw-r--r--archinstall/locales/tr/LC_MESSAGES/base.po7
-rw-r--r--archinstall/locales/ur/LC_MESSAGES/base.po7
-rw-r--r--examples/guided.py4
-rw-r--r--examples/only_hd.py2
-rw-r--r--examples/swiss.py6
46 files changed, 638 insertions, 364 deletions
diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml
index 6a4a9860..20c98f3b 100644
--- a/.github/workflows/mypy.yaml
+++ b/.github/workflows/mypy.yaml
@@ -15,4 +15,8 @@ jobs:
# one day this will be enabled
# run: mypy --strict --module archinstall || exit 0
- name: run mypy
- run: mypy --follow-imports=silent archinstall/lib/menu/selection_menu.py archinstall/lib/menu/global_menu.py archinstall/lib/models/network_configuration.py archinstall/lib/menu/list_manager.py archinstall/lib/user_interaction/network_conf.py archinstall/lib/models/users.py archinstall/lib/disk/blockdevice.py archinstall/lib/user_interaction/subvolume_config.py archinstall/lib/disk/btrfs/btrfs_helpers.py archinstall/lib/translationhandler.py archinstall/lib/disk/diskinfo.py
+ run: mypy --follow-imports=silent archinstall/lib/menu/abstract_menu.py archinstall/lib/menu/global_menu.py
+ archinstall/lib/models/network_configuration.py archinstall/lib/menu/list_manager.py archinstall/lib/user_interaction/network_conf.py archinstall/lib/models/users.py
+ archinstall/lib/disk/blockdevice.py archinstall/lib/user_interaction/subvolume_config.py archinstall/lib/disk/btrfs/btrfs_helpers.py
+ archinstall/lib/translationhandler.py archinstall/lib/disk/diskinfo.py archinstall/lib/menu/table_selection_menu.py archinstall/lib/hsm
+ archinstall/lib/disk/encryption.py archinstall/lib/models/disk_encryption.py
diff --git a/archinstall/__init__.py b/archinstall/__init__.py
index c6135e74..e496d213 100644
--- a/archinstall/__init__.py
+++ b/archinstall/__init__.py
@@ -37,18 +37,14 @@ from .lib.menu import Menu
from .lib.menu.list_manager import ListManager
from .lib.menu.text_input import TextInput
from .lib.menu.global_menu import GlobalMenu
-from .lib.menu.selection_menu import (
+from .lib.menu.abstract_menu import (
Selector,
- GeneralMenu
+ AbstractMenu
)
from .lib.translationhandler import TranslationHandler, DeferredTranslation
from .lib.plugins import plugins, load_plugin # This initiates the plugin loading ceremony
from .lib.configuration import *
from .lib.udev import udevadm_info
-from .lib.hsm import (
- get_fido2_devices,
- fido2_enroll
-)
parser = ArgumentParser()
__version__ = "2.5.2"
diff --git a/archinstall/lib/configuration.py b/archinstall/lib/configuration.py
index 2a43174d..ce782f6c 100644
--- a/archinstall/lib/configuration.py
+++ b/archinstall/lib/configuration.py
@@ -5,15 +5,18 @@ import logging
import pathlib
from typing import Optional, Dict
+from .hsm.fido import Fido2
+from .models.disk_encryption import DiskEncryption
from .storage import storage
from .general import JSON, UNSAFE_JSON
from .output import log
from .exceptions import RequirementError
-from .hsm import get_fido2_devices
+
def configuration_sanity_check():
- if storage['arguments'].get('HSM'):
- if not get_fido2_devices():
+ disk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption')
+ if disk_encryption.hsm_device:
+ if not Fido2.get_fido2_devices():
raise RequirementError(
f"In order to use HSM to pair with the disk encryption,"
+ f" one needs to be accessible through /dev/hidraw* and support"
@@ -21,6 +24,7 @@ def configuration_sanity_check():
+ f" 'systemd-cryptenroll --fido2-device=list'."
)
+
class ConfigurationOutput:
def __init__(self, config: Dict):
"""
@@ -39,8 +43,8 @@ class ConfigurationOutput:
self._user_creds_file = "user_credentials.json"
self._disk_layout_file = "user_disk_layout.json"
- self._sensitive = ['!users', '!encryption-password']
- self._ignore = ['abort', 'install', 'config', 'creds', 'dry_run']
+ self._sensitive = ['!users']
+ self._ignore = ['abort', 'install', 'config', 'creds', 'dry_run', 'disk_encryption']
self._process_config()
diff --git a/archinstall/lib/disk/encryption.py b/archinstall/lib/disk/encryption.py
new file mode 100644
index 00000000..67f656c8
--- /dev/null
+++ b/archinstall/lib/disk/encryption.py
@@ -0,0 +1,162 @@
+from typing import Dict, Optional, Any, TYPE_CHECKING, List
+
+from ..menu.abstract_menu import Selector, AbstractSubMenu
+from ..menu.menu import MenuSelectionType
+from ..menu.table_selection_menu import TableMenu
+from ..models.disk_encryption import EncryptionType, DiskEncryption
+from ..user_interaction.partitioning_conf import current_partition_layout
+from ..user_interaction.utils import get_password
+from ..menu import Menu
+from ..general import secret
+from ..hsm.fido import Fido2Device, Fido2
+
+if TYPE_CHECKING:
+ _: Any
+
+
+class DiskEncryptionMenu(AbstractSubMenu):
+ def __init__(self, data_store: Dict[str, Any], preset: Optional[DiskEncryption], disk_layouts: Dict[str, Any]):
+ if preset:
+ self._preset = preset
+ else:
+ self._preset = DiskEncryption()
+
+ self._disk_layouts = disk_layouts
+ super().__init__(data_store=data_store)
+
+ def _setup_selection_menu_options(self):
+ self._menu_options['encryption_password'] = \
+ Selector(
+ _('Encryption password'),
+ lambda x: select_encrypted_password(),
+ display_func=lambda x: secret(x) if x else '',
+ default=self._preset.encryption_password,
+ enabled=True
+ )
+ self._menu_options['encryption_type'] = \
+ Selector(
+ _('Encryption type'),
+ func=lambda preset: select_encryption_type(preset),
+ display_func=lambda x: EncryptionType.type_to_text(x) if x else None,
+ dependencies=['encryption_password'],
+ default=self._preset.encryption_type,
+ enabled=True
+ )
+ self._menu_options['partitions'] = \
+ 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,
+ dependencies=['encryption_password'],
+ default=self._preset.partitions,
+ preview_func=self._prev_disk_layouts,
+ enabled=True
+ )
+ self._menu_options['HSM'] = \
+ Selector(
+ description=_('Use HSM to unlock encrypted drive'),
+ func=lambda preset: select_hsm(preset),
+ display_func=lambda x: self._display_hsm(x),
+ dependencies=['encryption_password'],
+ default=self._preset.hsm_device,
+ enabled=True
+ )
+
+ def run(self, allow_reset: bool = True) -> Optional[DiskEncryption]:
+ super().run(allow_reset=allow_reset)
+
+ if self._data_store.get('encryption_password', None):
+ return DiskEncryption(
+ encryption_password=self._data_store.get('encryption_password', None),
+ encryption_type=self._data_store['encryption_type'],
+ partitions=self._data_store.get('partitions', None),
+ hsm_device=self._data_store.get('HSM', None)
+ )
+
+ return None
+
+ def _display_hsm(self, device: Optional[Fido2Device]) -> Optional[str]:
+ if device:
+ return device.manufacturer
+
+ if not Fido2.get_fido2_devices():
+ return str(_('No HSM devices available'))
+ return None
+
+ def _prev_disk_layouts(self) -> Optional[str]:
+ selector = self._menu_options['partitions']
+ if selector.has_selection():
+ partitions: List[Any] = selector.current_selection
+ output = str(_('Partitions to be encrypted')) + '\n'
+ output += current_partition_layout(partitions, with_title=False)
+ return output.rstrip()
+ return None
+
+
+def select_encryption_type(preset: EncryptionType) -> Optional[EncryptionType]:
+ title = str(_('Select disk encryption option'))
+ options = [
+ # _type_to_text(EncryptionType.FullDiskEncryption),
+ EncryptionType.type_to_text(EncryptionType.Partition)
+ ]
+
+ preset_value = EncryptionType.type_to_text(preset)
+ choice = Menu(title, options, preset_values=preset_value).run()
+
+ match choice.type_:
+ case MenuSelectionType.Reset: return None
+ case MenuSelectionType.Skip: return preset
+ case MenuSelectionType.Selection: return EncryptionType.text_to_type(choice.value) # type: ignore
+
+
+def select_encrypted_password() -> Optional[str]:
+ if passwd := get_password(prompt=str(_('Enter disk encryption password (leave blank for no encryption): '))):
+ return passwd
+ return None
+
+
+def select_hsm(preset: Optional[Fido2Device] = None) -> Optional[Fido2Device]:
+ title = _('Select a FIDO2 device to use for HSM')
+ fido_devices = Fido2.get_fido2_devices()
+
+ if fido_devices:
+ choice = TableMenu(title, data=fido_devices).run()
+ match choice.type_:
+ case MenuSelectionType.Reset:
+ return None
+ case MenuSelectionType.Skip:
+ return preset
+ case MenuSelectionType.Selection:
+ return choice.value # type: ignore
+
+ return None
+
+
+def select_partitions_to_encrypt(disk_layouts: Dict[str, Any], preset: List[Any]) -> List[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 = []
+ for blockdevice in disk_layouts.values():
+ if partitions := blockdevice.get('partitions'):
+ partitions = [p for p in partitions if p['mountpoint'] != '/boot']
+ all_partitions += partitions
+
+ if all_partitions:
+ title = str(_('Select which partitions to encrypt'))
+ partition_table = current_partition_layout(all_partitions, with_title=False).strip()
+
+ choice = TableMenu(
+ title,
+ table_data=(all_partitions, partition_table),
+ multi=True
+ ).run()
+
+ match choice.type_:
+ case MenuSelectionType.Reset:
+ return []
+ case MenuSelectionType.Skip:
+ return preset
+ case MenuSelectionType.Selection:
+ return choice.value # type: ignore
+
+ return []
diff --git a/archinstall/lib/disk/filesystem.py b/archinstall/lib/disk/filesystem.py
index af5879aa..bdfa502a 100644
--- a/archinstall/lib/disk/filesystem.py
+++ b/archinstall/lib/disk/filesystem.py
@@ -5,6 +5,8 @@ import json
import pathlib
from typing import Optional, Dict, Any, TYPE_CHECKING
# https://stackoverflow.com/a/39757388/929999
+from ..models.disk_encryption import DiskEncryption
+
if TYPE_CHECKING:
from .blockdevice import BlockDevice
_: Any
@@ -107,33 +109,22 @@ class Filesystem:
continue
if partition.get('filesystem', {}).get('format', False):
-
# needed for backward compatibility with the introduction of the new "format_options"
format_options = partition.get('options',[]) + partition.get('filesystem',{}).get('format_options',[])
- if partition.get('encrypted', False):
+ disk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption')
+
+ if partition in disk_encryption.partitions:
if not partition['device_instance']:
raise DiskError(f"Internal error caused us to loose the partition. Please report this issue upstream!")
- if not partition.get('!password'):
- if not storage['arguments'].get('!encryption-password'):
- if storage['arguments'] == 'silent':
- raise ValueError(f"Missing encryption password for {partition['device_instance']}")
-
- from ..user_interaction import get_password
-
- prompt = str(_('Enter a encryption password for {}').format(partition['device_instance']))
- storage['arguments']['!encryption-password'] = get_password(prompt)
-
- partition['!password'] = storage['arguments']['!encryption-password']
-
if partition.get('mountpoint',None):
loopdev = f"{storage.get('ENC_IDENTIFIER', 'ai')}{pathlib.Path(partition['mountpoint']).name}loop"
else:
loopdev = f"{storage.get('ENC_IDENTIFIER', 'ai')}{pathlib.Path(partition['device_instance'].path).name}"
- partition['device_instance'].encrypt(password=partition['!password'])
+ partition['device_instance'].encrypt(password=disk_encryption.encryption_password)
# Immediately unlock the encrypted device to format the inner volume
- with luks2(partition['device_instance'], loopdev, partition['!password'], auto_unmount=True) as unlocked_device:
+ with luks2(partition['device_instance'], loopdev, disk_encryption.encryption_password, auto_unmount=True) as unlocked_device:
if not partition.get('wipe'):
if storage['arguments'] == 'silent':
raise ValueError(f"Missing fs-type to format on newly created encrypted partition {partition['device_instance']}")
diff --git a/archinstall/lib/disk/helpers.py b/archinstall/lib/disk/helpers.py
index 256f7abb..a5164b76 100644
--- a/archinstall/lib/disk/helpers.py
+++ b/archinstall/lib/disk/helpers.py
@@ -469,12 +469,6 @@ def disk_layouts() -> Optional[Dict[str, Any]]:
return None
-def encrypted_partitions(blockdevices :Dict[str, Any]) -> bool:
- for blockdevice in blockdevices.values():
- for partition in blockdevice.get('partitions', []):
- if partition.get('encrypted', False):
- yield partition
-
def find_partition_by_mountpoint(block_devices :List[BlockDevice], relative_mountpoint :str) -> Partition:
for device in block_devices:
for partition in block_devices[device]['partitions']:
diff --git a/archinstall/lib/disk/partition.py b/archinstall/lib/disk/partition.py
index 04d33453..9febf102 100644
--- a/archinstall/lib/disk/partition.py
+++ b/archinstall/lib/disk/partition.py
@@ -91,7 +91,6 @@ class Partition:
self._path = path
self._part_id = part_id
self._target_mountpoint = mountpoint
- self._encrypted = None
self._encrypted = encrypted
self._wipe = False
self._type = 'primary'
diff --git a/archinstall/lib/hsm/__init__.py b/archinstall/lib/hsm/__init__.py
index c0888b04..a3f64019 100644
--- a/archinstall/lib/hsm/__init__.py
+++ b/archinstall/lib/hsm/__init__.py
@@ -1,4 +1 @@
-from .fido import (
- get_fido2_devices,
- fido2_enroll
-) \ No newline at end of file
+from .fido import Fido2
diff --git a/archinstall/lib/hsm/fido.py b/archinstall/lib/hsm/fido.py
index 49f36957..4cd956a3 100644
--- a/archinstall/lib/hsm/fido.py
+++ b/archinstall/lib/hsm/fido.py
@@ -1,57 +1,92 @@
-import typing
-import pathlib
import getpass
import logging
+
+from dataclasses import dataclass
+from pathlib import Path
+from typing import List
+
from ..general import SysCommand, SysCommandWorker, clear_vt100_escape_codes
from ..disk.partition import Partition
from ..general import log
-def get_fido2_devices() -> typing.Dict[str, typing.Dict[str, str]]:
- """
- Uses systemd-cryptenroll to list the FIDO2 devices
- connected that supports FIDO2.
- Some devices might show up in udevadm as FIDO2 compliant
- when they are in fact not.
-
- The drawback of systemd-cryptenroll is that it uses human readable format.
- That means we get this weird table like structure that is of no use.
-
- So we'll look for `MANUFACTURER` and `PRODUCT`, we take their index
- and we split each line based on those positions.
- """
- worker = clear_vt100_escape_codes(SysCommand(f"systemd-cryptenroll --fido2-device=list").decode('UTF-8'))
-
- MANUFACTURER_POS = 0
- PRODUCT_POS = 0
- devices = {}
- for line in worker.split('\r\n'):
- if '/dev' not in line:
- MANUFACTURER_POS = line.find('MANUFACTURER')
- PRODUCT_POS = line.find('PRODUCT')
- continue
-
- path = line[:MANUFACTURER_POS].rstrip()
- manufacturer = line[MANUFACTURER_POS:PRODUCT_POS].rstrip()
- product = line[PRODUCT_POS:]
-
- devices[path] = {
- 'manufacturer' : manufacturer,
- 'product' : product
- }
-
- return devices
-
-def fido2_enroll(hsm_device_path :pathlib.Path, partition :Partition, password :str) -> bool:
- worker = SysCommandWorker(f"systemd-cryptenroll --fido2-device={hsm_device_path} {partition.real_device}", peak_output=True)
- pw_inputted = False
- pin_inputted = False
- while worker.is_alive():
- if pw_inputted is False and bytes(f"please enter current passphrase for disk {partition.real_device}", 'UTF-8') in worker._trace_log.lower():
- worker.write(bytes(password, 'UTF-8'))
- pw_inputted = True
-
- elif pin_inputted is False and bytes(f"please enter security token pin", 'UTF-8') in worker._trace_log.lower():
- worker.write(bytes(getpass.getpass(" "), 'UTF-8'))
- pin_inputted = True
-
- log(f"You might need to touch the FIDO2 device to unlock it if no prompt comes up after 3 seconds.", level=logging.INFO, fg="yellow") \ No newline at end of file
+
+@dataclass
+class Fido2Device:
+ path: Path
+ manufacturer: str
+ product: str
+
+
+class Fido2:
+ _loaded: bool = False
+ _fido2_devices: List[Fido2Device] = []
+
+ @classmethod
+ def get_fido2_devices(cls, reload: bool = False) -> List[Fido2Device]:
+ """
+ Uses systemd-cryptenroll to list the FIDO2 devices
+ connected that supports FIDO2.
+ Some devices might show up in udevadm as FIDO2 compliant
+ when they are in fact not.
+
+ The drawback of systemd-cryptenroll is that it uses human readable format.
+ That means we get this weird table like structure that is of no use.
+
+ So we'll look for `MANUFACTURER` and `PRODUCT`, we take their index
+ and we split each line based on those positions.
+
+ Output example:
+
+ PATH MANUFACTURER PRODUCT
+ /dev/hidraw1 Yubico YubiKey OTP+FIDO+CCID
+ """
+
+ # to prevent continous reloading which will slow
+ # down moving the cursor in the menu
+ if not cls._loaded or reload:
+ ret = SysCommand(f"systemd-cryptenroll --fido2-device=list").decode('UTF-8')
+ if not ret:
+ log('Unable to retrieve fido2 devices', level=logging.ERROR)
+ return []
+
+ fido_devices = clear_vt100_escape_codes(ret)
+
+ manufacturer_pos = 0
+ product_pos = 0
+ devices = []
+
+ for line in fido_devices.split('\r\n'):
+ if '/dev' not in line:
+ manufacturer_pos = line.find('MANUFACTURER')
+ product_pos = line.find('PRODUCT')
+ continue
+
+ path = line[:manufacturer_pos].rstrip()
+ manufacturer = line[manufacturer_pos:product_pos].rstrip()
+ product = line[product_pos:]
+
+ devices.append(
+ Fido2Device(path, manufacturer, product)
+ )
+
+ cls._loaded = True
+ cls._fido2_devices = devices
+
+ return cls._fido2_devices
+
+ @classmethod
+ def fido2_enroll(cls, hsm_device: Fido2Device, partition :Partition, password :str):
+ worker = SysCommandWorker(f"systemd-cryptenroll --fido2-device={hsm_device.path} {partition.real_device}", peak_output=True)
+ pw_inputted = False
+ pin_inputted = False
+
+ while worker.is_alive():
+ if pw_inputted is False and bytes(f"please enter current passphrase for disk {partition.real_device}", 'UTF-8') in worker._trace_log.lower():
+ worker.write(bytes(password, 'UTF-8'))
+ pw_inputted = True
+
+ elif pin_inputted is False and bytes(f"please enter security token pin", 'UTF-8') in worker._trace_log.lower():
+ worker.write(bytes(getpass.getpass(" "), 'UTF-8'))
+ pin_inputted = True
+
+ log(f"You might need to touch the FIDO2 device to unlock it if no prompt comes up after 3 seconds.", level=logging.INFO, fg="yellow")
diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py
index 18f6e244..1926f593 100644
--- a/archinstall/lib/installer.py
+++ b/archinstall/lib/installer.py
@@ -15,16 +15,16 @@ from .hardware import has_uefi, is_vm, cpu_vendor
from .locale_helpers import verify_keyboard_layout, verify_x11_keyboard_layout
from .disk.helpers import findmnt
from .mirrors import use_mirrors
+from .models.disk_encryption import DiskEncryption
from .plugins import plugins
from .storage import storage
-# from .user_interaction import *
from .output import log
from .profiles import Profile
from .disk.partition import get_mount_fs_type
from .exceptions import DiskError, ServiceException, RequirementError, HardwareIncompatibilityError, SysCallError
-from .hsm import fido2_enroll
from .models.users import User
from .models.subvolume import Subvolume
+from .hsm import Fido2
if TYPE_CHECKING:
_: Any
@@ -135,6 +135,8 @@ class Installer:
self._zram_enabled = False
+ self._disk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption')
+
def log(self, *args :str, level :int = logging.DEBUG, **kwargs :str):
"""
installer.log() wraps output.log() mainly to set a default log-level for this install session.
@@ -196,7 +198,7 @@ class Installer:
def _create_keyfile(self,luks_handle , partition :dict, password :str):
""" roiutine to create keyfiles, so it can be moved elsewhere
"""
- if partition.get('generate-encryption-key-file'):
+ if self._disk_encryption.generate_encryption_file(partition):
if not (cryptkey_dir := pathlib.Path(f"{self.target}/etc/cryptsetup-keys.d")).exists():
cryptkey_dir.mkdir(parents=True)
# Once we store the key as ../xyzloop.key systemd-cryptsetup can automatically load this key
@@ -244,26 +246,20 @@ class Installer:
mount_queue = {}
# we manage the encrypted partititons
- for partition in [entry for entry in list_part if entry.get('encrypted', False)]:
+ for partition in self._disk_encryption.partitions:
# open the luks device and all associate stuff
- if not (password := partition.get('!password', None)) and storage['arguments'].get('!encryption-password'):
- password = storage['arguments'].get('!encryption-password')
- elif not password:
- raise RequirementError(f"Missing partition encryption password in layout: {partition}")
-
loopdev = f"{storage.get('ENC_IDENTIFIER', 'ai')}{pathlib.Path(partition['device_instance'].path).name}"
# note that we DON'T auto_unmount (i.e. close the encrypted device so it can be used
- with (luks_handle := luks2(partition['device_instance'], loopdev, password, auto_unmount=False)) as unlocked_device:
- if partition.get('generate-encryption-key-file', False) and not self._has_root(partition):
- list_luks_handles.append([luks_handle, partition, password])
+ with (luks_handle := luks2(partition['device_instance'], loopdev, self._disk_encryption.encryption_password, auto_unmount=False)) as unlocked_device:
+ if self._disk_encryption.generate_encryption_file(partition) and not self._has_root(partition):
+ list_luks_handles.append([luks_handle, partition, self._disk_encryption.encryption_password])
# this way all the requesrs will be to the dm_crypt device and not to the physical partition
partition['device_instance'] = unlocked_device
- if self._has_root(partition) and partition.get('generate-encryption-key-file', False) is False:
- if storage['arguments'].get('HSM'):
- hsm_device_path = storage['arguments']['HSM']
- fido2_enroll(hsm_device_path, partition['device_instance'], password)
+ if self._has_root(partition) and self._disk_encryption.generate_encryption_file(partition) is False:
+ if self._disk_encryption.hsm_device:
+ Fido2.fido2_enroll(self._disk_encryption.hsm_device, partition['device_instance'], self._disk_encryption.encryption_password)
btrfs_subvolumes = [entry for entry in list_part if entry.get('btrfs', {}).get('subvolumes', [])]
@@ -650,7 +646,7 @@ class Installer:
mkinit.write(f"BINARIES=({' '.join(self.BINARIES)})\n")
mkinit.write(f"FILES=({' '.join(self.FILES)})\n")
- if not storage['arguments'].get('HSM'):
+ if not self._disk_encryption.hsm_device:
# For now, if we don't use HSM we revert to the old
# way of setting up encryption hooks for mkinitcpio.
# This is purely for stability reasons, we're going away from this.
@@ -694,7 +690,7 @@ class Installer:
self.HOOKS.remove('fsck')
if self.detect_encryption(partition):
- if storage['arguments'].get('HSM'):
+ if self._disk_encryption.hsm_device:
# Required bby mkinitcpio to add support for fido2-device options
self.pacstrap('libfido2')
@@ -758,7 +754,7 @@ class Installer:
# TODO: Use python functions for this
SysCommand(f'/usr/bin/arch-chroot {self.target} chmod 700 /root')
- if storage['arguments'].get('HSM'):
+ if self._disk_encryption.hsm_device:
# TODO:
# A bit of a hack, but we need to get vconsole.conf in there
# before running `mkinitcpio` because it expects it in HSM mode.
@@ -886,7 +882,7 @@ class Installer:
kernel_options = f"options"
- if storage['arguments'].get('HSM'):
+ if self._disk_encryption.hsm_device:
# Note: lsblk UUID must be used, not PARTUUID for sd-encrypt to work
kernel_options += f" rd.luks.name={real_device.uuid}=luksdev"
# Note: tpm2-device and fido2-device don't play along very well:
diff --git a/archinstall/lib/menu/selection_menu.py b/archinstall/lib/menu/abstract_menu.py
index 8a08812c..61466e3e 100644
--- a/archinstall/lib/menu/selection_menu.py
+++ b/archinstall/lib/menu/abstract_menu.py
@@ -2,15 +2,12 @@ from __future__ import annotations
import logging
import sys
-import pathlib
from typing import Callable, Any, List, Iterator, Tuple, Optional, Dict, TYPE_CHECKING
from .menu import Menu, MenuSelectionType
from ..locale_helpers import set_keyboard_language
from ..output import log
from ..translationhandler import TranslationHandler, Language
-from ..hsm.fido import get_fido2_devices
-
from ..user_interaction.general_conf import select_archinstall_language
if TYPE_CHECKING:
@@ -167,8 +164,9 @@ class Selector:
if status and not self.is_enabled():
self.set_enabled(True)
-class GeneralMenu:
- def __init__(self, data_store :dict = None, auto_cursor=False, preview_size :float = 0.2):
+
+class AbstractMenu:
+ def __init__(self, data_store: Dict[str, Any] = None, auto_cursor=False, preview_size :float = 0.2):
"""
Create a new selection menu.
@@ -196,7 +194,7 @@ class GeneralMenu:
def last_choice(self):
return self._last_choice
- def __enter__(self, *args :Any, **kwargs :Any) -> GeneralMenu:
+ def __enter__(self, *args :Any, **kwargs :Any) -> AbstractMenu:
self.is_context_mgr = True
return self
@@ -209,9 +207,9 @@ class GeneralMenu:
raise args[1]
for key in self._menu_options:
- sel = self._menu_options[key]
+ selector = self._menu_options[key]
if key and key not in self._data_store:
- self._data_store[key] = sel._current_selection
+ self._data_store[key] = selector.current_selection
self.exit_callback()
@@ -286,7 +284,7 @@ class GeneralMenu:
selector = option[0][1]
return config_name, selector
- def run(self):
+ def run(self, allow_reset: bool = False):
""" Calls the Menu framework"""
# we synch all the options just in case
for item in self.list_options():
@@ -304,6 +302,8 @@ class GeneralMenu:
padding = self._get_menu_text_padding(list(enabled_menus.values()))
menu_options = [m.menu_text(padding) for m in enabled_menus.values()]
+ warning_msg = str(_('All settings will be reset, are you sure?'))
+
selection = Menu(
_('Set/Modify the below options'),
menu_options,
@@ -312,33 +312,39 @@ class GeneralMenu:
preview_command=self._preview_display,
preview_size=self.preview_size,
skip_empty_entries=True,
- skip=False
+ skip=False,
+ allow_reset=allow_reset,
+ allow_reset_warning_msg=warning_msg
).run()
- if selection.type_ == MenuSelectionType.Selection:
- value = selection.value
+ match selection.type_:
+ case MenuSelectionType.Reset:
+ self._data_store = {}
+ return
+ case MenuSelectionType.Selection:
+ value: str = selection.value # type: ignore
- if self.auto_cursor:
- cursor_pos = menu_options.index(value) + 1 # before the strip otherwise fails
+ if self.auto_cursor:
+ cursor_pos = menu_options.index(value) + 1 # before the strip otherwise fails
- # in case the new position lands on a "placeholder" we'll skip them as well
- while True:
- if cursor_pos >= len(menu_options):
- cursor_pos = 0
- if len(menu_options[cursor_pos]) > 0:
- break
- cursor_pos += 1
+ # in case the new position lands on a "placeholder" we'll skip them as well
+ while True:
+ if cursor_pos >= len(menu_options):
+ cursor_pos = 0
+ if len(menu_options[cursor_pos]) > 0:
+ break
+ cursor_pos += 1
- value = value.strip()
+ value = value.strip()
- # if this calls returns false, we exit the menu
- # we allow for an callback for special processing on realeasing control
- if not self._process_selection(value):
- break
+ # if this calls returns false, we exit the menu
+ # we allow for an callback for special processing on realeasing control
+ if not self._process_selection(value):
+ break
# we get the last action key
actions = {str(v.description):k for k,v in self._menu_options.items()}
- self._last_choice = actions[selection.value.strip()]
+ self._last_choice = actions[selection.value.strip()] # type: ignore
if not self.is_context_mgr:
self.__exit__()
@@ -472,26 +478,16 @@ class GeneralMenu:
self._translation_handler.activate(language)
return language
- def _select_hsm(self, preset :Optional[pathlib.Path] = None) -> Optional[pathlib.Path]:
- title = _('Select which partitions to mark for formatting:')
- title += '\n'
-
- fido_devices = get_fido2_devices()
- indexes = []
- for index, path in enumerate(fido_devices.keys()):
- title += f"{index}: {path} ({fido_devices[path]['manufacturer']} - {fido_devices[path]['product']})"
- indexes.append(f"{index}|{fido_devices[path]['product']}")
+class AbstractSubMenu(AbstractMenu):
+ def __init__(self, data_store: Dict[str, Any] = None):
+ super().__init__(data_store=data_store)
- title += '\n'
-
- choice = Menu(title, indexes, multi=False).run()
-
- match choice.type_:
- case MenuSelectionType.Esc: return preset
- case MenuSelectionType.Selection:
- selection: Any = choice.value
- index = int(selection.split('|',1)[0])
- return pathlib.Path(list(fido_devices.keys())[index])
-
- return None
+ self._menu_options['__separator__'] = Selector('')
+ self._menu_options['back'] = \
+ Selector(
+ _('Back'),
+ no_store=True,
+ enabled=True,
+ exec_func=lambda n, v: True,
+ )
diff --git a/archinstall/lib/menu/global_menu.py b/archinstall/lib/menu/global_menu.py
index 444ba7ee..0d348227 100644
--- a/archinstall/lib/menu/global_menu.py
+++ b/archinstall/lib/menu/global_menu.py
@@ -3,12 +3,13 @@ from __future__ import annotations
from typing import Any, List, Optional, Union, Dict, TYPE_CHECKING
import archinstall
-from ..disk import encrypted_partitions
+from ..disk.encryption import DiskEncryptionMenu
from ..general import SysCommand, secret
from ..hardware import has_uefi
from ..menu import Menu
-from ..menu.selection_menu import Selector, GeneralMenu
+from ..menu.abstract_menu import Selector, AbstractMenu
from ..models import NetworkConfiguration
+from ..models.disk_encryption import DiskEncryption, EncryptionType
from ..models.users import User
from ..output import FormattedOutput
from ..profiles import is_desktop_profile, Profile
@@ -25,7 +26,6 @@ from ..user_interaction import ask_to_configure_network
from ..user_interaction import get_password, ask_for_a_timezone, save_config
from ..user_interaction import select_additional_repositories
from ..user_interaction import select_disk_layout
-from ..user_interaction import select_encrypted_partitions
from ..user_interaction import select_harddrives
from ..user_interaction import select_kernel
from ..user_interaction import select_language
@@ -39,7 +39,7 @@ if TYPE_CHECKING:
_: Any
-class GlobalMenu(GeneralMenu):
+class GlobalMenu(AbstractMenu):
def __init__(self,data_store):
self._disk_check = True
super().__init__(data_store=data_store, auto_cursor=True, preview_size=0.3)
@@ -91,18 +91,13 @@ class GlobalMenu(GeneralMenu):
preview_func=self._prev_disk_layouts,
display_func=lambda x: self._display_disk_layout(x),
dependencies=['harddrives'])
- self._menu_options['!encryption-password'] = \
+ self._menu_options['disk_encryption'] = \
Selector(
- _('Encryption password'),
- lambda x: self._select_encrypted_password(),
- display_func=lambda x: secret(x) if x else 'None',
- dependencies=['harddrives'])
- self._menu_options['HSM'] = Selector(
- description=_('Use HSM to unlock encrypted drive'),
- func=lambda preset: self._select_hsm(preset),
- dependencies=['!encryption-password'],
- default=None
- )
+ _('Disk encryption'),
+ lambda preset: self._disk_encryption(preset),
+ preview_func=self._prev_disk_encryption,
+ display_func=lambda x: self._display_disk_encryption(x),
+ dependencies=['disk_layouts'])
self._menu_options['swap'] = \
Selector(
_('Swap'),
@@ -209,28 +204,6 @@ class GlobalMenu(GeneralMenu):
def post_callback(self,name :str = None ,result :Any = None):
self._update_install_text(name, result)
- def exit_callback(self):
- if self._data_store.get('harddrives', None) and self._data_store.get('!encryption-password', None):
- # 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).
- if len(list(encrypted_partitions(storage['arguments'].get('disk_layouts', [])))) == 0:
- for blockdevice in storage['arguments']['disk_layouts']:
- if storage['arguments']['disk_layouts'][blockdevice].get('partitions'):
- for partition_index in select_encrypted_partitions(
- title=_('Select which partitions to encrypt:'),
- partitions=storage['arguments']['disk_layouts'][blockdevice]['partitions'],
- filter_=(lambda p: p['mountpoint'] != '/boot')
- ):
-
- partition = storage['arguments']['disk_layouts'][blockdevice]['partitions'][partition_index]
- partition['encrypted'] = True
- partition['!password'] = storage['arguments']['!encryption-password']
-
- # We make sure generate-encryption-key-file is set on additional partitions
- # other than the root partition. Otherwise they won't unlock properly #1279
- if partition['mountpoint'] != '/':
- partition['generate-encryption-key-file'] = True
-
def _install_text(self):
missing = len(self._missing_configs())
if missing > 0:
@@ -246,6 +219,20 @@ class GlobalMenu(GeneralMenu):
else:
return str(cur_value)
+ def _disk_encryption(self, preset: Optional[DiskEncryption]) -> Optional[DiskEncryption]:
+ data_store: Dict[str, Any] = {}
+
+ selector = self._menu_options['disk_layouts']
+
+ if selector.has_selection():
+ layouts: Dict[str, Dict[str, Any]] = selector.current_selection
+ else:
+ # this should not happen as the encryption menu has the disk layout as dependency
+ raise ValueError('No disk layout specified')
+
+ disk_encryption = DiskEncryptionMenu(data_store, preset, layouts).run()
+ return disk_encryption
+
def _prev_network_config(self) -> Optional[str]:
selector = self._menu_options['nic']
if selector.has_selection():
@@ -283,6 +270,30 @@ class GlobalMenu(GeneralMenu):
return f'{total_nr} {_("Partitions")}'
return ''
+ def _prev_disk_encryption(self) -> Optional[str]:
+ selector = self._menu_options['disk_encryption']
+ if selector.has_selection():
+ encryption: DiskEncryption = selector.current_selection
+
+ enc_type = EncryptionType.type_to_text(encryption.encryption_type)
+ 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.hsm_device:
+ output += f'HSM: {encryption.hsm_device.manufacturer}'
+
+ return output
+
+ return None
+
+ def _display_disk_encryption(self, current_value: Optional[DiskEncryption]) -> str:
+ if current_value:
+ return EncryptionType.type_to_text(current_value.encryption_type)
+ return ''
+
def _prev_install_missing_config(self) -> Optional[str]:
if missing := self._missing_configs():
text = str(_('Missing configurations:\n'))
@@ -327,11 +338,10 @@ class GlobalMenu(GeneralMenu):
password = get_password(prompt=prompt)
return password
- def _select_encrypted_password(self) -> Optional[str]:
- if passwd := get_password(prompt=str(_('Enter disk encryption password (leave blank for no encryption): '))):
- return passwd
- else:
- return None
+ # def _select_encrypted_password(self) -> Optional[str]:
+ # if passwd := get_password(prompt=str(_('Enter disk encryption password (leave blank for no encryption): '))):
+ # return passwd
+ # return None
def _select_ntp(self, preset :bool = True) -> bool:
ntp = ask_ntp(preset)
diff --git a/archinstall/lib/menu/list_manager.py b/archinstall/lib/menu/list_manager.py
index ae3a6eb5..1e09d987 100644
--- a/archinstall/lib/menu/list_manager.py
+++ b/archinstall/lib/menu/list_manager.py
@@ -104,7 +104,7 @@ class ListManager:
return options, header
def _run_actions_on_entry(self, entry: Any):
- options = self.filter_options(entry,self._sub_menu_actions) + [self._cancel_action]
+ options = self.filter_options(entry, self._sub_menu_actions) + [self._cancel_action]
display_value = self.selected_action_display(entry)
prompt = _("Select an action for '{}'").format(display_value)
diff --git a/archinstall/lib/menu/menu.py b/archinstall/lib/menu/menu.py
index 773ff1de..09685c55 100644
--- a/archinstall/lib/menu/menu.py
+++ b/archinstall/lib/menu/menu.py
@@ -18,8 +18,8 @@ if TYPE_CHECKING:
class MenuSelectionType(Enum):
Selection = auto()
- Esc = auto()
- Ctrl_c = auto()
+ Skip = auto()
+ Reset = auto()
@dataclass
@@ -56,8 +56,8 @@ class Menu(TerminalMenu):
preview_size: float = 0.0,
preview_title: str = 'Info',
header :Union[List[str],str] = None,
- raise_error_on_interrupt :bool = False,
- raise_error_warning_msg :str = '',
+ allow_reset :bool = False,
+ allow_reset_warning_msg :str = '',
clear_screen: bool = True,
show_search_hint: bool = True,
cycle_cursor: bool = True,
@@ -150,17 +150,10 @@ class Menu(TerminalMenu):
self._skip = skip
self._default_option = default_option
self._multi = multi
- self._raise_error_on_interrupt = raise_error_on_interrupt
- self._raise_error_warning_msg = raise_error_warning_msg
+ self._raise_error_on_interrupt = allow_reset
+ self._raise_error_warning_msg = allow_reset_warning_msg
self._preview_command = preview_command
- menu_title = f'\n{title}\n\n'
-
- if header:
- if not isinstance(header,(list,tuple)):
- header = [header]
- menu_title += '\n'.join(header)
-
action_info = ''
if skip:
action_info += str(_('ESC to skip'))
@@ -173,7 +166,15 @@ class Menu(TerminalMenu):
action_info += ', ' if len(action_info) > 0 else ''
action_info += str(_('TAB to select'))
- menu_title += action_info + '\n'
+ if action_info:
+ action_info += '\n\n'
+
+ menu_title = f'\n{action_info}{title}\n'
+
+ if header:
+ if not isinstance(header,(list,tuple)):
+ header = [header]
+ menu_title += '\n' + '\n'.join(header)
if default_option:
# if a default value was specified we move that one
@@ -215,7 +216,7 @@ class Menu(TerminalMenu):
try:
idx = self.show()
except KeyboardInterrupt:
- return MenuSelection(type_=MenuSelectionType.Ctrl_c)
+ return MenuSelection(type_=MenuSelectionType.Reset)
def check_default(elem):
if self._default_option is not None and f'{self._default_option} {self._default_str}' in elem:
@@ -234,7 +235,7 @@ class Menu(TerminalMenu):
result = check_default(self._menu_options[idx])
return MenuSelection(type_=MenuSelectionType.Selection, value=result)
else:
- return MenuSelection(type_=MenuSelectionType.Esc)
+ return MenuSelection(type_=MenuSelectionType.Skip)
def _preview_wrapper(self, preview_command: Optional[Callable], current_selection: str) -> Optional[str]:
if preview_command:
@@ -246,15 +247,15 @@ class Menu(TerminalMenu):
def run(self) -> MenuSelection:
ret = self._show()
- if ret.type_ == MenuSelectionType.Ctrl_c:
+ if ret.type_ == MenuSelectionType.Reset:
if self._raise_error_on_interrupt and len(self._raise_error_warning_msg) > 0:
response = Menu(self._raise_error_warning_msg, Menu.yes_no(), skip=False).run()
if response.value == Menu.no():
return self.run()
-
- if ret.type_ is not MenuSelectionType.Selection and not self._skip:
- system('clear')
- return self.run()
+ elif ret.type_ is MenuSelectionType.Skip:
+ if not self._skip:
+ system('clear')
+ return self.run()
return ret
diff --git a/archinstall/lib/menu/table_selection_menu.py b/archinstall/lib/menu/table_selection_menu.py
new file mode 100644
index 00000000..09cd6ee2
--- /dev/null
+++ b/archinstall/lib/menu/table_selection_menu.py
@@ -0,0 +1,107 @@
+from typing import Any, Tuple, List, Dict, Optional
+
+from .menu import MenuSelectionType, MenuSelection
+from ..output import FormattedOutput
+from ..menu import Menu
+
+
+class TableMenu(Menu):
+ def __init__(
+ self,
+ title: str,
+ data: List[Any] = [],
+ table_data: Optional[Tuple[List[Any], str]] = None,
+ custom_menu_options: List[str] = [],
+ default: Any = None,
+ multi: bool = False
+ ):
+ """
+ param title: Text that will be displayed above the menu
+ :type title: str
+
+ param data: List of objects that will be displayed as rows
+ :type data: List
+
+ param table_data: Tuple containing a list of objects and the corresponding
+ Table representation of the data as string; this can be used in case the table
+ has to be crafted in a more sophisticated manner
+ :type table_data: Optional[Tuple[List[Any], str]]
+
+ param custom_options: List of custom options that will be displayed under the table
+ :type custom_menu_options: List
+ """
+ if not data and not table_data:
+ raise ValueError('Either "data" or "table_data" must be provided')
+
+ self._custom_options = custom_menu_options
+ self._multi = multi
+
+ if multi:
+ header_padding = 7
+ else:
+ header_padding = 2
+
+ if len(data):
+ table_text = FormattedOutput.as_table(data)
+ rows = table_text.split('\n')
+ table = self._create_table(data, rows, header_padding=header_padding)
+ elif table_data is not None:
+ # we assume the table to be
+ # h1 | h2
+ # -----------
+ # r1 | r2
+ data = table_data[0]
+ rows = table_data[1].split('\n')
+ table = self._create_table(data, rows, header_padding=header_padding)
+
+ self._options, header = self._prepare_selection(table)
+
+ super().__init__(
+ title,
+ self._options,
+ header=header,
+ skip_empty_entries=True,
+ show_search_hint=False,
+ allow_reset=True,
+ multi=multi,
+ default_option=default
+ )
+
+ def run(self) -> MenuSelection:
+ choice = super().run()
+
+ match choice.type_:
+ case MenuSelectionType.Selection:
+ if self._multi:
+ choice.value = [self._options[val] for val in choice.value] # type: ignore
+ else:
+ choice.value = self._options[choice.value] # type: ignore
+
+ return choice
+
+ def _create_table(self, data: List[Any], rows: List[str], header_padding: int = 2) -> Dict[str, Any]:
+ # these are the header rows of the table and do not map to any data obviously
+ # we're adding 2 spaces as prefix because the menu selector '> ' will be put before
+ # the selectable rows so the header has to be aligned
+ padding = ' ' * header_padding
+ display_data = {f'{padding}{rows[0]}': None, f'{padding}{rows[1]}': None}
+
+ for row, entry in zip(rows[2:], data):
+ row = row.replace('|', '\\|')
+ display_data[row] = entry
+
+ return display_data
+
+ def _prepare_selection(self, table: Dict[str, Any]) -> Tuple[Dict[str, Any], str]:
+ # header rows are mapped to None so make sure to exclude those from the selectable data
+ options = {key: val for key, val in table.items() if val is not None}
+ header = ''
+
+ if len(options) > 0:
+ table_header = [key for key, val in table.items() if val is None]
+ header = '\n'.join(table_header)
+
+ custom = {key: None for key in self._custom_options}
+ options.update(custom)
+
+ return options, header
diff --git a/archinstall/lib/models/disk_encryption.py b/archinstall/lib/models/disk_encryption.py
new file mode 100644
index 00000000..80627767
--- /dev/null
+++ b/archinstall/lib/models/disk_encryption.py
@@ -0,0 +1,43 @@
+from dataclasses import dataclass, field
+from enum import Enum, auto
+from typing import Optional, List, Dict, TYPE_CHECKING, Any
+
+from archinstall.lib.hsm.fido import Fido2Device
+
+if TYPE_CHECKING:
+ _: Any
+
+
+class EncryptionType(Enum):
+ Partition = auto()
+ # FullDiskEncryption = auto()
+
+ @classmethod
+ def _encryption_type_mapper(cls) -> Dict[str, 'EncryptionType']:
+ return {
+ # str(_('Full disk encryption')): EncryptionType.FullDiskEncryption,
+ str(_('Partition encryption')): EncryptionType.Partition
+ }
+
+ @classmethod
+ def text_to_type(cls, text: str) -> 'EncryptionType':
+ mapping = cls._encryption_type_mapper()
+ return mapping[text]
+
+ @classmethod
+ def type_to_text(cls, type_: 'EncryptionType') -> str:
+ mapping = cls._encryption_type_mapper()
+ type_to_text = {type_: text for text, type_ in mapping.items()}
+ return type_to_text[type_]
+
+
+@dataclass
+class DiskEncryption:
+ encryption_type: EncryptionType = EncryptionType.Partition
+ encryption_password: str = ''
+ partitions: List[str] = field(default_factory=list)
+ hsm_device: Optional[Fido2Device] = None
+
+ def generate_encryption_file(self, partition) -> bool:
+ return partition in self.partitions and partition['mountpoint'] != '/'
+
diff --git a/archinstall/lib/user_interaction/__init__.py b/archinstall/lib/user_interaction/__init__.py
index a1ca2652..2bc46759 100644
--- a/archinstall/lib/user_interaction/__init__.py
+++ b/archinstall/lib/user_interaction/__init__.py
@@ -4,7 +4,7 @@ from .backwards_compatible_conf import generic_select, generic_multi_select
from .locale_conf import select_locale_lang, select_locale_enc
from .system_conf import select_kernel, select_harddrives, select_driver, ask_for_bootloader, ask_for_swap
from .network_conf import ask_to_configure_network
-from .partitioning_conf import select_partition, select_encrypted_partitions
+from .partitioning_conf import select_partition
from .general_conf import (ask_ntp, ask_for_a_timezone, ask_for_audio_selection, select_language, select_mirror_regions,
select_profile, select_archinstall_language, ask_additional_packages_to_install,
select_additional_repositories, ask_hostname, add_number_of_parrallel_downloads)
diff --git a/archinstall/lib/user_interaction/disk_conf.py b/archinstall/lib/user_interaction/disk_conf.py
index b5ed6967..554d13ef 100644
--- a/archinstall/lib/user_interaction/disk_conf.py
+++ b/archinstall/lib/user_interaction/disk_conf.py
@@ -45,13 +45,13 @@ def select_disk_layout(preset: Optional[Dict[str, Any]], block_devices: list, ad
choice = Menu(
_('Select what you wish to do with the selected block devices'),
modes,
- raise_error_on_interrupt=True,
- raise_error_warning_msg=warning
+ allow_reset=True,
+ allow_reset_warning_msg=warning
).run()
match choice.type_:
- case MenuSelectionType.Esc: return preset
- case MenuSelectionType.Ctrl_c: return None
+ case MenuSelectionType.Skip: return preset
+ case MenuSelectionType.Reset: return None
case MenuSelectionType.Selection:
if choice.value == wipe_mode:
return get_default_partition_layout(block_devices, advanced_options)
@@ -77,7 +77,7 @@ def select_disk(dict_o_disks: Dict[str, BlockDevice]) -> Optional[BlockDevice]:
choice = Menu(title, drives).run()
- if choice.type_ == MenuSelectionType.Esc:
+ if choice.type_ == MenuSelectionType.Skip:
return None
drive = dict_o_disks[choice.value]
diff --git a/archinstall/lib/user_interaction/general_conf.py b/archinstall/lib/user_interaction/general_conf.py
index efd746a4..76631a98 100644
--- a/archinstall/lib/user_interaction/general_conf.py
+++ b/archinstall/lib/user_interaction/general_conf.py
@@ -48,7 +48,7 @@ def ask_for_a_timezone(preset: str = None) -> str:
).run()
match choice.type_:
- case MenuSelectionType.Esc: return preset
+ case MenuSelectionType.Skip: return preset
case MenuSelectionType.Selection: return choice.value
@@ -60,7 +60,7 @@ def ask_for_audio_selection(desktop: bool = True, preset: str = None) -> str:
choice = Menu(_('Choose an audio server'), choices, preset_values=preset, default_option=default).run()
match choice.type_:
- case MenuSelectionType.Esc: return preset
+ case MenuSelectionType.Skip: return preset
case MenuSelectionType.Selection: return choice.value
@@ -107,12 +107,12 @@ def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]:
list(mirrors.keys()),
preset_values=preselected,
multi=True,
- raise_error_on_interrupt=True
+ allow_reset=True
).run()
match selected_mirror.type_:
- case MenuSelectionType.Ctrl_c: return {}
- case MenuSelectionType.Esc: return preset_values
+ case MenuSelectionType.Reset: return {}
+ case MenuSelectionType.Skip: return preset_values
case _: return {selected: mirrors[selected] for selected in selected_mirror.value}
@@ -134,7 +134,7 @@ def select_archinstall_language(languages: List[Language], preset_value: Languag
).run()
match choice.type_:
- case MenuSelectionType.Esc:
+ case MenuSelectionType.Skip:
return preset_value
case MenuSelectionType.Selection:
return options[choice.value]
@@ -163,21 +163,21 @@ def select_profile(preset) -> Optional[Profile]:
selection = Menu(
title=title,
p_options=list(options.keys()),
- raise_error_on_interrupt=True,
- raise_error_warning_msg=warning
+ allow_reset=True,
+ allow_reset_warning_msg=warning
).run()
match selection.type_:
case MenuSelectionType.Selection:
return options[selection.value] if selection.value is not None else None
- case MenuSelectionType.Ctrl_c:
+ case MenuSelectionType.Reset:
storage['profile_minimal'] = False
storage['_selected_servers'] = []
storage['_desktop_profile'] = None
storage['arguments']['desktop-environment'] = None
storage['arguments']['gfx_driver_packages'] = None
return None
- case MenuSelectionType.Esc:
+ case MenuSelectionType.Skip:
return None
@@ -259,10 +259,10 @@ def select_additional_repositories(preset: List[str]) -> List[str]:
sort=False,
multi=True,
preset_values=preset,
- raise_error_on_interrupt=True
+ allow_reset=True
).run()
match choice.type_:
- case MenuSelectionType.Esc: return preset
- case MenuSelectionType.Ctrl_c: return []
+ case MenuSelectionType.Skip: return preset
+ case MenuSelectionType.Reset: return []
case MenuSelectionType.Selection: return choice.value
diff --git a/archinstall/lib/user_interaction/locale_conf.py b/archinstall/lib/user_interaction/locale_conf.py
index 15720064..bbbe070b 100644
--- a/archinstall/lib/user_interaction/locale_conf.py
+++ b/archinstall/lib/user_interaction/locale_conf.py
@@ -23,7 +23,7 @@ def select_locale_lang(preset: str = None) -> str:
match selected_locale.type_:
case MenuSelectionType.Selection: return selected_locale.value
- case MenuSelectionType.Esc: return preset
+ case MenuSelectionType.Skip: return preset
def select_locale_enc(preset: str = None) -> str:
@@ -39,4 +39,4 @@ def select_locale_enc(preset: str = None) -> str:
match selected_locale.type_:
case MenuSelectionType.Selection: return selected_locale.value
- case MenuSelectionType.Esc: return preset
+ case MenuSelectionType.Skip: return preset
diff --git a/archinstall/lib/user_interaction/network_conf.py b/archinstall/lib/user_interaction/network_conf.py
index 557e8ed8..5e637f23 100644
--- a/archinstall/lib/user_interaction/network_conf.py
+++ b/archinstall/lib/user_interaction/network_conf.py
@@ -71,7 +71,7 @@ class ManualNetworkConfig(ListManager):
available = set(all_ifaces) - set(existing_ifaces)
choice = Menu(str(_('Select interface to add')), list(available), skip=True).run()
- if choice.type_ == MenuSelectionType.Esc:
+ if choice.type_ == MenuSelectionType.Skip:
return None
return choice.value
@@ -154,13 +154,13 @@ def ask_to_configure_network(
list(network_options.values()),
cursor_index=cursor_idx,
sort=False,
- raise_error_on_interrupt=True,
- raise_error_warning_msg=warning
+ allow_reset=True,
+ allow_reset_warning_msg=warning
).run()
match choice.type_:
- case MenuSelectionType.Esc: return preset
- case MenuSelectionType.Ctrl_c: return None
+ case MenuSelectionType.Skip: return preset
+ case MenuSelectionType.Reset: return None
if choice.value == network_options['none']:
return None
diff --git a/archinstall/lib/user_interaction/partitioning_conf.py b/archinstall/lib/user_interaction/partitioning_conf.py
index f2e6b881..cff76dc2 100644
--- a/archinstall/lib/user_interaction/partitioning_conf.py
+++ b/archinstall/lib/user_interaction/partitioning_conf.py
@@ -119,7 +119,7 @@ def select_partition(
choice = Menu(title, partition_indexes, multi=multiple).run()
- if choice.type_ == MenuSelectionType.Esc:
+ if choice.type_ == MenuSelectionType.Skip:
return None
if isinstance(choice.value, list):
@@ -150,7 +150,6 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
delete_all_partitions = str(_('Clear/Delete all partitions'))
assign_mount_point = str(_('Assign mount-point for a partition'))
mark_formatted = str(_('Mark/Unmark a partition to be formatted (wipes data)'))
- mark_encrypted = str(_('Mark/Unmark a partition as encrypted'))
mark_compressed = str(_('Mark/Unmark a partition as compressed (btrfs only)'))
mark_bootable = str(_('Mark/Unmark a partition as bootable (automatic for /boot)'))
set_filesystem_partition = str(_('Set desired filesystem for a partition'))
@@ -167,7 +166,6 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
delete_all_partitions,
assign_mount_point,
mark_formatted,
- mark_encrypted,
mark_bootable,
mark_compressed,
set_filesystem_partition,
@@ -207,7 +205,7 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
fs_choice = Menu(_('Enter a desired filesystem type for the partition'), fs_types()).run()
- if fs_choice.type_ == MenuSelectionType.Esc:
+ if fs_choice.type_ == MenuSelectionType.Skip:
continue
prompt = str(_('Enter the start sector (percentage or block number, default: {}): ')).format(
@@ -322,15 +320,6 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
# Negate the current wipe marking
block_device_struct["partitions"][partition]['wipe'] = not block_device_struct["partitions"][partition].get('wipe', False)
- elif task == mark_encrypted:
- title = _('{}\n\nSelect which partition to mark as encrypted').format(current_layout)
- partition = select_partition(title, block_device_struct["partitions"])
-
- if partition is not None:
- # Negate the current encryption marking
- block_device_struct["partitions"][partition]['encrypted'] = \
- not block_device_struct["partitions"][partition].get('encrypted', False)
-
elif task == mark_bootable:
title = _('{}\n\nSelect which partition to mark as bootable').format(current_layout)
partition = select_partition(title, block_device_struct["partitions"])
@@ -371,30 +360,3 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
block_device_struct["partitions"][partition]['btrfs']['subvolumes'] = result
return block_device_struct
-
-
-def select_encrypted_partitions(
- title :str,
- partitions :List[Partition],
- multiple :bool = True,
- filter_ :Callable = None
-) -> Optional[int, List[int]]:
- partition_indexes = _get_partitions(partitions, filter_)
-
- if len(partition_indexes) == 0:
- return None
-
- # show current partition layout:
- if len(partitions):
- title += current_partition_layout(partitions, with_idx=True) + '\n'
-
- choice = Menu(title, partition_indexes, multi=multiple).run()
-
- if choice.type_ == MenuSelectionType.Esc:
- return None
-
- if isinstance(choice.value, list):
- for partition_index in choice.value:
- yield int(partition_index)
- else:
- yield (partition_index)
diff --git a/archinstall/lib/user_interaction/save_conf.py b/archinstall/lib/user_interaction/save_conf.py
index f542bc9b..d60ef995 100644
--- a/archinstall/lib/user_interaction/save_conf.py
+++ b/archinstall/lib/user_interaction/save_conf.py
@@ -55,7 +55,7 @@ def save_config(config: Dict):
preview_command=preview
).run()
- if choice.type_ == MenuSelectionType.Esc:
+ if choice.type_ == MenuSelectionType.Skip:
return
while True:
diff --git a/archinstall/lib/user_interaction/system_conf.py b/archinstall/lib/user_interaction/system_conf.py
index 8b574b2c..42a6cec7 100644
--- a/archinstall/lib/user_interaction/system_conf.py
+++ b/archinstall/lib/user_interaction/system_conf.py
@@ -32,13 +32,13 @@ def select_kernel(preset: List[str] = None) -> List[str]:
sort=True,
multi=True,
preset_values=preset,
- raise_error_on_interrupt=True,
- raise_error_warning_msg=warning
+ allow_reset=True,
+ allow_reset_warning_msg=warning
).run()
match choice.type_:
- case MenuSelectionType.Esc: return preset
- case MenuSelectionType.Ctrl_c: return []
+ case MenuSelectionType.Skip: return preset
+ case MenuSelectionType.Reset: return []
case MenuSelectionType.Selection: return choice.value
@@ -62,13 +62,13 @@ def select_harddrives(preset: List[str] = []) -> List[str]:
list(options.keys()),
preset_values=preset,
multi=True,
- raise_error_on_interrupt=True,
- raise_error_warning_msg=warning
+ allow_reset=True,
+ allow_reset_warning_msg=warning
).run()
match selected_harddrive.type_:
- case MenuSelectionType.Ctrl_c: return []
- case MenuSelectionType.Esc: return preset
+ case MenuSelectionType.Reset: return []
+ case MenuSelectionType.Skip: return preset
case MenuSelectionType.Selection: return [options[i] for i in selected_harddrive.value]
@@ -132,7 +132,7 @@ def ask_for_bootloader(advanced_options: bool = False, preset: str = None) -> st
).run()
match selection.type_:
- case MenuSelectionType.Esc: return preset
+ case MenuSelectionType.Skip: return preset
case MenuSelectionType.Selection: bootloader = 'grub-install' if selection.value == Menu.yes() else bootloader
else:
# We use the common names for the bootloader as the selection, and map it back to the expected values.
@@ -141,7 +141,7 @@ def ask_for_bootloader(advanced_options: bool = False, preset: str = None) -> st
value = ''
match selection.type_:
- case MenuSelectionType.Esc: value = preset_val
+ case MenuSelectionType.Skip: value = preset_val
case MenuSelectionType.Selection: value = selection.value
if value != "":
@@ -165,5 +165,5 @@ def ask_for_swap(preset: bool = True) -> bool:
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes(), preset_values=preset_val).run()
match choice.type_:
- case MenuSelectionType.Esc: return preset
+ case MenuSelectionType.Skip: return preset
case MenuSelectionType.Selection: return False if choice.value == Menu.no() else True
diff --git a/archinstall/locales/ar/LC_MESSAGES/base.po b/archinstall/locales/ar/LC_MESSAGES/base.po
index 51b6c3d6..1a9fc1aa 100644
--- a/archinstall/locales/ar/LC_MESSAGES/base.po
+++ b/archinstall/locales/ar/LC_MESSAGES/base.po
@@ -721,7 +721,7 @@ msgstr ""
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr ""
-msgid "Select which partitions to encrypt:"
+msgid "Select which partitions to encrypt"
msgstr ""
msgid "very weak"
diff --git a/archinstall/locales/base.pot b/archinstall/locales/base.pot
index 7398d33a..2becbbf3 100644
--- a/archinstall/locales/base.pot
+++ b/archinstall/locales/base.pot
@@ -761,7 +761,7 @@ msgstr ""
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr ""
-msgid "Select which partitions to encrypt:"
+msgid "Select which partitions to encrypt"
msgstr ""
msgid "very weak"
diff --git a/archinstall/locales/cs/LC_MESSAGES/base.po b/archinstall/locales/cs/LC_MESSAGES/base.po
index 733c9cae..b3dea244 100644
--- a/archinstall/locales/cs/LC_MESSAGES/base.po
+++ b/archinstall/locales/cs/LC_MESSAGES/base.po
@@ -756,8 +756,8 @@ msgstr "Zadané uživatelské jméno není platné. Zkuste to znovu"
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "Má být \"{}\" superuživatelem (sudoer)?"
-msgid "Select which partitions to encrypt:"
-msgstr "Zvolte oddíl, který bude označen jako šifrovaný:"
+msgid "Select which partitions to encrypt"
+msgstr "Zvolte oddíl, který bude označen jako šifrovaný"
msgid "very weak"
msgstr "velmi slabé"
diff --git a/archinstall/locales/de/LC_MESSAGES/base.po b/archinstall/locales/de/LC_MESSAGES/base.po
index 46782bc3..dee2b481 100644
--- a/archinstall/locales/de/LC_MESSAGES/base.po
+++ b/archinstall/locales/de/LC_MESSAGES/base.po
@@ -776,11 +776,8 @@ msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "Soll {} ein superuser sein (sudoer)?"
#, fuzzy
-msgid "Select which partitions to encrypt:"
-msgstr ""
-"{}\n"
-"\n"
-"Bitte wählen sie welche Partition verschlüsselt werden soll"
+msgid "Select which partitions to encrypt"
+msgstr "Bitte wählen sie welche Partition verschlüsselt werden soll"
msgid "very weak"
msgstr ""
diff --git a/archinstall/locales/el/LC_MESSAGES/base.po b/archinstall/locales/el/LC_MESSAGES/base.po
index 6425ba96..c41dbb7e 100644
--- a/archinstall/locales/el/LC_MESSAGES/base.po
+++ b/archinstall/locales/el/LC_MESSAGES/base.po
@@ -763,7 +763,7 @@ msgstr "Το όνομα χρήστη που εισάγατε δεν είναι
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "Θα έπρεπε ο \"{}\" να είναι υπερχρήστης (sudo);"
-msgid "Select which partitions to encrypt:"
+msgid "Select which partitions to encrypt"
msgstr "Επιλέξτε ποιες διαμερίσεις να κρυπτογραφηθούν."
msgid "very weak"
diff --git a/archinstall/locales/en/LC_MESSAGES/base.po b/archinstall/locales/en/LC_MESSAGES/base.po
index 01f59274..62543eaa 100644
--- a/archinstall/locales/en/LC_MESSAGES/base.po
+++ b/archinstall/locales/en/LC_MESSAGES/base.po
@@ -717,7 +717,7 @@ msgstr ""
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr ""
-msgid "Select which partitions to encrypt:"
+msgid "Select which partitions to encrypt"
msgstr ""
msgid "very weak"
diff --git a/archinstall/locales/es/LC_MESSAGES/base.po b/archinstall/locales/es/LC_MESSAGES/base.po
index 3bdbe72f..f744daae 100644
--- a/archinstall/locales/es/LC_MESSAGES/base.po
+++ b/archinstall/locales/es/LC_MESSAGES/base.po
@@ -762,8 +762,8 @@ msgstr "El nombre de usuario que ingresó no es válido. Intente nuevamente"
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "¿Debe \"{}\" ser un superusuario (sudo)?"
-msgid "Select which partitions to encrypt:"
-msgstr "Seleccione qué particiones cifrar:"
+msgid "Select which partitions to encrypt"
+msgstr "Seleccione qué particiones cifrar"
msgid "very weak"
msgstr ""
diff --git a/archinstall/locales/fr/LC_MESSAGES/base.po b/archinstall/locales/fr/LC_MESSAGES/base.po
index e58592bf..f5946503 100644
--- a/archinstall/locales/fr/LC_MESSAGES/base.po
+++ b/archinstall/locales/fr/LC_MESSAGES/base.po
@@ -765,11 +765,8 @@ msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "\"{}\" devrait-il être un superutilisateur (sudo) ?"
#, fuzzy
-msgid "Select which partitions to encrypt:"
-msgstr ""
-"{}\n"
-"\n"
-"Sélectionner la partition à marquer comme chiffrée"
+msgid "Select which partitions to encrypt"
+msgstr "Sélectionner la partition à marquer comme chiffrée"
msgid "very weak"
msgstr ""
diff --git a/archinstall/locales/id/LC_MESSAGES/base.po b/archinstall/locales/id/LC_MESSAGES/base.po
index 0ace1b09..85479389 100644
--- a/archinstall/locales/id/LC_MESSAGES/base.po
+++ b/archinstall/locales/id/LC_MESSAGES/base.po
@@ -763,8 +763,8 @@ msgstr "Nama pengguna yang Anda masukkan tidak valid. Coba lagi"
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "Haruskah \"{}\" menjadi superuser (sudo)?"
-msgid "Select which partitions to encrypt:"
-msgstr "Pilih partisi mana yang akan dienkripsi:"
+msgid "Select which partitions to encrypt"
+msgstr "Pilih partisi mana yang akan dienkripsi"
msgid "very weak"
msgstr "sangat lemah"
diff --git a/archinstall/locales/it/LC_MESSAGES/base.po b/archinstall/locales/it/LC_MESSAGES/base.po
index d122b87f..176d3959 100644
--- a/archinstall/locales/it/LC_MESSAGES/base.po
+++ b/archinstall/locales/it/LC_MESSAGES/base.po
@@ -763,8 +763,8 @@ msgstr "Il nome utente inserito non è valido. Riprova"
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "\"{}\" dovrebbe essere un superutente? (sudo)"
-msgid "Select which partitions to encrypt:"
-msgstr "Seleziona le partizioni da crittografare:"
+msgid "Select which partitions to encrypt"
+msgstr "Seleziona le partizioni da crittografare"
msgid "very weak"
msgstr "molto debole"
diff --git a/archinstall/locales/nl/LC_MESSAGES/base.po b/archinstall/locales/nl/LC_MESSAGES/base.po
index 4eb93e22..b7323059 100644
--- a/archinstall/locales/nl/LC_MESSAGES/base.po
+++ b/archinstall/locales/nl/LC_MESSAGES/base.po
@@ -791,11 +791,8 @@ msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "Moet {} gebruiker een beheerder (sudoer) worden?"
#, fuzzy
-msgid "Select which partitions to encrypt:"
-msgstr ""
-"{}\n"
-"\n"
-"Kies welke partitie moet worden versleuteld"
+msgid "Select which partitions to encrypt"
+msgstr "Kies welke partitie moet worden versleuteld"
msgid "very weak"
msgstr ""
diff --git a/archinstall/locales/pl/LC_MESSAGES/base.po b/archinstall/locales/pl/LC_MESSAGES/base.po
index 2d9968dc..6655bbbd 100644
--- a/archinstall/locales/pl/LC_MESSAGES/base.po
+++ b/archinstall/locales/pl/LC_MESSAGES/base.po
@@ -763,11 +763,9 @@ msgstr "Wprowadzona nazwa użytkownika jest nieprawidłowa. Spróbuj ponownie"
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "Czy \"{}\" powinien być superuserem (sudo)?"
-msgid "Select which partitions to encrypt:"
-msgstr ""
-"{}\n"
-"\n"
-"Wybierz partycje, które mają zostać zaszyfrowane:"
+#, fuzzy
+msgid "Select which partitions to encrypt"
+msgstr "Wybierz partycja która ma zostać zaszyfrowana"
msgid "very weak"
msgstr "bardzo słabe"
diff --git a/archinstall/locales/pt/LC_MESSAGES/base.po b/archinstall/locales/pt/LC_MESSAGES/base.po
index 55569546..683de0ad 100644
--- a/archinstall/locales/pt/LC_MESSAGES/base.po
+++ b/archinstall/locales/pt/LC_MESSAGES/base.po
@@ -811,11 +811,8 @@ msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "Deve {} ser um superutilizador (sudoer)?"
#, fuzzy
-msgid "Select which partitions to encrypt:"
-msgstr ""
-"{}\n"
-"\n"
-"Seleciona a partição a marcar como encriptada"
+msgid "Select which partitions to encrypt"
+msgstr "Seleciona a partição a marcar como encriptada"
msgid "very weak"
msgstr ""
diff --git a/archinstall/locales/pt_BR/LC_MESSAGES/base.po b/archinstall/locales/pt_BR/LC_MESSAGES/base.po
index 1981c799..938f5068 100644
--- a/archinstall/locales/pt_BR/LC_MESSAGES/base.po
+++ b/archinstall/locales/pt_BR/LC_MESSAGES/base.po
@@ -761,8 +761,8 @@ msgstr "O nome de usuário que você digitou é inválido. Tente novamente"
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "\"{}\" deve ser um superusuário (sudo)?"
-msgid "Select which partitions to encrypt:"
-msgstr "Selecione quais partições encriptar:"
+msgid "Select which partitions to encrypt"
+msgstr "Selecione quais partições encriptar"
msgid "very weak"
msgstr "muito fraca"
diff --git a/archinstall/locales/ru/LC_MESSAGES/base.po b/archinstall/locales/ru/LC_MESSAGES/base.po
index 6d5799eb..a62a8385 100644
--- a/archinstall/locales/ru/LC_MESSAGES/base.po
+++ b/archinstall/locales/ru/LC_MESSAGES/base.po
@@ -764,8 +764,8 @@ msgstr "Введенное вами имя пользователя недейс
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "Должен ли \"{}\" быть суперпользователем (sudo)?"
-msgid "Select which partitions to encrypt:"
-msgstr "Выберите разделы для шифрования:"
+msgid "Select which partitions to encrypt"
+msgstr "Выберите разделы для шифрования"
msgid "very weak"
msgstr "очень слабый"
diff --git a/archinstall/locales/sv/LC_MESSAGES/base.po b/archinstall/locales/sv/LC_MESSAGES/base.po
index 9d7f7455..fc311551 100644
--- a/archinstall/locales/sv/LC_MESSAGES/base.po
+++ b/archinstall/locales/sv/LC_MESSAGES/base.po
@@ -772,11 +772,8 @@ msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "Är detta en superanvändare (sudo-rättigheter)?"
#, fuzzy
-msgid "Select which partitions to encrypt:"
-msgstr ""
-"{}\n"
-"\n"
-"Välj vilken partition som skall markeras för kryptering"
+msgid "Select which partitions to encrypt"
+msgstr "Välj vilken partition som skall markeras för kryptering"
msgid "very weak"
msgstr ""
diff --git a/archinstall/locales/ta/LC_MESSAGES/base.po b/archinstall/locales/ta/LC_MESSAGES/base.po
index 3ea3dd19..4375f477 100644
--- a/archinstall/locales/ta/LC_MESSAGES/base.po
+++ b/archinstall/locales/ta/LC_MESSAGES/base.po
@@ -763,8 +763,8 @@ msgstr "நீங்கள் உள்ளிட்ட பயனர்பெய
msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "\"{}\" ஒரு சூப்பர் யூசராக (sudo) இருக்க வேண்டுமா?"
-msgid "Select which partitions to encrypt:"
-msgstr "குறியாக்கம் செய்ய வேண்டிய பகிர்வுகளைத் தேர்ந்தெடுக்கவும்:"
+msgid "Select which partitions to encrypt"
+msgstr "குறியாக்கம் செய்ய வேண்டிய பகிர்வுகளைத் தேர்ந்தெடுக்கவும்"
msgid "very weak"
msgstr "மிகவும் பலவீனமானது"
diff --git a/archinstall/locales/tr/LC_MESSAGES/base.po b/archinstall/locales/tr/LC_MESSAGES/base.po
index c38f467e..fd1e2393 100644
--- a/archinstall/locales/tr/LC_MESSAGES/base.po
+++ b/archinstall/locales/tr/LC_MESSAGES/base.po
@@ -772,11 +772,8 @@ msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "{} bir süper kullanıcı (sudoer) olmalı mı?"
#, fuzzy
-msgid "Select which partitions to encrypt:"
-msgstr ""
-"{}\n"
-"\n"
-"Hangi disk bölümünün şifrelenmiş olarak işaretleneceğini seçin"
+msgid "Select which partitions to encrypt"
+msgstr "Hangi disk bölümünün şifrelenmiş olarak işaretleneceğini seçin"
msgid "very weak"
msgstr ""
diff --git a/archinstall/locales/ur/LC_MESSAGES/base.po b/archinstall/locales/ur/LC_MESSAGES/base.po
index 8ab6c4e2..0b024031 100644
--- a/archinstall/locales/ur/LC_MESSAGES/base.po
+++ b/archinstall/locales/ur/LC_MESSAGES/base.po
@@ -794,11 +794,8 @@ msgid "Should \"{}\" be a superuser (sudo)?"
msgstr "کیا {} کو سپر یوزر (sudoer) ہونا چاہیے؟"
#, fuzzy
-msgid "Select which partitions to encrypt:"
-msgstr ""
-"{}\n"
-"\n"
-"منتخب کریں کہ کس پارٹیشن کو انکرپٹڈ یا خفیہ رکھنا ہے"
+msgid "Select which partitions to encrypt"
+msgstr "منتخب کریں کہ کس پارٹیشن کو انکرپٹڈ یا خفیہ رکھنا ہے"
msgid "very weak"
msgstr ""
diff --git a/examples/guided.py b/examples/guided.py
index eba78a1a..4b655240 100644
--- a/examples/guided.py
+++ b/examples/guided.py
@@ -54,8 +54,8 @@ def ask_user_questions():
global_menu.enable('disk_layouts')
- # Get disk encryption password (or skip if blank)
- global_menu.enable('!encryption-password')
+ # Specify disk encryption options
+ global_menu.enable('disk_encryption')
if archinstall.arguments.get('advanced', False) or archinstall.arguments.get('HSM', None):
# Enables the use of HSM
diff --git a/examples/only_hd.py b/examples/only_hd.py
index b3379601..e3d18f0a 100644
--- a/examples/only_hd.py
+++ b/examples/only_hd.py
@@ -12,7 +12,7 @@ class OnlyHDMenu(archinstall.GlobalMenu):
super()._setup_selection_menu_options()
options_list = []
mandatory_list = []
- options_list = ['harddrives', 'disk_layouts', '!encryption-password','swap']
+ options_list = ['harddrives', 'disk_layouts', 'disk_encryption','swap']
mandatory_list = ['harddrives']
options_list.extend(['save_config','install','abort'])
diff --git a/examples/swiss.py b/examples/swiss.py
index 419bd859..442281de 100644
--- a/examples/swiss.py
+++ b/examples/swiss.py
@@ -153,7 +153,7 @@ def select_installed_locale(mode):
_menus
"""
-class SetupMenu(archinstall.GeneralMenu):
+class SetupMenu(archinstall.AbstractMenu):
def __init__(self,storage_area):
super().__init__(data_store=storage_area)
@@ -230,14 +230,14 @@ class MyMenu(archinstall.GlobalMenu):
mandatory_list = []
if self._execution_mode in ('full','lineal'):
options_list = ['keyboard-layout', 'mirror-region', 'harddrives', 'disk_layouts',
- '!encryption-password','swap', 'bootloader', 'hostname', '!root-password',
+ 'disk_encryption','swap', 'bootloader', 'hostname', '!root-password',
'!users', 'profile', 'audio', 'kernels', 'packages','additional-repositories','nic',
'timezone', 'ntp']
if archinstall.arguments.get('advanced',False):
options_list.extend(['sys-language','sys-encoding'])
mandatory_list = ['harddrives','bootloader','hostname']
elif self._execution_mode == 'only_hd':
- options_list = ['harddrives', 'disk_layouts', '!encryption-password','swap']
+ options_list = ['harddrives', 'disk_layouts', 'disk_encryption','swap']
mandatory_list = ['harddrives']
elif self._execution_mode == 'only_os':
options_list = ['keyboard-layout', 'mirror-region','bootloader', 'hostname',