Skip to content
Snippets Groups Projects
Select Git revision
  • a01755afed043d9d4da26ba1ec3bfa2902ce149e
  • debian default
  • 0.10-2-dev
  • 0.10-1-dev
  • master
  • patch-queue/debian
  • pristine-tar
  • debian/0.10-2
  • v0.10
  • v0.9.5
  • v0.9.4
  • v0.9.3
  • v0.9.2
  • debian/0.9.1-4.1
  • debian/0.9.1-2
  • debian/0.9.1-1
  • v0.9.1
  • v0.9
  • v0.8
  • v0.7.1
  • v0.7
  • v0.6.1
  • v0.6
  • v0.5
  • v0.4
  • v0.3.1
  • v0.3
27 results

__init__.py

Blame
  • ulif's avatar
    ulif authored
    The new option is not active yet.
    a01755af
    History
    __init__.py 7.26 KiB
    #  diceware -- passphrases to remember
    #  Copyright (C) 2015  Uli Fouquet
    #
    #  This program is free software: you can redistribute it and/or modify
    #  it under the terms of the GNU General Public License as published by
    #  the Free Software Foundation, either version 3 of the License, or
    #  (at your option) any later version.
    #
    #  This program is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty 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, see <http://www.gnu.org/licenses/>.
    """diceware -- rememberable passphrases
    """
    import argparse
    import os
    import pkg_resources
    import re
    import sys
    from random import SystemRandom
    
    __version__ = pkg_resources.get_distribution('diceware').version
    
    #: The directory in which wordlists are stored
    WORDLISTS_DIR = os.path.abspath(
        os.path.join(os.path.dirname(__file__), 'wordlists'))
    
    #: A regular expression matching 2 consecutive ASCII chars. We
    #: consider this to represent some language/country code.
    RE_LANG_CODE = re.compile('^[a-zA-Z]{2}$')
    
    #: Special chars inserted on demand
    SPECIAL_CHARS = r"~!#$%^&*()-=+[]\{}:;" + r'"' + r"'<>?/0123456789"
    
    
    GPL_TEXT = (
        """
        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty 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, see <http://www.gnu.org/licenses/>.
        """
        )
    
    
    def print_version():
        """Output current version and other infos.
        """
        print("diceware %s" % __version__)
        print("Copyright (C) 2015 Uli Fouquet")
        print("diceware is based on suggestions of Arnold G. Reinhold.")
        print("See http://diceware.com for details.")
    
        print("'Diceware' is a trademark of Arnold G. Reinhold.")
        print(GPL_TEXT)
    
    
    def get_random_sources():
        """Get a dictionary of all entry points called diceware_random_source.
    
        Returns a dictionary with names mapped to callables registered as
        `entry_point`s for the ``diceware_randomsource`` group.
    
        Callables should accept `options` when called and return something
        that provides a `choice(sequence)` method that works like the
        respective method in the standard Python lib `random` module.
        """
        result = dict()
        for entry_point in pkg_resources.iter_entry_points(
                group="diceware_random_sources"):
            result.update({entry_point.name: entry_point.load()})
        return result
    
    
    def handle_options(args):
        """Handle commandline options.
        """
        random_sources = get_random_sources().keys()
        parser = argparse.ArgumentParser(description="Create a passphrase")
        parser.add_argument(
            '-n', '--num', default=6, type=int,
            help='number of words to concatenate. Default: 6')
        cap_group = parser.add_mutually_exclusive_group()
        cap_group.add_argument(
            '-c', '--caps', action='store_true',
            help='Capitalize words. This is the default.')
        cap_group.add_argument(
            '--no-caps', action='store_false', dest='capitalize',
            help='Turn off capitalization.')
        parser.add_argument(
            '-s', '--specials', default=0, type=int, metavar='NUM',
            help="Insert NUM special chars into generated word.")
        parser.add_argument(
            '-d', '--delimiter', default='',
            help="Separate words by DELIMITER. Empty string by default.")
        parser.add_argument(
            '-r', '--randomsource', default='system', choices=random_sources,
            metavar="SOURCE",
            help=(
                "Get randomness from this source. Possible values: `%s'. "
                "Default: system" % "', `".join(random_sources)))
        parser.add_argument(
            'infile', nargs='?', metavar='INFILE', default=None,
            type=argparse.FileType('r'),
            help="Input wordlist. `-' will read from stdin.",
            )
        parser.add_argument(
            '--version', action='store_true',
            help='output version information and exit.',
            )
        parser.set_defaults(capitalize=True)
        args = parser.parse_args(args)
        return args
    
    
    def get_wordlist(file_descriptor):
        """Parse file in `file_descriptor` and build a word list of it.
    
        `file_descriptor` is expected to be a file descriptor, already
        opened for reading. The descriptor will be closed after
        processing.
    
        A wordlist is expected to contain lines of words. Each line a
        word. Empty lines are ignored. Returns a list of terms (lines)
        found.
        """
        result = [
            line.strip() for line in file_descriptor.readlines()
            if line.strip() != '']
        file_descriptor.close()
        return result
    
    
    def get_wordlist_path(lang):
        """Get path to a wordlist file for language `lang`.
    
        The `lang` string is a 2-char country code. Invalid codes raise a
        ValueError.
        """
        if not RE_LANG_CODE.match(lang):
            raise ValueError("Not a valid language code: %s" % lang)
        basename = 'wordlist_%s.txt' % lang
        return os.path.join(WORDLISTS_DIR, basename.lower())
    
    
    def insert_special_char(word, specials=SPECIAL_CHARS, rnd=None):
        """Insert a char out of `specials` into `word`.
    
        `rnd`, if passed in, will be used as a (pseudo) random number
        generator. We use `.choice()` only.
    
        Returns the modified word.
        """
        if rnd is None:
            rnd = SystemRandom()
        char_list = list(word)
        char_list[rnd.choice(range(len(char_list)))] = rnd.choice(specials)
        return ''.join(char_list)
    
    
    def get_passphrase(options=None):
        """Get a diceware passphrase.
    
        The passphrase returned will contain `options.num` words deliimted by
        `options.delimiter`.
    
        The passphrase returned will contain `options.specials` special chars.
    
        If `options.capitalize` is ``True``, all words will be capitalized.
    
        If `options.infile`, a file descriptor, is given, it will be used
        instead of a 'built-in' wordlist. `options.infile` must be open for
        reading.
        """
        if options is None:
            options = handle_options(args=[])
        if options.infile is None:
            options.infile = open(get_wordlist_path("en"), 'r')
        word_list = get_wordlist(options.infile)
        rnd = SystemRandom()
        words = [rnd.choice(word_list) for x in range(options.num)]
        if options.capitalize:
            words = [x.capitalize() for x in words]
        result = options.delimiter.join(words)
        for _ in range(options.specials):
            result = insert_special_char(result, rnd=rnd)
        return result
    
    
    def main(args=None):
        """Main programme.
    
        Called when `diceware` script is called.
    
        `args` is a list of command line arguments to process. If no such
        args are given, we use `sys.argv`.
        """
        if args is None:
            args = sys.argv[1:]
        options = handle_options(args)
        if options.version:
            print_version()
            raise SystemExit(0)
        print(get_passphrase(options))