Skip to content

hallucinaut/writerflow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WriterFlow v2.0 — Hardened Article Reader & Blog Platform

A clean, minimalist article reader and blog platform inspired by Medium. Built with FastAPI, Pydantic v2, and a zero-trust security architecture.

Architecture (Clean / Modular)

writerflow/
├── app/
│   ├── __main__.py        # Application factory + lifespan + middleware
│   ├── core/              # Config, JWT auth, CSRF, HTML rendering, IP resolution
│   │   ├── config.py      # Environment-enforced settings (_require_env)
│   │   ├── security.py    # RS256 JWT, Argon2/PBKDF2 hashing, CSRF tokens
│   │   ├── real_ip.py     # Trusted proxy IP resolution (drops private IPs)
│   │   └── html_renderer.py  # XSS-safe parametric template engine
│   ├── models/            # Domain entities (frozen dataclasses)
│   │   ├── entities.py    # Author, Category, Post
│   │   └── enums.py       # PostStatus
│   ├── schemas/           # Pydantic v2 request/response validators
│   │   ├── posts.py       # Create/Update/CreateResponse with field-level validation
│   │   ├── authors.py     # AuthorResponse
│   │   └── categories.py  # CategoryResponse
│   ├── services/          # Business logic layer (stateless)
│   │   ├── base.py        # DatabaseManager — SQLite persistence + row mapping
│   │   ├── post_service.py    # CRUD, listing, search, view tracking
│   │   ├── author_service.py  # Author lookup & listing
│   │   └── category_service.py# Category lookup & listing
│   └── routes/            # HTTP route handlers (one responsibility each)
│       ├── public_routes.py   # Home, post detail, categories, authors, search
│       ├── admin_routes.py    # Auth-gated dashboard + CRUD with CSRF guards
│       └── api_routes.py      # Public JSON API endpoints
├── tests/                 # pytest suite (48+ test cases)
│   ├── test_post_service.py     # CRUD, filtering, pagination, tags, analytics
│   ├── test_security.py         # JWT roundtrip/expiry, password hashing, CSRF, IP resolution
│   ├── test_api_integration.py  # End-to-end route testing with TestClient
│   └── test_static_assets.py    # Security headers, CSP, input sanitization
├── docs/
│   └── HALLUCINAUT_SECURITY_REPORT.md
├── main.py               # Entry point (shim for `python -m app`)
├── requirements.txt
├── .env.example
└── .gitignore

Quick Start

1. Install Dependencies

pip install -r requirements.txt --break-system-packages

2. Configure Environment

cp .env.example .env
# Edit .env — set a strong SECRET_KEY

Required: SECRET_KEY (minimum 32 bytes). The app will refuse to start without it.

3. Run

python -m app.__main__
# or
uvicorn app.__main__:app --reload

The platform is available at http://localhost:8000.

Admin Access

All admin routes (/admin, /admin/posts, etc.) require the header:

X-Admin-Token: <valid_RS256_JWT_token>

Generate a token using the security utilities:

from app.core.security import encode_token
token = encode_token({"sub": "admin", "role": "superuser"})

API Endpoints

Public Pages

Method Path Description
GET / Blog feed (paginated, filterable by ?category= or ?author=)
GET /post/{slug} Article detail with view tracking
GET /category/{slug} Category listing
GET /author/{slug} Author profile

Public API

Method Path Description
GET /api/posts List published posts (?limit=20&offset=0)
GET /api/posts/{slug} Single post by slug
GET /api/categories All categories
GET /api/authors All authors
GET /api/search Search posts (?query=...&limit=10)

Admin (Authenticated)

Method Path Description
GET /admin Dashboard with all posts
POST /admin/posts Create a new post (requires CSRF token)
POST /admin/posts/{id}/delete Delete a post (requires CSRF token)
GET /api/admin/posts Admin API — list all posts including drafts

Health

Method Path Description
GET /health { "status": "healthy", "service": "writerflow" }

Security Hardening Checklist

  • XSS Prevention — All user values HTML-escaped via html.escape() before embedding in markup or JS literals
  • JWT Authentication (RS256) — Admin routes require valid signed token with exp, iat, type claims
  • CSRF Protection — Tokens generated via secrets.token_hex(32), stored in cookies, validated with hmac.compare_digest()
  • CORS Lockdown — Origins explicitly configured via CORS_ORIGINS env var (no wildcards)
  • Security Headers — CSP, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy applied to all responses
  • Trusted IP Resolution — Loopback/private IPs stripped from X-Forwarded-For chain
  • Pydantic Validation — Field-level validation on all POST/PUT bodies (length limits, status enum, tag sanitization)
  • Parameterized Queries — All SQL uses parameterized statements (no string interpolation)
  • Insecure Defaults Blocked — App refuses to start without SECRET_KEY environment variable
  • Password Hashing — Argon2id via passlib (PBKDF2-SHA512 fallback at 600k iterations)

Testing

pip install pytest --break-system-packages
cd writerflow
python -m pytest tests/ -v

Four test modules, 48+ assertions:

  • test_post_service.py — 20 tests (CRUD, filtering, pagination, search, analytics)
  • test_security.py — 14 tests (JWT, hashing, CSRF, IP resolution)
  • test_api_integration.py — 9 tests (end-to-end routes, auth guards)
  • test_static_assets.py — 5 tests (security headers, CSP, sanitization)

License

MIT

About

WriterFlow - A clean, minimalist article reader and blog platform inspired by Medium. Built with FastAPI and Jinja2 templates.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages