跳转到主要内容

bitwardentools

项目描述

与 vaultwarden/bitwarden (_rs) 和 vaultier 一起工作的工具

此包包含一个python3+客户端,用于bitwarden,它使用原生python实现,同时也包装了官方的npm @bitwarden/cli

最终目标是当然只依赖于python实现,针对 vaultwarden/bitwarden_rs 服务器实现。

  • .github/workflows/cicd.yml

功能

  • 可由api控制的客户端
  • 在组织、集合、密钥、用户(也可禁用/启用)和附件上创建、读取、更新、删除
  • 将密钥附加到组织集合
  • 在组织、集合和用户级别设置访问权限。
  • 向宝库和组织下载/上传附件
  • 客户端还集成了对官方npm CLI的薄包装(请参阅 call 方法)
  • 阅读 api 获取更多详细信息

作为Python库安装

pip install bitwardentools

在开发模式下运行

配置

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

构建

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

运行

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

运行测试

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

致谢和参考文献

文档

另请参阅 USAGE(或在下文PyPI上阅读)

变更记录

1.0.57

  • QA & CI/CD修复 [kiorky]
  • 修复较新版本的vaultwarden补丁 [kiorky]
  • 修复较新版本的vaultwarden添加用户 [kiorky]
  • 修复较新版本的vaultwarden创建组织 [kiorky]
  • 修复较新版本的vaultwarden设置组织访问 [kiorky]

1.0.56

  • 自定义身份验证负载支持(双因素、API身份验证)[Markus Kötter koetter@cispa.de]

1.0.55

  • 确保requests包含在需求中 [kiorky]

1.0.54

1.0.53

  • kdfIterations有效负载更改修复 [kiorky]
  • 添加delete_user [kiorky]

1.0.51

1.0.49

  • 完成vaultier AS_SINGLE_ORG=false acls
  • 使用全局accessAll=true用户,同时提供收藏集访问。

1.0.47

  • Vaultier迁移:添加通知脚本
  • Vaultier迁移:完成循环
  • 添加组织/收藏集成员管理方法
  • 重命名tokens属性
  • 改进错误消息
  • 优化登录和令牌管理
  • 缓存重整和因式分解
  • Vaultier AsOneOrganization导入变体
  • 阐明文档

1.0.46

  • 与bitwarden_rs 1.20的兼容性遗留问题。

1.0.45

  • 与bitwarden_rs 1.20的兼容性(以前是1.18)。

1.0.44

  • 初始发布

发布版本

./release.sh $version

用法

client = Client(server, email, password)
client.sync()
#
# direct object creation methods
# organization
client.create_organization('foo', 'foo@foo.com')
# collection
client.create_collection('bar', orga='foo')
# default item/login
payload = {
    "notes": "supernote",
    "login": {
        "totp": "aze",
        'username': "alice", "password": "rabbit",
        "uris": [{"match": None, "uri": "http://a"}]
    }
}
client.create_item("sec5", orga, collections=[col], **payload)
# if orga is None cipher will go inside user vault
client.create_item("secpersonal", **payload)
## is a synoym: client.create_login
# identity
# title": "Mr/Mrs/Ms/Dr"
payload = {
    "identity": {
        "address1": "foo", "address2": "foo", "address3": "foo", "city": "foo", "postalCode": "foo",
        "country": "foo", "state": "foo", "username": "foo", "company": "foo",
        "phone": "foo", "email": "foo",
        "title": "Mrs", "firstName": "foo", "lastName": "foo", "middleName": "foo",
        "ssn": "foo", "licenseNumber": "foo", "passportNumber": "foo",
    },
    "notes": "foo",
}
client.create_identity("sec1", orga, collections=[col], **payload)
# note
payload = {
    "fields": [{"name": "thisisabool", "type": 2, "value": False}],
    "notes": "notenote",
    "secureNote": {"type": 0},
}
client.create_securenote("sec2", orga, collections=[col], **payload)
# card
payload = {
    "card": {"brand": "sec", "cardholderName": "foo",
             "number": "aaa", "code": "123456",
             "expMonth": "10", "expYear": "2013"},
    "fields": [{"name": "aaa", "type": 0, "value": "aaa"}],
    "notes": "aaa"
}
client.create_card("sec4", orga, collections=[col], **payload)
#
# create only with json payloads
orga = client.create(**{
    'object': 'organization',
    'name': "org",
    'email': email})
# Create a collection
col = client.create(**{
    'object': 'org-collection',
    'name': "testcol",
    'organizationId': client.item_or_id(orga)})
col2 = client.create(**{
    'object': 'org-collection',
    'name': "testcol2",
    'organizationId': client.item_or_id(orga)})
# Create a login within an organization, collectionIds is mandatory on bitwarden_rs 1.19+
cipher = client.create(**{
    "name": "test",
    "object": "item",
    "organizationId": orga.id,
    "notes": "supernote",
    "login": {'username': "alice", "password": "rabbit"},
    "collectionIds": [col2.id],})
# Create a login within your personal vault
cipher = client.create(**{
    "name": "test",
    "object": "item",
    "notes": "supernote",
    "login": {'username': "alice", "password": "rabbit"})
#
# Patch existing objects
testorg = client.get_organization("org")
client.edit_organization(testorg, name='fooorg')
#
testcol = client.get_collection("testcol")
client.edit_orgcollection(testcol, name='foocol')
#
# Play with ciphers
all_ciphers = client.get_ciphers()
cipher = client.get_cipher("test", collection=col, orga=orga)
# Put cipther in collection col2
client.link(cipher, col2)
#
# Attachments
client.attach(sec, "/path/to/foo.zip")
# reload cipher with it's new attachment
# default dir in current working directory, default filename is uploaded filename
client.download(sec.attachments[0],
                directory='/w/data/titi/toto',
                filename='tata.zip')
client.delete_attachments(sec)
#
# users management
#
users = client.get_users()  # > {"emails": {}, "ids": {}, "names": {}} users indexed dicts
# search one user
user = client.get_user(email="foo@bar.com")
user = client.get_user(name="foo")
user = client.get_user(id="424242424-4242-4242-4242-424242424242")
# enable/delete/disable methods can take id/email/name or user instances as kwargs:
client.disable_user(email="foo@bar.com")
client.disable_user(id="424242424-4242-4242-4242-424242424242")
client.disable_user(name="foo")
client.disable_user(user=user)
# other methods
client.enable_user(user=/name=/id=/email=)
client.delete_user(user=/name=/id=/email=)
# if not password, it will be autogenerated and in the return tuple
user, pw = client.create_user('foo@bar.com', password=, passwordhint=, name=)
# If you use bitwarden_rs and you setted up the bitwarden rs key,
# the user will be automatically validated
# you can manually validate an account with:
user = client.validate('foo@bar.com')
# you can also manage orgs invitations
acl = client.accept_invitation('foo@bar.com', orga)  # need bitwarden server private key
acl = client.confirm_invitation('foo@bar.com', orga)  # need bitwarden server private key
# you can also manage collection permissions
## add user to orga
c.add_user_to_organization(user, orga, collections=col)
## set them at orga level (will add to orga if not already member)
c.set_organization_access(user, orga, collections=col, hidepasswords=False, readOnly=True/False)
c.set_organization_access(user, orga, {"collection": col, "hidePasswords": False}, hidepasswords=True)
## add them at collection level
c.set_collection_access(user, col, hidepasswords=True/False, readOnly=True/False)
## remove from collection: col
c.set_organization_access(user, orga, {"collection": col, "remove": True})
### or
c.set_collection_access(user, {"collection": col, "remove": True})
## get acls infos
c.get_accesses(orga)
c.get_accesses(col)
c.get_accesses({"user": user, "collection": col})
c.get_accesses({"user": user, "orga": orga})
## remove from collection
c.remove_user_from_collection(userOrEmail, colc)
## remove from orga
c.remove_user_from_organization(userOrEmail, orga)

通过回调(2Factor)操作登录数据结构

这允许其他登录机制,如totp或API密钥

示例1

def mfa2fa(loginpayload):
    totp = pyotp.TOTP(otpseed)
    loginpayload.update(
        {
            "twoFactorToken": str(totp.now()),
            "twoFactorProvider": "0",
            "twoFactorRemember": "0"
        }
    )
    return loginpayload

client = Client(server, email, password, authentication_cb=mfa2fa)

示例1

def api_key(loginpayload):
    loginpayload.update(
        {
            "client_id": CLIENT_ID,
            "client_secret": CLIENT_SECRET,
            "scope": "api",
            "grant_type": "client_credentials"
        }
    )
    return loginpayload

client = Client(server, email, password, authentication_cb=api_key)

自动验证用户的vaultwarden/bitwarden_rs密钥编码

base64 $BITWARDEN_RS_SERVER_DATA/rsa_key.der|tr -d '\n'
=> copy paste the result in your .env.local this way
BITWARDEN_PRIVATE_KEY=MIIxxx

从vaultier迁移到bitwarden笔记

VAULTIER_KEY=$(echo $(base64 ~/vaultier_key.bin|tr -d '\n')
cat >>.env << EOF
VAULTIER_KEY=${VAULTIER_KEY}
# if your vauiltier has aditionnal httpauth
# VAULTIER_HTTP_PASSWORD=htpasswd
# VAULTIER_HTTP_USER=user
VAULTIER_EMAIL=myvaultier.email@d.com
VAULTIER_URL=https://vaultier.foo.net
VAULTIER_JSON=data/export/vaultierfile.json
BW_ORGA_NAME=MyBitwardenOrga
BITWARDEN_PW=MasterPassword
BITWARDEN_SERVER=https://bitwd.foo.net
BITWARDEN_EMAIL=foo@foo.com

将vaultier数据导出为json文件,用于卡片和文件附件

  • 它将生成数据/export/vaultname.json
  • 并下载data/export/secret$id/中的附件
time python src/bitwardentools/vaultier/export.py

将vaultier序列化的json vaults/cards加载到bitwarden orga/collections

由于bitwarden只有2个文件夹,而vaultier有3个,因此卡片迁移到bitwarden,并命名为$vault $card;这是两个系统之间的链接,请不要在您想要继续迁移的同时重命名卡片,否则将重复内容。

time python src/bitwardentools/vaultier/import_structure.py

同步秘密

time python src/bitwardentools/vaultier/sync_secrets.py

将vaultier的json成员加载为bitwarden用户配置文件,并将其与其秘密关联

python src/bitwardentools/vaultier/invite.py

通知用户其账户

python src/bitwardentools/vaultier/notify.py --dry-run=0

安全注意事项

我们提供了一个bitwardentools.client.bust_cache方法来使内存中的任何缓存失效,请在完成访问您的秘密后使用它。

from bitwardentools.client import bust_cache
bust_cache()

项目详情


下载文件

下载适合您平台的应用程序。如果您不确定要选择哪个,请了解更多关于安装包的信息。

源分布

bitwardentools-1.0.57.tar.gz (53.7 kB 查看散列)

上传

构建分布

bitwardentools-1.0.57-py3-none-any.whl (55.6 kB 查看散列)

上传 Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面