romkatv / powerlevel10k

A Zsh theme
MIT License
46.44k stars 2.19k forks source link

instant prompt behaves weirdly with keychain #277

Closed Syphdias closed 5 years ago

Syphdias commented 5 years ago

I use keychain and I added this to my ~/.zshrc as suggested by reddit:

if [[ -r ${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh ]]; then
    source ${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh
fi

To reproduce:

  1. docker run -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 -e TERM=$TERM -it --rm ubuntu bash -uexc ' 
    cd
    apt update && apt install -y zsh git keychain
    git clone --depth 1 https://github.com/romkatv/powerlevel10k.git
    ssh-keygen -t rsa -b 1024 -P secret -f /root/.ssh/id_rsa
    echo '\''
    POWERLEVEL9K_DISABLE_CONFIGURATION_WIZARD=trueOA
    if [[ -r ${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh ]]; then
      source ${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh
    fi
    source ~/powerlevel10k/powerlevel10k.zsh-theme
    keychain id_rsa --agents ssh    
    '\'' >~/.zshrc
    exec zsh'
  2. Ignore
  3. exec zsh
  4. Type in secret
  5. no color in keychain output
  6. exec zsh to get no color again but without the password weirdness
romkatv commented 5 years ago

Thanks for the high quality report.

This is hacks leaking through.

When you source p10k-instant-prompt-${(%):-%n}.zsh, it prints a "prompt" that isn't actually a prompt. It's just text that looks like prompt. To avoid random diagnostic text ruining "prompt", stdout and stderr are redirected to a file. Once a real prompt is ready, instant prompt is erased, the content of the file is printed and then it's zsh as usual.

This apparently breaks when:

  1. The diagnostic text has colors. Many tools are "smart" and will not output color codes when the output is not a TTY. So you get no colors. Probably not a big deal but still sucky.
  2. If zshrc runs an interactive tool that prints to TTY directly (like ssh-agent) or asks for user input, things go bad. This is worse than (1).

I'll need to think how to handle this better. I'm open to ideas and suggestions.

Syphdias commented 5 years ago

(1) is probably the behaviour grep shows. keychain has no --color=always as far as I can tell. Usually the output is not important so I could just 2>&- it away (sadly it puts everything on stderr, so I can't just filter the good stuff) - Now that I think about it, it might actually also kill the password prompt...

(2) This is quite a nice way to sniff secrets :smiling_imp:

romkatv commented 5 years ago

Now that I think about it, it might actually also kill the password prompt...

That one goes to TTY, as you saw.

romkatv commented 5 years ago

FYI: Powerlevel10k now closes stdin for the duration of initialization. Once instant prompt is printed, stdin is /dev/null while stdout and stderr are both going to a temporary file. When the real prompt is ready, the content of the temporary file get printed and then the usual file descriptors are restored.

I've made this change for the sake of safety and to avoid unpleasant surprises. My next item on the TODO list is to print a scary banner when anything has been printed to stdout or stderr while instant prompt was active. I think with good wording it can be made usable even by inexperienced zsh users.

romkatv commented 5 years ago

By the way, there is a better way to load your ssh keys into ssh agent. Basically, there are 3 decent options.

  1. Load ssh keys on boot.
  2. ... on zsh startup.
  3. ... on the first use.

1 is the worst, 2 is second best, 3 is the best. No need to type your passphrase if you aren't even going to use the keys.

To achieve (3), you need to ensure that ssh-agent is always running when you are using shell. If it doesn't start on boot for you, you can start it from zsh. This doesn't require password. Ubuntu starts ssh-agent for me on boot, so I don't do anything there. When using WSL, I source this: https://github.com/romkatv/dotfiles-public/blob/master/dotfiles/ssh-agent.zsh. You'll also need to add AddKeysToAgent yes. And voilà -- you are typing you ssh passphrase only once per boot (you can also make it expire if you like) and never typing it if you aren't even going to use keys. As a bonus, your zshrc won't ask for TTY input, so it'll work well with instant prompt.

This tangent doesn't imply that I'm going to ignore this issue in instant prompt. I still need to make it work well for people who use setup similar to yours.

Syphdias commented 5 years ago

Thanks for the hint. I didn't know AddKeysToAgent yes yet. I discovered on Debian there is a user systemd service unit for ssh-agent one can use for this purpose or you could easily create one (if you like systemd). From my perspective: I don't have an issue anymore, so close it if you want or keep it open if you want to find a solution for dealing with stdin.

romkatv commented 5 years ago

Thanks for the hint. I didn't know AddKeysToAgent yes yet. I discovered on Debian there is a user systemd service unit for ssh-agent one can use for this purpose or you could easily create one (if you like systemd).

When I log into Ubuntu, there is already an ssh agent running. I haven't set it up, it's a part of the default distro install. As far as I remember, it has always been like this, even before systemd came out. I thought it was the same in all distros.

But anyway, launching ssh-agent isn't hard, and it doesn't require a password. And once managed to ensure that ssh-agent is always running while you are logged in, AddKeysToAgent = yes works its magic.

From my perspective: I don't have an issue anymore, so close it if you want or keep it open if you want to find a solution for dealing with stdin.

I'll keep it open as a reminder that I need to write decent docs for instant prompt and to add scary warnings when there is console output during zsh initialization.

romkatv commented 5 years ago

This is sort of fixed, although not very satisfactorily. Basically, everything behaves just as before but you'll also get this wall of text when starting zsh.

[WARNING]: Console output during zsh initialization detected.

When using Powerlevel10k with instant prompt, console output during zsh
initialization may indicate issues.

You can:

  - Recommended: Change ~/.zshrc so that it does not perform console I/O
    after the instant prompt preamble. See the link below for details.

    * You will not see this error message again.
    * Zsh will start quickly and prompt will update smoothly.

  - Suppress this warning either by running p10k configure or by manually
    defining the following parameter:

      typeset -g POWERLEVEL9K_INSTANT_PROMPT=quiet

    * You will not see this error message again.
    * Zsh will start quickly but prompt will jump down after initialization.

  - Disable instant prompt either by running p10k configure or by manually
    defining the following parameter:

      typeset -g POWERLEVEL9K_INSTANT_PROMPT=off

    * You will not see this error message again.
    * Zsh will start slowly.

  - Do nothing.

    * You will see this error message every time you start zsh.
    * Zsh will start quickly but prompt will jump down after initialization.

For details, see:
https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt

-- console output produced during zsh initialization follows --

 * keychain 2.8.2 ~ http://www.funtoo.org
 * Found existing ssh-agent: 3204
 * Known ssh key: /root/.ssh/id_rsa

This doesn't remove the weirdness but instead makes it more obvious and clearly assigns blame for it to powerlevel10k. The warning lists multiple options for resolving the problem, including relatively simple instructions for disabling instant prompt.

Will revisit this issue if too many users get confused by the "solution".

dmuiX commented 7 months ago

Thanks for this input. Disabling instant prompt with adding typeset -g POWERLEVEL9K_INSTANT_PROMPT=off to .zshrc solved my problem of not being able to enter ssh and gpg passprases for zsh keychain plugin. Kind of thought this might be it but you pointed me in the right direction. Unsure if there is now a better way??

romkatv commented 7 months ago

A better way is to perform all console I/O before activating instant prompt. Specifically for GPG and keychain, an even better way is to ask for password on first use rather than shell startup.

dmuiX commented 7 months ago

A better way is to perform all console I/O before activating instant prompt.

This did not really work....

Specifically for GPG and keychain, an even better way is to ask for password on first use rather than shell startup.

If the thing is breaking up again I will try that. Thanks.

Update:

Jip in the end is was the best way: Disable instant-prompt complete resp. throw it out of my .zshrc and then activate keychain and gpg-agent plugin for oh-my-zsh. It asks me now on every reboot to enter ssh and gpg-passphrase and then not anymore. So it is actuallly now what I wanted.