Exemple #1
0
    def setup(self, args):
        
        # assume we only log critical stuff
        loglevel = logging.CRITICAL

        # upgrade log levels if desired
        if args.verbose:
            loglevel = logging.INFO

        if args.super_verbose:
            loglevel = logging.DEBUG
        
        # set up logging
        logging.basicConfig(
            format='[Cred %(levelname)s] %(asctime)s: %(message)s',
            level=loglevel,
        )

        if not args.config:
            config = path.expanduser("~") + "/.credconf.yaml"

        with open(config, "r") as config:
            self.config = yaml.load(config)
 
        self.__check_config()

        # this causes python-gnupg to emit messages
        self.config['verbose'] = args.super_verbose

        # ensure the encrypting user is always in the recipient list
        self.config['default_recipients'].append(self.config['default_key'])
        # ensure credentials is an absolute path
        self.config['credentials'] = path.abspath(self.config['credentials'])
        # provide the config keys as the args to creds
        self.creds = Store(**self.config)
Exemple #2
0
class CLI(object):
    def setup(self, args):
        
        # assume we only log critical stuff
        loglevel = logging.CRITICAL

        # upgrade log levels if desired
        if args.verbose:
            loglevel = logging.INFO

        if args.super_verbose:
            loglevel = logging.DEBUG
        
        # set up logging
        logging.basicConfig(
            format='[Cred %(levelname)s] %(asctime)s: %(message)s',
            level=loglevel,
        )

        if not args.config:
            config = path.expanduser("~") + "/.credconf.yaml"

        with open(config, "r") as config:
            self.config = yaml.load(config)
 
        self.__check_config()

        # this causes python-gnupg to emit messages
        self.config['verbose'] = args.super_verbose

        # ensure the encrypting user is always in the recipient list
        self.config['default_recipients'].append(self.config['default_key'])
        # ensure credentials is an absolute path
        self.config['credentials'] = path.abspath(self.config['credentials'])
        # provide the config keys as the args to creds
        self.creds = Store(**self.config)

    def add(self, args):
        cred_path = self.creds.get_path(args.name)

        if path.exists(cred_path):
            raise Exception("Credential exists",
                            "try `cred modify %s`" % args.name)
        
        prompt_defaults = ", ".join(['username', 'password'])

        response = self.__prompt("Add which keys?", prompt_defaults)
        new_keys = response.split(",")

        # aggregate new and modified keys
        new_cred = []
        for key in new_keys:
            key = key.strip()
            new_val = self.__prompt(key)
            new_cred.append("%s: %s" % (key, new_val))

        # dump the yaml from a hopefully successful call to save
        new_cred = yaml.dump(
                             self.__save(args.name, new_cred),
                             default_flow_style=False,
                             )
        print "\n\nSaved cred is..."
        print new_cred
        return 0

    def get(self, args):
        if args.name:
            cred = self.__get(args.name)
            if args.fields:
                for field in args.fields:
                    print cred.get(field)
            elif args.list_keys:
                for field in cred:
                    print field
            else:
                print yaml.dump(cred, default_flow_style=False)
        else:
            cred_list = self.list_credentials()
            for namespace in self.list_namespaces():
                for cred in self.list_credentials(namespace):
                    cred_list.append(path.join(namespace, cred))
            for cred in cred_list:
                # relpath because relpath is how you'll refer to them
                print path.relpath(cred, self.config['credentials'])
        return 0
    
    def list_credentials(self, namespace=False):
        """List all the credentials in the configured credential directory,
        alternatively constrain to a subsidiary namespace."""
        pattern = "*" + self.config['extension']
        if namespace:
            creds = path.join(self.config['credentials'], namespace, pattern)
        else:
            creds = path.join(self.config['credentials'], pattern)
        creds = glob.glob(creds)
        return [cred.replace(self.config['extension'], "") for cred in creds]

    def list_namespaces(self):
        """List namespace subdirectories in the configured cred directory"""
        namespaces = list()
        for namespace in listdir(self.config['credentials']):
            ns_path = path.join(self.config['credentials'], namespace)
            if path.isdir(ns_path):
                namespaces.append(ns_path)
        return namespaces

    def __check_config(self):
        """Check the config for completeness and also excesses (though only
        log a warning on excesses)."""
        required_keys = [
                            "credentials",
                            "default_key",
                            "default_recipients",
                            "extension",
                            "gpg_home",
                            "sign",
                            "use_agent",
                        ]
        config_keys = self.config.keys()
        config_keys.sort()
        if config_keys != required_keys:
            missing_set = Set(required_keys) - Set(config_keys)
            excess_set = Set(config_keys) - Set(required_keys)
            for key in missing_set:
                logging.critical("Missing config key: %s", key)
            if excess_set:
                for excess_parameter in excess_set:
                    del self.config[excess_parameter]
                    logging.warn(
                                    "Excess parameter in config: %s",
                                    excess_parameter
                                    )
            else:
                raise Exception(
                                "Incomplete configuration",
                                "missing %d key(s)." % len(missing_set)
                                )
    
    def __prompt(self, query, default=False):
        """Present a prompt with an optional default so that the user may press
        enter to accept the default of the prompt."""
        if default:
            prompt = "%s [%s]:  " % (query, default)
        else:
            prompt = "%s: " % query
        logging.debug("Asking for %s", query)
        response = raw_input(prompt)
        if not response:
            return default
        else:
            return response

    def __get(self, name):
        try:
            return self.creds.get(name)
        except NeedsPassphrase:
            self.creds.passphrase = getpass.getpass()
            return self.__get(name)
    
    def __save(self, name, new_cred):
        logging.info("Trying to save: %s", name)
        try:
            return self.creds.save(name, new_cred)
        except NeedsPassphrase:
            self.creds.passphrase = getpass.getpass()
            logging.info("Got passphrase, re-trying save.")
            return self.__save(name, new_cred)

    def modify(self, args):
        """Prompt to add or update keys in an existing credential."""
        orig_cred = self.__get(args.name)
        orig_cred_keys = orig_cred.keys()
        # add all credential keys as prompt defaults
        prompt_defaults = ", ".join(orig_cred_keys)

        response = self.__prompt("Modify", prompt_defaults)
        mod_keys = [key.strip() for key in response.split(",")]

        # aggregate new and modified keys
        new_cred = []
        for key in mod_keys:
            value = orig_cred.get(key, False)
            new_val = self.__prompt(key, value)
            new_cred.append("%s: %s" % (key, new_val))

        # copy unchanged keys from the orig_cred
        for key in orig_cred_keys:
            if key not in mod_keys:
                new_cred.append("%s: %s" % (key, orig_cred[key]))

        changed_cred = yaml.dump(
                                 self.__save(args.name, new_cred),
                                 default_flow_style=False,
                                )
        print "\n\nChanged cred is..."
        print changed_cred
        return 0