A modern Node.js implementation of the Secret Note application - a secure, self-destructing note sharing service.
| Aspect | Flask Version | Node.js Version |
|---|---|---|
| Framework | Flask | Express.js |
| Database | sqlite3 (Python) | sqlite3 (Node.js) |
| Templating | Jinja2 | EJS |
| Encryption | cryptography (Fernet) | TweetNaCl.js (secretbox) |
| Runtime | Python 3.8+ | Node.js 18+ |
- ✅ Encrypt messages with random keys or custom salts
- ✅ Generate shareable links for encrypted notes
- ✅ Self-destructing notes (deleted after first read)
- ✅ SQLite database for persistence
- ✅ Same UI/UX experience with Bootstrap 5
- 🚀 Faster performance (Node.js vs Python)
- 📦 Smaller deployment footprint
- 🔄 Modern async/await patterns
- 📝 Better error handling
secret-note/
├── server.js # Main Express application
├── crypto-utils.js # Encryption/decryption functions
├── db-utils.js # Database operations
├── db-setup.js # Database initialization
├── package.json # Dependencies
├── static/ # Static files (CSS, images)
│ ├── styles.css
│ └── favicon.ico
├── views/ # EJS templates
│ ├── layout.ejs
│ ├── index.ejs
│ ├── note_link.ejs
│ ├── display_note.ejs
│ └── display_error.ejs
├── secret.db # SQLite database (created on first run)
└── README.md
- Node.js 18+
- npm or yarn
-
Install dependencies:
npm install
-
Initialize the database:
npm run setup-db
-
Start the server:
npm start
The app will be available at
http://localhost:3000
For development with auto-reload:
npm run dev- express (4.18.2) - Web framework
- sqlite3 (5.1.6) - Database driver
- uuid (9.0.1) - Unique ID generation
- tweetnacl (1.0.3) - Encryption library
- tweetnacl-util (0.15.1) - TweetNaCl utilities
The Node.js version uses TweetNaCl.js for encryption with the following approach:
- Secret Box: NaCl's authenticated encryption (XSalsa20 + Poly1305)
- Key Derivation: PBKDF2 with SHA-256 (100,000 iterations)
- Random Keys: 32-byte keys generated via
crypto.randomBytes()
Encrypted messages are stored as:
- Nonce (24 bytes) + Encrypted data (variable)
- Everything is Base64-encoded for storage
Display the form to create a new secret note.
Create a new encrypted note.
Request Body:
message(required): The text to encryptsalt(optional): Custom salt for key derivation
Response: Displays a page with a shareable link
Retrieve and decrypt a note. The note is automatically deleted after viewing (self-destruct).
Response: Displays the decrypted message or an error page
@app.route('/note/<note_id>')
def note(note_id):
row = cursor.execute('SELECT message, salt FROM notes WHERE id = ?', (note_id,)).fetchone()
if row:
message = functions.decrypt_message(row[0], row[1])
delete_message(note_id)
return render_template('display_note.html', message=message)app.get('/note/:noteId', async (req, res) => {
const row = await db.getNote(req.params.noteId);
if (row) {
const message = crypto.decryptMessage(row.message, row.salt);
await db.deleteNote(req.params.noteId);
res.render('display_note', { message });
}
});Optional configuration via .env file:
PORT=3000
CREATE TABLE IF NOT EXISTS notes (
id TEXT PRIMARY KEY,
message TEXT,
salt TEXT
)- id: UUID for the note
- message: Base64-encoded encrypted message (with nonce)
- salt: Base64-encoded key (either generated or derived from user's salt)
- HTTPS Only: Always use HTTPS in production
- Salt Storage: The hardcoded salt in
crypto-utils.jsshould be environment-specific - Database: Use a proper database backend instead of SQLite for production
- Rate Limiting: Consider implementing rate limiting on POST requests
- Input Validation: Additional validation may be needed for production
- Error Handling: Generic error messages are recommended in production
PORT=3001 npm startDelete the secret.db* files and reinitialize:
rm secret.db*
npm run setup-dbnpm install
npm audit fixContributions are welcome! Please feel free to fork the repository, make changes, and submit a pull request. If you have any suggestions or issues, please post them in the issues section of the GitHub repository.
Creative Commons Attribution-ShareAlike (CC BY-SA 4.0)
- Conversion of the original Secret Note Flask version by Jordan Halliday @ProfJordan
- Node.js conversion maintains feature parity with the original application
- Buy me a Beer 🍺
This is a proof of concept application for educational purposes only. NOT SUITABLE FOR PRODUCTION.
Security considerations:
- Uses a hardcoded salt for key derivation (compromises custom salt functionality)
- No rate limiting or DDoS protection
- Not recommended for sensitive data on public networks
