Skip to content

Commit

Permalink
Merge pull request #11 from facorazza/container-image
Browse files Browse the repository at this point in the history
Container image
  • Loading branch information
facorazza authored Nov 14, 2024
2 parents 4205a04 + 8d1a44a commit e99232b
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 24 deletions.
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.github
.gitignore
README.md
41 changes: 41 additions & 0 deletions .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Build container image

on:
push:
branches:
- "*"
tags:
- "*"

jobs:

build_and_push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{github.actor}}
password: ${{secrets.GITHUB_TOKEN}}
- name: Set image tag
id: image-tag
run: |
if [[ ${{ github.ref }} == refs/tags/* ]]; then
echo "IMAGE_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
elif [[ ${{ github.ref }} == refs/heads/main ]]; then
echo "IMAGE_TAG=latest" >> $GITHUB_OUTPUT
elif [[ ${{ github.ref }} == refs/heads/develop ]]; then
echo "IMAGE_TAG=develop" >> $GITHUB_OUTPUT
else
echo "IMAGE_TAG=${GITHUB_SHA::8}" >> $GITHUB_OUTPUT
fi
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ghcr.io/facorazza/passwords2bitwarden:${{ steps.image-tag.outputs.IMAGE_TAG }}
22 changes: 22 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM python:3.13-slim

# Set the working directory in the container
WORKDIR /app

# Create an output directory for the converted files
RUN mkdir -p /app/output

COPY requirements.txt /app

RUN python -m pip install --no-cache-dir --user --disable-pip-version-check --upgrade pip
RUN python -m pip install --no-cache-dir --user -r requirements.txt

# Copy the current directory contents into the container at /app
COPY . /app

# Make sure the main script is executable
RUN chmod +x main.py

# Default command for running the script, accepts zip file and output directory as arguments
ENTRYPOINT ["python", "./main.py"]
CMD ["/app/archive.zip", "/app/output"]
54 changes: 35 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,12 @@ Vault converter from Nextcloud Passwords to Bitwarden or Vaultwarden.

## Requirements

The script requires at least Python 3.10.
The script requires at least Python 3.10. Otherwise, you can run the script in a container.

If you're using an older version, you can work around it by using the code mentioned [here](https://github.com/facorazza/Passwords2Bitwarden/issues/8) even though I have not tested it.
If you're using an older version, you can work around it by using the code mentioned [here](https://github.com/facorazza/Passwords2Bitwarden/issues/8) even though I have not tested it.

## How to...

Clone the repo locally:

```
git clone https://github.com/facorazza/Passwords2Bitwarden.git
cd Passwords2Bitwarden
```

### Requirements

Install Python requirements:

```
python -m pip install -r requirements.txt
```

### Nextcloud Passwords

> :warning: Before exporting your passwords, you must change your Nextcloud language to English. Got to `Settings > Personal info > Language`. You can revert the change once downloaded the archive.
Expand All @@ -36,11 +21,42 @@ Enter your Nextcloud instance go to `Passwords > More > Backup & Restore`. Selec
3. Run Export
4. Download CSV

## Conversion
### Conversion

To convert the zip archive call the script like so:
There are two options to run the conversion: the first one is using Docker or Podman, the second one is to run the script by directly cloning the repository.

The former is more robust in terms of dependencies and you don't need to install anything if you already have a container runtime installed. However, it is yet to be tested. Please open an issue if you find problems with this method or if it worked and the instructions were clear enough.

The latter method requires you to install a few Python dependencies, but it's been tested and is fairly consistent.

#### Docker

> You can use the automatically built container image on GitHub or you can build your own using the Dockerfile contained in the repository.
```shell
docker run --name passwords2bitwarden --rm -v ./<path-to-archive>/<archive-name>.zip:/app/archive.zip -v ./passwords2bitwarden:/app/output facorazza/passwords2bitwarden
```

You'll find the exported dump under `passwords2bitwarden`.

#### Bare-Metal

Clone the repo locally:

```shell
git clone https://github.com/facorazza/Passwords2Bitwarden.git
cd Passwords2Bitwarden
```

Install Python requirements:

```shell
python -m pip install -r requirements.txt
```

To convert the zip archive call the script like so:

```shell
python main.py ~/Downloads/.../path/to/zip/archive.zip
```

Expand Down
19 changes: 15 additions & 4 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import csv
import json
import zipfile
import os

import click

from utils import parse_custom_fields

@click.command()
@click.argument("zip_filepath", type=click.Path(exists=True))
def cli(zip_filepath):
@click.argument("output_dir", type=click.Path(exists=False), default=".")
def cli(zip_filepath, output_dir):
# Extract the ZIP archive
with zipfile.ZipFile(zip_filepath, "r") as zf:
zf.extractall()

dump = {}
dump["folders"] = []
dump["items"] = []

# Process Folders.csv
with open("Folders.csv", "r", encoding="utf-8") as f:
folder_structure = {}
folders = []
Expand Down Expand Up @@ -44,6 +48,7 @@ def cli(zip_filepath):
dump["folders"].append({"id": folder["id"], "name": path})
folders.pop(index)

# Process Passwords.csv
with open("Passwords.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
Expand All @@ -68,10 +73,16 @@ def cli(zip_filepath):
"collectionIds": [],
})

with open("dump.json", "w", encoding="utf-8") as f:
f.write(json.dumps(dump))
# Ensure output directory exists
if not os.path.exists(output_dir):
os.makedirs(output_dir)

print("Done! Upload dump.json to Bitwarden or Vaultwarden.")
# Save to the output directory
output_file = os.path.join(output_dir, "dump.json")
with open(output_file, "w", encoding="utf-8") as f:
f.write(json.dumps(dump, indent=4))

print(f"Done! Upload {output_file} to Bitwarden or Vaultwarden.")


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def parse_custom_fields(fields):
case "secret":
field_type = 1 # Hidden field
case _:
field_type = 0 # Default to text field
field_type = 0 # Defaults to text field

custom_fields.append({
"name": field[0],
Expand Down

0 comments on commit e99232b

Please sign in to comment.