149 lines
3.5 KiB
Python
149 lines
3.5 KiB
Python
import sys
|
|
import time
|
|
from pathlib import Path
|
|
|
|
from archinstall.lib.menu.helpers import Confirmation, Input
|
|
from archinstall.lib.models.users import Password, PasswordStrength
|
|
from archinstall.lib.translationhandler import tr
|
|
from archinstall.tui.components import InputInfo, tui
|
|
from archinstall.tui.menu_item import MsgLevelType
|
|
from archinstall.tui.result import ResultType
|
|
|
|
|
|
async def get_password(
|
|
header: str | None = None,
|
|
allow_skip: bool = False,
|
|
preset: str | None = None,
|
|
no_confirmation: bool = False,
|
|
) -> Password | None:
|
|
def password_hint(value: str) -> InputInfo | None:
|
|
if not value:
|
|
return None
|
|
strength = PasswordStrength.strength(value)
|
|
if strength in (PasswordStrength.VERY_WEAK, PasswordStrength.WEAK):
|
|
return InputInfo(message=tr('Password strength: Weak'), msg_level=MsgLevelType.MsgError)
|
|
elif strength == PasswordStrength.MODERATE:
|
|
return InputInfo(message=tr('Password strength: Moderate'), msg_level=MsgLevelType.MsgWarning)
|
|
elif strength == PasswordStrength.STRONG:
|
|
return InputInfo(message=tr('Password strength: Strong'), msg_level=MsgLevelType.MsgInfo)
|
|
return None
|
|
|
|
while True:
|
|
result = await Input(
|
|
header=header,
|
|
allow_skip=allow_skip,
|
|
default_value=preset,
|
|
password=True,
|
|
info_callback=password_hint,
|
|
).show()
|
|
|
|
if result.type_ == ResultType.Skip:
|
|
if allow_skip:
|
|
return None
|
|
else:
|
|
continue
|
|
elif result.type_ == ResultType.Selection:
|
|
if not result.get_value():
|
|
if allow_skip:
|
|
return None
|
|
else:
|
|
continue
|
|
|
|
password = Password(plaintext=result.get_value())
|
|
break
|
|
|
|
if no_confirmation:
|
|
return password
|
|
|
|
confirmation_header = f'{tr("Password")}: {password.hidden()}\n\n'
|
|
confirmation_header += tr('Confirm password')
|
|
|
|
def _validate(value: str) -> str | None:
|
|
if value != password._plaintext:
|
|
return tr('The password did not match, please try again')
|
|
return None
|
|
|
|
result = await Input(
|
|
header=confirmation_header,
|
|
allow_skip=allow_skip,
|
|
password=True,
|
|
validator_callback=_validate,
|
|
).show()
|
|
|
|
if result.type_ == ResultType.Skip:
|
|
return None
|
|
|
|
return password
|
|
|
|
|
|
async def prompt_dir(
|
|
header: str | None = None,
|
|
validate: bool = True,
|
|
must_exist: bool = True,
|
|
allow_skip: bool = False,
|
|
preset: str | None = None,
|
|
) -> Path | None:
|
|
def validate_path(path: str | None) -> str | None:
|
|
if path:
|
|
dest_path = Path(path)
|
|
|
|
if must_exist:
|
|
if dest_path.exists() and dest_path.is_dir():
|
|
return None
|
|
else:
|
|
return None
|
|
|
|
return tr('Not a valid directory')
|
|
|
|
if validate:
|
|
validate_func = validate_path
|
|
else:
|
|
validate_func = None
|
|
|
|
result = await Input(
|
|
header=header,
|
|
allow_skip=allow_skip,
|
|
validator_callback=validate_func,
|
|
default_value=preset,
|
|
).show()
|
|
|
|
match result.type_:
|
|
case ResultType.Skip:
|
|
return None
|
|
case ResultType.Selection:
|
|
if not result.get_value():
|
|
return None
|
|
return Path(result.get_value())
|
|
case _:
|
|
return None
|
|
|
|
|
|
async def confirm_abort() -> bool:
|
|
prompt = tr('Do you really want to abort?') + '\n'
|
|
|
|
result = await Confirmation(
|
|
header=prompt,
|
|
allow_skip=False,
|
|
preset=False,
|
|
).show()
|
|
|
|
return result.get_value()
|
|
|
|
|
|
def delayed_warning(message: str) -> bool:
|
|
# Issue a final warning before we continue with something un-revertable.
|
|
# We count down from 5 to 0.
|
|
print(message, end='', flush=True)
|
|
|
|
try:
|
|
countdown = '\n5...4...3...2...1\n'
|
|
for c in countdown:
|
|
print(c, end='', flush=True)
|
|
time.sleep(0.25)
|
|
except KeyboardInterrupt:
|
|
ret: bool = tui.run(confirm_abort)
|
|
if ret:
|
|
sys.exit(1)
|
|
|
|
return True
|