49 lines
1.7 KiB
Python
49 lines
1.7 KiB
Python
from __future__ import annotations
|
|
|
|
import platform
|
|
import shutil
|
|
import subprocess
|
|
|
|
|
|
class CredentialDialogError(RuntimeError):
|
|
"""Raised when the local macOS credential dialog cannot return a value."""
|
|
|
|
|
|
def _dialog_text(prompt: str, hidden: bool) -> str:
|
|
if platform.system() != "Darwin":
|
|
raise CredentialDialogError("Secure credential dialogs are supported only on macOS")
|
|
osascript = shutil.which("osascript")
|
|
if osascript is None:
|
|
raise CredentialDialogError("osascript is unavailable")
|
|
|
|
hidden_clause = " with hidden answer" if hidden else ""
|
|
script = (
|
|
f'text returned of (display dialog "{prompt}" default answer ""'
|
|
f'{hidden_clause} buttons {{"Отмена", "Продолжить"}} '
|
|
'default button "Продолжить" cancel button "Отмена")'
|
|
)
|
|
try:
|
|
result = subprocess.run(
|
|
[osascript, "-e", script],
|
|
check=False,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=300,
|
|
)
|
|
except (OSError, subprocess.SubprocessError) as exc:
|
|
raise CredentialDialogError("macOS credential dialog failed") from exc
|
|
|
|
if result.returncode != 0:
|
|
raise CredentialDialogError("Credential entry was cancelled")
|
|
value = result.stdout.rstrip("\r\n")
|
|
if not value:
|
|
raise CredentialDialogError("Credential value must not be empty")
|
|
return value
|
|
|
|
|
|
def prompt_wifi_credentials() -> tuple[str, str]:
|
|
"""Collect Wi-Fi credentials locally without placing them in command arguments."""
|
|
ssid = _dialog_text("Имя Wi-Fi сети, к которой подключён Mac", hidden=False)
|
|
password = _dialog_text("Пароль этой Wi-Fi сети", hidden=True)
|
|
return ssid, password
|