Mercurial > libervia-backend
comparison sat_frontends/jp/base.py @ 3049:9839ce068140
jp: password is now prompted if needed:
if password is not specified on command line, it is now prompted if it is needed to start
a profile session or connect it. The password is prompted with echo disabled, so somebody
seing the computer screen can't see the password.
fix 207
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 01 Oct 2019 22:49:11 +0200 |
parents | d9f328374473 |
children | ee2654308a57 |
comparison
equal
deleted
inserted
replaced
3048:1761e4823527 | 3049:9839ce068140 |
---|---|
44 from sat.tools.common.ansi import ANSI as A | 44 from sat.tools.common.ansi import ANSI as A |
45 from sat.core import exceptions | 45 from sat.core import exceptions |
46 import sat_frontends.jp | 46 import sat_frontends.jp |
47 from sat_frontends.jp.loops import QuitException, getJPLoop | 47 from sat_frontends.jp.loops import QuitException, getJPLoop |
48 from sat_frontends.jp.constants import Const as C | 48 from sat_frontends.jp.constants import Const as C |
49 from sat_frontends.bridge.bridge_frontend import BridgeException | |
49 from sat_frontends.tools import misc | 50 from sat_frontends.tools import misc |
50 import xml.etree.ElementTree as ET # FIXME: used temporarily to manage XMLUI | 51 import xml.etree.ElementTree as ET # FIXME: used temporarily to manage XMLUI |
51 from collections import OrderedDict | 52 from collections import OrderedDict |
52 | 53 |
53 ## bridge handling | 54 ## bridge handling |
286 parent = self.parents[parent_name] = argparse.ArgumentParser(add_help=False) | 287 parent = self.parents[parent_name] = argparse.ArgumentParser(add_help=False) |
287 parent.add_argument( | 288 parent.add_argument( |
288 "-p", "--profile", action="store", type=str, default='@DEFAULT@', | 289 "-p", "--profile", action="store", type=str, default='@DEFAULT@', |
289 help=_("Use PROFILE profile key (default: %(default)s)")) | 290 help=_("Use PROFILE profile key (default: %(default)s)")) |
290 parent.add_argument( | 291 parent.add_argument( |
291 "--pwd", action="store", default='', metavar='PASSWORD', | 292 "--pwd", action="store", metavar='PASSWORD', |
292 help=_("Password used to connect profile, if necessary")) | 293 help=_("Password used to connect profile, if necessary")) |
293 | 294 |
294 profile_parent, profile_session_parent = (self.parents['profile'], | 295 profile_parent, profile_session_parent = (self.parents['profile'], |
295 self.parents['profile_session']) | 296 self.parents['profile_session']) |
296 | 297 |
771 except AttributeError: | 772 except AttributeError: |
772 pass | 773 pass |
773 | 774 |
774 return dest_jids | 775 return dest_jids |
775 | 776 |
777 async def a_pwd_input(self, msg=''): | |
778 """Like ainput but with echo disabled (useful for passwords)""" | |
779 # we disable echo, code adapted from getpass standard module which has been | |
780 # written by Piers Lauder (original), Guido van Rossum (Windows support and | |
781 # cleanup) and Gregory P. Smith (tty support & GetPassWarning), a big thanks | |
782 # to them (and for all the amazing work on Python). | |
783 stdin_fd = sys.stdin.fileno() | |
784 old = termios.tcgetattr(sys.stdin) | |
785 new = old[:] | |
786 new[3] &= ~termios.ECHO | |
787 tcsetattr_flags = termios.TCSAFLUSH | |
788 if hasattr(termios, 'TCSASOFT'): | |
789 tcsetattr_flags |= termios.TCSASOFT | |
790 try: | |
791 termios.tcsetattr(stdin_fd, tcsetattr_flags, new) | |
792 pwd = await self.ainput(msg=msg) | |
793 finally: | |
794 termios.tcsetattr(stdin_fd, tcsetattr_flags, old) | |
795 sys.stderr.flush() | |
796 self.disp('') | |
797 return pwd | |
798 | |
799 async def connectOrPrompt(self, method, err_msg=None): | |
800 """Try to connect/start profile session and prompt for password if needed | |
801 | |
802 @param method(callable): bridge method to either connect or start profile session | |
803 It will be called with password as sole argument, use lambda to do the call | |
804 properly | |
805 @param err_msg(str): message to show if connection fail | |
806 """ | |
807 password = self.args.pwd | |
808 while True: | |
809 try: | |
810 await method(password or '') | |
811 except Exception as e: | |
812 if ((isinstance(e, BridgeException) | |
813 and e.classname == 'PasswordError' | |
814 and self.args.pwd is None)): | |
815 if password is not None: | |
816 self.disp(A.color(C.A_WARNING, _("invalid password"))) | |
817 password = await self.a_pwd_input( | |
818 _("please enter profile password:")) | |
819 else: | |
820 self.disp(err_msg.format(profile=self.profile, e=e), error=True) | |
821 self.quit(C.EXIT_ERROR) | |
822 else: | |
823 break | |
824 | |
776 async def connect_profile(self): | 825 async def connect_profile(self): |
777 """Check if the profile is connected and do it if requested | 826 """Check if the profile is connected and do it if requested |
778 | 827 |
779 @exit: - 1 when profile is not connected and --connect is not set | 828 @exit: - 1 when profile is not connected and --connect is not set |
780 - 1 when the profile doesn't exists | 829 - 1 when the profile doesn't exists |
792 start_session = self.args.start_session | 841 start_session = self.args.start_session |
793 except AttributeError: | 842 except AttributeError: |
794 pass | 843 pass |
795 else: | 844 else: |
796 if start_session: | 845 if start_session: |
797 try: | 846 await self.connectOrPrompt( |
798 await self.bridge.profileStartSession(self.args.pwd, self.profile) | 847 lambda pwd: self.bridge.profileStartSession(pwd, self.profile), |
799 except Exception as e: | 848 err_msg="Can't start {profile}'s session: {e}" |
800 self.disp(_(f"Can't start {self.profile}'s session: {e}"), err=True) | 849 ) |
801 self.quit(1) | |
802 return | 850 return |
803 elif not await self.bridge.profileIsSessionStarted(self.profile): | 851 elif not await self.bridge.profileIsSessionStarted(self.profile): |
804 if not self.args.connect: | 852 if not self.args.connect: |
805 self.disp(_( | 853 self.disp(_( |
806 f"Session for [{self.profile}] is not started, please start it " | 854 f"Session for [{self.profile}] is not started, please start it " |
814 if not hasattr(self.args, 'connect'): | 862 if not hasattr(self.args, 'connect'): |
815 # a profile can be present without connect option (e.g. on profile | 863 # a profile can be present without connect option (e.g. on profile |
816 # creation/deletion) | 864 # creation/deletion) |
817 return | 865 return |
818 elif self.args.connect is True: # if connection is asked, we connect the profile | 866 elif self.args.connect is True: # if connection is asked, we connect the profile |
819 try: | 867 await self.connectOrPrompt( |
820 await self.bridge.connect(self.profile, self.args.pwd, {}) | 868 lambda pwd: self.bridge.connect(self.profile, pwd, {}), |
821 except Exception as e: | 869 err_msg = 'Can\'t connect profile "{profile!s}": {e}' |
822 self.disp(_(f"Can't connect profile: {e}"), error=True) | 870 ) |
823 self.quit(1) | |
824 return | 871 return |
825 else: | 872 else: |
826 if not await self.bridge.isConnected(self.profile): | 873 if not await self.bridge.isConnected(self.profile): |
827 log.error( | 874 log.error( |
828 _(f"Profile [{self.profile}] is not connected, please connect it " | 875 _(f"Profile [{self.profile}] is not connected, please connect it " |