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!
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.
Most helpful comment
cool, I really should setup some kind of repository for kittens some day.