nyxt icon indicating copy to clipboard operation
nyxt copied to clipboard

Add password interface to support `bitwarden-cli`

Open r3k2 opened this issue 2 years ago • 18 comments

Please add support for bitwarden-cli on nyxt 3.x I have check the support for keepassXC on libraries/password-managers and seems for someone with lisp knowladge could be super simple to convert since bitwarden-cli is very similar. As of now I use qutebrowser with https://github.com/qutebrowser/qutebrowser/blob/master/misc/userscripts/qute-bitwarden and is the only thing at this moment preventing me from fully migrating to nyxt. I have look around, to see if I can do this myself, but I have 0 idea of lisp, just starting to pick up the syntax now, I come from C/GO etc and is very differente :)
PS: gopass is already kind of supported since is 100% compatible with "pass" unfortunately I only use gopass for system/services credentials not web credentials.

r3k2 avatar Jun 11 '22 05:06 r3k2

I've definitely seen an issue about bitwarden support before, but I can't find it...

Bitwarden is quite unknown of a ground for most of the team. None of us used it, I suppose. However, it should be pretty possible to support it if you say that the CLI API is similar to KeePassXC. What would help there is a listing of commands (and an explanation of what input those require) to:

  • Access/unlock the Vault.
  • List all the password names.
  • Get a password by entry name.
  • Get a username by entry name.
  • Create an entry given a username and password.

aartaka avatar Jun 11 '22 06:06 aartaka

Guix has the rbw package which is an unofficial CLI.

Ambrevar avatar Jun 11 '22 07:06 Ambrevar

@aartaka Thanks, sorry was out for work trip this last days. yeah the bitwarden-cli is "bw" and works similar as in takes some flags. the output of the help examples:

Examples:

    bw login
    bw lock
    bw unlock myPassword321
    bw list --help
    bw list items --search google
    bw get item 99ee88d2-6046-4ea7-92c2-acac464b1412
    bw get password google.com
    echo '{"name":"My Folder"}' | bw encode
    bw create folder eyJuYW1lIjoiTXkgRm9sZGVyIn0K
    bw edit folder c7c7b60b-9c61-40f2-8ccd-36c49595ed72 eyJuYW1lIjoiTXkgRm9sZGVyMiJ9Cg==
    bw delete item 99ee88d2-6046-4ea7-92c2-acac464b1412
    bw generate -lusn --length 18
    bw config server https://bitwarden.example.com
    bw send -f ./file.ext
    bw send "text to send"
    echo "text to send" | bw send
    bw receive https://vault.bitwarden.com/#/send/rg3iuoS_Akm2gqy6ADRHmg/Ht7dYjsqjmgqUM3rjzZDSQ

examples of list/finding by diff ways notice the --url

Examples:

    bw list items
    bw list items --folderid 60556c31-e649-4b5d-8daf-fc1c391a1bf2
    bw list items --search google --folderid 60556c31-e649-4b5d-8daf-fc1c391a1bf2
    bw list items --url https://google.com
    bw list items --folderid null
    bw list items --organizationid notnull
    bw list items --folderid 60556c31-e649-4b5d-8daf-fc1c391a1bf2 --organizationid notnull
    bw list items --trash
    bw list folders --search email
    bw list org-members --organizationid 60556c31-e649-4b5d-8daf-fc1c391a1bf2

Examples of get


  Examples:

    bw get item 99ee88d2-6046-4ea7-92c2-acac464b1412
    bw get password https://google.com
    bw get totp google.com
    bw get notes google.com
    bw get exposed yahoo.com
    bw get attachment b857igwl1dzrs2 --itemid 99ee88d2-6046-4ea7-92c2-acac464b1412 --output ./photo.jpg
    bw get attachment photo.jpg --itemid 99ee88d2-6046-4ea7-92c2-acac464b1412 --raw
    bw get folder email
    bw get template folder

if you aready did bw login once then you just need to unlock by requesting a command, in my case I have dmenu pop up asking me for the login/pass and the stdout of the request result. There is a great example on how qutebrowser does this with python on the link I sent above. https://github.com/qutebrowser/qutebrowser/blob/master/misc/userscripts/qute-bitwarden Hope this helps.

r3k2 avatar Jun 15 '22 03:06 r3k2

I had a look at rbw: it misses the following from what you've listed:

  • create
  • send
  • receive

My guess is that rbw does not need them. Documentation: https://git.tozt.net/rbw/tree/README.md

@r3k2 From the author's comment, it seems that rbw is more practical to use than bw. Is there a good reason to use bw instead?

Ambrevar avatar Jun 15 '22 07:06 Ambrevar

@Ambrevar well I like bw more, mainly because is the "officially" supported, but if this is build around rbw that is ok, will be easy to change tool, as long rbw has a big community and fast development to assist in any new security issue or bug knowing this is a password manager not just any other simple desktop software. I like the idea of BW of having to enter credentials each time I look for a web password, the last thing I need is for my laptop to be stolen while on, meaning my drive is then unencrypted and logged into the system as my user... when it comes to security/privacy I do not mind practicality as much, the point of securing a password manager is to be able to use other apps like webbrowsers and what not, in a more practical way, but not the password manager it self :)

r3k2 avatar Jun 16 '22 20:06 r3k2

Hello, grats on the pre-release :fireworks: any chance this can make it? if to busy, can you point me out the files/libs/places I can look, so I can try to write this, I have no lisp experience only with C/GO and some scripting languages like Python/Ruby and such

r3k2 avatar Jul 13 '22 21:07 r3k2

I've forgotten about this, sorry. If you care enough to try implementing it yourself, then libraries/password-manager/ and source/mode/password.lisp in the Nyxt source tree are the files to look at for templates and techniques. I'll be glad to get a PR and help you with the bits that may seem unintuitive ;)

aartaka avatar Jul 14 '22 12:07 aartaka

@aartaka i'm willing to make a pull request with bitwarden integration, but currently stuck making dev environment to work under NixOS.

Is there's any clear way to setup up dev environment using shell.nix?

Everything from the manual works fine, i can start Nyxt instance without compiling using (nyxt:start) command.

I tried to add /libraries/password-manager/password-bitwarden.lisp and then modified nyxt/password-manager package innyxt.asd:

(defsystem "nyxt/password-manager"
  :defsystem-depends-on (nyxt-asdf)
  :class :nyxt-system
  :depends-on (bordeaux-threads
               cl-ppcre
               str
               trivial-clipboard
               uiop
               nyxt/class-star
               serapeum)
  :pathname #p"NYXT:libraries;password-manager;"
  :components ((:file "package")
               (:file "password")
               (:file "password-keepassxc")
               (:file "password-security")
               (:file "password-pass")
               ;; Keep password-bitwarden last so that it has higher priority.
               (:file "password-bitwarden")))

Updated user config to use Bitwarden by default.

(define-configuration nyxt/password-mode:password-mode
  ((nyxt/password-mode:password-interface (make-instance 'password:bitwarden-interface))))

And after restarted Nyxt using (ql:quickload :nyxt/gtk-application) and (nyxt:start), but it fails:

* (nyxt:start)
Nyxt version 3
<INFO> [20:54:14] Source location: #P"/home/andrey/quicklisp/dists/quicklisp/software/nyxt-20220707-git/"
<INFO> [20:54:14] Listening to socket #P"/run/user/1000/nyxt/nyxt.socket".
<INFO> [20:54:14] Loading Lisp file #P"/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/config.lisp".
; compiling file "/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/bitwarden.lisp" (written 02 AUG 2022 07:08:06 PM):
;
; caught ERROR:
;   READ error during COMPILE-FILE:
;
;     Symbol "BITWARDEN-INTERFACE" not found in the PASSWORD package.
;
;       Line: 4, Column: 86, File-Position: 166
;
;       Stream: #<SB-INT:FORM-TRACKING-STREAM for "file /home/andrey/.config/dotfiles/config/nyxt/nyxt-3/bitwarden.lisp" {10084DDDD3}>

; compilation aborted after 0:00:00.000
While evaluating the form starting at line 29, column 0
  of #P"/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/init.lisp":
While evaluating the form starting at line 4, column 0
  of #P"/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/config.lisp":

debugger invoked on a UIOP/LISP-BUILD:COMPILE-FILE-ERROR in thread
#<THREAD "main thread" RUNNING {1001678073}>:
  COMPILE-FILE-ERROR while
  compiling #<CL-SOURCE-FILE "nyxt-user/basic-config" "bitwarden">

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [RETRY                        ] Retry
                                     compiling #<CL-SOURCE-FILE "nyxt-user/basic-config" "bitwarden">.
  1: [ACCEPT                       ] Continue, treating
                                     compiling #<CL-SOURCE-FILE "nyxt-user/basic-config" "bitwarden">
                                     as having been successful.
  2:                                 Retry ASDF operation.
  3: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the
                                     configuration.
  4:                                 Retry ASDF operation.
  5:                                 Retry ASDF operation after resetting the
                                     configuration.
  6: [RETRY                        ] Retry EVAL of current toplevel form.
  7: [CONTINUE                     ] Ignore error and continue loading file "/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/init.lisp".
  8: [ABORT                        ] Abort loading file "/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/init.lisp".
  9:                                 Retry EVAL of current toplevel form.
 10:                                 Ignore error and continue loading file "/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/config.lisp".
 11:                                 Abort loading file "/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/config.lisp".
 12:                                 Exit debugger, returning to top level.

After looking around fro some clues i checked ~/.cache/common-lisp/sbcl-2.2.6.nixos-linux-x64/home/andrey/quicklisp/dists/quicklisp/software/nyxt-20220707-git/libraries/password-manager/ and ~/quicklisp/dists/quicklisp/software/nyxt-20220707-git/libraries/password-manager/ folders and none of them contains newly added /libraries/password-manager/password-bitwarden.lisp file.

From what i see, there must be some sort of cache happening, but i can't figure out where or how exactly should i clear it.

I tried deleting ~/.cache/common-lisp/sbcl-2.2.6.nixos-linux-x64/home/andrey/quicklisp/dists/quicklisp/software/nyxt-20220707-git/ and ~/quicklisp/dists/quicklisp/software/nyxt-20220707-git/ but it didn't help.

What am i missing here?

andreystepanov avatar Aug 02 '22 18:08 andreystepanov

@aartaka i'm willing to make a pull request with bitwarden integration, but currently stuck making dev environment to work under NixOS.

Is there's any clear way to setup up dev environment using shell.nix?

No, I suppose. @jmercouris is using NixOS too, so maybe he has found a better way, but the last time I've heard, Quicklisp was the simplest way to load Nyxt & deps due to Nix's Lisp unfriendliness :D

Everything from the manual works fine, i can start Nyxt instance without compiling using (nyxt:start) command.

I tried to add /libraries/password-manager/password-bitwarden.lisp and then modified nyxt/password-manager package innyxt.asd:

(defsystem "nyxt/password-manager"
  :defsystem-depends-on (nyxt-asdf)
  :class :nyxt-system
  :depends-on (bordeaux-threads
               cl-ppcre
               str
               trivial-clipboard
               uiop
               nyxt/class-star
               serapeum)
  :pathname #p"NYXT:libraries;password-manager;"
  :components ((:file "package")
               (:file "password")
               (:file "password-keepassxc")
               (:file "password-security")
               (:file "password-pass")
               ;; Keep password-bitwarden last so that it has higher priority.
               (:file "password-bitwarden")))

So far so good, I don't see anything outright wrong there.

Updated user config to use Bitwarden by default.

(define-configuration nyxt/password-mode:password-mode
  ((nyxt/password-mode:password-interface (make-instance 'password:bitwarden-interface))))

And after restarted Nyxt using (ql:quickload :nyxt/gtk-application) and (nyxt:start), but it fails:

I have a habit of restarting the whole Lisp image from scratch to test a new feature, because by the time you finish it the image goes infinitely polluted and ASDF remember the old list of files. May be worth it to try restarting the image there ;)

* (nyxt:start)
Nyxt version 3
<INFO> [20:54:14] Source location: #P"/home/andrey/quicklisp/dists/quicklisp/software/nyxt-20220707-git/"
<INFO> [20:54:14] Listening to socket #P"/run/user/1000/nyxt/nyxt.socket".
<INFO> [20:54:14] Loading Lisp file #P"/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/config.lisp".
; compiling file "/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/bitwarden.lisp" (written 02 AUG 2022 07:08:06 PM):
;
; caught ERROR:
;   READ error during COMPILE-FILE:
;
;     Symbol "BITWARDEN-INTERFACE" not found in the PASSWORD package.
;
;       Line: 4, Column: 86, File-Position: 166
;
;       Stream: #<SB-INT:FORM-TRACKING-STREAM for "file /home/andrey/.config/dotfiles/config/nyxt/nyxt-3/bitwarden.lisp" {10084DDDD3}>

; compilation aborted after 0:00:00.000
While evaluating the form starting at line 29, column 0
  of #P"/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/init.lisp":
While evaluating the form starting at line 4, column 0
  of #P"/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/config.lisp":

debugger invoked on a UIOP/LISP-BUILD:COMPILE-FILE-ERROR in thread
#<THREAD "main thread" RUNNING {1001678073}>:
  COMPILE-FILE-ERROR while
  compiling #<CL-SOURCE-FILE "nyxt-user/basic-config" "bitwarden">

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [RETRY                        ] Retry
                                     compiling #<CL-SOURCE-FILE "nyxt-user/basic-config" "bitwarden">.
  1: [ACCEPT                       ] Continue, treating
                                     compiling #<CL-SOURCE-FILE "nyxt-user/basic-config" "bitwarden">
                                     as having been successful.
  2:                                 Retry ASDF operation.
  3: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the
                                     configuration.
  4:                                 Retry ASDF operation.
  5:                                 Retry ASDF operation after resetting the
                                     configuration.
  6: [RETRY                        ] Retry EVAL of current toplevel form.
  7: [CONTINUE                     ] Ignore error and continue loading file "/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/init.lisp".
  8: [ABORT                        ] Abort loading file "/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/init.lisp".
  9:                                 Retry EVAL of current toplevel form.
 10:                                 Ignore error and continue loading file "/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/config.lisp".
 11:                                 Abort loading file "/home/andrey/.config/dotfiles/config/nyxt/nyxt-3/config.lisp".
 12:                                 Exit debugger, returning to top level.

Have you exported bitwarden-interface? It usually is either (export-always 'bitwarden-interface) or

(:export-class-name-p t)
(:export-accessor-names-p t)
(:accessor-name-transformer (class*:make-name-transformer name))

in define-class definition.

After looking around fro some clues i checked ~/.cache/common-lisp/sbcl-2.2.6.nixos-linux-x64/home/andrey/quicklisp/dists/quicklisp/software/nyxt-20220707-git/libraries/password-manager/ and ~/quicklisp/dists/quicklisp/software/nyxt-20220707-git/libraries/password-manager/ folders and none of them contains newly added /libraries/password-manager/password-bitwarden.lisp file.

From what i see, there must be some sort of cache happening, but i can't figure out where or how exactly should i clear it.

I tried deleting ~/.cache/common-lisp/sbcl-2.2.6.nixos-linux-x64/home/andrey/quicklisp/dists/quicklisp/software/nyxt-20220707-git/ and ~/quicklisp/dists/quicklisp/software/nyxt-20220707-git/ but it didn't help.

Yes, that could well be a cache issue. But let's try all the other suggestions above first :)

aartaka avatar Aug 02 '22 19:08 aartaka

I have a habit of restarting the whole Lisp image from scratch to test a new feature, because by the time you finish it the image goes infinitely polluted and ASDF remember the old list of files.

I wish i new how to do it from the top of my head :) Can you please provide some commands/steps you use for that?

I'm new to common-lisp, but quite familiar with Elisp. So writing common-lisp doesn't scares me all that much, but configuring the environment does.

Have you exported bitwarden-interface? It usually is either (export-always 'bitwarden-interface) or

Yes i did. I just used password-keepassxs.lisp as a template, renaming class name and executable.

(define-class bitwarden-interface (password-interface)
  ((executable (pathname->string (sera:resolve-executable "bw")))
   (password-file)
   (master-password nil
                    :type (or null string))
   (entries-cache nil
                  :type list
                  :documentation "The cache to speed the entry listing up."))
  (:export-class-name-p t)
  (:export-accessor-names-p t)
  (:accessor-name-transformer (class*:make-name-transformer name)))

Yes, that could well be a cache issue. But let's try all the other suggestions above first :)

Yesterday i notice that after i delete all the cache and try to follow the steps described in Hacking section, it doesn't really uses my local copy, but instead the definition of the package from beta.quicklisp.org/dist/quicklisp/2022-07-08/systems.txt.

How do you personally developing Nyxt using local repository you make changes to?

andreystepanov avatar Aug 03 '22 07:08 andreystepanov

How do you personally developing Nyxt using local repository you make changes to?

One dirty and discouraged hack is to add those to asdf:*central-registry*, as it overrides Quicklisp configuration:

(push #p"/path/to/local/checkout/" asdf:*central-registry*)

There probably are better ways, but this one works in 100% of cases.

aartaka avatar Aug 03 '22 08:08 aartaka

Alright, i've got it working. Not the way you suggested though.

Here's a helpful link to others searching for answers: http://blog.quicklisp.org/2018/01/the-quicklisp-local-projects-mechanism.html

I might make some changes to MANUAL.org file as well, so others wouldn't waste their time on this issue.

andreystepanov avatar Aug 03 '22 10:08 andreystepanov

Yes, local projects are probably even better of a way for Quicklisp-based workflow :) MANUAL mention of that wouldn't hurt!

aartaka avatar Aug 03 '22 10:08 aartaka

Hello everyone, pleased to see someone is working on this, since I have no idea on LISP, how is this comming along?

r3k2 avatar Sep 03 '22 18:09 r3k2

The main contributors are a bit swamped by high priority tasks. Things should settle down in a month or 2. Sorry :/

Ambrevar avatar Sep 05 '22 08:09 Ambrevar

@andreystepanov, you've said you've got the prototype working. Mind opening a PR then? If it's not yet ready and you've no time, we can take it from there!

aartaka avatar Sep 05 '22 08:09 aartaka

Looks like this has been stale a while, any chance you've gotten it working? If not I'll probably go ahead and make this myself in the next couple days.

hypotrochoid avatar Sep 23 '23 06:09 hypotrochoid

This is should be relatively easy to do by sub classing password-interface. It is not a priority as of today, but PRs are welcome. We can help :)

aadcg avatar Oct 25 '23 08:10 aadcg