Metadata-Version: 2.3
Name: kp2bw
Version: 3.4.1
Summary: Imports and existing KeePass db with REF fields into Bitwarden
Keywords: bitwarden,cli,keepass,migration,password-manager
Author: Kaj Kowalski
Author-email: Kaj Kowalski <info@kajkowalski.nl>
Classifier: Environment :: Console
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Dist: httpx>=0.28.0
Requires-Dist: pykeepass>=4.1.1.post1
Requires-Dist: rich>=13.0.0
Requires-Python: >=3.14
Project-URL: Changelog, https://github.com/kjanat/kp2bw/blob/master/CHANGELOG.md
Project-URL: Issues, https://github.com/kjanat/kp2bw/issues
Project-URL: Repository, https://github.com/kjanat/kp2bw
Description-Content-Type: text/markdown

# KP2BW - KeePass to Bitwarden Converter

<a href="https://pypi.org/project/kp2bw/">
  <img src="https://img.shields.io/pypi/v/kp2bw?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMS42OTYgMzAuMDI0Ij48ZyBzdHJva2U9IiNjY2MiIHN0cm9rZS1saW5lam9pbj0iYmV2ZWwiIHN0cm9rZS13aWR0aD0iLjM1NSI%2BPHBhdGggZmlsbD0iI2Y3ZjdmNCIgZD0ibS4xNzggNS45MTIgMTUuNTU1IDUuNjYyTDMxLjUxOSA1LjgzIDE1Ljk2My4xNjd6Ii8%2BPHBhdGggZmlsbD0iI2ZmZiIgZD0iTTE1LjczMyAxMS41NzR2MTguMjgzbDE1Ljc4Ni01Ljc0NlY1LjgzeiIvPjxwYXRoIGZpbGw9IiNlZmVlZWEiIGQ9Im0uMTc4IDUuOTEyIDE1LjU1NSA1LjY2MnYxOC4yODNMLjE3OCAyNC4xOTV6Ii8%2BPC9nPjwvc3ZnPg%3D%3D&color=3775A9" alt="PyPI">
</a>

> Fork of [jampe/kp2bw], modernized.

Migrates KeePass databases to Bitwarden via the `bw` CLI, with advantages over
the built-in Bitwarden importer:

- **Encrypted in-memory transfer** -- data never hits disk unencrypted (except
  attachments, which are cleaned up after upload)
- **KeePass REF resolution** -- username/password references are resolved:
  matching credentials merge URLs into one entry; differing ones create new
  entries
- **Passkey migration** -- KeePassXC FIDO2/passkey credentials
  (`KPEX_PASSKEY_*`) are converted to Bitwarden `fido2Credentials`
- **Custom properties & attachments** -- imported as Bitwarden custom fields or
  attachments (values > 10k chars auto-upload as files)
- **Long notes handling** -- notes exceeding 10k chars are uploaded as
  `notes.txt` attachments
- **Idempotent re-runs that sync changes** -- safe to run repeatedly; existing
  entries are updated in place when their KeePass content changed (notes,
  credentials, URIs, fields) and never duplicated. Disable with `--no-update`
- **Nested folders** -- KeePass folder hierarchy is recreated in Bitwarden
- **Recycle Bin filtering** -- deleted entries are automatically excluded
- **Expiry awareness** -- expired entries are marked `[EXPIRED]` in notes;
  optionally skip them entirely with `--skip-expired`
- **Metadata preservation** -- KeePass tags, expiry dates, and created/modified
  timestamps are stored as Bitwarden custom fields
- **Tag filtering** -- import only entries matching specific tags
- **Organization & collection support** -- upload into a Bitwarden organization
  with automatic or manual collection assignment
- **Full UTF-8 & cross-platform** -- works on Windows, macOS, and Linux

## Installation

```bash
# install with:
uv tool install kp2bw
kp2bw passwords.kdbx

# or run directly without installing:
uvx kp2bw
```

or from a GitHub URL:

```bash
# install with:
uv tool install git+https://github.com/kjanat/kp2bw
kp2bw passwords.kdbx

# run directly without installing:
uvx --from git+https://github.com/kjanat/kp2bw kp2bw passwords.kdbx
```

## Prerequisites

Install the [Bitwarden CLI] and log in once before using `kp2bw`:

```bash
# optional: point to a self-hosted instance
bw config server https://your-domain.com/

# log in (only needed once; kp2bw uses `bw unlock` afterwards)
bw login <user>
```

## Usage

```console
kp2bw [-h] [-V] [-k PASSWORD] [-K FILE] [-b PASSWORD] [-o ID]
       [-t TAG [TAG ...]] [-c ID] [--path-to-name | --no-path-to-name]
       [--path-to-name-skip N] [--skip-expired | --no-skip-expired]
       [--include-recycle-bin | --no-include-recycle-bin]
       [--metadata | --no-metadata] [--update | --no-update]
       [--include-oversize-secrets] [-y] [-v] [-d]
       FILE
```

| Flag                                   | Description                                                                                                                                                        | Env var                               |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------- |
| `keepass_file`                         | Path to your KeePass 2.x database                                                                                                                                  | -                                     |
| `-k, --keepass-password`               | KeePass password (prompted if omitted)                                                                                                                             | `KP2BW_KEEPASS_PASSWORD`              |
| `-K, --keepass-keyfile`                | KeePass key file                                                                                                                                                   | `KP2BW_KEEPASS_KEYFILE`               |
| `-b, --bitwarden-password`             | Bitwarden password (prompted if omitted)                                                                                                                           | `KP2BW_BITWARDEN_PASSWORD`            |
| `-o, --bitwarden-org`                  | Bitwarden Organization ID                                                                                                                                          | `KP2BW_BITWARDEN_ORG`                 |
| `-c, --bitwarden-collection`           | Collection ID, or `auto` to derive from top-level folder names                                                                                                     | `KP2BW_BITWARDEN_COLLECTION`          |
| `-t, --import-tags`                    | Only import entries with these tags                                                                                                                                | `KP2BW_IMPORT_TAGS` (comma-separated) |
| `--path-to-name` / `--no-path-to-name` | Prepend folder path to entry names (default: off)                                                                                                                  | `KP2BW_PATH_TO_NAME`                  |
| `--path-to-name-skip`                  | Skip first N folders in path prefix (default: 1)                                                                                                                   | `KP2BW_PATH_TO_NAME_SKIP`             |
| `--skip-expired`                       | Skip entries that have expired in KeePass                                                                                                                          | `KP2BW_SKIP_EXPIRED`                  |
| `--include-recycle-bin`                | Include Recycle Bin entries (excluded by default)                                                                                                                  | `KP2BW_INCLUDE_RECYCLE_BIN`           |
| `--metadata` / `--no-metadata`         | Toggle KeePass metadata as custom fields (default: on)                                                                                                             | `KP2BW_MIGRATE_METADATA`              |
| `--update` / `--no-update`             | Update existing entries changed in KeePass (default: on)                                                                                                           | `KP2BW_UPDATE`                        |
| `--include-oversize-secrets`           | Offload over-limit secret fields (hidden OTP secrets, passkey attributes, KeePass-protected fields) to a `.txt` attachment instead of dropping them (default: off) | `KP2BW_INCLUDE_OVERSIZE_SECRETS`      |
| `-y, --yes`                            | Skip the Bitwarden CLI setup confirmation prompt                                                                                                                   | `KP2BW_YES`                           |
| `-v, --verbose`                        | Verbose output                                                                                                                                                     | `KP2BW_VERBOSE`                       |
| `-d, --debug`                          | Debug output — includes third-party library logs                                                                                                                   | `KP2BW_DEBUG`                         |
| `-V, --version`                        | Print the installed `kp2bw` version and exit                                                                                                                       | -                                     |

Configuration precedence is always: CLI flag > environment variable > built-in default.

## Troubleshooting

### `bw` not found on `PATH`

kp2bw shells out to the [Bitwarden CLI]. If `bw` isn't installed or isn't on
your `PATH`, kp2bw stops before prompting for any passwords with:

```text
ERROR: Bitwarden CLI ('bw') not found on your PATH. ...
```

Install the CLI and make sure `bw --version` runs in the same shell, then retry.

### "Invalid master password" on `bw unlock`

If your password contains special shell characters (`?`, `>`, `&`, etc.), wrap
it in double quotes when prompted. See jampe/kp2bw#10 and
libkeepass/pykeepass#254 for details.

### `bw serve` startup timeout

kp2bw starts `bw serve` on a random localhost port. If it times out after 60s:

- Check that `bw` is installed and on your `PATH`
- Run `bw login` once if you haven't already
- Ensure no firewall rules block localhost connections
- Try `bw serve --port 8087 --hostname 127.0.0.1` manually to see if it starts

### Items skipped unexpectedly during org import

When importing with `--bitwarden-org`, items already present in the
organization vault are matched by folder + name. If you're importing into a
specific collection (`--bitwarden-collection`), only items already in *that*
collection are matched — items in other collections are created.

### Re-running to pick up KeePass changes

Re-running `kp2bw` against the same database updates matched entries in place
when their KeePass content changed (notes, password, username, URIs or custom
fields), so you no longer need to purge the vault to push edits. Unchanged
entries are left untouched. A re-run also uploads any `notes.txt` / long-field
/ file attachment that a previously imported entry was missing, and refreshes
one whose contents changed in KeePass even when it keeps the same filename (the
stale copy is removed only once the new one has uploaded). Pass `--no-update`
(or `KP2BW_UPDATE=0`) to keep the old skip-only behavior and preserve manual
Bitwarden-side edits.

### An attachment failed to upload

Attachment uploads are sent through `bw serve`, which forwards them to your
Bitwarden/Vaultwarden server. A rejected file (for example, an image too large
for your plan, or an upload that needs premium/organization storage) now
reports the server's actual message and is skipped — it no longer aborts the
whole migration, so the rest of your entries still import. Resolve the
underlying limit and re-run to upload the remaining files.

[jampe/kp2bw]: https://github.com/jampe/kp2bw
[Bitwarden CLI]: https://bitwarden.com/help/cli/
