A private, encrypted AI chat application running entirely on Val Town. Your conversations are encrypted client-side before being stored, and your password never leaves your device.
- π Client-side encryption - All chats encrypted with AES-256-GCM before storage
- π Password-protected - Each chat requires a password to unlock
- πΎ Self-hosted on Val Town - Your data stays in your own Val Town SQLite database
- π« No tracking - No analytics, no third parties
- π§ Local AI - Uses WebLLM to run AI models directly in your browser
- π΄ Fork-friendly - Easy to remix and run your own instance
- Create a chat with a password
- Your messages are encrypted in the browser using your password
- Encrypted data is stored in your Val Town SQLite database
- Only you can decrypt your chats with the correct password
Your password is never sent to the server. Encryption happens entirely in your browser.
- Click the "Remix" button on Val Town (or fork this repository)
- This creates your own private copy of the app
When you first run your forked val, check the console logs. You'll see a message like:
β οΈ STORAGE_API_KEY not set! Auto-generated key: a1b2c3d4-e5f6-7890-abcd-ef1234567890
β οΈ Save this key to your STORAGE_API_KEY environment variable!
Important: Save this API key! It protects your storage endpoint.
- Go to your Val Town settings
- Navigate to Environment Variables
- Add a new variable:
- Name:
STORAGE_API_KEY - Value: (paste the key from console logs)
- Name:
- Save and restart your val
In lib/api.ts, update line 3 with your storage val URL:
const STORAGE_URL = "https://your-username--your-storage-val-id.web.val.run";
You can find this URL from your forked storage val.
Visit your main val's URL and start chatting! Create your first encrypted chat with a strong password.
β SQL Injection Prevention - All database queries use parameterized statements β API Authentication - Storage endpoint requires API key β Client-side Encryption - AES-256-GCM with PBKDF2 key derivation β Password Protection - Each chat requires password to unlock
- Algorithm: AES-GCM (256-bit)
- Key Derivation: PBKDF2 with 100,000 iterations
- Random Salt & IV: Generated for each encryption
- Password: Never leaves your device
Your Val Town SQLite database stores:
- Chat ID (random UUID)
- Chat name (plain text)
- Encrypted chat data (ciphertext + salt + IV)
- Timestamps
Without your password, the encrypted data is unreadable.
| Variable | Required | Description |
|---|---|---|
STORAGE_API_KEY | Yes | Protects your storage API from unauthorized access |
FRONTEND_URL | No | Optional CORS restriction (e.g., https://yourapp.val.run) |
βββββββββββββββββββ
β Browser β
β (React App) β
β β
β β’ WebLLM AI β
β β’ Encryption β
β β’ UI β
ββββββββββ¬βββββββββ
β
β HTTPS + API Key
β
ββββββββββΌβββββββββ
β Val Town β
β Storage API β
β β
β β’ SQLite DB β
β β’ Auth Check β
βββββββββββββββββββ
βββ main.ts # Entry point, serves HTML
βββ App.tsx # Main React component
βββ api/
β βββ storage.ts # Storage API with authentication
βββ lib/
β βββ api.ts # Client-side API calls
β βββ crypto.ts # Encryption/decryption logic
βββ hooks/
β βββ useEncryption.ts # Encryption state management
β βββ useWebLLM.ts # AI model integration
βββ screens/
β βββ HomeScreen.tsx # Chat list
β βββ UnlockScreen.tsx # Password entry
β βββ NewChatScreen.tsx # Create new chat
β βββ ChatScreen.tsx # Chat interface
βββ components/
βββ MessageBubble.tsx # Message display
βββ StatusBadge.tsx # AI status indicator
βββ EmptyState.tsx # Empty state UI
Use strong, unique passwords for each chat. Since encryption happens client-side, your password is the only thing protecting your data.
There is no password recovery. If you forget your password, your chat data is permanently inaccessible. This is by design - we don't have access to your passwords.
Since this is self-hosted, you're responsible for backups. Val Town SQLite data persists, but you may want to:
- Export your encrypted data periodically
- Save your passwords securely (use a password manager)
- Consider backing up your Val Town val
Problem: API calls return 401 Unauthorized
Solution:
- Check that
STORAGE_API_KEYis set in environment variables - Make sure the key matches in both your main val and storage val
- Restart both vals after setting the variable
Problem: Can't unlock a chat
Solution:
- Double-check your password (passwords are case-sensitive)
- There is no password recovery - if you forgot it, the chat is inaccessible
Problem: No chats appear on home screen
Solution:
- Check browser console for errors
- Verify
STORAGE_URLinlib/api.tspoints to your storage val - Ensure storage val is running and accessible
Problem: WebLLM status shows error
Solution:
- WebLLM downloads models to browser (can be 1-2 GB)
- Check your internet connection
- Try refreshing the page
- Check browser console for specific errors
For stronger encryption, increase iterations in lib/crypto.ts (line 25):
iterations: 600000, // Increased from 100,000
Trade-off: Higher security, slower encryption/decryption.
To only allow requests from your frontend:
- Set
FRONTEND_URLenvironment variable - Value:
https://your-main-val.val.run - Restart storage val
This prevents other websites from calling your API (browser-level protection).
Edit hooks/useWebLLM.ts to use a different WebLLM-supported model. See WebLLM documentation for available models.
None. This app doesn't collect, track, or transmit any data beyond what's necessary for functionality:
- Your chats are encrypted and stored in your Val Town SQLite database
- Your password never leaves your browser
- No analytics, no tracking, no third parties
Only you. When you fork this val:
- You own the Val Town vals
- You control the database
- You set the API key
- You hold the encryption passwords
No one else (including the original author) can access your chats.
Found a bug or want to improve the code? Feel free to:
- Fork this val
- Make your improvements
- Share your enhanced version!
This is open source - make it your own.
While this app implements strong encryption and security practices, please note:
- β οΈ This is a personal project, not audited by security professionals
- β οΈ API keys are visible in browser DevTools (use strong, unique keys)
- β οΈ Val Town is a public platform - keep your vals private if needed
- β οΈ No rate limiting implemented (could be added if needed)
For maximum security:
- Use strong, unique passwords
- Set a strong
STORAGE_API_KEY - Keep your Val Town account secure
- Consider enabling 2FA on your Val Town account
Built with:
- Val Town - Hosting & SQLite
- React - UI framework
- WebLLM - Browser-based AI
- Web Crypto API - Encryption
- Tailwind CSS - Styling
MIT License - Feel free to fork, remix, and make it your own!
Remember: Your password is your key. Keep it safe, keep it secret, keep it strong.