From 18f256ff8418586ddf5863a93cf9a42c58d92901 Mon Sep 17 00:00:00 2001 From: Roger Gonzalez Date: Tue, 20 Feb 2024 10:36:05 -0300 Subject: [PATCH 1/6] Stopped using the docker-compose file --- Dockerfile | 6 +++++- bitwarden-to-keepass.py | 29 ++++++++++++----------------- entrypoint.sh | 12 ++++++++++++ 3 files changed, 29 insertions(+), 18 deletions(-) create mode 100755 entrypoint.sh diff --git a/Dockerfile b/Dockerfile index 1f01dd2..c21884b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,11 @@ RUN apt-get update && \ rm -rf bw.zip WORKDIR /bitwarden-to-keepass -COPY . . +COPY requirements.txt ./ RUN pip install --no-cache-dir --upgrade pip && \ pip install --no-cache-dir -r requirements.txt + +COPY . . + +CMD ["./entrypoint.sh"] diff --git a/bitwarden-to-keepass.py b/bitwarden-to-keepass.py index bd1bdc9..375cb5b 100644 --- a/bitwarden-to-keepass.py +++ b/bitwarden-to-keepass.py @@ -3,6 +3,7 @@ import logging import os import re import subprocess +from datetime import datetime from argparse import ArgumentParser from typing import Dict, List, Optional @@ -21,25 +22,29 @@ logging.basicConfig( datefmt='%Y-%m-%d %H:%M:%S', ) +NOW = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") +DATABASE_PATH = f"/exports/vaultwarden-{NOW}.kdbx" +BW_PATH = "/usr/local/bin/bw" + kp: Optional[PyKeePass] = None def bitwarden_to_keepass(args): global kp try: - kp = PyKeePass(args.database_path, password=args.database_password, keyfile=args.database_keyfile) + kp = PyKeePass(DATABASE_PATH, password=args.database_password, keyfile=args.database_keyfile) except FileNotFoundError: logging.info('KeePass database does not exist, creating a new one.') - kp = create_database(args.database_path, password=args.database_password, keyfile=args.database_keyfile) + kp = create_database(DATABASE_PATH, password=args.database_password, keyfile=args.database_keyfile) except CredentialsError as e: logging.error(f'Wrong password for KeePass database: {e}') return - folders = subprocess.check_output([args.bw_path, 'list', 'folders', '--session', args.bw_session], encoding='utf8') + folders = subprocess.check_output([BW_PATH, 'list', 'folders', '--session', args.bw_session], encoding='utf8') folders = json.loads(folders) groups_by_id = load_folders(folders) logging.info(f'Folders done ({len(groups_by_id)}).') - items = subprocess.check_output([args.bw_path, 'list', 'items', '--session', args.bw_session], encoding='utf8') + items = subprocess.check_output([BW_PATH, 'list', 'items', '--session', args.bw_session], encoding='utf8') items = json.loads(items) logging.info(f'Starting to process {len(items)} items.') for item in items: @@ -85,7 +90,7 @@ def bitwarden_to_keepass(args): for attachment in bw_item.get_attachments(): attachment_raw = subprocess.check_output([ - args.bw_path, 'get', 'attachment', attachment['id'], '--raw', '--itemid', bw_item.get_id(), + BW_PATH, 'get', 'attachment', attachment['id'], '--raw', '--itemid', bw_item.get_id(), '--session', args.bw_session, ]) attachment_id = kp.add_binary(attachment_raw) @@ -166,8 +171,8 @@ def check_args(args): logging.error('Key File for KeePass database is not readable.') return False - if not os.path.isfile(args.bw_path) or not os.access(args.bw_path, os.X_OK): - logging.error('bitwarden-cli was not found or not executable. Did you set correct \'--bw-path\'?') + if not os.path.isfile(BW_PATH) or not os.access(BW_PATH, os.X_OK): + logging.error('bitwarden-cli was not found or not executable. Make sure bw-cli is installed and in PATH.') return False return True @@ -186,11 +191,6 @@ parser.add_argument( help='Session generated from bitwarden-cli (bw login)', **environ_or_required('BW_SESSION'), ) -parser.add_argument( - '--database-path', - help='Path to KeePass database. If database does not exists it will be created.', - **environ_or_required('DATABASE_PATH'), -) parser.add_argument( '--database-password', help='Password for KeePass database', @@ -201,11 +201,6 @@ parser.add_argument( help='Path to Key File for KeePass database', default=os.environ.get('DATABASE_KEYFILE', None), ) -parser.add_argument( - '--bw-path', - help='Path for bw binary', - default=os.environ.get('BW_PATH', 'bw'), -) args = parser.parse_args() check_args(args) and bitwarden_to_keepass(args) diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 0000000..d5f15c7 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,12 @@ +#!/bin/sh + + +bw config server http://192.168.0.186:9998 + +export BW_SESSION="$(bw login --raw)" + +bw sync + +python3 bitwarden-to-keepass.py + +bw lock From 9ca85b6f705540bf7483244f08f8df5f4a0d4679 Mon Sep 17 00:00:00 2001 From: Roger Gonzalez Date: Tue, 20 Feb 2024 11:00:27 -0300 Subject: [PATCH 2/6] Going back to using env vars on the entrypoint --- bitwarden-to-keepass.py | 23 ++++++++++++++--------- entrypoint.sh | 16 +++++++++++----- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/bitwarden-to-keepass.py b/bitwarden-to-keepass.py index 375cb5b..61a344d 100644 --- a/bitwarden-to-keepass.py +++ b/bitwarden-to-keepass.py @@ -22,12 +22,12 @@ logging.basicConfig( datefmt='%Y-%m-%d %H:%M:%S', ) -NOW = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") -DATABASE_PATH = f"/exports/vaultwarden-{NOW}.kdbx" -BW_PATH = "/usr/local/bin/bw" - kp: Optional[PyKeePass] = None +NOW = datetime.now().strftime('%Y-%m-%d-%s') +DATABASE_PATH = f'/exports/vaultwarden-{NOW}.kdbx' + + def bitwarden_to_keepass(args): global kp try: @@ -39,12 +39,12 @@ def bitwarden_to_keepass(args): logging.error(f'Wrong password for KeePass database: {e}') return - folders = subprocess.check_output([BW_PATH, 'list', 'folders', '--session', args.bw_session], encoding='utf8') + folders = subprocess.check_output([args.bw_path, 'list', 'folders', '--session', args.bw_session], encoding='utf8') folders = json.loads(folders) groups_by_id = load_folders(folders) logging.info(f'Folders done ({len(groups_by_id)}).') - items = subprocess.check_output([BW_PATH, 'list', 'items', '--session', args.bw_session], encoding='utf8') + items = subprocess.check_output([args.bw_path, 'list', 'items', '--session', args.bw_session], encoding='utf8') items = json.loads(items) logging.info(f'Starting to process {len(items)} items.') for item in items: @@ -90,7 +90,7 @@ def bitwarden_to_keepass(args): for attachment in bw_item.get_attachments(): attachment_raw = subprocess.check_output([ - BW_PATH, 'get', 'attachment', attachment['id'], '--raw', '--itemid', bw_item.get_id(), + args.bw_path, 'get', 'attachment', attachment['id'], '--raw', '--itemid', bw_item.get_id(), '--session', args.bw_session, ]) attachment_id = kp.add_binary(attachment_raw) @@ -171,8 +171,8 @@ def check_args(args): logging.error('Key File for KeePass database is not readable.') return False - if not os.path.isfile(BW_PATH) or not os.access(BW_PATH, os.X_OK): - logging.error('bitwarden-cli was not found or not executable. Make sure bw-cli is installed and in PATH.') + if not os.path.isfile(args.bw_path) or not os.access(args.bw_path, os.X_OK): + logging.error('bitwarden-cli was not found or not executable. Did you set correct \'--bw-path\'?') return False return True @@ -201,6 +201,11 @@ parser.add_argument( help='Path to Key File for KeePass database', default=os.environ.get('DATABASE_KEYFILE', None), ) +parser.add_argument( + '--bw-path', + help='Path for bw binary', + default=os.environ.get('BW_PATH', 'bw'), +) args = parser.parse_args() check_args(args) and bitwarden_to_keepass(args) diff --git a/entrypoint.sh b/entrypoint.sh index d5f15c7..2492674 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,12 +1,18 @@ #!/bin/sh +# Login to a VaultWarden instance +echo "Connecting to Vaultwarden instance at $VAULTWARDEN_URL" +bw config server "$VAULTWARDEN_URL" +BW_SESSION="$(bw login --raw)" +export BW_SESSION -bw config server http://192.168.0.186:9998 - -export BW_SESSION="$(bw login --raw)" +# Set environment variables for the script +BW_PATH="$(which bw)" +export BW_PATH +# Convert the VaultWarden data to a KeePass file bw sync - python3 bitwarden-to-keepass.py - bw lock + +echo "KeePass file created successfully!" From 844202f960e489c690b55ee75557d70b26f4955a Mon Sep 17 00:00:00 2001 From: Roger Gonzalez Date: Tue, 20 Feb 2024 11:15:18 -0300 Subject: [PATCH 3/6] Reverted back to only using environment variables --- bitwarden-to-keepass.py | 14 +++++++------- entrypoint.sh | 5 ++++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/bitwarden-to-keepass.py b/bitwarden-to-keepass.py index 61a344d..bd1bdc9 100644 --- a/bitwarden-to-keepass.py +++ b/bitwarden-to-keepass.py @@ -3,7 +3,6 @@ import logging import os import re import subprocess -from datetime import datetime from argparse import ArgumentParser from typing import Dict, List, Optional @@ -24,17 +23,13 @@ logging.basicConfig( kp: Optional[PyKeePass] = None -NOW = datetime.now().strftime('%Y-%m-%d-%s') -DATABASE_PATH = f'/exports/vaultwarden-{NOW}.kdbx' - - def bitwarden_to_keepass(args): global kp try: - kp = PyKeePass(DATABASE_PATH, password=args.database_password, keyfile=args.database_keyfile) + kp = PyKeePass(args.database_path, password=args.database_password, keyfile=args.database_keyfile) except FileNotFoundError: logging.info('KeePass database does not exist, creating a new one.') - kp = create_database(DATABASE_PATH, password=args.database_password, keyfile=args.database_keyfile) + kp = create_database(args.database_path, password=args.database_password, keyfile=args.database_keyfile) except CredentialsError as e: logging.error(f'Wrong password for KeePass database: {e}') return @@ -191,6 +186,11 @@ parser.add_argument( help='Session generated from bitwarden-cli (bw login)', **environ_or_required('BW_SESSION'), ) +parser.add_argument( + '--database-path', + help='Path to KeePass database. If database does not exists it will be created.', + **environ_or_required('DATABASE_PATH'), +) parser.add_argument( '--database-password', help='Password for KeePass database', diff --git a/entrypoint.sh b/entrypoint.sh index 2492674..abc8f60 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -10,9 +10,12 @@ export BW_SESSION BW_PATH="$(which bw)" export BW_PATH +DATABASE_PATH="/exports/$DATABASE_NAME" +export DATABASE_PATH + # Convert the VaultWarden data to a KeePass file bw sync python3 bitwarden-to-keepass.py bw lock -echo "KeePass file created successfully!" +echo "KeePass file $DATABASE_NAME generated successfully" From 18eacf97eca66d811b1abb4eacabe219d6ec46f4 Mon Sep 17 00:00:00 2001 From: Roger Gonzalez Date: Tue, 20 Feb 2024 11:27:21 -0300 Subject: [PATCH 4/6] Made it compatible with any bitwarden instance --- entrypoint.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index abc8f60..a0dca1d 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,8 +1,11 @@ #!/bin/sh -# Login to a VaultWarden instance -echo "Connecting to Vaultwarden instance at $VAULTWARDEN_URL" -bw config server "$VAULTWARDEN_URL" +# Login to a custom Bitwarden instance +if [ "$BITWARDEN_URL" ]; then + echo "Connecting to Bitwarden instance at $BITWARDEN_URL" + bw config server "$BITWARDEN_URL" +fi + BW_SESSION="$(bw login --raw)" export BW_SESSION @@ -13,7 +16,7 @@ export BW_PATH DATABASE_PATH="/exports/$DATABASE_NAME" export DATABASE_PATH -# Convert the VaultWarden data to a KeePass file +# Convert the Bitwarden data to a KeePass file bw sync python3 bitwarden-to-keepass.py bw lock From 821567c5159515f4d907ef109ca3613f5c6a9e74 Mon Sep 17 00:00:00 2001 From: Roger Gonzalez Date: Tue, 20 Feb 2024 11:30:25 -0300 Subject: [PATCH 5/6] Removed unnecesary files --- .env | 4 ---- exports/.gitkeep | 0 2 files changed, 4 deletions(-) delete mode 100644 .env delete mode 100644 exports/.gitkeep diff --git a/.env b/.env deleted file mode 100644 index 6af09d1..0000000 --- a/.env +++ /dev/null @@ -1,4 +0,0 @@ -DATABASE_PASSWORD=CHANGE_ME -#DATABASE_KEYFILE= -BW_PATH=/usr/local/bin/bw -DATABASE_PATH=/exports/bitwarden-export.kdbx diff --git a/exports/.gitkeep b/exports/.gitkeep deleted file mode 100644 index e69de29..0000000 From c4f8684cc7e2be4510ffa1cf28d22a0e9eece33c Mon Sep 17 00:00:00 2001 From: Roger Gonzalez Date: Tue, 20 Feb 2024 11:49:26 -0300 Subject: [PATCH 6/6] Added error handling and logging --- entrypoint.sh | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index a0dca1d..7eee086 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,6 +1,12 @@ #!/bin/sh -# Login to a custom Bitwarden instance +# Check that the database password is set +if [ -z "$DATABASE_PASSWORD" ]; then + echo "DATABASE_PASSWORD is not set" + exit 1 +fi + +# If BITWARDEN_URL is not empty, set a custom Bitwarden instance if [ "$BITWARDEN_URL" ]; then echo "Connecting to Bitwarden instance at $BITWARDEN_URL" bw config server "$BITWARDEN_URL" @@ -9,16 +15,30 @@ fi BW_SESSION="$(bw login --raw)" export BW_SESSION +if [ -z "$BW_SESSION" ]; then + echo "Failed to log in to Bitwarden" + exit 1 +fi + # Set environment variables for the script BW_PATH="$(which bw)" export BW_PATH +if [ -z "$DATABASE_NAME" ]; then + DATABASE_NAME="bitwarden.kdbx" +fi + DATABASE_PATH="/exports/$DATABASE_NAME" export DATABASE_PATH + # Convert the Bitwarden data to a KeePass file -bw sync -python3 bitwarden-to-keepass.py +bw sync || { echo "Failed to sync Bitwarden data"; exit 1; } +echo "Generating KeePass file $DATABASE_PATH" +python3 bitwarden-to-keepass.py || { echo "Failed to convert to KeePass"; exit 1; } bw lock -echo "KeePass file $DATABASE_NAME generated successfully" +echo "KeePass file $DATABASE_PATH generated successfully" + +# Log out of Bitwarden +bw logout