227 lines
7.6 KiB
Python
227 lines
7.6 KiB
Python
|
# Ask Remote Desktop text spoke
|
||
|
#
|
||
|
# Asks the user if a text mode or remote desktop based access should be used.
|
||
|
#
|
||
|
# Copyright (C) 2024 Red Hat, Inc.
|
||
|
#
|
||
|
# This copyrighted material is made available to anyone wishing to use,
|
||
|
# modify, copy, or redistribute it subject to the terms and conditions of
|
||
|
# the GNU General Public License v.2, or (at your option) any later version.
|
||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||
|
# ANY WARRANTY expressed or implied, including the implied warranties of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||
|
# Public License for more details. You should have received a copy of the
|
||
|
# GNU General Public License along with this program; if not, write to the
|
||
|
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||
|
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
|
||
|
# source code or documentation are not subject to the GNU General Public
|
||
|
# License and may only be used or replicated with the express permission of
|
||
|
# Red Hat, Inc.
|
||
|
#
|
||
|
import sys
|
||
|
|
||
|
from pyanaconda.core.configuration.anaconda import conf
|
||
|
from pyanaconda.ui.tui.spokes import NormalTUISpoke
|
||
|
from pyanaconda.core.constants import USERDP, USETEXT, QUIT_MESSAGE
|
||
|
from pyanaconda.core.i18n import N_, _
|
||
|
from pyanaconda.ui.tui import exception_msg_handler
|
||
|
from pyanaconda.core.util import execWithRedirect, ipmi_abort
|
||
|
|
||
|
from simpleline import App
|
||
|
from simpleline.event_loop.signals import ExceptionSignal
|
||
|
from simpleline.render.containers import ListColumnContainer
|
||
|
from simpleline.render.prompt import Prompt
|
||
|
from simpleline.render.screen import InputState
|
||
|
from simpleline.render.screen_handler import ScreenHandler
|
||
|
from simpleline.render.adv_widgets import YesNoDialog
|
||
|
from simpleline.render.widgets import TextWidget
|
||
|
|
||
|
|
||
|
def exception_msg_handler_and_exit(signal, data):
|
||
|
"""Display an exception and exit so that we don't end up in a loop."""
|
||
|
exception_msg_handler(signal, data)
|
||
|
sys.exit(1)
|
||
|
|
||
|
|
||
|
class AskRDSpoke(NormalTUISpoke):
|
||
|
"""
|
||
|
.. inheritance-diagram:: AskRDPSpoke
|
||
|
:parts: 3
|
||
|
"""
|
||
|
title = N_("RDP")
|
||
|
|
||
|
# This spoke is kinda standalone, not meant to be used with a hub
|
||
|
# We pass in some fake data just to make our parents happy
|
||
|
def __init__(self, data, storage=None, payload=None, message=""):
|
||
|
super().__init__(data, storage, payload)
|
||
|
self.input_required = True
|
||
|
self.initialize_start()
|
||
|
self._container = None
|
||
|
|
||
|
# The TUI hasn't been initialized with the message handlers yet. Add an
|
||
|
# exception message handler so that the TUI exits if anything goes wrong
|
||
|
# at this stage.
|
||
|
loop = App.get_event_loop()
|
||
|
loop.register_signal_handler(ExceptionSignal, exception_msg_handler_and_exit)
|
||
|
self._message = message
|
||
|
self._rdp_username = ""
|
||
|
self._rdp_password = ""
|
||
|
self._use_rd = False
|
||
|
self.initialize_done()
|
||
|
|
||
|
@property
|
||
|
def use_remote_desktop(self):
|
||
|
"""Should a remote desktop solution be used instead of text mode ?"""
|
||
|
return self._use_rd
|
||
|
|
||
|
@property
|
||
|
def rdp_username(self):
|
||
|
"""User provided RDP user name (if any)."""
|
||
|
return self._rdp_username
|
||
|
|
||
|
@property
|
||
|
def rdp_password(self):
|
||
|
"""User provided RDP password (if any)."""
|
||
|
return self._rdp_password
|
||
|
|
||
|
@property
|
||
|
def indirect(self):
|
||
|
return True
|
||
|
|
||
|
def refresh(self, args=None):
|
||
|
super().refresh(args)
|
||
|
|
||
|
self.window.add_with_separator(TextWidget(self._message))
|
||
|
|
||
|
self._container = ListColumnContainer(1, spacing=1)
|
||
|
|
||
|
# choices are
|
||
|
# USE RDP
|
||
|
self._container.add(TextWidget(_(USERDP)), self._use_rdp_callback)
|
||
|
# USE TEXT
|
||
|
self._container.add(TextWidget(_(USETEXT)), self._use_text_callback)
|
||
|
|
||
|
self.window.add_with_separator(self._container)
|
||
|
|
||
|
def _use_rdp_callback(self, data):
|
||
|
self._use_rd = True
|
||
|
new_rdp_spoke = RDPAuthSpoke(self.data)
|
||
|
ScreenHandler.push_screen_modal(new_rdp_spoke)
|
||
|
self._rdp_username = new_rdp_spoke._username
|
||
|
self._rdp_password = new_rdp_spoke._password
|
||
|
|
||
|
def _use_text_callback(self, data):
|
||
|
self._use_rd = False
|
||
|
|
||
|
def input(self, args, key):
|
||
|
"""Override input so that we can launch the RDP user name & password spoke"""
|
||
|
if self._container.process_user_input(key):
|
||
|
self.apply()
|
||
|
return InputState.PROCESSED_AND_CLOSE
|
||
|
else:
|
||
|
if key.lower() == Prompt.QUIT:
|
||
|
d = YesNoDialog(_(QUIT_MESSAGE))
|
||
|
ScreenHandler.push_screen_modal(d)
|
||
|
if d.answer:
|
||
|
ipmi_abort(scripts=self.data.scripts)
|
||
|
if conf.system.can_reboot:
|
||
|
execWithRedirect("systemctl", ["--no-wall", "reboot"])
|
||
|
else:
|
||
|
sys.exit(1)
|
||
|
else:
|
||
|
return super().input(args, key)
|
||
|
|
||
|
def apply(self):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class RDPAuthSpoke(NormalTUISpoke):
|
||
|
"""
|
||
|
.. inheritance-diagram:: RDPAuthSpoke
|
||
|
:parts: 3
|
||
|
"""
|
||
|
|
||
|
def __init__(self, data, username=None, password=None):
|
||
|
super().__init__(data, storage=None, payload=None)
|
||
|
self.title = N_("RDP User name & Password")
|
||
|
if username is not None:
|
||
|
self._username = username
|
||
|
else:
|
||
|
self._username = ""
|
||
|
if password is not None:
|
||
|
self._password = password
|
||
|
else:
|
||
|
self._password = ""
|
||
|
|
||
|
@property
|
||
|
def indirect(self):
|
||
|
return True
|
||
|
|
||
|
@property
|
||
|
def completed(self):
|
||
|
return True # We're always complete
|
||
|
|
||
|
def refresh(self, args=None):
|
||
|
super().refresh(args)
|
||
|
self.window.add_with_separator(TextWidget(self.message))
|
||
|
|
||
|
@property
|
||
|
def message(self):
|
||
|
text = ""
|
||
|
if not self._username and not self._password:
|
||
|
text = _("Please provide RDP user name & password.")
|
||
|
elif self._username:
|
||
|
text = _("Please provide RDP password.")
|
||
|
else:
|
||
|
text = _("Please provide RDP user name.")
|
||
|
|
||
|
# if we want the password, add a note about typing it twice
|
||
|
if not self._password:
|
||
|
text = text + "\n" + _("You will have to type the password twice.")
|
||
|
|
||
|
return text
|
||
|
|
||
|
def prompt(self, args=None):
|
||
|
"""Override prompt as password typing is special."""
|
||
|
# first make sure username is set
|
||
|
if not self._username:
|
||
|
username = self.get_user_input(_("User name: "), False)
|
||
|
if username:
|
||
|
self._username = username
|
||
|
else:
|
||
|
self._print_error_and_redraw(_("User name not set!"))
|
||
|
return None
|
||
|
|
||
|
# next try to get the password
|
||
|
if not self._password:
|
||
|
p1 = self.get_user_input(_("Password: "), True)
|
||
|
p2 = self.get_user_input(_("Password (confirm): "), True)
|
||
|
|
||
|
if p1 != p2:
|
||
|
self._print_error_and_redraw(_("Passwords do not match!"))
|
||
|
return None
|
||
|
elif not p1:
|
||
|
self._print_error_and_redraw((_("The password must not be empty.")))
|
||
|
return None
|
||
|
elif 0 < len(p1) < 6:
|
||
|
self._print_error_and_redraw((_("The password must be at least "
|
||
|
"six characters long.")))
|
||
|
return None
|
||
|
else:
|
||
|
self._password = p1
|
||
|
|
||
|
# do we finally have everything ?
|
||
|
if self._username and self._password:
|
||
|
self.apply()
|
||
|
self.close()
|
||
|
|
||
|
# ruff: noqa: PLR1711
|
||
|
return None
|
||
|
|
||
|
def _print_error_and_redraw(self, msg):
|
||
|
print(msg)
|
||
|
self.redraw()
|
||
|
|
||
|
def apply(self):
|
||
|
pass
|