From 5b1c15150e0c6499cffb8171eae28fc2ce01fd27 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Fri, 1 Jul 2016 18:28:49 +0200 Subject: [feat] use subcommands in the cli Reorganize all the commands to don't use '--' but parse each subcommand separately. --- src/leap/bitmask/cli/bitmask_cli.py | 375 ++++-------------------------------- 1 file changed, 37 insertions(+), 338 deletions(-) (limited to 'src/leap/bitmask/cli/bitmask_cli.py') diff --git a/src/leap/bitmask/cli/bitmask_cli.py b/src/leap/bitmask/cli/bitmask_cli.py index 79e15051..76b27c94 100755 --- a/src/leap/bitmask/cli/bitmask_cli.py +++ b/src/leap/bitmask/cli/bitmask_cli.py @@ -18,27 +18,20 @@ """ Bitmask Command Line interface: zmq client. """ -import json import sys -import getpass -import argparse -from colorama import init as color_init from colorama import Fore -from twisted.internet import reactor -from txzmq import ZmqEndpoint, ZmqEndpointType -from txzmq import ZmqFactory, ZmqREQConnection -from txzmq import ZmqRequestTimeoutError +from twisted.internet import reactor, defer -from leap.bitmask.core import ENDPOINT -from leap.keymanager.validation import ValidationLevels +from leap.bitmask.cli.eip import Eip +from leap.bitmask.cli.keys import Keys +from leap.bitmask.cli.mail import Mail +from leap.bitmask.cli.command import Command +from leap.bitmask.cli.user import User -class BitmaskCLI(object): - - def __init__(self): - parser = argparse.ArgumentParser( - usage='''bitmask_cli [] +class BitmaskCLI(Command): + usage = '''bitmask_cli [] Controls the Bitmask application. @@ -55,347 +48,53 @@ GENERAL COMMANDS: launch launch the Bitmask backend daemon shutdown shutdown Bitmask backend daemon status displays general status about the running Bitmask services - debug show some debug info about bitmask-core - - -''', epilog=("Use 'bitmask_cli --help' to learn more " - "about each command.")) - parser.add_argument('command', help='Subcommand to run') - - # parse_args defaults to [1:] for args, but you need to - # exclude the rest of the args too, or validation will fail - args = parser.parse_args(sys.argv[1:2]) - self.args = args - self.subargs = None + stats show some debug info about bitmask-core + help show this help message - if not hasattr(self, args.command): - print 'Unrecognized command' - parser.print_help() - exit(1) +''' + epilog = ("Use 'bitmask_cli help' to learn more " + "about each command.") + commands = ['shutdown', 'status', 'stats'] - # use dispatch pattern to invoke method with same name - getattr(self, args.command)() + def user(self, raw_args): + user = User() + return user.execute(raw_args) - def user(self): - parser = argparse.ArgumentParser( - description=('Handles Bitmask accounts: creation, authentication ' - 'and modification'), - prog='bitmask_cli user') - parser.add_argument('username', nargs='?', - help='username ID, in the form ') - parser.add_argument('--create', action='store_true', - help='register a new user, if possible') - parser.add_argument('--authenticate', action='store_true', - help='logs in against the provider') - parser.add_argument('--logout', action='store_true', - help='ends any active session with the provider') - parser.add_argument('--active', action='store_true', - help='shows the active user, if any') - # now that we're inside a subcommand, ignore the first - # TWO argvs, ie the command (bitmask_cli) and the subcommand (user) - args = parser.parse_args(sys.argv[2:]) - self.subargs = args + def mail(self, raw_args): + mail = Mail() + return mail.execute(raw_args) - def mail(self): - parser = argparse.ArgumentParser( - description='Bitmask Encrypted Mail service', - prog='bitmask_cli mail') - parser.add_argument('--start', action='store_true', - help='tries to start the mail service') - parser.add_argument('--stop', action='store_true', - help='stops the mail service if running') - parser.add_argument('--status', action='store_true', - help='displays status about the mail service') - parser.add_argument('--enable', action='store_true') - parser.add_argument('--disable', action='store_true') - parser.add_argument('--get-token', action='store_true', - help='returns token for the mail service') - parser.add_argument('--get-smtp-certificate', action='store_true', - help='downloads a new smtp certificate') - parser.add_argument('--check-smtp-certificate', action='store_true', - help='downloads a new smtp certificate ' - '(NOT IMPLEMENTED)') + def eip(self, raw_args): + eip = Eip() + return eip.execute(raw_args) - args = parser.parse_args(sys.argv[2:]) - self.subargs = args - - def eip(self): - parser = argparse.ArgumentParser( - description='Encrypted Internet Proxy service', - prog='bitmask_cli eip') - parser.add_argument('--start', action='store_true', - help='Start service') - parser.add_argument('--stop', action='store_true', help='Stop service') - parser.add_argument('--status', action='store_true', - help='Display status about service') - parser.add_argument('--enable', action='store_true') - parser.add_argument('--disable', action='store_true') - args = parser.parse_args(sys.argv[2:]) - self.subargs = args - - def keys(self): - parser = argparse.ArgumentParser( - description='Bitmask Keymanager management service', - prog='bitmask_cli keys') - parser.add_argument('--list', action='store_true', - help='List all known keys') - parser.add_argument('--export', action='store_true', - help='Export the given key') - parser.add_argument('--import', action='store', metavar='file', - dest='imprt', - help='Import a key from the file') - parser.add_argument('--delete', action='store_true', - help='Delete the given key') - parser.add_argument('--private', action='store_true', - help='Use private keys (by default uses public)') - parser.add_argument('--validation', choices=list(ValidationLevels), - default='Fingerprint', - help='Validation level for the key') - parser.add_argument('address', nargs='?', - help='email address of the key') - args = parser.parse_args(sys.argv[2:]) - self.subargs = args + def keys(self, raw_args): + keys = Keys() + return keys.execute(raw_args) # Single commands - def launch(self): - pass - - def shutdown(self): - pass - - def status(self): - pass - - def version(self): - pass - - def debug(self): - pass - - -def get_zmq_connection(): - zf = ZmqFactory() - e = ZmqEndpoint(ZmqEndpointType.connect, ENDPOINT) - return ZmqREQConnection(zf, e) - - -def error(msg, stop=False): - print Fore.RED + "[!] %s" % msg + Fore.RESET - if stop: - reactor.stop() - else: - sys.exit(1) - - -def timeout_handler(failure, stop_reactor=True): - # TODO ---- could try to launch the bitmask daemon here and retry - - if failure.trap(ZmqRequestTimeoutError) == ZmqRequestTimeoutError: - print (Fore.RED + "[ERROR] Timeout contacting the bitmask daemon. " - "Is it running?" + Fore.RESET) - reactor.stop() - - -def do_print_result(stuff): - obj = json.loads(stuff[0]) - if not obj['error']: - print Fore.GREEN + '%s' % obj['result'] + Fore.RESET - else: - print Fore.RED + 'ERROR:' + '%s' % obj['error'] + Fore.RESET - - -def do_print_key_list(stuff): - obj = json.loads(stuff[0]) - if obj['error']: - do_print_result(stuff) - return - - keys = obj['result'] - print Fore.GREEN - for key in keys: - print key["fingerprint"] + " " + key['address'] - print Fore.RESET - - -def do_print_key(stuff): - obj = json.loads(stuff[0]) - if obj['error']: - do_print_result(stuff) - return - - key = obj['result'] - print Fore.GREEN - print "Uids: " + ', '.join(key['uids']) - print "Fingerprint: " + key['fingerprint'] - print "Length: " + str(key['length']) - print "Expiration: " + key['expiry_date'] - print "Validation: " + key['validation'] - print("Used: " + "sig:" + str(key['sign_used']) + - ", encr:" + str(key['encr_used'])) - print "Refresed: " + key['refreshed_at'] - print Fore.RESET - print "" - print key['key_data'] - - -def send_command(cli): - - args = cli.args - subargs = cli.subargs - cb = do_print_result - - cmd = args.command - - if cmd == 'launch': + def launch(self, raw_args): # XXX careful! Should see if the process in PID is running, # avoid launching again. import commands commands.getoutput('bitmaskd') - reactor.stop() - return - - elif cmd == 'version': - do_print_result([json.dumps( - {'result': 'bitmask_cli: 0.0.1', - 'error': None})]) - data = ('version',) - - elif cmd == 'status': - data = ('status',) + return defer.succeed(None) - elif cmd == 'shutdown': - data = ('shutdown',) + def version(self, raw_args): + print Fore.GREEN + 'bitmask_cli: 0.0.1' + Fore.RESET + self.data = ['version'] + return self._send() - elif cmd == 'debug': - data = ('stats',) - elif cmd == 'user': - if 1 != (subargs.active + subargs.create + - subargs.authenticate + subargs.logout): - error('Use bitmask_cli user --help to see available subcommands', - stop=True) - return - - data = ['user'] - - if subargs.active: - data += ['active', '', ''] - - else: - if subargs.create: - data.append('signup') - elif subargs.authenticate: - data.append('authenticate') - elif subargs.logout: - data.append('logout') - - username = subargs.username - if username and '@' not in username: - error("Username ID must be in the form ", - stop=True) - return - if not subargs.logout and not username: - error("Missing username ID but needed for this command", - stop=True) - return - elif not username: - username = '' - data.append(username) - - if not subargs.logout: - passwd = getpass.getpass() - data.append(passwd) - - elif cmd == 'mail': - data = ['mail'] - - if subargs.status: - data += ['status'] - - elif subargs.enable: - data += ['enable'] - - elif subargs.disable: - data += ['disable'] - - elif subargs.get_token: - data += ['get_token'] - - elif subargs.get_smtp_certificate: - data += ['get_smtp_certificate'] - - else: - error('Use bitmask_cli mail --help to see available subcommands', - stop=True) - return - - elif cmd == 'eip': - data = ['eip'] - - if subargs.status: - data += ['status'] - - elif subargs.enable: - data += ['enable'] - - elif subargs.disable: - data += ['disable'] - - elif subargs.start: - data += ['start'] - - elif subargs.stop: - data += ['stop'] - - else: - error('Use bitmask_cli eip --help to see available subcommands', - stop=True) - return - - elif cmd == 'keys': - data = ['keys'] - - if subargs.list: - data += ['list'] - cb = do_print_key_list - - elif subargs.export: - data += ['export', subargs.address] - cb = do_print_key - - elif subargs.imprt: - with open(subargs.imprt, 'r') as keyfile: - rawkey = keyfile.read() - - data += ['add', subargs.address, subargs.validation, rawkey] - cb = do_print_key - - elif subargs.delete: - data += ['delete', subargs.address] - - else: - error('Use bitmask_cli keys --help to see available subcommands', - stop=True) - return - - if subargs.private: - data += ['private'] - else: - data += ['public'] - - s = get_zmq_connection() - - d = s.sendMsg(*data, timeout=60) - d.addCallback(cb) - d.addCallback(lambda x: reactor.stop()) - d.addErrback(timeout_handler) +def execute(): + cli = BitmaskCLI() + d = cli.execute(sys.argv[1:]) + d.addCallback(lambda _: reactor.stop()) def main(): - color_init() - cli = BitmaskCLI() - reactor.callWhenRunning(reactor.callLater, 0, send_command, cli) + reactor.callWhenRunning(reactor.callLater, 0, execute) reactor.run() if __name__ == "__main__": -- cgit v1.2.3