How can i access signup function elements from verify function? - node.js

I'm new to website building. I am using node js, express, and express-handlebars. I have 3 hbs page file called signup, verify, and login. I am trying to check if signup page has any errors using exports.signup and then if it's alright then rendering verify page and authenticating it using otp. Now my problem is I need to enter signup page values from verify page in the database after user is verified. How can I get signup page values from exports.signup and use it in exports.verify function?
This works to check in signup page:
exports.signup = (req, res) => { console.log(req.body);
const { name, email, password, passwordConfirm } = req.body;
db.query("select email from test where email=?",[email],async (error, results) => {
if (error) {
console.log(error);
}
if (results.length > 0) {
return res.render("signup", {
message: "The email is already in use",
});
} else if (password !== passwordConfirm) {
return res.render("signup", {
message: "Passwords do not match",
});
}
let hashedPassword = await bcrypt.hash(password, 8);
console.log(hashedPassword);
var digits = "0123456789";
let OTP = "";
for (let i = 0; i < 6; i++) {
OTP += digits[Math.floor(Math.random() * 10)];
}
let transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.GMAIL,
pass: process.env.GMAIL_PASSWORD,
},
});
let mailOptions = {
from: "checkmate.sdp#gmail.com",
to: email,
subject: "Verification code for Checkmate profile.",
text: "Your OTP is : " + OTP,
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log("Email sent: " + info.response);
res.render("verify");
}
});
}
);
};
This verifies the user and enters values in database: (I haven't added anything here yet)
exports.verify = (req, res) => {
console.log(req.body);
};

Just an overview for you
signup.js
'use-strict';
exports.signup = (params) => { console.log("Hit", params) }
controller.js
'use-strict';
var signup = require('./signup');
var http = require('http');
// you can now access the signup function,
signup.signup({username: 'test', password: 'test'})
Looks like you want this to be an HTTP endpoint reciever,
depending on what library youre using, example with Koa route
Backend--
signup.js
var route = require('koa-route');
exports.init = (app) => {
app.use(route.post('/signup', signup));
}
async function signup(ctx) {
var body = ctx.request.body;
//operate
}
Frontend --
$.ajax({
url: "/signup",
type: "post",
data: JSON.stringify({username: 'get from html', password: 'get from html'})
});

Related

Struggling to verify new users: Node JS

I am trying to implement a mechanism to allow new users to verify their account with a link sent to their email address.
Here's is my subscribe route in routes/user/index.js, which is working to send the email correctly:
require('dotenv').config();
const { v4 } = require('uuid');
const nodemailer = require('nodemailer');
const sibApiV3Sdk = require('sib-api-v3-sdk');
const express = require('express');
const stripe = require('../middlewares/stripe')
const db = require("../models");
const cors = require('cors');
const User = db.user;
const Feedback = db.feedback;
const defaultClient = sibApiV3Sdk.ApiClient.instance;
// Configure API key authorization: api-key
const apiKey = defaultClient.authentications['api-key'];
apiKey.apiKey = process.env.SENDINBLUE_API_KEY;
const transactionalEmailsApi = new sibApiV3Sdk.TransactionalEmailsApi();
// Configure nodemailer
const transporter = nodemailer.createTransport({
host: "smtp-relay.sendinblue.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "noreply#redacted.ai",
pass: "redacted"
}
});
// Define generateVerificationToken function
function generateVerificationToken() {
return v4();
}
// Prepare Core Router
let app = express.Router()
app.post('/stripe/subscribe', async (req, res) => {
const domainURL = process.env.DOMAIN;
const { priceId, trial } = req.body
try {
let user = await User.findOne({ _id: req.user._id });
let customer = user.customerId ? { customer: user.customerId } : {customer_email: user.email};
const subscription_data = trial ? { trial_period_days: 7 } : {};
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
payment_method_types: ['card'],
...customer,
line_items: [
{
price: priceId,
quantity: 1,
},
],
subscription_data,
success_url: `${domainURL}/index.html`,
cancel_url: `${domainURL}/signup/failed`,
});
let credits = 0;
if (priceId === process.env.STRIPE_PRODUCT_FREE) {
credits = 0;
} else if (priceId === process.env.STRIPE_PRODUCT_ENTRY) {
credits = 0;
} else if (priceId === process.env.STRIPE_PRODUCT_PRO) {
credits = 0;
}
// Check if user already has a verification_token
if (!user.verification_token) {
const token = generateVerificationToken();
console.log("generated token: ", token);
const updatedUser = await User.findOneAndUpdate({ _id: req.user._id },
{
credits: credits,
verification_token: token,
isVerified: false
},
{
new: true
});
console.log("updatedUser: ", updatedUser);
const verificationLink = `${domainURL}/verify?token=${updatedUser.verification_token}`;
const mailOptions = {
from: 'noreply#redacted.ai',
to: user.email,
subject: 'Verify your email address',
html: `Please click on the following link to verify your email address: ${verificationLink}`
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
} else {
console.log('User already has a verification token.');
}
const updateResult = await User.updateOne({_id: req.user._id}, {verification_token: user.verification_token}, {upsert: true});
console.log("updateResult: ", updateResult);
// Send verification email after stripe step completes
if (!user.isVerified) {
const verificationLink = `${domainURL}/verify?token=${user.verification_token}`;
const mailOptions = {
from: 'noreply#redacted.ai',
to: user.email,
subject: 'Verify your email address',
html: `Please click on the following link to verify your email address: ${verificationLink}`
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
}
// Redirect user to the verify route
res.redirect(303, session.url);
} catch (e) {
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
});
Immediately after this, I then have a verify route:
app.get('/verify', cors(), async (req, res) => {
const { token } = req.query;
try {
// Find user with matching token
let user = await User.findOne({ verification_token: token });
if (!user) {
throw new Error('Invalid token');
}
// Update user verification status
user.isVerified = true;
const savedUser = await user.save();
// Send verification email
if (savedUser.isVerified) {
const mailOptions = {
from: 'noreply#redacted.ai',
to: savedUser.email,
subject: 'Email Verified!',
html: `Your email has been verified! Welcome to redacted.ai`
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
}
// Redirect user to success page
res.redirect('/index.html#/verify/success');
} catch (e) {
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
});
I also have a file called src/verify.js to deal with things on the front-end:
import React, { useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom';
function Verify(props) {
const [isVerified, setIsVerified] = useState(false);
const { token } = props.match.params;
const history = useHistory();
useEffect(() => {
// logic to process token and set isVerified to true/false
fetch(`/verify/${token}`)
.then(res => res.json())
.then(data => {
if (data.isVerified) {
setIsVerified(true);
}
});
}, [token]);
useEffect(() => {
// redirect to success page if isVerified is true
if (isVerified) {
history.push('/index.html#/verify/success');
}
}, [isVerified, history]);
return (
<div>
{isVerified ? (
<div>Your email has been verified! Welcome to redacted.ai</div>
) : (
<div>Invalid token.</div>
)}
</div>
);
}
export default Verify;
However, when the user clicks on the link in their email, the verify route does not initiate. Rather, nothing happens at all in the terminal except for profile refresh, and I'm not sure why.
As an aside, I can see in the database that the new user has a verification_token and isVerfied is set to false. That verification_token matches the one sent in the email.
I'm very new to Node JS so suspect I'm missing something obvious! Thanks so much in advance.
PS.
As a work around, I attempted to try a different approach, and created a form that the user could go to and copy and paste in their verification_token: the form looked like this:
import React, { useState } from 'react';
import TOOLS from './tools'
import config from './config'
import Header from './Header'
let baseURL = config.baseURL
const VerifyPage = () => {
const [verificationToken, setVerificationToken] = useState('');
const [error, setError] = useState('');
const [responseData, setResponseData] = useState({});
const handleSubmit = async (event) => {
event.preventDefault();
const token = window.localStorage.getItem('token');
console.log('Token: ', token);
console.log('Authorization header: ', `Bearer ${token}`);
// Make a request to your API to verify the token
try {
const response = await fetch(`${baseURL}user/verify`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ verificationToken })
});
console.log('Request URL: ', `${baseURL}user/verify`);
console.log('Request body: ', JSON.stringify({ verificationToken }));
const responseJson = await response.json();
setResponseData(responseJson);
console.log('Response status: ', response.status);
console.log('Response text: ', await response.text());
if (!response.ok) {
throw new Error(responseJson.message);
}
// Show a success message or redirect to another page
} catch (error) {
setError(error.message);
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="verificationToken">Verification Token:</label>
<input
type="text"
id="verificationToken"
value={verificationToken}
onChange={(event) => setVerificationToken(event.target.value)}
/>
</div>
{error && <p style={{ color: 'red' }}>{error}</p>}
<button type="submit">Verify</button>
{responseData && JSON.stringify(responseData)}
</form>
);
};
export default VerifyPage;
And with this in place, I altered my verify route to looks like this:
app.post("/verify", (req, res) =\> {
console.log('Received request to /verify');
const { token } = req.body;
console.log('Received verification token:', token);
User.findOne({ token }, (err, user) => {
if (err) {
console.error('Error finding user:', err);
return res.status(500).send({ error: "Error verifying account" });
}
if (!user) {
console.error('No user found with provided verification token');
return res.status(400).send({ error: "Invalid Token" });
}
user.isVerified = true;
user.verificationToken = undefined;
user.save((err) => {
if (err) {
console.error('Error saving user:', err);
return res.status(500).send({ error: "Error verifying account" });
}
console.log('User verified successfully');
return res.send({ message: "Account verified successfully" });
});
});
});`
But whenever the user attempted to put in their valid token, they would get something like this:
"Unexpected token 'F', "Forbidden" is not valid JSON"
Moreover, this is all that would show up in the terminal:
`"OPTIONS /api/user/verify 204 0.285 ms - 0 POST /api/user/verify 403 1.558 ms - 9" `
And, under the JWT code, this would show up in the console: "Failed to load resource: the server responded with a status of 403 (Forbidden)"
Truth be told, I'd be happy to get this working either via the form, or by having users click the link in the email. The latter is preferable - but either would work.

Send email through nodemailer nodejs

First I am checking the email present in the database, if present then it will generate the hashcode and after that it will update the database and once the hashcode is generated then email will be send to the user. So I am stuck how to send email please any help.
const md5 = require('md5');
let transporter = require("../config/transporter");
export const newemail = async(req,res ) => {
try{
var re = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const user = await db.findOne('USER', { email: req.body.email });
res.status(200).json(user);
if (!re.test(req.body.email)) {
res.json('Email address is not valid!');
} else {
const email = req.body.email;
const name = email.substring(0, email.lastIndexOf("#"));
const domain = email.substring(email.lastIndexOf("#") +1);
const hashCode = md5(name + domain);
function sendingMail(referredBy){
const user = await db.findOneandUpdate('USER', { email: req.body.email, referralCode: hashCode, referredBy: referredBy });
const email = user.email;
console.log(email + "email");
//send verification mail
let mailOptions = {
from: 'xxyyzz#gmail.com', // sender address
to: email, // list of receivers
subject: settingsConfig.subjectLine, // Subject line
text: settingsConfig.message, // plaintext body
html: settingConfig.message // html body
};
console.log("MAILING!");
console.log(mailOptions)
// send mail with defined transport object
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
return console.log(error);
}
console.log('Message sent: ' + info.response);
});
};
}
}
catch (err) {
console.log(err)
res.status(500).json({ message: "Something went wrong" });
}
}
Please anyone how to move further.
const md5 = require('md5');
let transporter = require("../config/transporter");
export const sendEmail = async (to, from, subject, body) => {
// use any mailer library to send the email
}
export const isValidEmail = async (email) => {
const regex = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return regex.test(email);
}
export const findUserByEmail = async (email) => {
// db instance
return await db.findOne('USER', { email });
}
export const generateHash = async (email) => {
const name = email.substring(0, email.lastIndexOf("#"));
const domain = email.substring(email.lastIndexOf("#") +1);
return md5(name + domain);
}
export const verifyAndEmail = async(req,res ) => {
try{
// var re = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
// const user = await db.findOne('USER', { email: req.body.email });
// res.status(200).json(user);
// step-1 destructure email from request body
const {
email
} = req.body;
// step-2, validate the email id
const isEmailValid = await isValidEmail(email);
if(!isEmailValid) {
throw new Error('Invalid email');
// return appropiate response
}
// step-3 find a user by email
const user = await findUserByEmail(email);
// step-4 validate, if user does not exists
if (!user) {
throw new Error('User does not exist');
// return appropiate response
}
//step-5 generate the hash using user's email
const hash = await generateHash(email);
// step-6, call send email method with the parameters
}
catch (err) {
console.log(err)
res.status(500).json({ message: "Something went wrong" });
}
}
I would suggest, you should refactor your code to following.
Run it and let me know if you face any issues.
This approach will help you to debug the error.

How to send user from nodemailer reset password mail to my react native app

i build full functions that worked and send emil to user when he "forgot password",its worked perfect on postMan, now the problem is when i clicked on the email url is direct me to "Cannot GET /resetpassword/eyJhbGciOiJIUzI1NiIsInR5cCeyJfaWQiOiI1ZmQ5ZmFmZjFjODA2YTgyMjZjMTQ5YmUiLCJp"
if i was do that for web app its work, but how can i redirect to open my app and show the screen for reset password?
exports.sendEmail = emailData => {
const transporter = nodeMailer.createTransport({
host: "smtp.gmail.com",
port: 587,
secure: false,
requireTLS: true,
auth: {
user: "roeigr7#gmail.com",
pass: "iaoqymixqarajkbv",
},
});
return transporter.sendMail(emailData);
};
and the data send to:
const emailData = {
from: "noreply#Lior.com",
to: email,
subject: "Password Reset Instructions",
text: `Please use the following link to reset your password: ${process.env.CLIENT_URL}/resetpassword/${token}`,
html: `<p>Please use the following link to reset your password:</p> <p>${process.env.CLIENT_URL}/resetpassword/${token}</p>`,
---------reset password FUNCTION:
exports.resetPassword = (req, res) => {
const { resetPassword, newPassword } = req.body;
User.findOne({ resetPassword }, (err, user) => {
// if err or no user
if (err || !user)
return res.status("401").json({
error: "Invalid Link!",
});
const updatedFields = {
password: newPassword,
resetPassword: "",
};
user = _.extend(user, updatedFields);
user.updated = Date.now();
user.save((err, result) => {
if (err) {
return res.status(400).json({
error: err,
});
}
res.json({
message: `סיסמא שונתה בהצלחה`,
});
});
});
};`
--------- resetPassword component:
const resetPassword = async resetInfo => {
try {
const response = await indexApi.put("resetPassword", {
resetInfo,
});
console.log("forgot password response: ", response);
} catch (err) {
console.log(err.response.data.error);
}
};
const resetPassModal = () => {
return (
<View style={{ marginVertical: 30 }}>
<Text onPress={resetPassword} style={styles.titletext}>
reset
</Text>

How to send cookies in express?

router.post('/login', async (req, res) => {
const logInEnvironment = browser(req.headers['user-agent']);
const ipAddress = requestIp.getClientIp(req);
const userEmail = req.body.userEmail.toLowerCase();
const password = req.body.password;
// Form validation
const validation = await validateLoginInput(req.body);
// Check validation
if (!validation.isValid) {
return res.status(400).json(validation.errors);
}
// Find user by email
const auth = await Auth.findOne({ userEmail }, { userLoginInfo: 0 });
//Check if user exists
if (auth === null) {
console.log('aaaa');
res.cookie('send2', 'shhhhhent!');
res.status(200);
return res
.status(400)
.json({ authFailedMessage: 'Email or password is incorrect' });
} else if (auth !== null) {
bcrypt.compare(password, auth.password).then((isMatch) => {
if (isMatch) {
return res.cookie('failed', 'yess!').status(200).json({succeeded: 'hiii'})
} else if (!isMatch) {
return res.cookie('succeeedd', 'noooo!').status(400).json({failed: 'hiii'})
}
});
}
});
I have this code. But, the res.json has been returned without cookies.
Moreover, I added these commands in my index.js file
const cookieParser = require('cookie-parser');
app.use(cookieParser());
I also tested if res.cookie() was working in another route
router.get('/cookie', (req, res) => {
res.cookie('hellooo', 'hiiiiii')
res.send('woooorked?')
})
This was returning cookie and I can see that in the dev-panel on Chrome. What have I done wrong in the first code that cookies are not sent to the browser?
Did you try to split the code like
router.get('/cookie', (req, res) => {
res.cookie('hellooo', 'hiiiiii')
res.send('woooorked?')
})
Can you test with this code
router.post('/login', async (req, res) => {
const logInEnvironment = browser(req.headers['user-agent']);
const ipAddress = requestIp.getClientIp(req);
const userEmail = req.body.userEmail.toLowerCase();
const password = req.body.password;
// Form validation
const validation = await validateLoginInput(req.body);
// Check validation
if (!validation.isValid) {
return res.status(400).json(validation.errors);
}
// Find user by email
const auth = await Auth.findOne({ userEmail }, { userLoginInfo: 0 });
res.cookie('send2', 'shhhhhent!');
return res.json({ authFailedMessage: 'Email or password is incorrect' });
});
Then you check the header of the request and find the header name set-cookie, if it visible, you have got it

Content for confirmation email not showing when sent through nodemailer?

In my Node.js/MERN app, I get error 250 2.0.0 OK 1590267554 o18sm275551eje.40 - gsmtp & something went wrong when I register my user for authentication and receive an email with EMPTY body. I am using the code from https://blog.bitsrc.io/email-confirmation-with-react-257e5d9de725
I can see user is added to mongodb database with confirmed set to false. Why am I not getting the complete email with confirmation?
Please find my attached code for my MERN application. I would really appreciate a reply! Thank you!
Register
Register route in users which takes you to login and on React side OnSubmit starts chain of sending and confirming email.
router.post("/register", type, function (req, res, next) {
// var tmp_path = req.file.path;
if(!req.file){
console.log("File missing");
}
/** The original name of the uploaded file
stored in the variable "originalname". **/
// var target_path = 'uploads/' + req.file.originalname;
// /** A better way to copy the uploaded file. **/
// var src = fs.createReadStream(tmp_path);
// var dest = fs.createWriteStream(target_path);
// src.pipe(dest);
// fs.unlink(tmp_path);
// src.on('end', function() { res.render('complete'); });
// src.on('error', function(err) { res.render('error'); });
// Form validation
const { errors, isValid } = validateRegisterInput(req.body);
const url = req.protocol + '://' + req.get('host')
// Check validation
if (!isValid) {
return res.status(400).json(errors);
}
//Checks email against registered emails in database
registeredemails.findOne({ email: req.body.email}).select("email").lean().then(result => {
if (!result) {
return res.status(400).json({email: "Email not provided"});
}
});
User.findOne({ email: req.body.email }).then(user =>
{
if (user) {return res.status(400).json({ email: "Email already exists" })
}
else if(!user){
const newUser = new User({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: req.body.password,
fileimg: url + '/public/' + req.file.filename
});
// // Hash password before saving in database
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then(newUser =>
sendEmail(newUser.email),
templates.confirm(newUser._id)
)
.then(() => res.json({ msg: msgs.confirm }))
.catch(err => console.log(err))
}
)}
)}
else if (user && !user.confirmed) {
sendEmail(user.email, templates.confirm(user._id))
.then(() => res.json({ msg: msgs.resend })).catch(err => console.log(err))
}
// The user has already confirmed this email address
else {
res.json({ msg: msgs.alreadyConfirmed })
}
}).catch(err => console.log(err))
sendemail as used in the MEDIUM articles
const nodemailer = require('nodemailer');
const { CLIENT_ORIGIN } = require('../../config')
// const mg = require('nodemailer-mailgun-transport');
// The credentials for the email account you want to send mail from.
const credentials = {
secure: true,
service: 'Gmail',
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASS
// These environment variables will be pulled from the .env file
// apiKey: 'b61286bf9e28b149fac32220f0c7349f-e5e67e3e-00a38515',
// domain: 'sandbox0b8a7f0ebcc74c0d8161304f24909bd2.mailgun.org'
}
}
// Getting Nodemailer all setup with the credentials for when the 'sendEmail()'
// function is called.
const transporter = nodemailer.createTransport(credentials)
// exporting an 'async' function here allows 'await' to be used
// as the return value of this function.
module.exports = async (to, content) => {
// The from and to addresses for the email that is about to be sent.
const contacts = {
from: process.env.MAIL_USER,
to // An array if you have multiple recipients.
// subject: 'React Confirm Email',
// html: `
// <a href='${CLIENT_ORIGIN}/confirm/${id}'>
// click to confirm email
// </a>
// `,
// text: `Copy and paste this link: ${CLIENT_ORIGIN}/confirm/${id}`
}
// Combining the content and contacts into a single object that can
// be passed to Nodemailer.
const email = Object.assign({}, content, contacts)
// This file is imported into the controller as 'sendEmail'. Because
// 'transporter.sendMail()' below returns a promise we can write code like this
// in the contoller when we are using the sendEmail() function.
//
// sendEmail()
// .then(() => doSomethingElse())
//
// If you are running into errors getting Nodemailer working, wrap the following
// line in a try/catch. Most likely is not loading the credentials properly in
// the .env file or failing to allow unsafe apps in your gmail settings.
await transporter.sendMail(email, function(error, info){
if(error)
{
return console.log(error);
}
else
{
return console.log(info.response);
}
})
}
templates.confirm as used in Medium article
onst { CLIENT_ORIGIN } = require('../../config')
// This file is exporting an Object with a single key/value pair.
// However, because this is not a part of the logic of the application
// it makes sense to abstract it to another file. Plus, it is now easily
// extensible if the application needs to send different email templates
// (eg. unsubscribe) in the future.
module.exports = {
confirm: id => ({
subject: 'React Confirm Email',
html: `
<a href='${CLIENT_ORIGIN}/confirm/${id}'>
click to confirm email
</a>
`,
text: `Copy and paste this link: ${CLIENT_ORIGIN}/confirm/${id}`
})
}

Resources