InQuest / omnibus

The OSINT Omnibus (beta release)
MIT License
316 stars 69 forks source link

Additional command line support: argparse with cmd2 #21

Open deadbits opened 5 years ago

deadbits commented 5 years ago

By leveraging cmd2's support for argparse we can get rid of a lot of commands and add argument support to many existing ones. For example, we'll now have support for commands like: tags --view inquest.net, tags --add inquest.net these are my tags, https://inquest.net, artifact --new inquest.net, artifact --view inquest.net, etc etc.

The parsers will go in their own library that we import into omnibus-cli so it doesn't look like garbage inside that script. lets add them to lib/parsers.py

Example of the tags parser:

# do_tags parsere
tags_parser = argparse.ArgumentParser()
id_tags = tags_parser.add_mutually_exclusive_group()
manage_tags = tags_parser.add_mutually_exclusive_group()

manage_tags.add_argument('-a', '--add', action='store_true', help='add tag')
manage_tags.add_argument('-v', '--view', action='store_true', help='view tags')

id_tags.add_argument('-l', '--last', action='store_true', help='use last created artifact')
id_tags.add_argument('-n', '--name', action='store', help='artifact name')
id_tags.add_argument('-i', '--id', action='store', help='artifact session ID')

tags_parser.add_argument('tags', nargs='?', help='comma separated tags')

and we'd port tags to look something like this:

    @cmd2.with_argparser(tags_parser)
    def do_tags(self, args):
        """Manage artifact tags"""
        artifact = self.parse_identifier(args)
        if artifact is None:
            return

        _type = detect_type(artifact)

        if args.view:
            result = self.db.get_value(_type, {'name': artifact}, 'tags')
            info('%s tags: %s' % (artifact, result))
            return

        elif args.add:
            if args.tags == '':
                error('Tags not specified')
            else:
                tags = args.tags

                new_tags = []
                if ',' in tags:
                    for t in tags.split(','):
                        t = t.strip()
                        new_tags.append(t)
                else:
                    new_tags = tags

                if self.db.exists(_type, {'name': artifact}):
                    self.db.update_one(_type, {'name': artifact}, {'tags': new_tags})
                    success('Added tags to artifact (%s: %s)' % (artifact, new_tags))
                else:
                    warning('Failed to find artifact in MongoDB. Run "new <artifact name>" before using the tags command')

        else:
            info('Run "tags --help" or "help tags" for all available commands')
deadbits commented 5 years ago

Since many of the commands will accept artifacts as an argument, we'll also add a generic parser that will handle these more standard args of -l, --last for last created artifact, -n, --name for artifact by name, and -i, --id for artifact by session ID like seen in the last comment for tags.

Generic parser example

    def parse_identifier(self, args):
        """Parse artifact name out of argparse arguments"""
        identifier = None

        if args.last:
            if args.name or args.id:
                error('Only one argument can be specified: --last, --name, --id')
                return None

            identifier = self.session.receive('artifacts')

        elif args.id:
            is_key, value = lookup_key(self.session, args.id)

            if is_key and value is None:
                error('Unable to find artifact key in session (%s)' % args.id)
                return None

            elif is_key and value is not None:
                identifier = value

        elif args.name:
            identifier = args.name.strip()

        else:
            error('Must specify one of: --last, --name, --id')
            return None

        return identifier