Online Secure Encrypted Notes Storage

Online Secure Encrypted Notes Storage

Your notes are encrypted and stored locally in your browser.

Create Master Password

This password will encrypt all your notes. If you forget it, your notes cannot be recovered.

Click on the 'Add/Edit Note' tab to create your first one!

`; return; } // Sort notes by timestamp, newest first const sortedNotes = [...notes].sort((a, b) => b.timestamp - a.timestamp); sortedNotes.forEach(note => { const noteElement = document.createElement('div'); noteElement.className = 'p-4 border rounded-lg bg-gray-50 flex flex-col sm:flex-row justify-between items-start sm:items-center'; const decryptedTitle = decrypt(note.title, sessionPassword) || "Decryption Error"; const date = new Date(note.timestamp).toLocaleString('en-US', { dateStyle: 'medium', timeStyle: 'short' }); noteElement.innerHTML = `

${decryptedTitle}

Last updated: ${date}

`; notesList.appendChild(noteElement); }); }; // --- TAB NAVIGATION LOGIC --- const updateNavButtons = () => { prevBtn.style.visibility = currentTab === 0 ? 'hidden' : 'visible'; nextBtn.style.visibility = currentTab === TOTAL_TABS - 1 ? 'hidden' : 'visible'; }; const changeTab = (tabIndex) => { // IV. B. Guard clause if (tabIndex < 0 || tabIndex >= TOTAL_TABS) return; document.getElementById(`tabContent-${currentTab}`).classList.add('hidden'); document.getElementById(`tab-${currentTab}`).classList.remove('tab-active'); document.getElementById(`tab-${currentTab}`).classList.add('tab-inactive'); document.getElementById(`tabContent-${tabIndex}`).classList.remove('hidden'); document.getElementById(`tab-${tabIndex}`).classList.add('tab-active'); document.getElementById(`tab-${tabIndex}`).classList.remove('tab-inactive'); currentTab = tabIndex; updateNavButtons(); }; window.app.changeTab = changeTab; const navigateTabs = (direction) => { const newIndex = direction === 'next' ? currentTab + 1 : currentTab - 1; changeTab(newIndex); }; window.app.navigateTabs = navigateTabs; // --- CRUD & FORM LOGIC --- const clearForm = () => { noteForm.reset(); noteIdInput.value = ''; noteFormTitle.textContent = 'Add a New Note'; }; window.app.clearForm = clearForm; const handleFormSubmit = (e) => { e.preventDefault(); const id = noteIdInput.value; const title = noteTitleInput.value; const content = noteContentInput.value; const encryptedTitle = encrypt(title, sessionPassword); const encryptedContent = encrypt(content, sessionPassword); if (!encryptedTitle || !encryptedContent) { alert("Error: Could not encrypt note data."); return; } if (id) { // Editing existing note const noteIndex = notes.findIndex(n => n.id === id); if (noteIndex > -1) { notes[noteIndex].title = encryptedTitle; notes[noteIndex].content = encryptedContent; notes[noteIndex].timestamp = Date.now(); } } else { // Creating new note const newNote = { id: 'note_' + Date.now(), title: encryptedTitle, content: encryptedContent, timestamp: Date.now() }; notes.push(newNote); } saveNotesToStorage(); renderNotes(); clearForm(); changeTab(0); // Switch to 'My Notes' tab after saving }; const editNote = (id) => { const note = notes.find(n => n.id === id); if (note) { const decryptedTitle = decrypt(note.title, sessionPassword); const decryptedContent = decrypt(note.content, sessionPassword); if (decryptedTitle === null || decryptedContent === null) { alert("Error decrypting note for editing."); return; } noteIdInput.value = note.id; noteTitleInput.value = decryptedTitle; noteContentInput.value = decryptedContent; noteFormTitle.textContent = 'Edit Note'; changeTab(1); } }; window.app.editNote = editNote; const deleteNote = (id) => { if (confirm('Are you sure you want to permanently delete this note?')) { notes = notes.filter(n => n.id !== id); saveNotesToStorage(); renderNotes(); } }; window.app.deleteNote = deleteNote; // --- PDF DOWNLOAD FUNCTIONALITY --- const downloadNote = (id) => { const note = notes.find(n => n.id === id); if (note) { const title = decrypt(note.title, sessionPassword); const content = decrypt(note.content, sessionPassword); if (title === null || content === null) { alert("Error decrypting note for download."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); // Set document properties and styles doc.setFont("helvetica", "bold"); doc.setFontSize(22); doc.setTextColor(40); // Dark gray doc.text(title, 105, 20, null, null, 'center'); doc.setFont("helvetica", "normal"); doc.setFontSize(12); doc.setTextColor(80); // Lighter gray const date = new Date(note.timestamp).toLocaleString('en-US'); doc.text(`Saved on: ${date}`, 105, 30, null, null, 'center'); // Add content with line wrapping const splitContent = doc.splitTextToSize(content, 180); // 180mm width doc.text(splitContent, 15, 50); // Sanitize title for filename const fileName = `${title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.pdf`; doc.save(fileName); } }; window.app.downloadNote = downloadNote; // --- AUTHENTICATION & INITIALIZATION --- const initialize = () => { if (localStorage.getItem(STORAGE_KEY)) { // Vault exists, ask for password setPasswordContainer.classList.add('hidden'); loginContainer.classList.remove('hidden'); } else { // No vault, ask to set a password setPasswordContainer.classList.remove('hidden'); loginContainer.classList.add('hidden'); } }; setPasswordForm.addEventListener('submit', (e) => { e.preventDefault(); passwordError.textContent = ''; const newPass = document.getElementById('newPassword').value; const confirmPass = document.getElementById('confirmPassword').value; if (newPass.length < 8) { passwordError.textContent = 'Password must be at least 8 characters long.'; return; } if (newPass !== confirmPass) { passwordError.textContent = 'Passwords do not match.'; return; } sessionPassword = newPass; saveNotesToStorage(); // Save the initial empty vault passwordOverlay.classList.add('hidden'); mainApp.classList.remove('hidden'); renderNotes(); updateNavButtons(); }); loginForm.addEventListener('submit', (e) => { e.preventDefault(); passwordError.textContent = ''; const pass = document.getElementById('loginPassword').value; sessionPassword = pass; if (loadNotesFromStorage()) { passwordOverlay.classList.add('hidden'); mainApp.classList.remove('hidden'); renderNotes(); updateNavButtons(); } else { passwordError.textContent = 'Incorrect password. Please try again.'; sessionPassword = null; } }); logoutButton.addEventListener('click', () => { sessionPassword = null; notes = []; mainApp.classList.add('hidden'); passwordOverlay.classList.remove('hidden'); loginForm.reset(); initialize(); }); // IV. C. Event Handling: Attaching primary listeners here noteForm.addEventListener('submit', handleFormSubmit); // Initial call to set up the app state initialize(); });
Scroll to Top