corpusops / bitwardentools

bitwarden python api client and additional tools like for migrating from vaultier to bitwarden (bitwarden_rs)
Other
38 stars 15 forks source link

confirm_invitation unnecessarily requires server private key #7

Closed OdyX closed 3 years ago

OdyX commented 3 years ago

First, thanks a lot for this quite excellent Bitwarden Python API implementation, it spared me insane lots of rewriting!

While implementing an automated synchronization tool between our employee directory and a (1.22.2) Vaultwarden server, I stumbled upon the requirement of the server private key to confirm users in organizations.

But as far as I could quick patch, I can correctly confirm users by going this way:

bwcli =  Client(…)
orga = bwcli.get_organization("My Org")
# Get organization-level accesses
accesses = bwcli.get_accesses(orga)["daccess"]
for email, access in orga_accesses.items():
    if access["status"] == 1: # 1: Accepted
        bwcli.confirm_invitation(orga=orga, email=email, id=access["userId"])

… with confirm_invitation patched as follows:

--- a/src/bitwardentools/client.py
+++ b/src/bitwardentools/client.py
@@ -3111,12 +3111,9 @@ class Client(object):
     def confirm_invitation(
         self, orga, email, id=None, name=None, sync=None, token=None
     ):
-        self.ensure_private_key()
         token = self.get_token(token=token)
         orga = self.get_organization(orga, token=token)
         orgkey = self.get_organization_key(orga, token=token)
-        user = self.get_user(email=email, name=name, id=id, sync=sync)
-        email = user.email
         oaccess = self.get_accesses(orga, token=token)
         try:
             acl = oaccess["daccess"][email]
@@ -3138,7 +3135,7 @@ class Client(object):
                 exc = AlreadyConfirmedError(log)
                 exc.orga, exc.email = orga, email
                 raise exc
-        resp = self.r(f"/api/users/{user.id}/public-key", method="get")
+        resp = self.r(f"/api/users/{id}/public-key", method="get")
         self.assert_bw_response(resp)
         userorgkey = b64decode(resp.json()["PublicKey"])

In other words, it seems that confirm_invitation relies on get_users having access to /admin/users to "just" get the userId; but that's now directly accessible in organization access lists.

Feel free to integrate any variation of my patch. Alternatively, I'd be happy to provide a more precise patch if you'd be interested in shipping something like that! Guidance might be needed to avoid wreaking havoc!

kiorky commented 3 years ago

I see the point, but the search for the user must be based on whatever criterion the user want (email, id, or name). Basically, your patch is good, i ll integrate the idea.

kiorky commented 3 years ago

Afterall, i came up with the same patch, so i merged yours, congrats ! :tada: