Skip to content

Repository files navigation

🔐 WebPass

A web-based password manager with zero-knowledge architecture. All cryptography happens client-side in the browser using OpenPGP.js. The server stores only encrypted blobs — it never sees plaintext passwords or private keys.

CIIntegration TestsLicense: MITGo Version

✨ Features

  • Client-side encryption — PGP encryption/decryption in the browser with OpenPGP.js
  • Zero-knowledge architecture — Server never sees plaintext passwords or private keys
  • Multi-user support — Each user identified by their PGP key fingerprint
  • Two-factor authentication — Optional TOTP (2FA) for server access
  • Import/Export — Compatible with standard .password-store directory format (pass CLI compatible)
  • Password generator — Configurable random password generation
  • Session management — 5-minute JWT sessions with automatic expiry
  • Git sync — Backup and sync encrypted entries to any Git repository (GitHub, GitLab, Gitea)
  • TOTP codes — Store and generate TOTP codes using otpauth:// URI format (pass-otp compatible)
  • Theme toggle — Auto-switching light/dark themes based on time of day (8AM-10PM)
  • Account management — Clear local data or permanently delete account with passphrase confirmation
  • Auto-hide sensitive content — Password and notes auto-hide after 15 seconds with countdown timer
  • PGP key auto-lock — Decrypted PGP key auto-locks after 30s of inactivity
  • Rate limiting — Sliding window rate limiting on authentication endpoints (5 attempts / 15 min default)
  • Registration protection — TOTP-based registration codes to prevent unauthorized account creation

🏗️ Architecture

┌─────────────────────────────────────┐
│ Browser (SPA) │
│ + OpenPGP.js + IndexedDB │
│ + PGP encrypt/decrypt │
│ + TOTP code generation │
└────────────────────────────────────┘
│ HTTPS + CORS + JWT
┌──────────────▼──────────────────────┐
│ Go API Server (SQLite backend) │
│ + JWT Auth + bcrypt + TOTP │
│ + Rate limiting │
│ + Git sync (go-git) │
└─────────────────────────────────────┘
│ HTTPS (PAT) / SSH (key)
┌──────────────▼──────────────────────┐
│ Remote Git Repo (optional) │
│ └── *.gpg (encrypted blobs) │
└─────────────────────────────────────┘

🛠️ Tech Stack

LayerTechnology
FrontendTypeScript + Preact + Vite
CryptoOpenPGP.js + Web Crypto API (PBKDF2)
BackendGo 1.26 + SQLite (pure-Go, no CGO)
Gitgo-git (pure Go, no Git CLI needed)
Authbcrypt + JWT (5-min) + TOTP (2FA)
TestingPlaywright (81 E2E tests) + Vitest
DeployDocker (single container)

🚀 Quick Start

Prerequisites

  • Go 1.26+
  • Node.js 24+
  • npm
  • Docker (for container deployment)

Build

# Build backend
go build -o webpass-server ./cmd/srv
# Build frontend (optional, for static serving)cd frontend && npm run build

Run

# Set environment variablesexport JWT_SECRET=$(openssl rand -hex 32)export DB_PATH=./db.sqlite3
# Run server (development)
go run ./cmd/srv
# Or run the compiled binary
./webpass-server

Server listens on :8080 by default.

Deployment

Docker

# Build image
docker build -t webpass:latest .# Run container
docker run -d \
--name webpass \
-p 8080:8080 \
-v webpass-data:/data \
-e JWT_SECRET="$(openssl rand -hex 32)" \
--read-only \
--security-opt no-new-privileges:true \
webpass:latest

Docker Compose

# Configure environment
cp .env.example .env
# Edit .env and set JWT_SECRET# Start
docker compose up -d

Database Migrations & Upgrades

Migrations are applied automatically on startup via embedded SQL files in db/migrations/. They are numbered (NNN-name.sql) and tracked in a migrations table — each runs exactly once.

Forward upgrade ✅ — Fully supported. All migrations only add columns/tables, never remove or rename. Upgrading from older versions (e.g. v0.4.6) to latest is safe.

Rollback ❌ — Not supported. Because sqlc generates SELECT * queries, the old binary will fail to scan rows if new columns were added. To downgrade, restore both the binary and the database from backup.

Security Hardening

The container runs with:

  • Non-root user (UID/GID 8080)
  • Read-only filesystem (--read-only)
  • No privilege escalation (--security-opt no-new-privileges:true)
  • Writable path only /data (SQLite + git repos)

Testing

Unit Tests

# Backend tests
go test ./...
# Frontend unit testscd frontend && npm test

E2E Tests (Playwright)

81 browser-based integration tests across 5 phases:

# Run comprehensive test suite
./frontend/playwright-e2e-test.sh
# Or use npx directlycd frontend && npx playwright test# Run with interactive UI
npx playwright test --ui
# Run with visible browser
npx playwright test --headed
# View HTML report
npx playwright show-report

Test Coverage:

  • Phase 1: Rate limit tests (3 tests)
  • Phase 2: All tests in Protected mode (62 tests)
  • Phase 3: Registration tests in Open mode (6 tests)
  • Phase 4: Registration tests in Protected mode (8 tests)
  • Phase 5: Registration tests in Disabled mode (2 tests)

Git Sync Test Configuration

Git sync E2E tests require a real Git repository. Set credentials via:

# Option 1: .env file (gitignored)
WEBPASS_REPO_URL="https://gitea.example.com/user/password-store.git"
WEBPASS_REPO_PAT="your-personal-access-token"# Option 2: Environment variablesexport WEBPASS_REPO_URL="..."export WEBPASS_REPO_PAT="..."# Option 3: GitHub Secrets (CI/CD)# Add WEBPASS_REPO_URL and WEBPASS_REPO_PAT to repository secrets

📡 API Endpoints

All endpoints require JWT authentication except where noted.

Authentication & User Management

MethodPathAuthDescription
POST/apiNoCreate user (first-time setup)
GET/api/{fingerprint}JWTGet user info
POST/api/{fingerprint}/loginNoLogin → returns JWT or 2FA challenge
POST/api/{fingerprint}/login/2faNoComplete 2FA login
DELETE/api/{fingerprint}/accountJWTDelete account permanently
POST/api/{fingerprint}/passwordJWTChange password

Registration (TOTP-based)

MethodPathAuthDescription
GET/api/registration/modeNoGet registration mode (open/protected/disabled)
POST/api/registration/validateNoValidate registration TOTP code

TOTP Setup

MethodPathAuthDescription
POST/api/{fingerprint}/totp/setupJWTBegin TOTP 2FA setup
POST/api/{fingerprint}/totp/confirmJWTConfirm TOTP 2FA setup

Entries (Password Store)

MethodPathAuthDescription
GET/api/{fingerprint}/entriesJWTList all entry paths
GET/api/{fingerprint}/entries/*JWTDownload encrypted blob
PUT/api/{fingerprint}/entries/*JWTUpload encrypted blob
DELETE/api/{fingerprint}/entries/*JWTDelete entry
POST/api/{fingerprint}/entries/moveJWTRename/move entry

Import/Export

MethodPathAuthDescription
GET/api/{fingerprint}/exportJWTExport all entries as .tar.gz
POST/api/{fingerprint}/importJWTImport password store (JSON or .tar.gz)

Git Sync

MethodPathAuthDescription
GET/api/{fingerprint}/git/statusJWTGet git sync status
GET/api/{fingerprint}/git/configJWTGet git configuration
POST/api/{fingerprint}/git/configJWTConfigure git sync
POST/api/{fingerprint}/git/sessionJWTSet git token for current session
POST/api/{fingerprint}/git/pushJWTManual push to remote (force overwrite)
POST/api/{fingerprint}/git/pullJWTManual pull from remote (fresh clone)
POST/api/{fingerprint}/git/toggle-syncJWTEnable/disable git sync
GET/api/{fingerprint}/git/logJWTGet sync operation history (last 50)

System

MethodPathAuthDescription
GET/api/healthNoHealth check
GET/api/versionNoGet server version

🔒 Security Model

  • Private keys never leave the browser — Stored AES-wrapped in IndexedDB
  • Server stores only PGP-encrypted blobs — Database leak reveals nothing
  • Password validates locally first — Wrong password fails before network call
  • 5-minute sessions — JWT expiry enforced server-side
  • PGP key auto-lock — Private key automatically locked after 30s of inactivity (hardcoded in frontend/src/lib/session.ts)
  • CORS locked to specific origins via CORS_ORIGINS env var
  • All traffic over HTTPS required in production
  • Rate limiting on authentication endpoints (sliding window, 5 attempts / 15 min default)
  • Registration protection with TOTP-based codes (optional, configurable)

Reporting Vulnerabilities

Please do not open public issues for security vulnerabilities.

  1. Email: Send details to the maintainers privately
  2. GitHub: Use private vulnerability reporting

Response Timeline:

  • Acknowledgment: Within 48 hours
  • Initial Assessment: Within 1 week
  • Fix Timeline: Depends on severity (Critical: 24-72h, High: 1-2 weeks, Medium: 2-4 weeks)

⚙️ Environment Variables

See .env.example for all available options with detailed comments.

VariableRequiredDescription
JWT_SECRETYes32-byte hex string for JWT signing
DB_PATHNoPath to SQLite database (default: /data/db/db.sqlite3)
STATIC_DIRNoPath to frontend dist/ directory
CORS_ORIGINSNoComma-separated allowed origins
PORTNoHTTP listen port (default: 8080)
GIT_REPO_ROOTNoGit repos directory (default: /data/git-repos)
SESSION_HARDLIMIT_MINUTESNoJWT hard limit (max session time) in minutes (default: 30, range: 5-480)
SESSION_SOFTLIMIT_MINUTESNoJWT soft limit (browser close detection) in minutes (default: 5, range: 1-60)
DISABLE_FRONTENDNoDisable frontend (1 or true)
BCRYPT_COSTNoPassword hashing cost factor (default: 12, range: 10-15)
RATE_LIMIT_ATTEMPTSNoMax requests per window (default: 5)
RATE_LIMIT_WINDOW_MINUTESNoTime window in minutes (default: 15)

Registration Configuration

VariableDefaultDescription
REGISTRATION_ENABLEDfalseEnable registration (1 or true)
REGISTRATION_TOTP_SECRET(empty)Base32 TOTP secret (required for protected mode)
REGISTRATION_TOTP_PERIOD3600Code validity period in seconds (15-86400)
REGISTRATION_TOTP_ALGOSHA1Hash algorithm (SHA1/SHA256/SHA512)
REGISTRATION_CODE_FILE/data/registration_code.txtPath to write current code

Registration Modes:

REGISTRATION_ENABLEDREGISTRATION_TOTP_SECRETMode
false(any)Disabled — No registration allowed
true(not set)Open — No code required
true(set)Protected — 6-digit TOTP code required

🔄 Git Sync

One-way overwrite sync with fresh clone/export:

  • Pull: Remote → Local (clone remote, replace local DB)
  • Push: Local → Remote (export local DB, force-push to remote)
  • No merge conflicts — Last write wins
  • Fresh operations — Local git repo is temporary, cleaned before/after each operation
  • Per-user configuration — Each user has their own repo URL
  • Two authentication methods:
    • HTTPS — PGP-encrypted Personal Access Token
    • SSH — PGP-encrypted SSH private key with TOFU host key verification

Git Repository Structure

repo-root/
├── .git/
├── email.gpg
├── work/
│ └── database.gpg
└── social/
└── twitter.gpg
  • All files are .gpg encrypted blobs (client-side PGP encryption)
  • Files at repo root (no .password-store/ subdirectory)
  • Compatible with standard pass CLI after cloning

Branch Detection

Default branch auto-detection (branch = "HEAD"):

  1. Read remote HEAD symbolic reference
  2. If HEAD not found → try main
  3. If main not found → try master

Theme System

Auto-switching theme system with manual override:

ThemeDescription
OceanDark blue professional theme (default for night)
DaylightClean white/blue light theme (default for day)

Auto mode (default):

  • 8:00 AM - 10:00 PM → Daylight theme
  • 10:00 PM - 8:00 AM → Ocean theme

Manual override: Click theme toggle button to cycle: 🔄 Auto → 🌙 Ocean → ☀️ Daylight → Auto

Preference saved to localStorage and persists across sessions.

📁 Project Structure

.
├── .github/workflows/ # CI/CD pipelines
├── cmd/srv/ # Main binary entrypoint
── srv/ # HTTP server + handlers
├── db/ # Database migrations + sqlc queries
├── frontend/ # Preact + TypeScript SPA
│ ├── src/
│ ├── index.html
│ └── package.json
── Dockerfile
├── docker-compose.yml
└── .github/ # GitHub Actions workflows

🤝 Contributing

Contributions are welcome! Please read CONTRIBUTING.md for guidelines and AGENTS.md for the development guide.

Quick Start for Contributors

# Clone repository
git clone https://github.com/johnwmail/webpass.git
cd webpass
# Backend
go mod download
go test ./...
# Frontendcd frontend
npm install
npm run dev

Testing Requirements

  • Backend: go test ./... must pass
  • Frontend unit: npm test must pass
  • E2E tests: ./frontend/playwright-e2e-test.sh must pass (81 tests)
  • Type check: npm run typecheck must pass

Code Standards

Go:

  • Follow Effective Go
  • Use gofmt or goimports
  • Add tests for new packages

TypeScript:

  • Use TypeScript for all new code
  • Follow existing code style
  • Add types for function signatures

General:

  • Write self-documenting code
  • Keep PRs under 400 lines when possible
  • Update tests with code changes

Security Considerations

Never commit:

  • Passwords or secrets
  • API keys or tokens
  • Private encryption keys
  • Production database files

📄 License

MIT License — see LICENSE for details.

🙏 Acknowledgments

About

🔐 Zero-knowledge web password manager with client-side PGP encryption. Docker-ready, Git sync compatible with pass.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages