7.1 KiB
7.1 KiB
SpotNotes
SpotNotes is a privacy-first, location-based note-taking web application. It allows users to drop notes on an interactive map, organize them into notepads, and share them publicly or securely with specific users using zero-knowledge end-to-end encryption.
🔒 Encryption-First Architecture (Zero-Knowledge E2EE)
SpotNotes is built with an encryption-first mindset:
- Public Notes: Stored unencrypted at rest on the server and served openly for community guides, road trips, and landmarks.
- Private Notes: 100% End-to-End Encrypted (E2EE) at rest. All private notes (including title, content, and geographic coordinates) are encrypted client-side in the user's browser using the standard Web Crypto API before transmission.
- Zero-Knowledge for Server Operators: The server operator, database administrators, and hosting infrastructure cannot read private notes, note titles, or note coordinates. The server stores only ciphertext payloads.
- Secure Asymmetric Sharing:
- Collaborators: When an owner shares a private notepad with another user, the owner's browser retrieves the recipient's RSA public key and encrypts the symmetric notepad key with it. Only the collaborator's private key can decrypt the notepad.
- Zero-Knowledge Link Sharing: When sharing a private note or notepad via link, the decryption key is placed into the URL hash fragment (
#key=...). Browsers never send the URL hash to the HTTP server, ensuring zero-knowledge link sharing. - Decrypted Client-Side CSV Export: When exporting private notepads to CSV, notes are decrypted and formatted directly in the browser.
Cryptographic Specifications
- User Keypairs: RSA-OAEP (2048-bit modulus, SHA-256).
- Password Key Derivation (KEK): PBKDF2 with SHA-256, 100,000 iterations, and a unique 16-byte random salt per user.
- Private Key Protection: The user's RSA private key is encrypted with AES-GCM-256 using the password-derived KEK before being stored on the server.
- Notepad Keys: Symmetric AES-GCM 256-bit keys, wrapped per user via RSA-OAEP.
- Note Payload Encryption: AES-GCM-256 with a unique 12-byte cryptographic nonce (IV) per note revision.
Features
- Interactive Map: View and create notes on a high-performance Leaflet & OpenStreetMap interface.
- Location-Based Notes: Every note is placed at precise coordinates.
- Public & Private Notepads: Choose between open public discovery or zero-knowledge private notes.
- E2EE Collaboration: Add collaborators with Read or Read/Write permissions with public-key key exchange.
- Zero-Knowledge Sharing Links: Share private notes/notepads securely via link tokens and URL key fragments.
- Local Decrypted Search & Geocoding: Search notes across public feeds and client-side decrypted private notebooks, or geocode addresses globally.
- Client-Side CSV Export: Download clean CSV backups of your decrypted notes.
- Mobile-Optimized Interface: Responsive bottom-sheet design with fully rounded open/close menu toggle handles.
- Admin Panel: Content moderation for public notes and IP management without exposing private ciphertext.
Tech Stack
- Backend: Python, Flask, Flask-SQLAlchemy (SQLite for development / PostgreSQL for production), Gunicorn.
- Frontend: Vanilla HTML5, Modern CSS3 with Glassmorphism, Vanilla JavaScript (ES6+), Web Crypto API, Leaflet.js.
- Security: Web Crypto API (
crypto.subtle), PBKDF2, AES-GCM, RSA-OAEP, Werkzeug password hashing.
Project Structure
spotnotes.app/
│
├── app.py # Main application entry point & DB initialization
├── config.py # Configuration settings
├── extensions.py # Flask extensions (SQLAlchemy, CORS)
├── requirements.txt # Python dependencies
├── seed_notes.py # CLI tool to seed public landmark notes from CSV
│
├── blueprints/ # Flask Blueprints (Controllers)
│ ├── admin.py # Admin dashboard routes
│ ├── api.py # REST API for notes, notepads, keys, & collaborators
│ ├── auth.py # User authentication with public key exchange
│ ├── search.py # Search (public notes) and geocoding proxy
│ └── static_routes.py # Serving static HTML pages
│
├── models/ # SQLAlchemy Database Models
│ ├── banned_ip.py # Security model for IP bans
│ ├── collaborator.py # Notepad collaboration permissions
│ ├── favorite.py # User's favorited notepads
│ ├── note.py # Note model (supports encrypted & plaintext notes)
│ ├── notepad.py # Collections of notes
│ ├── notepad_key.py # User-specific wrapped AES notepad keys
│ └── user.py # User model with RSA public key & encrypted private key
│
└── static/ # Frontend Assets
├── index.html # Main map interface
├── login.html # Login page with private key unlock
├── register.html # Registration page with keypair generation
├── admin.html # Admin moderation interface
├── about.html # About page & privacy overview
├── contact.html # Contact page
└── assets/
├── css/ # Modular stylesheets (base, map, navbar, sidebar, modals)
├── js/
│ ├── crypto.js # Client-side cryptographic engine (E2EE)
│ ├── actions.js # Notepad/note creation and modal actions
│ ├── index.js # Core app controller, note loader, and renderer
│ ├── map.js # Leaflet map configuration and marker logic
│ ├── sidebar.js # Collapsible sidebar & notepad navigation
│ ├── auth.js # Client authentication & key initialization
│ ├── search.js # Dual public + decrypted local note search
│ ├── nav.js # Navbar & session management
│ └── admin.js # Admin dashboard controller
└── images/ # Icons and branding
Getting Started
Prerequisites
- Python 3.8+
- Modern Web Browser (Chrome, Edge, Firefox, Safari) with Web Crypto API support
Installation
-
Clone the repository:
git clone <repository-url> cd spotnotes.app -
Set up a Virtual Environment:
python -m venv .venv # On Windows: .venv\Scripts\activate # On macOS/Linux: source .venv/bin/activate -
Install Dependencies:
pip install -r requirements.txt -
Seed Sample Public Notes (Optional):
python seed_notes.py notes/general_public.csv "Global Public Notes" python seed_notes.py notes/route66.csv "Route 66 Landmarks" python seed_notes.py notes/birding.csv "Birding Hotspots" -
Run the Application:
python app.pyThe application will start on
http://127.0.0.1:5000/.
License
All rights reserved.