diff --git a/backend/db.js b/backend/db.js index d71fd95..8c71563 100644 --- a/backend/db.js +++ b/backend/db.js @@ -73,7 +73,7 @@ async function insertUser(username, password){ const values = [username, password]; try { - const signupData = await db .query(query, values); + const signupData = await db.query(query, values); console.log('Account created:', signupData.rows[0].username); } catch (err) { console.error('Error inserting data:', err.stack); @@ -81,9 +81,21 @@ async function insertUser(username, password){ } } +async function changePassword(username, password) { + try { + await db.query( + 'UPDATE accounts SET password = $1 WHERE username = $2', + [password, username] + ); + } catch (err) { + console.error('Failed to update password') + throw err; + } +} module.exports = { db , insertUser, isUserExists, + changePassword }; diff --git a/frontend/js/settings.js b/frontend/js/settings.js index 380ec43..7b26e28 100644 --- a/frontend/js/settings.js +++ b/frontend/js/settings.js @@ -1,4 +1,5 @@ const logoutButton = document.getElementById('logout'); +const messageBox = document.getElementById('messageBox'); logoutButton.onclick = logout; function logout() { @@ -16,3 +17,27 @@ function logout() { console.error('Logout failed:', error); }); } + +function togglePopup() { + const overlay = document.getElementById('popupOverlay'); + overlay.classList.toggle('show'); +} + +// change password form +document.getElementById('changePasswordForm').addEventListener('submit', async (e) => { + e.preventDefault(); + const cPassword = document.getElementById('cPassword').value.trim(); + const nPassword = document.getElementById('nPassword').value.trim(); + + const jsonData = JSON.stringify({ cPassword, nPassword }); + const response = await fetch('/auth/changepassword', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: jsonData + }); + const result = await response.json(); + // display result message (successful or no) + messageBox.innerText = result.message; +}) \ No newline at end of file diff --git a/frontend/routes/settings.html b/frontend/routes/settings.html index fff0949..8e52b64 100644 --- a/frontend/routes/settings.html +++ b/frontend/routes/settings.html @@ -6,12 +6,33 @@ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> Settings - +

SETTINGS

- + + + +
+ + +
\ No newline at end of file diff --git a/frontend/stylesheet/settings.css b/frontend/stylesheet/settings.css new file mode 100644 index 0000000..86f92f1 --- /dev/null +++ b/frontend/stylesheet/settings.css @@ -0,0 +1,117 @@ +body { + margin: 0; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + height: 100vh; + background-color: #f0f0f0; + font-family: Arial, sans-serif; +} + +.btn-open-popup { + padding: 12px 24px; + font-size: 18px; + background-color: green; + color: #fff; + border: none; + border-radius: 8px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.btn-open-popup:hover { + background-color: #4caf50; +} + +.overlay-container { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.6); + justify-content: center; + align-items: center; + opacity: 0; + transition: opacity 0.3s ease; +} + +.popup-box { + background: #fff; + padding: 24px; + border-radius: 12px; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.4); + width: 320px; + text-align: center; + opacity: 0; + transform: scale(0.8); + animation: fadeInUp 0.5s ease-out forwards; +} + +.form-container { + display: flex; + flex-direction: column; +} + +.form-label { + margin-bottom: 10px; + font-size: 16px; + color: #444; + text-align: left; +} + +.form-input { + padding: 10px; + margin-bottom: 20px; + border: 1px solid #ccc; + border-radius: 8px; + font-size: 16px; + width: 100%; + box-sizing: border-box; +} + +.btn-submit, +.btn-close-popup { + padding: 12px 24px; + border: none; + border-radius: 8px; + cursor: pointer; + transition: background-color 0.3s ease, color 0.3s ease; +} + +.btn-submit { + background-color: green; + color: #fff; +} + +.btn-close-popup { + margin-top: 12px; + background-color: #e74c3c; + color: #fff; +} + +.btn-submit:hover, +.btn-close-popup:hover { + background-color: #4caf50; +} + +/* Keyframes for fadeInUp animation */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(2px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Animation for popup */ +.overlay-container.show { + display: flex; + opacity: 1; +} \ No newline at end of file diff --git a/index.js b/index.js index 67b9cb7..67c7fb4 100644 --- a/index.js +++ b/index.js @@ -6,7 +6,7 @@ const app = express(); const cookieParser = require('cookie-parser'); const path = require('path'); -const { insertUser, isUserExists, db } = require('./backend/db.js'); +const { insertUser, isUserExists, changePassword, db } = require('./backend/db.js'); const { initializeSocket } = require('./backend/socket.js'); const bcrypt = require('bcrypt'); @@ -14,6 +14,7 @@ const saltRounds = 10; const { createServer } = require('node:http'); const server = createServer(app); const jwt = require('jsonwebtoken'); +const {decode} = require("jsonwebtoken"); const jwtSecret = process.env.JWT_SECRET; @@ -65,12 +66,46 @@ app.get('/auth/token', (req, res) => { res.send(token); }); -app.post('/auth/changepassword', (req, res) => { +app.post('/auth/changepassword', async (req, res) => { + const token = req.cookies.token; + const { cPassword, nPassword } = req.body; + if(!cPassword && nPassword) { + return res.json({ message: 'Field is empty' }) + } + + console.log(cPassword, nPassword) + let username; + try { + const decoded = jwt.verify(token, jwtSecret); + username = username = decoded.username; + } catch (err) { + return res.status(400).json({ message: 'Unauthorized'}); + } + try { + const result = await db.query('SELECT * FROM accounts WHERE username = $1', [username]); + // checks that passwords are matching + const match = await bcrypt.compare(cPassword, result.rows[0].password); + // if not return information + if(!match){ + return res.json({ message: 'Current password is not valid', success: false }) + } + // hash password + const salt = await bcrypt.genSalt(saltRounds); + const hash = await bcrypt.hash(nPassword, salt); + await changePassword(username, hash); + + //TODO make href to login screen on front after success!!! + return res.status(200).json({ message: 'Successfully changed password', success: true }); + } catch (err) { + return res.status(500).json({ message: 'Failed to change password', success: false}); + } }); + // get username app.get('/auth/user', (req, res) => { const token = req.cookies.token; + // verify token if(token) { jwt.verify(token, jwtSecret, (err, user) => { if(err) { @@ -86,6 +121,7 @@ app.get('/auth/user', (req, res) => { // serving the login page app.get('/login', (req, res) => { const token = req.cookies.token; + // verify token if (token) { res.json({ Error: 'Already logged in' }); } else { @@ -109,7 +145,6 @@ app.get('/settings', (req, res) => { res.redirect('/login'); return; } - // verify token jwt.verify(token, jwtSecret, (err) => { if (err) { @@ -160,7 +195,7 @@ async function signupUser(req, res) { } // Hash password - const salt = await bcrypt.genSalt(saltRounds); + const salt = await bcrypt.genSalt(saltRounds); const hash = await bcrypt.hash(password, salt); // Insert user