Giter Site home page Giter Site logo

corpusops / bitwardentools Goto Github PK

View Code? Open in Web Editor NEW
31.0 4.0 14.0 187 KB

bitwarden python api client and additional tools like for migrating from vaultier to bitwarden (bitwarden_rs)

License: Other

Shell 4.11% Dockerfile 1.72% Python 94.17%
vaultier bitwarden-rs bitwarden bitwarden-cli python python3

bitwardentools's Introduction

tools for working with vaultwarden/bitwarden (_rs) and vaultier

This package containers a python3+ client for bitwarden which uses both a native python implementation but also wraps the official the official npm @bitwarden/cli.

The ultimate goal is certainly only to rely on python implementation against the vaultwarden/bitwarden_rs server implementation.

  • .github/workflows/cicd.yml

Features

  • api controllable client
  • Create, Read, Update, Delete, on organizations, collection, ciphers, users (also disable/enable), and attachments
  • Attach Ciphers to organization collections
  • Set access at orgas, collections and users levels.
  • Download/Upload attachments to vault and organizations
  • The client also integrate a thin wrapper to official npm CLI (see call mathod)
  • Read api for longer details

install as a python lib

pip install bitwardentools

Run in dev

Configure

cp .env.dist .env
cp .env.local.dist .env.local
printf "USER_UID=$(id -u)\nUSER_GID=$(id -g)\n">>.env

Build

eval $(egrep -hv '^#|^\s*$' .env .env.local|sed  -e "s/^/export /g"| sed -e "s/=/='/" -e "s/$/'/g"|xargs)
COMPOSE_FILE="docker-compose.yml:docker-compose-build.yml" docker-compose build

Run

docker-compose run --rm app bash
sed -i -e "/COMPOSE_FILE/d" .env
echo "COMPOSE_FILE=docker-compose.yml:docker-compose-dev.yml" >> .env
docker-compose up -d --force-recreate
docker-compose exec -u app app bash

run tests

sed -i -e "/COMPOSE_FILE/d" .env
echo "COMPOSE_FILE=docker-compose.yml:docker-compose-dev.yml:docker-compose-test.yml" >> .env
docker-compose exec -u app app tox -e linting,coverage

Credits and bibliography

Doc

see also USAGE (or read below on pypi)

bitwardentools's People

Contributors

commonism avatar kiorky avatar kriechi avatar mandruis7 avatar mavensk avatar odyx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

bitwardentools's Issues

Missing dependency - ModuleNotFoundError: No module named 'packaging'

When after installing bitwardentools in an empty 3.12 venv

>>> import bitwardentools
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/demo/lib/python3.12/site-packages/bitwardentools/__init__.py", line 1, in <module>
    from bitwardentools.client import *  # noqa
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/demo/lib/python3.12/site-packages/bitwardentools/client.py", line 24, in <module>
    from packaging import version as _version
ModuleNotFoundError: No module named 'packaging'

installing packaging from pip helped.

Argon2id algorithm support?

When attempting to login to a vaultwarden instance using argon2id the program crashes with a invalid username or password.

image

from bitwardentools import Client


client = Client(SERVER, EMAIL, PASSWORD)


client.sync()
Traceback (most recent call last):
  File "E:\Users\Garulf\Projects\Garulf\bitwarden-flow\src\plugin.py", line 11, in <module>
    client = Client(SERVER, EMAIL, PASSWORD)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "E:\Users\Garulf\Projects\Garulf\bitwarden-flow\.venv\Lib\site-packages\bitwardentools\client.py", line 728, in __init__
    self.login()
  File "E:\Users\Garulf\Projects\Garulf\bitwarden-flow\.venv\Lib\site-packages\bitwardentools\client.py", line 829, in login
    raise exc
bitwardentools.client.LoginError: Failed login for *****@****.com ()

This is the text response from the server:

{"ErrorModel":{"Message":"Username or password is incorrect. Try again","Object":"error"},"ExceptionMessage":null,"ExceptionStackTrace":null,"InnerExceptionMessage":null,"Message":"Username or password is incorrect. Try again","Object":"error","ValidationErrors":{"":["Username or password is incorrect. Try again"]},"error":"","error_description":""}

Error when trying to create a login

Trying to create a secret in a organization results in a error tested against a Bitwarden_RS instance
Here It's the code to reproduce the error

from bitwardentools import client as bwclient
from variables import email,password,server,organization

client = bwclient.Client(server, email, password)
client.sync()

orga = client.get_organization(organization)

cipherp = {
    "object": "item",
    "name": "testitp",
    "organizationId": orga.id,
    "notes": "supernote",
    "login": {"username": "alice", "password": "rabbit"},
}

cipher = client.create(**cipherp)

Here It's the traceback

Traceback (most recent call last):
  File "/home/manu/Documents/Cloudsphere/DevOps/tools/bitwarden-restapi/teste.py", line 9, in <module>
    cipher = client.create(**{
  File "/home/manu/.local/lib/python3.9/site-packages/bitwardentools/client.py", line 1551, in create
    return BWFactory.create(self, *args, **kw)
  File "/home/manu/.local/lib/python3.9/site-packages/bitwardentools/client.py", line 368, in create
    return kls.patch("create", client, *args, **kw)
  File "/home/manu/.local/lib/python3.9/site-packages/bitwardentools/client.py", line 363, in patch
    ret = api_method(**jsond)
  File "/home/manu/.local/lib/python3.9/site-packages/bitwardentools/client.py", line 976, in create_item
    obj = self._upload_object(u, method=method, data=data, key=key, log=log)
  File "/home/manu/.local/lib/python3.9/site-packages/bitwardentools/client.py", line 876, in _upload_object
    assert resp.status_code == 200
AssertionError

add edit_item/edit_login functionality

Would be nice to have an option to edit/update existing items. Here https://pypi.org/project/bitwardentools/ it does not say if edit itmes/logins is possible, but I can see in the pyton code edit_login = edit_item. Is this supported already?

I am able to add items, logins, collections and get ciphers, but not edit or update.
I have tried to update the password of a login with JSON payload like this:

>>> payload = {
...     "login": {
...         "username": "root", "password": "password2"
...     }
... }
>>> client.edit_login("server1", orga="organization1", collections=["collection1"], **payload)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/.local/lib/python3.10/site-packages/bitwardentools/client.py", line 1297, in edit_item
    return self.create_item(*a, **kw)
  File "/home/user/.local/lib/python3.10/site-packages/bitwardentools/client.py", line 1265, in create_item
    u = f'/api/ciphers/{data["id"]}'
KeyError: 'id'
>>> client.edit_login(name="server1", orga="organization1", collection="collection1", **payload)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/.local/lib/python3.10/site-packages/bitwardentools/client.py", line 1297, in edit_item
    return self.create_item(*a, **kw)
  File "/home/user/.local/lib/python3.10/site-packages/bitwardentools/client.py", line 1265, in create_item
    u = f'/api/ciphers/{data["id"]}'
KeyError: 'id'
>>>

OS: Fedora 35
Python: 3.10

Error with get_cipher

First of all, thx a lot for this library.

I'm trying to use it on self hosted vaultwarden instance and faced an issue.
code
cipher = client.get_cipher(item_or_id_or_name="elk", collection=col, orga=orga)
error
Traceback (most recent call last): File "main.py", line 21, in <module> cipher = client.get_cipher(item_or_id_or_name="elk", collection=col, orga=orga) File "/home/vscode/.local/lib/python3.8/site-packages/bitwardentools/client.py", line 1883, in get_cipher ret = ret[0] TypeError: 'odict_values' object is not subscriptable

Can u help me?

add TOTP support

We would like to use bitwardentools with TOTP as we require all users to have 2FA with Google Authenticator, Authy or other. Would be nice to have the option to use the Authenticator Key in the client. Something like this:
client = Client('https://bitwarden.example.com', '[email protected]', 'user_password', 'authenticator_key');

Edit the cipher username and password. Is it possible?

Hi,
I'm trying to edit the username but I have no idea what I'm doing wrong. I looked at the test_client.py code and I read a closed issue on this topic. Successfully edited the note, but I can't edit the username and password. I've been struggling with it for 2 days.

WORKING GREAT

secitem = client.search_objects({"name": 'sv_admin'}, sync=True)[0]
client.edit_item(secitem, notes="its test only")

DON'T WORK

secitem = client.search_objects({"name": 'sv_admin'}, sync=True)[0]
client.edit_login(secitem, username="svroot")
client.edit_login(secitem, password="qwe321")

Additionally, could you tell me how I can delete the collection? Removing ciphers works great, but when I want to delete the collection, the script does not show any error, but the collection is not deleted.
I tried to do it the same way as deleting the cipher.

secitem = client.search_objects({"name": 'COLLECTION2'}, sync=True)[0]
client.delete(secitem)

Thank you! :)

Admin page requests end in NotFounds (vaultwarden)

As the title mentions, any function that calls the adminr function always results in a 404 not found, as the request is not properly authenticated. The admin page on vaultwarden uses cookies to authenticate the admin, but the adminr function does not do so. I wrote a quick fix for this problem:

    res = requests.post(
        f'{self.server}/admin',
        data=f'token={admin_password}',
        headers={
            "content-type": "application/x-www-form-urlencoded"
        },
        allow_redirects=False
    )

    headers = {
        'cookie': res.headers.get('set-cookie')
    }

We then need to pass these headers into the call.

One problem with this approach is timeouts, requesting too many tokens very quickly leads to a timeout, which I think can be fixed by only updating the cookie if the request is a 404 and then retrying the request.

raising keyerror on 'kdfIterations'

Issue when login in with the client.

Code

self.bitwarden_client = client = Client(
   server="https://vault.bitwarden.com", 
   email=self.BITWARDEN_EMAIL, 
   password=self.BITWARDEN_PASSWORD
)

Error

←[31mERROR←[0m:    
Traceback (most recent call last):
  File "c:\users\sarah\pycharmprojects\stella_manager\venv\lib\site-packages\starlette\routing.py", line 635, in lifespan
    async with self.lifespan_context(app):
  File "c:\users\sarah\pycharmprojects\stella_manager\venv\lib\site-packages\starlette\routing.py", line 530, in __aenter__
    await self._router.startup()
  File "c:\users\sarah\pycharmprojects\stella_manager\venv\lib\site-packages\starlette\routing.py", line 612, in startup
    await handler()
  File "C:\Users\sarah\PycharmProjects\stella_manager\.\main.py", line 10, in starter
    await api.startup()
  File "C:\Users\sarah\PycharmProjects\stella_manager\.\core\models.py", line 41, in startup
    await asyncio.to_thread(self.startup_sync)
  File "C:\Users\sarah\AppData\Local\Programs\Python\Python310\lib\asyncio\threads.py", line 25, in to_thread
    return await loop.run_in_executor(None, func_call)
  File "C:\Users\sarah\AppData\Local\Programs\Python\Python310\lib\concurrent\futures\thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "C:\Users\sarah\PycharmProjects\stella_manager\.\core\models.py", line 30, in startup_sync
    self.bitwarden_client = client = Client(
  File "c:\users\sarah\pycharmprojects\stella_manager\venv\lib\site-packages\bitwardentools\client.py", line 719, in __init__
    self.login()
  File "c:\users\sarah\pycharmprojects\stella_manager\venv\lib\site-packages\bitwardentools\client.py", line 798, in login
    iterations = jdata["KdfIterations"]
KeyError: 'KdfIterations'

After investigating, the dictionary in jdata outputs the following

{'kdf': 0, 'kdfIterations': 5000}

So it seems like they changed the key capitalization.

confirm_invitation unnecessarily requires server private key

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!

Requests dependency missing

Hello,

After installing bitwardentools module on freshly installed RHEL 8 VM with Python 3.9, following error appears during bitwardentools python module import:

$ python3
Python 3.9.2 (default, May 20 2021, 01:29:22) 
[GCC 8.4.1 20200928 (Red Hat 8.4.1-1.0.1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from bitwardentools import Client;
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.9/site-packages/bitwardentools/__init__.py", line 1, in <module>
    from bitwardentools.client import *  # noqa
  File "/usr/local/lib/python3.9/site-packages/bitwardentools/client.py", line 22, in <module>
    import requests
ModuleNotFoundError: No module named 'requests'
>>> 

Installation of py39-requests RPM package resolves this issue, so I guess that requests module is missing in bitwardentools dependencies.

Changing the item name

Due to the use of the name as variable name in the signature of the create_item method

def create_item(
self,
name,
orga=None,
last_known_revision_date=None,
favorite=False,
collections=None,
cipher_type=CipherType.Login,
method="post",
token=None,
**jsond,
):

updating an item name by passing name in the **jsond is not possible.

Editing login with passkey invalidates date in passkey (or elsewhere in item) and makes login non-editable.

Thanks for this tool - I have used it to automate updating http:// to https:// (I will upload python script and link back to this repository), but where there is a passkey saved on the login, the resulting vault item remains useable, but not editable.

This has been tested against vaultwarden 1.30.1 (https://github.com/dani-garcia/vaultwarden/releases/tag/1.30.1) using server version 2023.12.1 browser plug in, vaultwarden web Version 2023.10.0, and Bitwarden windows client 2023.12.0 against the latest vaultwarden server version which is 2023.9.1.

I don't have a bitwarden subscription to test against, but I'm happy to set one up to test if this also occurs against bitwarden.

A visual inspection of the passkey component of the login via vscode debugging shows no obvious difference between the working and non-working versions. Partially redacted versions are included below.

The error displayed is:
An error has occurred.
Invalid time value

It is apparent that it is the passkey that has the invalid time value as the field that displays the passkey normally displays the create date of the passkey. Instead it is variously blank (vaultwarden web application) or just shows Created (browser plugin, windows app).

image

Grabbing the fido2Credentials from the login in the cipher before and after the update that makes the passkey creation date apparently invalid shows the following:

In each case, I've redacted credentialId, keyValue, userDisplayName, userHandle, and UserName, and single quotes with double quotes, and None is quoted, for better display on github.

All other items are as copied.

{
"counter": "0", 
"creationDate": "2023-12-21T23:22:09.074Z", 
"credentialId": "guid-ending-in-ef19", 
"discoverable": "true", 
"keyAlgorithm": "ECDSA", 
"keyCurve": "P-256", 
"keyType": "public-key", 
"keyValue": "MIGHA-I've-checked-it's-the-same-OZNTAd7", 
"response": "None", 
"rpId": "amazon.com", "rpName": "Amazon", 
"userDisplayName": "BJReplay", 
"userHandle": "again-its-the-same", 
"userName": "[email protected]"
}
{
"counter": "0", 
"creationDate": "2023-12-21T23:22:09.074Z", 
"credentialId": "guid-ending-in-ef19", 
"discoverable": "true", "keyAlgorithm": "ECDSA", 
"keyCurve": "P-256", 
"keyType": "public-key", 
"keyValue": "MIGHA-I've-checked-it's-the-same-OZNTAd7", 
"response": "None", 
"rpId": "amazon.com", 
"rpName": "Amazon", 
"userDisplayName": "BJReplay", 
"userHandle": "again-its-the-same", 
"userName": "[email protected]"
}

Saving a new passkey over the top works, and makes the item editable again.

image

image

vaultwarden docker logs don't report any errors while attempting to edit / save the corrupted items.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.