Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
# Backend Environment Variables
SECRET_KEY=your_super_secret_django_key
# Copy to .env and adjust. Every value is optional in development.

# Django
SECRET_KEY=change-me-to-a-long-random-string
DEBUG=True
DATABASE_URL=postgres://username:password@localhost:5432/vaultify_db
ALLOWED_HOSTS=localhost,127.0.0.1
# CSRF_TRUSTED_ORIGINS=https://vault.example.com

# Database (defaults to SQLite at backend/db.sqlite3 when unset)
# DATABASE_URL=postgres://username:password@localhost:5432/vaultify_db

# Encryption key(s) for vault secrets. Generate one with:
# python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# Comma-separate several keys to rotate: the first encrypts, all can decrypt.
# VAULT_ENCRYPTION_KEY=

# Frontend Environment Variables (if using Vite)
VITE_API_BASE_URL=http://localhost:8000/api
# Security
VAULT_SESSION_TIMEOUT=1800
LOGIN_MAX_ATTEMPTS=5
LOGIN_LOCKOUT_SECONDS=300
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: CI

on:
push:
pull_request:

jobs:
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: backend/requirements.txt
- run: pip install -r requirements.txt
- run: python manage.py check
- run: python manage.py makemigrations --check --dry-run
- run: python manage.py test vault
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,11 @@ db.sqlite3
media/
staticfiles/

.venv/
venv/
env/
.coverage
htmlcov/
.DS_Store
.idea/
.vscode/
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Thank you for considering contributing to Vaultify! We welcome contributions fro
## Code Style

- Follow PEP8 for Python
- Use ES6+ syntax for JavaScript/React
- Use modern (ES2020+) vanilla JavaScript — no build step
- Run `python manage.py test vault` before opening a PR
- Keep functions modular and well-commented
- Ensure your code is linted and tested

Expand Down
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
WORKDIR /app

COPY backend/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt "psycopg[binary]>=3.1"

COPY backend/ .
RUN DEBUG=False SECRET_KEY=build-only python manage.py collectstatic --noinput

EXPOSE 8000
CMD ["sh", "-c", "python manage.py migrate --noinput && gunicorn vaultify.wsgi:application --bind 0.0.0.0:8000 --workers 3"]
146 changes: 120 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,139 @@
# Vaultify 🔐

Vaultify is a secure, RESTful web app built using Django + DRF for storing encrypted personal data or secrets. PostgreSQL backs the data, and the encryption layer ensures high-grade protection of your information.
**An encrypted personal vault built with Django.** Store passwords, payment cards, API keys, Wi-Fi credentials and private notes, all encrypted at rest. It also includes a password generator, a security health audit, a full activity log and a REST API.

## Features
- 🔐 Encrypted Vault Storage
- 🧪 Unit Tested Models
- 📦 Django REST Framework API
- 🧠 Clean architecture with MVC pattern
- 🐘 PostgreSQL DB
- 🧪 Easy-to-use dev environment
- 🧰 Extensible and scalable folder structure
![Dashboard](docs/screenshots/dashboard.png)

## 🚀 Tech Stack
## ✨ Features

Backend | Database | Auth | Misc |
--------|----------|------|------|
Django | PostgreSQL | JWT | REST, CORS |
| | |
|---|---|
| 🔒 **Encryption at rest** | Secrets and notes are encrypted with Fernet (AES-128-CBC + HMAC-SHA256). Several keys can be configured, so you can rotate keys without downtime. |
| 🩺 **Security health** | A 0–100 score that flags weak, reused and stale passwords. Reuse is detected with keyed HMAC fingerprints, so the audit never decrypts your vault. |
| 🪄 **Password generator** | Uses Python's `secrets` module to make passwords or passphrases, with live entropy scoring. |
| 🧾 **Activity log** | Records every sign-in, failed sign-in, reveal, copy, edit, delete and export, with the IP address and time. |
| 🛡️ **Hardened by default** | Brute-force lockout, sessions that auto-lock when idle, CSRF protection, strict cookies and data scoped to its owner. Secrets never appear in page HTML: they are fetched on demand and hidden again after 20 seconds. |
| 🗂️ **Organisation** | Categories, tags, favourites, instant search and keyboard shortcuts (`/` search, `n` new item). |
| 🌗 **Polished UI** | Responsive dark and light themes, built with no frontend build step. |
| 🔌 **REST API** | Django REST Framework with JWT auth, pagination, throttling and filtering. |
| 📦 **Export** | Download a decrypted JSON backup after confirming your password. |

<table>
<tr>
<td><img src="docs/screenshots/item.png" alt="Item detail"></td>
<td><img src="docs/screenshots/generator.png" alt="Password generator"></td>
</tr>
<tr>
<td><img src="docs/screenshots/health.png" alt="Security health"></td>
<td><img src="docs/screenshots/landing.png" alt="Landing page"></td>
</tr>
</table>

## 🛠️ Setup Instructions
## 🚀 Quick start

Requires Python 3.11 or newer.

```bash
cd backend
python -m venv env
source env/bin/activate
git clone https://github.com/QuantumCoderrr/Vaultify.git
cd Vaultify/backend
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
python manage.py migrate
python manage.py seed_demo # optional: demo / vaultify-demo-2024
python manage.py runserver
```

📂 Environment Variables
Copy .env.example to .env and set appropriate keys.
Open http://127.0.0.1:8000. You can create an account, or sign in with the demo user that `seed_demo` creates.

Create an admin user with `python manage.py createsuperuser`. The admin site is at `/admin/` and shows item metadata only, never decrypted secrets.

### Docker

```bash
docker build -t vaultify .
docker run -p 8000:8000 -e SECRET_KEY=change-me -e DEBUG=False -e ALLOWED_HOSTS=localhost -e SECURE_SSL_REDIRECT=False vaultify
```
SECRET_KEY=your_secret_key
DATABASE_URL=your_postgres_url
DEBUG=True

## ⚙️ Configuration

Settings are read from environment variables or a `.env` file. See [`.env.example`](.env.example) for the full list.

| Variable | Default | Purpose |
|---|---|---|
| `SECRET_KEY` | dev key (only when `DEBUG=True`) | Django secret key. **Required in production.** |
| `DEBUG` | `True` | Turn off in production to enable HTTPS-only cookies, HSTS and the SSL redirect. |
| `DATABASE_URL` | SQLite | e.g. `postgres://user:pass@host:5432/vaultify` (install `psycopg[binary]`). |
| `VAULT_ENCRYPTION_KEY` | derived from `SECRET_KEY` | Comma-separated Fernet keys. The first one encrypts; all of them can decrypt. |
| `VAULT_SESSION_TIMEOUT` | `1800` | Seconds of inactivity before the vault auto-locks. |
| `LOGIN_MAX_ATTEMPTS` / `LOGIN_LOCKOUT_SECONDS` | `5` / `300` | Brute-force protection. |

Generate an encryption key:

```bash
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
```

## 🤝 Contributing
We welcome PRs and suggestions! Check out [CONTRIBUTING.md](CONTRIBUTING.md) to get started.
> ⚠️ Set `VAULT_ENCRYPTION_KEY` explicitly in production and back it up. If you lose it, you lose the data. If you leave it unset, changing `SECRET_KEY` makes existing secrets unreadable.

## 🔌 REST API

Base URL: `/api/v1/`. Authenticate with a JWT (`Authorization: Bearer <token>`) or a session cookie.

| Method | Endpoint | Description |
|---|---|---|
| `POST` | `auth/register/` | Create an account |
| `POST` | `auth/token/` · `auth/token/refresh/` | Get or refresh a JWT pair |
| `GET` `POST` | `items/` | List (`?q=`, `?category=`, `?favorite=true`) or create items |
| `GET` `PUT` `PATCH` `DELETE` | `items/{id}/` | Manage one item (the secret is write-only) |
| `GET` | `items/{id}/reveal/` | Decrypt the secret and notes (the reveal is logged) |
| `GET` | `items/health/` | Security health report |
| `GET` | `activity/` | Your activity log |
| `POST` | `tools/generate/` · `tools/strength/` | Generate a password, or score one |

```bash
TOKEN=$(curl -s -X POST localhost:8000/api/v1/auth/token/ \
-d username=demo -d password=vaultify-demo-2024 | python -c "import sys,json;print(json.load(sys.stdin)['access'])")
curl -H "Authorization: Bearer $TOKEN" localhost:8000/api/v1/items/
```

## 🧱 Architecture

```
backend/
├── vaultify/ # project settings & root URLs
└── vault/
├── models.py # VaultItem (encrypted fields) & ActivityLog
├── crypto.py # Fernet / MultiFernet helpers, key rotation
├── passwords.py # generator + entropy-based strength estimator
├── security.py # weak / reused / stale analysis
├── views.py, forms.py # server-rendered web UI
├── api.py, serializers.py, api_urls.py # REST API
├── signals.py # login / logout / failed-login auditing
├── templates/ static/ # UI (vanilla CSS + JS, no build step)
├── management/commands/seed_demo.py
└── tests/ # crypto, models, API and view tests
```

**Security model.** Encryption happens on the server, so the database alone never holds plaintext secrets. Whoever controls both the server and its encryption key can decrypt them. This is the same trust model as most self-hosted apps. Vaultify is not a zero-knowledge (client-side encryption) design.

## 🧪 Tests

```bash
cd backend
python manage.py test vault
```

CI runs the test suite on Python 3.11–3.13 for every push (see `.github/workflows/ci.yml`).

## 🤝 Contributing

PRs and suggestions are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) to get started.

## 💬 Code of Conduct

Kindness comes first. Please read our [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) before you start.

## 📄 License

## 💬 Code of Conduct
Kindness comes first. Read our [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) before diving in.
[MIT](LICENSE)
15 changes: 10 additions & 5 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
Django>=4.2
djangorestframework
psycopg2-binary
cryptography

Django>=5.2,<6.0
djangorestframework>=3.15
djangorestframework-simplejwt>=5.3
cryptography>=42.0
python-dotenv>=1.0
dj-database-url>=2.1
whitenoise>=6.6
gunicorn>=22.0
# Optional: install to use PostgreSQL via DATABASE_URL
# psycopg[binary]>=3.1
25 changes: 23 additions & 2 deletions backend/vault/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
from django.contrib import admin
from .models import VaultItem

admin.site.register(VaultItem)
from .models import ActivityLog, VaultItem


@admin.register(VaultItem)
class VaultItemAdmin(admin.ModelAdmin):
"""Admins can manage metadata but never see decrypted secrets."""

list_display = ("title", "user", "category", "favorite", "strength_score", "updated_at")
list_filter = ("category", "favorite")
search_fields = ("title", "username", "url", "user__username")
exclude = ("encrypted_secret", "encrypted_notes")
readonly_fields = ("secret_fingerprint", "strength_score", "created_at", "updated_at",
"secret_changed_at", "last_accessed_at")


@admin.register(ActivityLog)
class ActivityLogAdmin(admin.ModelAdmin):
list_display = ("created_at", "user", "action", "item_title", "ip_address")
list_filter = ("action",)
search_fields = ("user__username", "item_title", "ip_address")
readonly_fields = [f.name for f in ActivityLog._meta.fields]

def has_add_permission(self, request):
return False
Loading
Loading