aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2022-06-24 21:53:20 +0530
committerBobby <[email protected]>2022-06-24 21:53:20 +0530
commit555d44220b016978cd9cbddf8d1ac6bb84a1f142 (patch)
treee434151c4dea941f91652531d39262bdf6a82341
parent00e99b844c260e0263e5d5403d284ba07450005e (diff)
downloadthatcomputerscientist-555d44220b016978cd9cbddf8d1ac6bb84a1f142.tar.xz
thatcomputerscientist-555d44220b016978cd9cbddf8d1ac6bb84a1f142.zip
basic email validation on account page
-rw-r--r--functions/validate.js26
-rw-r--r--package-lock.json14
-rw-r--r--package.json1
-rw-r--r--routes/account.routes.js219
-rw-r--r--views/account.ejs19
-rw-r--r--views/error.ejs38
6 files changed, 247 insertions, 70 deletions
diff --git a/functions/validate.js b/functions/validate.js
index ecf90564..3e9ff111 100644
--- a/functions/validate.js
+++ b/functions/validate.js
@@ -15,6 +15,32 @@ function validateAuthorization(auth) {
}
}
+var emailRegex = /^[-!#$%&'*+\/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;
+
+function isEmailValid(email) {
+ if (!email)
+ return false;
+
+ if(email.length>254)
+ return false;
+
+ var valid = emailRegex.test(email);
+ if(!valid)
+ return false;
+
+ // Further checking of some things regex can't handle
+ var parts = email.split("@");
+ if(parts[0].length>64)
+ return false;
+
+ var domainParts = parts[1].split(".");
+ if(domainParts.some(function(part) { return part.length>63; }))
+ return false;
+
+ return true;
+}
+
module.exports = {
validateAuthorization,
+ isEmailValid
};
diff --git a/package-lock.json b/package-lock.json
index 17e83ffa..41bf5f09 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,7 @@
"mysql2": "^2.3.3",
"node-cron": "^3.0.1",
"node-fetch": "^3.2.5",
+ "nodemailer": "^6.7.5",
"uuid": "^8.3.2"
},
"devDependencies": {
@@ -1588,6 +1589,14 @@
"url": "https://opencollective.com/node-fetch"
}
},
+ "node_modules/nodemailer": {
+ "version": "6.7.5",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.5.tgz",
+ "integrity": "sha512-6VtMpwhsrixq1HDYSBBHvW0GwiWawE75dS3oal48VqRhUvKJNnKnJo2RI/bCVQubj1vgrgscMNW4DHaD6xtMCg==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/nodemon": {
"version": "2.0.16",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz",
@@ -3597,6 +3606,11 @@
"formdata-polyfill": "^4.0.10"
}
},
+ "nodemailer": {
+ "version": "6.7.5",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.5.tgz",
+ "integrity": "sha512-6VtMpwhsrixq1HDYSBBHvW0GwiWawE75dS3oal48VqRhUvKJNnKnJo2RI/bCVQubj1vgrgscMNW4DHaD6xtMCg=="
+ },
"nodemon": {
"version": "2.0.16",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz",
diff --git a/package.json b/package.json
index d20de2f3..73edc846 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
"mysql2": "^2.3.3",
"node-cron": "^3.0.1",
"node-fetch": "^3.2.5",
+ "nodemailer": "^6.7.5",
"uuid": "^8.3.2"
},
"devDependencies": {
diff --git a/routes/account.routes.js b/routes/account.routes.js
index f2f72e29..d7cbdfc5 100644
--- a/routes/account.routes.js
+++ b/routes/account.routes.js
@@ -4,70 +4,183 @@ const mysql = require("mysql2");
const jwt = require("jsonwebtoken");
const connectionString = process.env.DATABASE_URL;
const md5 = require("md5");
+const { isEmailValid } = require("../functions/validate");
-router.get('/', (req, res) => {
- const username = jwt.decode(req.cookies.token).username;
- const connection = mysql.createConnection(connectionString);
- connection.connect();
- const sql = "SELECT * FROM Profiles WHERE username = ?";
- connection.query(sql, [username], (err, results, fields) => {
- if (err) {
- res.status(500).render('error', {
- error: err,
- });
+router.get("/", (req, res) => {
+ const username = jwt.decode(req.cookies.token).username;
+ const connection = mysql.createConnection(connectionString);
+ connection.connect();
+ const sql = "SELECT * FROM Profiles WHERE username = ?";
+ connection.query(sql, [username], (err, results, fields) => {
+ if (err) {
+ res.status(500).render("error", {
+ error: err,
+ });
+ } else {
+ if (results.length > 0) {
+ const user = results[0];
+ renderRoute(req, res, "account", "My Account", true, {
+ user: {
+ ...user,
+ avatar: md5(user.gravatarEmail || user.email || ""),
+ url:
+ user.public == 1
+ ? `${req.protocol + "://" + req.get("host")}/profile/${
+ user.username
+ }`
+ : "",
+ },
+ });
+ } else {
+ renderRoute(req, res, "account", "My Account", true, {
+ user: null,
+ });
+ }
+ }
+ });
+ connection.end();
+});
+
+router.post("/sendVerificationEmail", (req, res) => {
+ jwt.verify(
+ req.cookies.token,
+ process.env.AUTHORIZATION_STRING,
+ (err, decoded) => {
+ if (err) {
+ renderRoute(req, res, "error", "Error", false, {
+ error: err,
+ });
+ } else {
+ const username = decoded.username;
+ const newEmail = req.body.email;
+ if (!newEmail || !isEmailValid(newEmail)) {
+ req.flash("mailsenderror", "Error sending verification email. Provided email is invalid.",);
+ res.redirect(req.get("referer"));
} else {
- if (results.length > 0) {
- const user = results[0];
- renderRoute(req, res, 'account', 'My Account', true, {
- user: {
- ...user,
- avatar: md5(user.email || '')
- }
- });
+ const connection = mysql.createConnection(connectionString);
+ connection.connect();
+ const sql = "SELECT * FROM Profiles WHERE username = ?";
+ connection.query(sql, [username], (err, results, fields) => {
+ if (err) {
+ renderRoute(req, res, "error", "Error", false, {
+ error: err.message,
+ });
} else {
- renderRoute(req, res, 'account', 'My Account', true, {
- user: null
+ if (results.length > 0) {
+ const user = results[0];
+ // const transporter = require("nodemailer").createTransport({
+ // service: "gmail",
+ // auth: {
+ // user: process.env.EMAIL_USER,
+ // pass: process.env.EMAIL_PASSWORD,
+ // },
+ // });
+ // // Generate a verification URL and send it to the user
+ const verificationUrl = `${req.get(
+ "origin"
+ )}/verifyemail?token=${jwt.sign(
+ {
+ username: user.username,
+ email: newEmail,
+ },
+ process.env.AUTHORIZATION_STRING,
+ {
+ expiresIn: "1h",
+ }
+ )}`;
+ // const mailOptions = {
+ // from: process.env.EMAIL_USER,
+ // to: newEmail,
+ // priority: "high",
+ // subject:
+ // "[That Computer Scientist] Request to change your email address",
+ // html: `<p>Hi ${user.firstname || user.username},</p>
+ // <p>We received a request to change your email address to <em><u>${newEmail}</u></em>.</p>
+ // <p>If you made this request, please click the link below to verify your new email address:</p>
+ // <p><a href="${verificationUrl}">${verificationUrl}</a></p>
+ // <p>If you did not make this request, you can ignore this email.</p>
+ // <p>Thanks,</p>
+ // <p>Kumar Priyansh</p>
+ // <p>That Computer Scientist</p>`,
+ // };
+ // transporter.sendMail(mailOptions, (err, info) => {
+ // if (err) {
+ // req.flash("mailsenderror", "Error sending verification email. Please try again later.",);
+ // req.redirect(req.get("referer"));
+ // } else {
+ req.flash(
+ "mailsendsuccess",
+ `Verification email sent! The link expires in 1 hour. Please check your email. Also, make sure to check your spam folder. Verification URL: ${verificationUrl}`
+ );
+ res.redirect(req.get("referer"));
+ // }
+ // });
+ } else {
+ res.status(500).render("error", {
+ error: "User not found",
});
+ }
}
+ });
+ connection.end();
}
- });
- connection.end();
+ }
+ }
+ );
});
-router.post('/updateAccount', (req, res) => {
- jwt.verify(req.cookies.token, process.env.AUTHORIZATION_STRING, (err, decoded) => {
- if (err) {
- renderRoute(req, res, 'error', 'Error', false)
- } else {
- const username = decoded.username;
- const firstname = req.body.firstname;
- const lastname = req.body.lastname;
- const location = req.body.location;
- const bio = req.body.bio;
- const public = req.body.isPublic;
- const emailPublic = req.body.emailPublic;
- const connection = mysql.createPool(connectionString);
- connection.getConnection((err, connection) => {
+router.post("/updateAccount", (req, res) => {
+ jwt.verify(
+ req.cookies.token,
+ process.env.AUTHORIZATION_STRING,
+ (err, decoded) => {
+ if (err) {
+ renderRoute(req, res, "error", "Error", false);
+ } else {
+ const username = decoded.username;
+ const firstname = req.body.firstname;
+ const lastname = req.body.lastname;
+ const location = req.body.location;
+ const bio = req.body.bio;
+ const gravatarEmail = req.body.gravatarEmail;
+ const public = req.body.isPublic;
+ const emailPublic = req.body.emailPublic || 0;
+ const connection = mysql.createPool(connectionString);
+ connection.getConnection((err, connection) => {
+ if (err) {
+ renderRoute(req, res, "error", "Error", false, {
+ error: err.message,
+ });
+ } else {
+ const sql =
+ "UPDATE Profiles SET firstname = ?, lastname = ?, location = ?, bio = ?, gravatarEmail = ?, public = ?, emailPublic = ? WHERE username = ?";
+ connection.query(
+ sql,
+ [
+ firstname,
+ lastname,
+ location,
+ bio,
+ gravatarEmail,
+ public,
+ emailPublic,
+ username,
+ ],
+ (err, results, fields) => {
if (err) {
- renderRoute(req, res, 'error', 'Error', false, {
- error: err.message
- });
+ req.flash("updateaccerror", err.message);
+ res.redirect(req.get("referer"));
} else {
- const sql = "UPDATE Profiles SET firstname = ?, lastname = ?, location = ?, bio = ?, public = ?, emailPublic = ? WHERE username = ?";
- connection.query(sql, [firstname, lastname, location, bio, public, emailPublic, username], (err, results, fields) => {
- if (err) {
- req.flash('updateaccerror', err.message);
- res.redirect(req.get('referer'));
- } else {
- req.flash('updateaccsuccess', 'Account updated successfully');
- res.redirect(req.get('referer'));
- }
- });
+ req.flash("updateaccsuccess", "Account updated successfully");
+ res.redirect(req.get("referer"));
}
- });
- }
- });
+ }
+ );
+ }
+ });
+ }
+ }
+ );
});
-
module.exports = router;
diff --git a/views/account.ejs b/views/account.ejs
index 6649eac4..06e4ca9e 100644
--- a/views/account.ejs
+++ b/views/account.ejs
@@ -10,9 +10,9 @@
<li>Do not send multiple support requests.</li>
<li>Please note that this is a support request related to your account. Please do not file any bugs here. If you have noticed a bug, please report it to the <a href="https://github.com/luciferreeves/thatcomputerscientist/issues">GitHub Issues</a> page.</li>
</ul>
- <p>Your avatar is fetched from gravatar. Update your gravatar email to fetch the avatar. If you don't have an account, you can sign up for one <a href="https://en.gravatar.com/" target="_blank">here</a>.</p>
- <% if (user.public == 1) { %>
- <p>Your account is publicly accessible at: <a href="/profile/<%= user.username %>"><span id="accountURL"></span></a>.</p>
+ <p>Your avatar is fetched from gravatar. Update your gravatar email to fetch the avatar. If you don't have an account, you can sign up for one <a href="https://en.gravatar.com/" target="_blank">here</a>. If you haven't set up your gravatar email, we would try to fetch your profile picture from your account email, by default. If your account email and gravatar email are the same, you do not need to set a gravatar email.</p>
+ <% if (user.url !== "") { %>
+ <p>Your account is publicly accessible at: <a href="<%= user.url %>" target="_blank"><%= user.url %></a></p>
<% } %>
<div class="account">
<div class="ac-sidebar">
@@ -51,6 +51,8 @@
<input type="text" name="firstname" id="firstname" value="<%= user.firstname %>" placeholder="First Name" />
<label for="lastname">Last Name</label>
<input type="text" name="lastname" id="lastname" value="<%= user.lastname %>" placeholder="Last Name" />
+ <label for="gravatarEmail">Gravatar Email</label>
+ <input type="text" name="gravatarEmail" id="gravatarEmail" value="<%= user.gravatarEmail %>" placeholder="Gravatar Email" />
<label for="location">Location</label>
<input type="text" name="location" id="location" value="<%= user.location %>" placeholder="Location" />
<label for="bio">Bio</label>
@@ -76,12 +78,21 @@
<% } %>
</fieldset>
</form>
- <form method="post" action="">
+ <form method="post" action="/account/sendVerificationEmail">
<fieldset>
<legend>Change Email</legend>
<label for="email">Your current registered email is <em><u><%= user.email %></u></em>. Please note that a verification email will be sent to the new email address in order to update the current email address. Please provide the new email address in the box below:</label>
<input type="email" name="email" id="email" placeholder="New Email" />
<input type="submit" value="Change Email" />
+ <% if (locals.messages.mailsenderror) { %>
+ <p class="error"><%= messages.mailsenderror %></p>
+ <% } %>
+ <% if (locals.messages.mailsendsuccess) { %>
+ <p class="success"><%= messages.mailsendsuccess %></p>
+ <script>
+ console.log("<%= messages.mailsendsuccess %>");
+ </script>
+ <% } %>
</fieldset>
</form>
</div>
diff --git a/views/error.ejs b/views/error.ejs
index d11cc4be..16a9f991 100644
--- a/views/error.ejs
+++ b/views/error.ejs
@@ -1,14 +1,26 @@
-<%- include('partials/header.ejs') %> <%- include('partials/sidebar.ejs') %>
-<div class="main">
- <div class="alert">
- <h1 class="error">error</h1>
- <p>
- <%= error %>
- </p>
- </div>
- <section>
- <h2>Recent Posts</h2>
- </section>
-</div>
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta
+ name="description"
+ content="Welcome to the home of That Computer Scientist. I am Kumar Priyansh. This is my personal website where I share all of my thoughts, ideas, and experiences."
+ />
+ <title>That Computer Scientist - <%= title %></title>
+ <!-- <link rel="stylesheet" href="css/fonts.css"> -->
+ <link preload rel="stylesheet" href="../css/main.css" />
+ </head>
+ <body>
+ <div class="main">
+ <div class="errorbox">
+ <h1 class="error">Whoops! Encountered an error!</h1>
+ <p><%= error %></p>
+ <p>Please click <a href="/">here</a> to go back to the home page.</p>
+ </div>
+ </div>
-<%- include('partials/footer.ejs') %>
+ <%- include('partials/footer.ejs') %>
+ </body>
+</html>