Example #1
0
 def test_select_entry(self):
     """Test password selection."""
     with TemporaryDirectory() as directory:
         touch(os.path.join(directory, 'foo.gpg'))
         touch(os.path.join(directory, 'bar.gpg'))
         touch(os.path.join(directory, 'baz.gpg'))
         program = PasswordStore(directory=directory)
         # Substring search.
         entry = program.select_entry('fo')
         assert entry.name == 'foo'
         # Fuzzy search.
         entry = program.select_entry('bz')
         assert entry.name == 'baz'
Example #2
0
 def test_select_entry_interactive(self):
     """Test interactive password selection."""
     with TemporaryDirectory() as directory:
         touch(os.path.join(directory, 'foo.gpg'))
         touch(os.path.join(directory, 'bar.gpg'))
         touch(os.path.join(directory, 'baz.gpg'))
         # Select entries using the command line filter 'a' and then use
         # interactive selection to narrow the choice down to 'baz' by
         # specifying the unique substring 'z'.
         program = PasswordStore(directory=directory)
         with CaptureOutput(input='z'):
             entry = program.select_entry('a')
             assert entry.name == 'baz'
Example #3
0
 def test_select_entry(self):
     """Test password selection."""
     with TemporaryDirectory() as directory:
         touch(os.path.join(directory, "foo.gpg"))
         touch(os.path.join(directory, "bar.gpg"))
         touch(os.path.join(directory, "baz.gpg"))
         program = PasswordStore(directory=directory)
         # Substring search.
         entry = program.select_entry("fo")
         assert entry.name == "foo"
         # Fuzzy search.
         entry = program.select_entry("bz")
         assert entry.name == "baz"
Example #4
0
 def test_smart_search(self):
     """Test smart searching."""
     with TemporaryDirectory() as directory:
         touch(os.path.join(directory, 'abcdef.gpg'))
         touch(os.path.join(directory, 'aabbccddeeff.gpg'))
         touch(os.path.join(directory, 'Google.gpg'))
         program = PasswordStore(directory=directory)
         # Test a substring match that avoids fuzzy matching.
         matches = program.smart_search('abc')
         assert len(matches) == 1
         assert matches[0].name == 'abcdef'
         # Test a fuzzy match to confirm that the fall back works.
         matches = program.smart_search('gg')
         assert len(matches) == 1
         assert matches[0].name == 'Google'
Example #5
0
 def test_no_matching_password_error(self):
     """Test the NoMatchingPasswordError exception."""
     with TemporaryDirectory() as directory:
         touch(os.path.join(directory, 'Whatever.gpg'))
         program = PasswordStore(directory=directory)
         self.assertRaises(NoMatchingPasswordError, program.smart_search,
                           'x')
Example #6
0
 def test_missing_password_store_error(self):
     """Test the MissingPasswordStoreError exception."""
     with TemporaryDirectory() as directory:
         missing = os.path.join(directory, 'missing')
         program = PasswordStore(directory=missing)
         self.assertRaises(MissingPasswordStoreError,
                           program.ensure_directory_exists)
Example #7
0
def main():
    """Command line interface for the ``qpass`` program."""
    # Initialize logging to the terminal.
    coloredlogs.install()
    # Prepare for command line argument parsing.
    action = show_matching_entry
    program_opts = dict(exclude_list=[])
    show_opts = dict(filters=[], use_clipboard=is_clipboard_supported())
    verbosity = 0
    # Parse the command line arguments.
    try:
        options, arguments = getopt.gnu_getopt(
            sys.argv[1:],
            "elnp:f:x:vqh",
            ["edit", "list", "no-clipboard", "password-store=", "filter=", "exclude=", "verbose", "quiet", "help"],
        )
        for option, value in options:
            if option in ("-e", "--edit"):
                action = edit_matching_entry
            elif option in ("-l", "--list"):
                action = list_matching_entries
            elif option in ("-n", "--no-clipboard"):
                show_opts["use_clipboard"] = False
            elif option in ("-p", "--password-store"):
                stores = program_opts.setdefault("stores", [])
                stores.append(PasswordStore(directory=value))
            elif option in ("-f", "--filter"):
                show_opts["filters"].append(value)
            elif option in ("-x", "--exclude"):
                program_opts["exclude_list"].append(value)
            elif option in ("-v", "--verbose"):
                coloredlogs.increase_verbosity()
                verbosity += 1
            elif option in ("-q", "--quiet"):
                coloredlogs.decrease_verbosity()
                verbosity -= 1
            elif option in ("-h", "--help"):
                usage(__doc__)
                return
            else:
                raise Exception("Unhandled option! (programming error)")
        if not (arguments or action == list_matching_entries):
            usage(__doc__)
            return
    except Exception as e:
        warning("Error: %s", e)
        sys.exit(1)
    # Execute the requested action.
    try:
        show_opts["quiet"] = verbosity < 0
        kw = show_opts if action == show_matching_entry else {}
        action(QuickPass(**program_opts), arguments, **kw)
    except PasswordStoreError as e:
        # Known issues don't get a traceback.
        logger.error("%s", e)
        sys.exit(1)
    except KeyboardInterrupt:
        # If the user interrupted an interactive prompt they most likely did so
        # intentionally, so there's no point in generating more output here.
        sys.exit(1)
Example #8
0
 def test_simple_search(self):
     """Test simple substring searching."""
     with TemporaryDirectory() as directory:
         touch(os.path.join(directory, 'foo.gpg'))
         touch(os.path.join(directory, 'bar.gpg'))
         touch(os.path.join(directory, 'baz.gpg'))
         program = PasswordStore(directory=directory)
         matches = program.simple_search('fo')
         assert len(matches) == 1
         assert matches[0].name == 'foo'
         matches = program.simple_search('a')
         assert len(matches) == 2
         assert matches[0].name == 'bar'
         assert matches[1].name == 'baz'
         matches = program.simple_search('b', 'z')
         assert len(matches) == 1
         assert matches[0].name == 'baz'
Example #9
0
 def test_simple_search(self):
     """Test simple substring searching."""
     with TemporaryDirectory() as directory:
         touch(os.path.join(directory, "foo.gpg"))
         touch(os.path.join(directory, "bar.gpg"))
         touch(os.path.join(directory, "baz.gpg"))
         program = PasswordStore(directory=directory)
         matches = program.simple_search("fo")
         assert len(matches) == 1
         assert matches[0].name == "foo"
         matches = program.simple_search("a")
         assert len(matches) == 2
         assert matches[0].name == "bar"
         assert matches[1].name == "baz"
         matches = program.simple_search("b", "z")
         assert len(matches) == 1
         assert matches[0].name == "baz"
Example #10
0
def main():
    """Command line interface for the ``qpass`` program."""
    # Initialize logging to the terminal.
    coloredlogs.install()
    # Prepare for command line argument parsing.
    action = show_matching_entry
    program_opts = dict()
    show_opts = dict(use_clipboard=is_clipboard_supported())
    # Parse the command line arguments.
    try:
        options, arguments = getopt.gnu_getopt(sys.argv[1:], 'elnp:vqh', [
            'edit',
            'list',
            'no-clipboard',
            'password-store=',
            'verbose',
            'quiet',
            'help',
        ])
        for option, value in options:
            if option in ('-e', '--edit'):
                action = edit_matching_entry
            elif option in ('-l', '--list'):
                action = list_matching_entries
            elif option in ('-n', '--no-clipboard'):
                show_opts['use_clipboard'] = False
            elif option in ('-p', '--password-store'):
                stores = program_opts.setdefault('stores', [])
                stores.append(PasswordStore(directory=value))
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
            else:
                raise Exception("Unhandled option! (programming error)")
        if not (arguments or action == list_matching_entries):
            usage(__doc__)
            return
    except Exception as e:
        warning("Error: %s", e)
        sys.exit(1)
    # Execute the requested action.
    try:
        action(QuickPass(**program_opts), arguments,
               **(show_opts if action == show_matching_entry else {}))
    except PasswordStoreError as e:
        # Known issues don't get a traceback.
        logger.error("%s", e)
        sys.exit(1)
    except KeyboardInterrupt:
        # If the user interrupted an interactive prompt they most likely did so
        # intentionally, so there's no point in generating more output here.
        sys.exit(1)
Example #11
0
def get_secret_from_store(name, directory=None):
    """
    Use :mod:`qpass` to get a secret from ``~/.password-store``.

    :param name: The name of a password or a search pattern that matches a
                 single entry in the password store (a string).
    :param directory: The directory to use (a string, defaults to
                      ``~/.password-store``).
    :returns: The secret (a string).
    :raises: :exc:`exceptions.ValueError` when the given `name` doesn't match
             any entries or matches multiple entries in the password store.
    """
    kw = dict(directory=directory) if directory else {}
    store = PasswordStore(**kw)
    matches = store.smart_search(name)
    if len(matches) != 1:
        msg = "Expected exactly one match in password database! (input: %s)"
        raise ValueError(format(msg, name))
    return matches[0].password
Example #12
0
 def test_fuzzy_search(self):
     """Test fuzzy searching."""
     with TemporaryDirectory() as directory:
         touch(os.path.join(directory, 'Personal/Zabbix.gpg'))
         touch(os.path.join(directory, 'Work/Zabbix.gpg'))
         touch(os.path.join(directory, 'Something else.gpg'))
         program = PasswordStore(directory=directory)
         # Test a fuzzy search with multiple matches.
         matches = program.fuzzy_search('zbx')
         assert len(matches) == 2
         assert any(entry.name == 'Personal/Zabbix' for entry in matches)
         assert any(entry.name == 'Work/Zabbix' for entry in matches)
         # Test a fuzzy search with a single match.
         matches = program.fuzzy_search('p/z')
         assert len(matches) == 1
         assert matches[0].name == 'Personal/Zabbix'
         # Test a fuzzy search with `the other' match.
         matches = program.fuzzy_search('w/z')
         assert len(matches) == 1
         assert matches[0].name == 'Work/Zabbix'
Example #13
0
 def test_password_discovery(self):
     """Test password discovery."""
     with TemporaryDirectory() as directory:
         touch(os.path.join(directory, 'foo.gpg'))
         touch(os.path.join(directory, 'foo/bar.gpg'))
         touch(os.path.join(directory, 'foo/bar/baz.gpg'))
         touch(os.path.join(directory, 'Also with spaces.gpg'))
         program = PasswordStore(directory=directory)
         assert len(program.entries) == 4
         assert program.entries[0].name == 'Also with spaces'
         assert program.entries[1].name == 'foo'
         assert program.entries[2].name == 'foo/bar'
         assert program.entries[3].name == 'foo/bar/baz'
Example #14
0
 def test_directory_variable(self):
     """Test support for ``$PASSWORD_STORE_DIR``."""
     with TemporaryDirectory() as directory:
         with PatchedItem(os.environ, DIRECTORY_VARIABLE, directory):
             program = PasswordStore()
             assert program.directory == directory
Example #15
0
 def test_empty_password_store_error(self):
     """Test the EmptyPasswordStoreError exception."""
     with TemporaryDirectory() as directory:
         program = PasswordStore(directory=directory)
         self.assertRaises(EmptyPasswordStoreError, program.smart_search)