Kitty: Are there any password manager plugins?

Created on 11 Dec 2018  路  12Comments  路  Source: kovidgoyal/kitty

I'm looking for a way to enter passwords from my password manager at password prompts. The password manager has a CLI (in this case, the security command in MacOS). Are there any kittens that allow me to integrate my password manager? If there aren't any existing kittens, is there any way to detect if a password prompt is showing (i.e. if STDIN is set to noecho) so you don't accidentally enter your password into the wrong prompt?

Btw: thanks for responding so quickly to my last question! kitty is awesome!

Most helpful comment

cool, I really should setup some kind of repository for kittens some day.

All 12 comments

Something like this would be really nice. I really liked the password manager of iTerm2, which uses macOS's keychain to store the passwords and has "a safety mechanism that ensures your password only gets entered at a password prompt". Currently I use the macOS keychain directly but that's a bit inconvenient and I have to copy the password to the clipboard.

There are no kitten that I know of, but it should be easy to write one. As for detecting noecho one can do it easily using termios. tcgetattr() is the name of the function IIRC. python has a termios module you can use for this.

Thanks!

Question: what fd do I pass to tcgetattr?

I currently have:

import termios
from kitty.utils import TTYIO

def main(args):
   pass

def handle_result(args, answer, target_window_id, boss):
    with TTYIO() as io:
        try:
            attr = termios.tcgetattr(io.tty_fd)
        except termios.error as err:
            errmsg = 'getecho() may not be called on this platform'
            if err.args[0] == errno.EINVAL:
                raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg))
            raise

        if attr[3] & termios.ECHO == 0:
            w = boss.window_id_map.get(target_window_id)
            if w is not None:
                w.paste("boom")

handle_result.no_ui = True

Is TTYIO().tty_fd the right fd for the terminal?

It always returns that ECHO is not set.

why are you using TTYIO there? handle_result() is for after the kitten runs and you want to apply the output of the kitten to the target window. Use the fd of the target window. w.child.fd IIRC

since you want a kitten with no UI you never need to use TTYIO.

Sorry, ruby programmer here :/ Trying to learn python as I go. I'll try that now! Thanks!

no worries :)

I've got this much so far:

from termios import error, tcgetattr, ECHO, ICANON, ISIG, ECHOCTL, ECHOKE
import re
import subprocess
import sys

def main(args):
    if not sys.stdin.isatty():
        data = sys.stdin.read().strip().split('\n')[-1]
        return data
    else:
        print("\a")
        print("Tried to read a tty")

def handle_result(args, data, target_window_id, boss):
    w = boss.window_id_map.get(target_window_id)
    if w is not None:
        fd = w.child.child_fd
        try:
            c_lflag = tcgetattr(fd)[3]
        except error as err:
            errmsg = 'getecho() may not be called on this platform'
            if err.args[0] == errno.EINVAL:
                raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg))
            raise

        def send_password():
            password = subprocess.run(args[1:], capture_output=True, text=True, check=True).stdout
            w.paste(password + '\r')

        def is_set(flag):
            return bool(c_lflag & flag)

        # print(f'c_lflag={c_lflag} icanon={c_lflag & ICANON} echo={c_lflag & ECHO} echoctl={c_lflag & ECHOCTL} echoke={c_lflag & ECHOKE} isig={c_lflag & ISIG} data={repr(data)}')
        if is_set(ISIG) and is_set(ICANON) and not is_set(ECHO):
            # ruby -rio/console -e 'STDIN.noecho { |io| puts io.gets.inspect }'
            # sudo <cmd>
            send_password()
        elif not is_set(ISIG) and not is_set(ICANON) and not is_set(ECHO) and re.match(r"Password.*:$", data):
            # ssh -t <host> <cmd> # same socket mode for kinit and cat :(
            send_password()
        else:
            print("\a")
            print("Ooops. Are you at a password prompt?")

handle_result.type_of_input = 'text'

I hit a couple spots in the documentation where I wished there'd been a little more detail. Open to documentation / example PRs? Specifically, to read STDIN in a kitten, you must do it from the main function, not the handle_result function.

Sure, docs PRs are most welcome.

Following up: here's the password manager kitten I wrote: https://github.com/nerdrew/kittens/blob/master/password.py

I've been using it for a few days and it seems to work for me.

I have the following config for it (I use a mac, security is the CLI for KeyChain Access):

map cmd+BACKSLASH kitten kittens/password.py security find-generic-password -a "Production Password" -w

cool, I really should setup some kind of repository for kittens some day.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Jomik picture Jomik  路  4Comments

keyofnight picture keyofnight  路  3Comments

Nudin picture Nudin  路  3Comments

wavexx picture wavexx  路  3Comments

lazarcf picture lazarcf  路  4Comments