|
|
--- |
|
|
title: Paper |
|
|
emoji: π |
|
|
colorFrom: purple |
|
|
colorTo: pink |
|
|
sdk: docker |
|
|
pinned: false |
|
|
--- |
|
|
|
|
|
# Paper β¨ |
|
|
|
|
|
A minimal, secure notepad for temporary notes. Zero tracking, zero accounts β just encrypted notes. |
|
|
|
|
|
## Features |
|
|
|
|
|
- π **Client-side encryption** β Your password never leaves your browser |
|
|
- ποΈ **Auto-delete** β Notes removed after 2 days of inactivity |
|
|
- π **Access anywhere** β Same password = same note, from any device |
|
|
- π« **No tracking** β No cookies, no analytics, no accounts |
|
|
|
|
|
## How It Works |
|
|
|
|
|
``` |
|
|
βββββββββββββββββββ βββββββββββββββββββ |
|
|
β Browser β β Server β |
|
|
βββββββββββββββββββ€ βββββββββββββββββββ€ |
|
|
β β β β |
|
|
β Password βββββββΌββΊ SHA-256 Hash (16 char) β |
|
|
β β β β β β |
|
|
β βΌ β β βΌ β |
|
|
β PBKDF2 Key β β File ID β |
|
|
β (250k rounds) β β (no password) β |
|
|
β β β β β |
|
|
β βΌ β β β |
|
|
β AES-GCM β β β |
|
|
β Encrypt/DecryptββββββββββΊβ Store/Load β |
|
|
β β β Encrypted Blob β |
|
|
βββββββββββββββββββ βββββββββββββββββββ |
|
|
``` |
|
|
|
|
|
**Key points:** |
|
|
- Password β PBKDF2 β AES-256-GCM key (client only) |
|
|
- Password β SHA-256 β File identifier (sent to server) |
|
|
- Server stores only: encrypted content + random salt |
|
|
- Server never sees: password or decrypted content |
|
|
|
|
|
## Architecture |
|
|
|
|
|
``` |
|
|
Paper/ |
|
|
βββ index.html # Single-page app (HTML + CSS + JS) |
|
|
βββ main.py # Flask backend |
|
|
βββ Dockerfile # Container setup |
|
|
βββ requirements.txt |
|
|
``` |
|
|
|
|
|
### Frontend (`index.html`) |
|
|
- Single HTML file with embedded CSS and JavaScript |
|
|
- Crypto API for AES-GCM encryption and PBKDF2 key derivation |
|
|
- Auto-save with debounce (1.5s after typing stops) |
|
|
- Dark theme with colorful accents |
|
|
|
|
|
### Backend (`main.py`) |
|
|
- Flask server with CORS support |
|
|
- Two endpoints: `/api/load` and `/api/save` |
|
|
- File-based storage (configurable via `DATA_DIR`) |
|
|
- Auto-cleanup: files older than 2 days or when storage exceeds limit |
|
|
|
|
|
## Environment Variables |
|
|
|
|
|
| Variable | Default | Description | |
|
|
|----------|---------|-------------| |
|
|
| `DATA_DIR` | `/tmp` | Storage directory | |
|
|
| `AGE_LIMIT_DAYS` | `2` | Days before auto-delete | |
|
|
| `MAX_TOTAL_SIZE_MB` | `100` | Max storage size | |
|
|
| `MAX_CONTENT_SIZE_MB` | `10` | Max note size | |
|
|
|
|
|
## Run Locally |
|
|
|
|
|
```bash |
|
|
# Install dependencies |
|
|
pip -r requirements.txt |
|
|
|
|
|
# Start server |
|
|
python main.py |
|
|
``` |
|
|
|
|
|
Open http://localhost:7860 |
|
|
|
|
|
## Deploy |
|
|
|
|
|
### Docker |
|
|
```bash |
|
|
docker build -t paper . |
|
|
docker run -p 7860:7860 paper |
|
|
``` |
|
|
|
|
|
## Security Notes |
|
|
|
|
|
- All encryption happens in your browser |
|
|
- Password is never transmitted or stored |
|
|
- Server cannot decrypt your notes |
|
|
- Use a strong, memorable password |
|
|
- No password recovery possible |
|
|
|
|
|
## License |
|
|
|
|
|
MIT |
|
|
|