bitwarden-py 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: bitwarden-py
3
+ Version: 0.1.0
4
+ Summary: A simple Python wrapper for the Bitwarden CLI — programmatically read and update passwords stored in your Bitwarden vault.
5
+ Keywords: bitwarden,bitwarden-cli
6
+ Author: SpaceShaman
7
+ Author-email: SpaceShaman <spaceshaman@tuta.io>
8
+ License-Expression: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Classifier: Programming Language :: Python :: 3.15
14
+ Requires-Python: >=3.12
15
+ Project-URL: Documentation, https://github.com/SpaceShaman/bitwarden-py
16
+ Project-URL: Homepage, https://github.com/SpaceShaman/bitwarden-py
17
+ Project-URL: Repository, https://github.com/SpaceShaman/bitwarden-py
18
+ Description-Content-Type: text/markdown
19
+
20
+ # bitwarden-py
21
+
22
+ > A simple Python wrapper for the [Bitwarden CLI](https://bitwarden.com/help/cli/) — programmatically read and update passwords stored in your Bitwarden vault.
23
+
24
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/bitwarden-py)](https://pypi.org/project/bitwarden-py)
25
+ [![PyPI - Version](https://img.shields.io/pypi/v/bitwarden-py)](https://pypi.org/project/bitwarden-py)
26
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-black)](https://github.com/psf/black)
27
+ [![Linting: Ruff](https://img.shields.io/badge/linting-Ruff-black?logo=ruff&logoColor=black)](https://github.com/astral-sh/ruff)
28
+ [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
29
+ [![GitHub License](https://img.shields.io/github/license/SpaceShaman/bitwarden-py)](https://github.com/SpaceShaman/bitwarden-py?tab=MIT-1-ov-file)
30
+
31
+ ---
32
+
33
+ ## Requirements
34
+
35
+ ### Bitwarden CLI
36
+
37
+ `bitwarden-py` calls the official `bw` binary under the hood, so you must have it installed and available in your `PATH`.
38
+
39
+ Install it by following the official guide:
40
+ 👉 [https://bitwarden.com/help/cli/#download-and-install](https://bitwarden.com/help/cli/#download-and-install)
41
+
42
+ Quick install options:
43
+
44
+ ```bash
45
+ # macOS (Homebrew)
46
+ brew install bitwarden-cli
47
+
48
+ # Windows (Chocolatey)
49
+ choco install bitwarden-cli
50
+
51
+ # npm (cross-platform)
52
+ npm install -g @bitwarden/cli
53
+ ```
54
+
55
+ After installation, verify it works:
56
+
57
+ ```bash
58
+ bw --version
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Installation
64
+
65
+ ```bash
66
+ pip install bitwarden-py
67
+ ```
68
+
69
+ Or with [uv](https://github.com/astral-sh/uv):
70
+
71
+ ```bash
72
+ uv add bitwarden-py
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Quick Start
78
+
79
+ ```python
80
+ from bitwarden_py import Bitwarden
81
+
82
+ bw = Bitwarden(
83
+ email="your@email.com",
84
+ password="your_master_password",
85
+ )
86
+
87
+ # Fetch a password by item name
88
+ db_password = bw.get_password("My Database")
89
+ print(db_password) # → "s3cr3t!"
90
+
91
+ # Update the password of an item
92
+ bw.set_password("My Database", "n3wp4ssw0rd")
93
+ ```
94
+
95
+ ### Using a self-hosted server
96
+
97
+ By default the library points to `https://vault.bitwarden.eu`.
98
+ Pass `server_url` to connect to a different instance:
99
+
100
+ ```python
101
+ bw = Bitwarden(
102
+ email="your@email.com",
103
+ password="your_master_password",
104
+ server_url="https://bitwarden.yourcompany.com",
105
+ )
106
+ ```
107
+
108
+ ---
109
+
110
+ ## API Reference
111
+
112
+ ### `Bitwarden(email, password, server_url?)`
113
+
114
+ Creates a new client and authenticates with the vault.
115
+
116
+ | Parameter | Type | Default | Description |
117
+ |--------------|-------|----------------------------------|------------------------------------|
118
+ | `email` | `str` | — | Your Bitwarden account email |
119
+ | `password` | `str` | — | Your master password |
120
+ | `server_url` | `str` | `"https://vault.bitwarden.eu"` | Bitwarden server URL |
121
+
122
+ ### `bw.get_password(item_name) → str`
123
+
124
+ Returns the password of the vault item matching `item_name`.
125
+
126
+ ### `bw.set_password(item_name, new_password) → None`
127
+
128
+ Updates the password of the vault item matching `item_name`.
129
+
130
+ ---
131
+
132
+ ## License
133
+
134
+ [MIT](LICENSE)
@@ -0,0 +1,115 @@
1
+ # bitwarden-py
2
+
3
+ > A simple Python wrapper for the [Bitwarden CLI](https://bitwarden.com/help/cli/) — programmatically read and update passwords stored in your Bitwarden vault.
4
+
5
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/bitwarden-py)](https://pypi.org/project/bitwarden-py)
6
+ [![PyPI - Version](https://img.shields.io/pypi/v/bitwarden-py)](https://pypi.org/project/bitwarden-py)
7
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-black)](https://github.com/psf/black)
8
+ [![Linting: Ruff](https://img.shields.io/badge/linting-Ruff-black?logo=ruff&logoColor=black)](https://github.com/astral-sh/ruff)
9
+ [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
10
+ [![GitHub License](https://img.shields.io/github/license/SpaceShaman/bitwarden-py)](https://github.com/SpaceShaman/bitwarden-py?tab=MIT-1-ov-file)
11
+
12
+ ---
13
+
14
+ ## Requirements
15
+
16
+ ### Bitwarden CLI
17
+
18
+ `bitwarden-py` calls the official `bw` binary under the hood, so you must have it installed and available in your `PATH`.
19
+
20
+ Install it by following the official guide:
21
+ 👉 [https://bitwarden.com/help/cli/#download-and-install](https://bitwarden.com/help/cli/#download-and-install)
22
+
23
+ Quick install options:
24
+
25
+ ```bash
26
+ # macOS (Homebrew)
27
+ brew install bitwarden-cli
28
+
29
+ # Windows (Chocolatey)
30
+ choco install bitwarden-cli
31
+
32
+ # npm (cross-platform)
33
+ npm install -g @bitwarden/cli
34
+ ```
35
+
36
+ After installation, verify it works:
37
+
38
+ ```bash
39
+ bw --version
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install bitwarden-py
48
+ ```
49
+
50
+ Or with [uv](https://github.com/astral-sh/uv):
51
+
52
+ ```bash
53
+ uv add bitwarden-py
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Quick Start
59
+
60
+ ```python
61
+ from bitwarden_py import Bitwarden
62
+
63
+ bw = Bitwarden(
64
+ email="your@email.com",
65
+ password="your_master_password",
66
+ )
67
+
68
+ # Fetch a password by item name
69
+ db_password = bw.get_password("My Database")
70
+ print(db_password) # → "s3cr3t!"
71
+
72
+ # Update the password of an item
73
+ bw.set_password("My Database", "n3wp4ssw0rd")
74
+ ```
75
+
76
+ ### Using a self-hosted server
77
+
78
+ By default the library points to `https://vault.bitwarden.eu`.
79
+ Pass `server_url` to connect to a different instance:
80
+
81
+ ```python
82
+ bw = Bitwarden(
83
+ email="your@email.com",
84
+ password="your_master_password",
85
+ server_url="https://bitwarden.yourcompany.com",
86
+ )
87
+ ```
88
+
89
+ ---
90
+
91
+ ## API Reference
92
+
93
+ ### `Bitwarden(email, password, server_url?)`
94
+
95
+ Creates a new client and authenticates with the vault.
96
+
97
+ | Parameter | Type | Default | Description |
98
+ |--------------|-------|----------------------------------|------------------------------------|
99
+ | `email` | `str` | — | Your Bitwarden account email |
100
+ | `password` | `str` | — | Your master password |
101
+ | `server_url` | `str` | `"https://vault.bitwarden.eu"` | Bitwarden server URL |
102
+
103
+ ### `bw.get_password(item_name) → str`
104
+
105
+ Returns the password of the vault item matching `item_name`.
106
+
107
+ ### `bw.set_password(item_name, new_password) → None`
108
+
109
+ Updates the password of the vault item matching `item_name`.
110
+
111
+ ---
112
+
113
+ ## License
114
+
115
+ [MIT](LICENSE)
@@ -0,0 +1,26 @@
1
+ [project]
2
+ name = "bitwarden-py"
3
+ version = "0.1.0"
4
+ description = "A simple Python wrapper for the Bitwarden CLI — programmatically read and update passwords stored in your Bitwarden vault."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ license = "MIT"
8
+ authors = [{ name = "SpaceShaman", email = "spaceshaman@tuta.io" }]
9
+ keywords = ["bitwarden", "bitwarden-cli"]
10
+ classifiers = [
11
+ "Programming Language :: Python :: 3",
12
+ "Programming Language :: Python :: 3.12",
13
+ "Programming Language :: Python :: 3.13",
14
+ "Programming Language :: Python :: 3.14",
15
+ "Programming Language :: Python :: 3.15",
16
+ ]
17
+ dependencies = []
18
+
19
+ [project.urls]
20
+ Documentation = "https://github.com/SpaceShaman/bitwarden-py"
21
+ Homepage = "https://github.com/SpaceShaman/bitwarden-py"
22
+ Repository = "https://github.com/SpaceShaman/bitwarden-py"
23
+
24
+ [build-system]
25
+ requires = ["uv_build>=0.11.14,<0.12.0"]
26
+ build-backend = "uv_build"
@@ -0,0 +1,3 @@
1
+ from .main import Bitwarden
2
+
3
+ __all__ = ["Bitwarden"]
@@ -0,0 +1,14 @@
1
+ import subprocess
2
+
3
+
4
+ def run_command(command: list[str]) -> str:
5
+ try:
6
+ return subprocess.run(
7
+ command,
8
+ capture_output=True,
9
+ text=True,
10
+ check=True,
11
+ stdin=subprocess.DEVNULL,
12
+ ).stdout.strip()
13
+ except subprocess.CalledProcessError as e:
14
+ raise RuntimeError(e.stderr.strip()) from e
@@ -0,0 +1,78 @@
1
+ import base64
2
+ import json
3
+ import os
4
+ from dataclasses import dataclass
5
+ from typing import Literal
6
+
7
+ from .command_runner import run_command
8
+
9
+
10
+ @dataclass
11
+ class Status:
12
+ status: Literal["locked", "unlocked", "unauthenticated"]
13
+ server_url: str
14
+
15
+
16
+ def get_status() -> Status:
17
+ output = run_command(["bw", "status"])
18
+ status_data = json.loads(output)
19
+ return Status(
20
+ status=status_data.get("status", "unauthenticated"),
21
+ server_url=status_data.get("serverUrl", ""),
22
+ )
23
+
24
+
25
+ def login(email: str, password: str) -> None:
26
+ run_command(
27
+ [
28
+ "bw",
29
+ "login",
30
+ email,
31
+ password,
32
+ "--raw",
33
+ ],
34
+ )
35
+
36
+
37
+ def logout() -> None:
38
+ run_command(["bw", "logout"])
39
+
40
+
41
+ def set_server_url(url: str) -> None:
42
+ run_command(["bw", "config", "server", url])
43
+
44
+
45
+ def get_session(password: str) -> str:
46
+ os.environ.setdefault("BW_PASSWORD", password)
47
+ return run_command(["bw", "unlock", "--raw", "--passwordenv", "BW_PASSWORD"])
48
+
49
+
50
+ def get_password(session: str, item_name: str) -> str:
51
+ return run_command(["bw", "get", "password", item_name, "--session", session])
52
+
53
+
54
+ def set_password(session: str, item_name: str, new_password: str) -> None:
55
+ item = json.loads(
56
+ run_command(["bw", "get", "item", item_name, "--session", session])
57
+ )
58
+
59
+ if not item.get("login"):
60
+ raise RuntimeError(f"Item '{item_name}' is not a login item")
61
+
62
+ item["login"]["password"] = new_password
63
+
64
+ encoded_item = base64.b64encode(
65
+ json.dumps(item, separators=(",", ":")).encode()
66
+ ).decode()
67
+
68
+ run_command(
69
+ [
70
+ "bw",
71
+ "edit",
72
+ "item",
73
+ item["id"],
74
+ encoded_item,
75
+ "--session",
76
+ session,
77
+ ]
78
+ )
@@ -0,0 +1,43 @@
1
+ from .commands import (
2
+ get_password,
3
+ get_session,
4
+ get_status,
5
+ login,
6
+ logout,
7
+ set_password,
8
+ set_server_url,
9
+ )
10
+
11
+
12
+ class Bitwarden:
13
+ def __init__(
14
+ self,
15
+ email: str,
16
+ password: str,
17
+ server_url: str = "https://vault.bitwarden.eu",
18
+ ):
19
+ self._email = email
20
+ self._password = password
21
+ self._server_url = server_url
22
+ self._session = None
23
+ self._setup()
24
+
25
+ def _setup(self) -> None:
26
+ status = get_status()
27
+ if status.status != "unauthenticated":
28
+ logout()
29
+ if status.server_url != self._server_url:
30
+ set_server_url(self._server_url)
31
+ status = get_status()
32
+ login(self._email, self._password)
33
+ self._session = get_session(self._password)
34
+
35
+ def get_password(self, item_name: str) -> str:
36
+ if not self._session:
37
+ raise RuntimeError("Bitwarden session is not established.")
38
+ return get_password(self._session, item_name)
39
+
40
+ def set_password(self, item_name: str, new_password: str) -> None:
41
+ if not self._session:
42
+ raise RuntimeError("Bitwarden session is not established.")
43
+ set_password(self._session, item_name, new_password)
File without changes