zulip-terminal icon indicating copy to clipboard operation
zulip-terminal copied to clipboard

pass command instead of password in zuliprc?

Open dkwo opened this issue 1 year ago • 27 comments

My zuliprc contains a [key] entry, which I guess is derived from the password. Would it be possible (or maybe already is? I did not find documentation) to have a pass comand instead, like e.g. in mbsync or similar, so the key entry would look more like "PassCmd "/usr/bin/pass name@domain"?

dkwo avatar May 20 '24 21:05 dkwo

Thanks for the inquiry! Is this a blocker to you being able to use Zulip or Zulip-terminal?

I wasn't familiar with mbsync, and it took me a while to figure out what you meant by a 'pass command', since I wasn't familiar with that tool either :)

My understanding of your query is that you're wanting to store the password-like detail centrally in a pass password store, and extract it on-demand upon starting the application?

Currently zuliprc (-style) files generated by the Zulip web app have the form of:

[api]
email=...  # login (email or username)
key=...    # key
site=...   # server

Zulip-terminal uses the python zulip wrapper library, and further details on the structure of this kind of zuliprc file is at: https://github.com/zulip/python-zulip-api/tree/main/zulip (README.md)

As a client we could implement this feature individually, since we could support arbitrary features/extensions in a zuliprc file, a little like we do right now for our current options. However, if we added such an option, we may want to coordinate with the larger community to coordinate on this.

The Zulip server supports other login methods that we have yet to incorporate, which are typically browser-based, and mostly about connecting to a central authority (see eg. https://zulip.com/help/configure-authentication-methods). My understanding is that your request is specifically for a local authentication feature; the reason I mention this is I'm wondering if the deferral of the authentication to a command might be a common factor to both if we implemented these.

neiljp avatar May 21 '24 17:05 neiljp

Thanks for looking at this, and sorry for being cryptic. You got me right. I'm mostly concerned with local auth, but indeed a pass cmd could also deal with tokens. My concern is that I don't want to store key material in the config (zuliprc), so that it can be checked in git with other dotfiles.

To keep the analogy with mbsync, the token case (for oauth) has PassCmd "~/bin/mutt_oauth2.py ${XDG_DATA_HOME}/oauth-tokens/gmail.tokens".

dkwo avatar May 21 '24 18:05 dkwo

To be unambiguous: the pass cmd option shuold let us use pass, gopass or whatever else we can use from the terminal.

dkwo avatar May 21 '24 18:05 dkwo

@dkwo To confirm the original intent here:

  • the zuliprc could be in a standard location (enabling eg. .config in git, as per #678)
  • the private password/token could be stored in a separate encrypted location
  • the zuliprc would have some way to point to a command that starts the extraction of the appropriate password/token (presumably prompted), rather than embedding it in the zuliprc file (ie. a PassCmd or equivalent)

Based on how we currently include zulip-terminal configuration as extra data in the zuliprc, the above would seem the approach to take.

However, we're hoping to look at #678 this Summer, and there are benefits from separating the client config from the bare zuliprc (with only the [api] section). For example, if one resets the API key then the file could be easily updated separately from config, and central config could be distinct from per-server config. If this separation was achieved, could the 'private' location you use also store the details in the [api] section in such a way that it would be easily integrated with an application?

If so, the bare zuliprc downloadable from Zulip (or via the API, or zulip-terminal) could be placed in the more secure location, with a redirection like PassCmd for the entirety of the login. Is that an established approach with these tools?

neiljp avatar Jun 02 '24 01:06 neiljp

@dkwo Thanks for your feedback so far, and it's absolutely fine to continue clarifying the requirements here, but just to let you know: I started a discussion on chat.zulip.org regarding this here, since this could be relevant for other code generating and consuming zuliprc files.

neiljp avatar Jun 02 '24 05:06 neiljp

Thanks for the update. I agree that xdg_config_home would be a good place for the dotfiles. Usually, the command is able to invoke whatever external tool one uses, a common use being pass. So the idea would be to have a line in the config that looks like PassCmd /usr/bin/pass entry.name@email. Makes sense?

dkwo avatar Jun 02 '24 14:06 dkwo

Re my last paragraph/question in this comment, I saw that pass can handle some extra data, but I wasn't sure how transparently it could handle eg. an entire normal zuliprc (without zulip-terminal data) - or other similar tools.

neiljp avatar Jun 12 '24 15:06 neiljp

I would like to resolve this , but I need some more additional information about the issue. could anyone help me to understand the problem in a better way?

Gopinath-Mahendiran avatar Mar 10 '25 16:03 Gopinath-Mahendiran

@Gopinath-Mahendiran Sure. What is unclear from the above discussion?

dkwo avatar Mar 12 '25 16:03 dkwo

explain in detail that how the flow should be once we run the application? It would help me to work with the problem clearly.

Gopinath-Mahendiran avatar Mar 15 '25 16:03 Gopinath-Mahendiran

The flow is: config file contains a line that specifies an external command that when invoked prints to stdout whatever password/token/secret, and zulip-term reads such output when a password is needed. This should be agnostic about which encryption or program is used, just use its output as it would use a password typed by the user.

dkwo avatar Mar 15 '25 21:03 dkwo

@dkwo is it ok to store the encrypted api key in separate file like ~/.zulip_api_key

when the application runs, command in the zuliprc file will retrieve the encrypted key and decrypt it and it can be used for login

or else ,want to create an password manger like system utility for securely storing the api key

Gopinath-Mahendiran avatar Mar 16 '25 09:03 Gopinath-Mahendiran

@zulipbot I need help

Gopinath-Mahendiran avatar Mar 19 '25 14:03 Gopinath-Mahendiran

is it possible to let the password manager deal with the key? The idea is that passcmd (as specified in config) is a command that gives back the key as std output. Think of it as e.g. age or pass or keepassxc-cli.

dkwo avatar Mar 21 '25 14:03 dkwo

i.e. where to store the key and how to store it is out of scope for zulip.

dkwo avatar Mar 21 '25 14:03 dkwo

@dkwo sorry for asking too much question ,because I am beginner to open source contribution. what should be the key (like password or public and private key)to retrieve the api_key ?

Gopinath-Mahendiran avatar Mar 21 '25 15:03 Gopinath-Mahendiran

I'm not sure I understand: isn't the api_key generated for you by zulip? is so, you can store it as you'd store any other password, and decrypt it when needed.

dkwo avatar Mar 21 '25 15:03 dkwo

Yes, the API key is provided by Zulip at the time of login only if the configuration file (zuliprc) is not found. Otherwise, it retrieves the previously stored key from the local configuration file.

Gopinath-Mahendiran avatar Mar 21 '25 16:03 Gopinath-Mahendiran

[api]
[email protected]
key=sdjfkw8345nws85ndfmsar8234mdnfsar8243jsdknf';aswer02wen
site=chat.zulip.org

Gopinath-Mahendiran avatar Mar 21 '25 16:03 Gopinath-Mahendiran

The API key will be encrypted upon receiving the configuration file from Zulip and stored as an api_hash in the configuration file. The hash will only be decrypted during the login process.

Gopinath-Mahendiran avatar Mar 21 '25 16:03 Gopinath-Mahendiran

Hi @neiljp ,

I hope you’re doing well! I have raised a pull request to enhance security by encrypting the api_key stored in the zuliprc file. This implementation ensures that credentials are not stored in plaintext and includes a seamless decryption mechanism.

Here is the PR link : https://github.com/zulip/zulip-terminal/pull/1564

Could you please review the changes and provide your feedback? Let me know if any modifications or improvements are needed. Looking forward to your thoughts!

Thanks for your time.

Best regards, Gopinath Mahendiran

Gopinath-Mahendiran avatar Mar 22 '25 15:03 Gopinath-Mahendiran

Hmm, it does not look at all like what I had in mind.

dkwo avatar Mar 22 '25 18:03 dkwo

@Gopinath-Mahendiran The confusion here may be that at least my vision for the revised zuliprc format was to have something like a key_command instead of key in the zuliprc, and use the value of that to fetch the key when needed. I'm not sure we directly need to handle any encryption.

It may be useful to look at other applications that have support for this, to compare their approaches.

It's worth noting that this may be something that is better handled at the python library level instead, which is why I started the conversation I linked in https://github.com/zulip/zulip-terminal/issues/1502#issuecomment-2143698265. Then it could be used for other applications, such as bots or other API users.

neiljp avatar Mar 29 '25 04:03 neiljp

@neiljp @dkwo I understand the issue and will work on resolving it. Additionally, I would like clarification on whether key_command should be a system binary or specific to the application. Should it be installed during the setup process? Also, should it be password protected or not ?”

Gopinath-Mahendiran avatar Apr 01 '25 18:04 Gopinath-Mahendiran

The whole thing should be agnostic of what key_command is: it can be a system binary, a user-provided script, but not something installed during zulip setup process. The only assumption is that the user can invoke the command in shell, and that the command gives back the key as standard output. Purely as an example, it could be cat my_password, /usr/bin/pass entry.name@email, keepassxc-cli something, age decrypt.

dkwo avatar Apr 07 '25 15:04 dkwo

@dkwo Currently, the application generates a zuliprc file at runtime (if not found) with the following format:

[api]
[email protected]
key=your_api_key_here
site=https://chat.zulip.org

Our goal is to move towards a more secure setup by replacing the key field with a passcmd field that points to a command capable of retrieving the API key securely at runtime. The desired format looks like this:

[api]
[email protected]
passcmd=command to retrieve the key
site=https://chat.zulip.org

To achieve this, here’s the proposed approach: • If the zuliprc file is not found at runtime, the application will generate two files: 1. A zuliprc file with the new format. 2. A temporary zulip_key file containing only the API key. • The generated zuliprc file will include guidance in comments, like so:

[api]
[email protected]
# Fill the passcmd field with a command that outputs the API key.
# The API key is temporarily stored in the 'zulip_key' file.
# After storing the key in a password manager, please delete the 'zulip_key' file.
passcmd=XXXXXXXXXX
site=https://chat.zulip.org

This allows users to replace XXXXXXXXXX with the appropriate shell command (e.g., pass show zulip_key, gpg, or secret-tool) and helps ensure API keys are managed securely moving forward.

Let me know if you have any suggestions or concerns.

Gopinath-Mahendiran avatar Apr 09 '25 16:04 Gopinath-Mahendiran

Makes sense. You could even have by default (mimick current behavior)

passcmd=cat zulip_key

instead of XXX, and suggest the user edits accordingly.

dkwo avatar Apr 09 '25 20:04 dkwo

chiming in just to report that zulip-api supports passing the key as a parameter or environment variable, so doing something like:

ZULIP_API_KEY=$(pass zulip-near) zulip-term

is a good workaround to avoid storing the key in the clear.

gilcu3 avatar Sep 25 '25 15:09 gilcu3