seanfarley / emacs-bitwarden

Emacs Bitwarden command wrapper.
GNU General Public License v3.0
47 stars 13 forks source link

+title: README

A Bitwarden command wrapper for Emacs.

** Installation

To use this package you will need the [[https://github.com/bitwarden/clients/tree/master/apps/cli][Bitwarden CLI]].

** Automatic unlock

Bitwarden has a concept of locking which is different from logging in. For two-factor authentication, this means that only logging in will require your 2fa token.

As a convenience, you can store your master password in your OS keychain and use the [[file:bitwarden.el::(defcustom%20bitwarden-automatic-unlock%20nil][bitwarden-automatic-unlock]] variable. For example, to temporarily set the =auth-source= to the macos keychain and then query that,

+begin_src emacs-lisp

(setq bitwarden-automatic-unlock (let* ((auth-sources '(macos-keychain-internet)) (matches (auth-source-search :user "sean@farley.io" :host "bitwarden.farley.in" :require '(:secret) :max 1)) (entry (nth 0 matches))) (plist-get entry :secret)))

+end_src

If your bitwarden store is kept on bitwarden servers (as opposed to hosting your own server), you may find that the above approach does not work and gives a =Symbol’s value as variable is void: print-message= error. This may be due to a recent change in bitwarden login procedures which require the use of an API application key. To check if this is indeed the problem try logging in from the command line with =bw login [username] 'password'= if you are prompted for an API key then the following instructions may resolve your problem.

Login to the [[https://vault.bitwarden.com][bitwarden web interface]], login to your vault, go to the =settings= tab and scroll down to the API Key section. Follow the instructions to setup your API key. You will need both your =client_id= and your =client_secret=. Then add to your init.el configuration two functions =bitwarden-api-client-id= and =bitwarden-api-client-secret= which have the same specification format as =bitwarden-automatic-unlock=. Here is an example emacs configuration,

+begin_src emacs-lisp

(setq bitwarden-api-secret-key (plist-get (car (auth-source-search :host "bitwarden.key")) :secret)) (setq bitwarden-api-client-id (plist-get (car (auth-source-search :host "bitwarden.id")) :secret))

+end_src

For those using =authinfo.gpg=, these two lines have the form,

+begin_quote

machine bitwarden.key login YYY password XXX machine bitwarden.id login YYY password XXX

+end_quote

** auth-source

There is read-only support for auth-source as well. You can run =bitwarden-auth-source-enable= to enable it. For example,

+begin_src emacs-lisp

(auth-source-search :host "github.com")

+end_src

will return all logins that match =github.com=.

** async support

For certain emacs tasks (e.g. github modeline), emacs will run the process asynchronously which means a new emacs process. For this reason, this bitwarden wrapper will need to be a macro so that the session is preserved. Here is an one such way to do that:

+begin_src emacs-lisp

(defmacro smf/bitwarden-init () "Needs to be a macro due to async.

Async doesn't load your entire config (for performance reasons) so this needs to be a macro and added to async hooks." `(progn (require 'bitwarden nil t) (setq bitwarden-user "sean@farley.io"

       bitwarden-automatic-unlock (let* ((auth-sources
                                          '(macos-keychain-internet))
                                         (matches (auth-source-search
                                                   :user "sean@farley.io"
                                                   :host "bitwarden.farley.io"
                                                   :require '(:secret)
                                                   :max 1))
                                         (entry (nth 0 matches)))
                                    (plist-get entry :secret)))
 (bitwarden-auth-source-enable)))

+end_src

And then add it to async hooks as such,

+begin_src emacs-lisp

(add-hook 'doom-modeline-before-github-fetch-notification-hook (lambda () (smf/bitwarden-init)))"

+end_src