bitwarden-menu icon indicating copy to clipboard operation
bitwarden-menu copied to clipboard

Switch bwcli to using the new `bw serve` command

Open firecat53 opened this issue 3 years ago • 11 comments

Bitwarden CLI v1.22.0 added a serve option to interact with the vault using a REST API. It seems faster than calling commands via subprocess, although need to wait to actually finish it publicly until they release the fix that binds the API to localhost. Right now it's wide open to the network.

Basic interaction:

items = 'http://localhost:8087/unlock'
headers = {'accept': 'application/json'}
payload = {'password': 'mypassword'}
res = requests.get(items, headers=headers, json=payload)

Probably start bw serve either in the main server process or perhaps in a separate thread that can be restarted with a different BITWARDENCLI_APPDATA_DIR to allow multiple vaults to be accessed.

firecat53 avatar Apr 12 '22 00:04 firecat53

I recently switched from keepass to bitwarden, and am searching for a replacement for keepmenu. My main issue with bitwarden-menu at the moment is that it takes a long time to initially open the database (it even seems to wait a second before prompting me for my password, though subsequent calls are quick enough).

Anyway, I'm curious if you think using the REST API as you describe here would reduce the startup time, or if you suspect the issue is elsewhere (it is possible I could be convinced to try implementing this if it isn't too difficult and is likely to reduce the startup time).

aclindsa avatar Jul 22 '25 01:07 aclindsa

Thanks for the interest! Even though I use it every day, I haven't made time to do any profiling as to where the significant delay is.

I'd be happy for any help if you'd like to poke at either the API or profiling the existing code! I can't vouch for difficulty though. I suspect it would be moderately challenging because of having to convert to using API calls. However, hopefully the code is decoupled enough so we could just redo bwm/bwcli.py and use the same internal function calls in the other modules.

firecat53 avatar Jul 25 '25 02:07 firecat53

I haven't made time to do any profiling as to where the significant delay is.

I just did some quick-n-dirty "profiling", and it seems like basically every call to the underlying CLI takes at least 2.5 seconds on my machine. When it takes 6 calls into the CLI on startup, you end up with at least 15 seconds of delay. Anyway, I've convinced myself that nearly all of the time is spent outside bitwarden-menu itself. I'm suspecting that most of the overhead is simply the nodejs startup cost, which does make me think its possible the bw serve command could help since we would only pay that startup cost 1x instead of 6x.

aclindsa avatar Jul 26 '25 00:07 aclindsa

Okay, I played around enough with bw serve by hitting a few endpoints with curl to convince myself that this would significantly reduce startup time. The /list/object/items request took 0.1 - 0.2 seconds while the equivalent bw list items command takes 2.5 - 3 seconds.

But it appears that the opened port is open to anyone on localhost, and that no login/session is required to be sent with each request. This is insecure in any environment where someone/something else is running on the same machine, because it would allow any other user on the same machine to access your vault. After searching, it appears there are a few relevant issues/PRs upstream:

  • https://github.com/bitwarden/clients/issues/13571 (same issue I just raised with you)
  • https://github.com/bitwarden/clients/pull/14262 (PR to add support for serving over UNIX domain sockets)
  • https://github.com/bitwarden/clients/issues/3932 (old and closed version of similar issue)

It feels like it could be workable with UNIX domain sockets as long as you can ensure only the owning user has access to it, but I'm not sure I want to invest time adding this to bitwarden-menu unless I can be somewhat confident that feature is actually going in upstream (I'm okay patching the bw CLI client briefly to test/develop, but it doesn't seem tenable to expect other users of bitwarden-menu to do so).

aclindsa avatar Jul 26 '25 00:07 aclindsa

Hmm, that implementation is disappointing. Thanks for testing, though! Well, it looks like they took your prompt and moved it to their engineering team for review, so that's promising! I'll keep an eye on that PR and see if they get it merged and then we can revisit. Really appreciate the work!!

firecat53 avatar Jul 28 '25 02:07 firecat53

Just was thinking about this...maybe I'm off base: if the session key returned by the login call is stored by the client on the user's filesystem with 600 permissions after the vault is unlocked, then any other user would not be able to access that session, right? On mobile right now so I can't test at the moment. If I'm thinking about it right, that seems to be about the same level of security as we have currently.

firecat53 avatar Jul 31 '25 17:07 firecat53

Just was thinking about this...maybe I'm off base: if the session key returned by the login call is stored by the client on the user's filesystem with 600 permissions after the vault is unlocked, then any other user would not be able to access that session, right? On mobile right now so I can't test at the moment. If I'm thinking about it right, that seems to be about the same level of security as we have currently.

I could be wrong, but my impression is that the session key is not required to make requests via the port opened by bw serve the same way it is when calling the command-line interface.

aclindsa avatar Jul 31 '25 17:07 aclindsa

You're right. You have to login to the vault to start bw serve but any user can make requests to that port. Sad.

firecat53 avatar Aug 01 '25 03:08 firecat53

Thanks for the help getting my PR noticed. In addition to CLI calls and server, you could bypass the CLI entirely and use the internal API to download and decrypt the Bitwarden vault in Python using the cryptography module. I had a go at implementing this here, although some features are not implemented yet.

Game4Move78 avatar Aug 01 '25 16:08 Game4Move78

Thanks a ton @Game4Move78!

@firecat53 Given that it looks like this is going to go in upstream, I did a very quick and very hacky prototype to see if it seemed workable. Here's what I did so far:

https://github.com/firecat53/bitwarden-menu/compare/main...aclindsa:bitwarden-menu:main

I'm sure I'm breaking your code's assumptions left and right (for example, I didn't even attempt to handle switching vaults) and many API calls still fall back to the CLI, but this got me far enough to prove I could get the initial loading time down to only ~2 seconds!

I don't know how you prefer to handle stuff like this, but I'm more than happy for you to take what I have and bend it into something that's more in your coding style, for you to do it on your own, or whatever - just let me know.

aclindsa avatar Aug 02 '25 01:08 aclindsa

It looks like the PR for binding to sockets has been released with bw cli v2025.9.0. @aclindsa If you'd like to finish up the work you did and make a PR, I'd be happy to review and test! Even if the initial PR just cuts the startup time and we still fall back to existing CLI calls, I think that would be a great start and would put the framework in place for expanding on it.

To be honest, I've been doing much less pure coding than I used to, so it's awesome that other people are interested and want to make it a community project! But I'll certainly attack the project if no one else does!

firecat53 avatar Sep 20 '25 20:09 firecat53