Giter VIP home page Giter VIP logo

Comments (3)

supuram avatar supuram commented on June 2, 2024

in the .ejs files use csrf properly

from passport.

jaredhanson avatar jaredhanson commented on June 2, 2024

It would be appreciated if you described the problems you are encountering with enough detail that allowed a discussion and proposed fixes. Feedback is always welcome, but complaints alone are not actionable.

from passport.

supuram avatar supuram commented on June 2, 2024

hey, I already solve the issue. In the documentation no mention of csrf in .ejs file. And without it i was getting constant error. Only when i added them i got the thing running. Plus now i have the full backend written properly - with signin , signup with jwtToken and the google, facebook using passport. But i could not have done this only by your documentation.
My full code
import express from 'express'
import cors from 'cors'
import { MongoClient, Binary } from 'mongodb'
import uri from './first.js'
import bcrypt from 'bcrypt'
import jwt from 'jsonwebtoken'
import session from 'express-session'
import crypto from 'crypto'
import nodemailer from 'nodemailer'
import multer from 'multer'
import NodeCache from 'node-cache'
import imageType from 'image-type'
import passport from 'passport'
import { Strategy as GoogleStrategy } from 'passport-google-oauth20'
import { Strategy as FacebookStrategy } from 'passport-facebook'
import cookieSession from 'cookie-session'
import a from './env.js'
import dotenv from 'dotenv'
dotenv.config()

const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: a.EMAIL,
pass: a.PASSWORD
},
})

const client = new MongoClient(uri)
const app = express()
app.use(cors())
app.use(express.json())
const jwtSecret = process.env.JWT_SECRET
const imageCache = new NodeCache();
app.use(
cookieSession({
name: 'session',
keys: process.env.COOKIE_SECRET,
maxAge: 24 * 60 * 60 * 1000, // 1 day
})
);
app.use(passport.initialize());
app.use(passport.session());

// Define your Google OAuth 2.0 credentials
const googleClientId = process.env.GOOGLE_CLIENT_ID
const googleClientSecret = process.env.GOOGLE_CLIENT_SECRET

// Define your Facebook OAuth 2.0 credentials
const facebookAppId = process.env.FACEBOOK_APP_ID
const facebookAppSecret = process.env.FACEBOOK_APP_SECRET

passport.use(
new GoogleStrategy(
{
clientID: googleClientId,
clientSecret: googleClientSecret,
callbackURL: '/auth/google/callback', // Define your callback URL
},
(accessToken, refreshToken, profile, done) => {
// Handle Google authentication here
// You can save the user profile data to your database or perform other actions
return done(null, profile);
})
);

// Passport setup for Facebook OAuth 2.0
passport.use(
new FacebookStrategy(
{
clientID: facebookAppId,
clientSecret: facebookAppSecret,
callbackURL: '/auth/facebook/callback', // Define your callback URL
},
(accessToken, refreshToken, profile, done) => {
// Handle Facebook authentication here
// You can save the user profile data to your database or perform other actions
return done(null, profile);
})
);

// Serialize and deserialize user (required for session support)
passport.serializeUser((user, done) => {
done(null, user);
});

passport.deserializeUser((user, done) => {
done(null, user);
});

async function startServer() {
try {
await client.connect()
const db = client.db('store')
const collection = db.collection('user_registration_information')
const friends = db.collection('allfriends')
const finalfriendslist = db.collection('finalfriendslist')
app.get('/', (req, res) => {
const data = { showHome: true }
res.json(data)
})

    // Define routes for initiating Google and Facebook authentication
    app.get(
        '/auth/google',
        passport.authenticate('google', {
        scope: ['profile', 'email'], // Define the required scopes
        })
    );
    
    app.get(
        '/auth/facebook',
        passport.authenticate('facebook', {
        scope: ['public_profile', 'email'], // Define the required scopes
        })
    );
    
    // Define the callback routes for Google and Facebook authentication
    app.get(
        '/auth/google/callback',
        passport.authenticate('google', { failureRedirect: '/Login-Page-Form' }),
        async(req, res) => {
        // Successful Google authentication
        const user = req.user
        await collection.insertOne(user);
        res.redirect('/LoggedInHomePage'); // Redirect to the profile page or any other page
        }
    );

    app.get(
        '/auth/facebook/callback',
        passport.authenticate('facebook', { failureRedirect: '/Login-Page-Form' }),
        async(req, res) => {
        // Successful Facebook authentication
        const user = req.user
        await collection.insertOne(user);
        res.redirect('/LoggedInHomePage'); // Redirect to the profile page or any other page
        }
    );

    app.use(session({
        secret: jwtSecret,
        resave: false,
        saveUninitialized: false
    }));

/* ------------------------------------------------------------------------------------------------------------ */
// *! Handles the upload of profile pictures. See ProfileImage.js

    // Function to determine the content type of the image
    function getImageContentType(imageData) {
        const type = imageType(Buffer.from(imageData));   // imageType library expects a buffer as its argument so imageData is converted to buffer before passing it to imageType
        if (type) {
            return `image/${type.ext}`;
        }
        // Default to PNG content type if not recognized
        return 'image/png';
    }

    const upload = multer({ storage: multer.memoryStorage() });
    // Handle image upload
    app.post('/upload', upload.single('image'), async(req, res) => {
        console.log('Post upload entry')
        if (!req.file) {
            console.log('No image uploaded')
            return res.status(400).send('No image uploaded');
        }
        console.log('Image file is found')
        const authHeader = req.headers.authorization
        const token = authHeader && authHeader.split(' ')[1]
        console.log('Entering check token')
        if (!token) {
            // No JWT provided
            console.log('Unauthorized')
            res.status(401).send('Unauthorized')
            return
        }
        let userEmail;
        console.log('After userEmail')
        try {
            // Verify JWT
            const decoded = jwt.verify(token, jwtSecret)
            userEmail = decoded.email
            console.log('Token verified')
        } 
        catch (error) {
            // Invalid JWT
            console.log('Forbidden')
            res.status(403).send('Forbidden')
        }

// Buffer.from is a method provided by Node.js's built-in Buffer module. It is used to create a new Buffer object from various sources, including binary data.
// req.file.buffer: The buffer property of the req.file object contains the binary data of the uploaded file. The Binary class is a part of the MongoDB Node.js driver. It is used to represent binary data, such as images, in a format that MongoDB can handle.
const imageBuffer = Buffer.from(req.file.buffer);
const imageBinary = new Binary(imageBuffer);
await collection.updateOne(
{ email: userEmail },
{ $set: { filename: req.file.originalname, image: imageBinary } }
);

        // Serialize the imageBinary before storing it in the cache
        const imageBinarySerialized = imageBinary.buffer.toString('base64');
        imageCache.set(userEmail, imageBinarySerialized);  // responsible for storing the image data in an image cache, associating it with the user's email address
        console.log('Image uploaded');
        return res.status(200).send('Image upload successful');
    });
    app.use(express.static('public'));   
    
    app.get('/user/image', async (req, res) => {
        // Verify the user's token and extract their email
        console.log('Entered server side /user/image')
        const authHeader = req.headers.authorization;
        const token = authHeader && authHeader.split(' ')[1];
        if (!token) {
            return res.status(401).send('Unauthorized');
        }
    
        let userEmail;
        try {
            const decoded = jwt.verify(token, jwtSecret);
            userEmail = decoded.email;
            console.log('Token Verified')
        } 
        catch (error) {
            return res.status(403).send('Forbidden');
        }
    
        // When retrieving from the cache, deserialize the data
        const cachedImageSerialized = imageCache.get(userEmail);
        if (cachedImageSerialized) {
            try {
                console.log('Enter if cachedImage')
                const cachedImageBinary = new Binary(Buffer.from(cachedImageSerialized, 'base64'));
                const imageContentType = getImageContentType(cachedImageBinary);  
                res.setHeader('Content-Type', imageContentType);
                res.send(cachedImageBinary.buffer);  // you are sending the raw binary image data as the response body
            } 
            catch (error) {
                console.error('Error serving cached image:', error);
                res.status(500).send('Internal Server Error');
            }
        } 
        else {
            try {
                // Retrieve user's image data from the database
                const user = await collection.findOne({ email: userEmail });
                console.log('Retrieve user image data from the database')
                if (!user || !user.image) {
                    console.log('User or image data not found')
                    return res.status(404).send('User or image data not found');
                }
                const imageBinary = user.image
                // Serialize the imageBinary before storing it in the cache
                const imageBinarySerialized = imageBinary.buffer.toString('base64');
                imageCache.set(userEmail, imageBinarySerialized);
    
                // Serve the image
                try {
                    console.log('Serve the image');
                    const imageSerialized = imageCache.get(userEmail);  // if there is image in the cache it returns true
                    if (imageSerialized) {
                        const imageBinary = new Binary(Buffer.from(imageSerialized, 'base64'));
                        const imageContentType = getImageContentType(imageBinary);
                        res.setHeader('Content-Type', imageContentType);
                        res.send(imageBinary.buffer);
                    } 
                    else {
                        // This could happen if there was an issue with caching the image data
                        res.status(404).send('Image not found in cache');
                    }
                } 
                catch (error) {
                    console.error('Error serving retrieved image:', error);
                    res.status(500).send('Internal Server Error');
                }
            } 
            catch (error) {
                console.error('Error retrieving image from database:', error);
                res.status(500).send('Internal Server Error');
            }
        }
    });     

/* ------------------------------------------------------------------------------------------------------------- */
// *! See ProfileForm.js , Here the user inputs his personal information

    app.put('/updateProfile', async(req, res) => {
        const authHeader = req.headers.authorization;
        const token = authHeader && authHeader.split(' ')[1];
        if (!token) {
            return res.status(401).send('Unauthorized');
        }
    
        let email;
        try {
            const decoded = jwt.verify(token, jwtSecret);
            email = decoded.email;
            console.log('Token Verified for updateProfile')
        } 
        catch (error) {
            return res.status(403).send('Forbidden');
        }

        const response = await collection.updateOne(
            { email: email },
            { $set: { fullname: req.body.name, dob: req.body.dob, school: req.body.school, college: req.body.college, university: req.body.uni, workplace: req.body.workplace } }
        );
        if (response.modifiedCount === 1) {
            console.log('Profile updated successfully');
            res.sendStatus(200);
        } else {
            console.log('Profile update failed');
            res.sendStatus(500); // Internal Server Error
        }
    })

    app.get('/userProfileData', async(req, res) => {
        const authHeader = req.headers.authorization;
        const token = authHeader && authHeader.split(' ')[1];
        if (!token) {
            return res.status(401).send('Unauthorized');
        }
    
        let email;
        try {
            const decoded = jwt.verify(token, jwtSecret);
            email = decoded.email;
            console.log('Token Verified for updateProfile')
            const user = await collection.findOne({ email: email });
            if (!user) {
                return res.status(404).send('User profile not found');
            }
            res.send(user)
        } 
        catch (error) {
            return res.status(403).send('Forbidden');
        }
    })

/* -------------------------------------------------------------------------------------------------------------- */

    app.get('/logout', (req, res) => {
        req.session.destroy((err) => {
            if (err) {
                console.log(err);
                res.status(500).send('Error occurred during logout');
            } 
            else {
                res.clearCookie('authToken');
                res.redirect('/')
            }
        });
    });


    // Verifies the JWT and authenticates the user
    app.get('/protected-route', (req, res) => {
        // Get JWT from Authorization header
        const authHeader = req.headers.authorization
        const token = authHeader && authHeader.split(' ')[1]
    
        if (!token) {
            // No JWT provided
            console.log('Unauthorized')
            res.status(401).send('Unauthorized')
            return
        }
        
        try {
            // Verify JWT
            const decoded = jwt.verify(token, jwtSecret)
            let email = decoded.email
            // Authentication successful
            res.status(200).send(email)
        } 
        catch (error) {
            // Invalid JWT
            console.log('Forbidden')
            res.status(403).send('Forbidden')
        }
    })        

    // Verify email route
    app.get('/verify', async (req, res) => {
        const verificationToken = req.query.token
        console.log('verificationToken = ',verificationToken)
        try {
            // Find the user in the database based on the verification token
            const user = await collection.findOne({ verificationToken })
            console.log('user = ', user)
    
        if (!user) {
            // User not found or already verified
            console.log('Invalid verification token')
            res.status(404).send('Invalid verification token')
            return
        }
        console.log('entered verify token email')
        // Update the user's status to "verified" in the database
        await collection.updateOne(
            { _id: user._id },
            { $set: { verified: true }, $unset:{ verificationToken: 1 } }
        )
        console.log('exit update email token to true')
        res.status(200).json({ message: 'Email verified successfully' });
        // Redirect the user to a success page or display a success message
        // res.redirect('/LoginPage')
        } 
        catch (error) {
            console.log(error.message)
            res.status(500).send('Error verifying email')
        }
    })  

    app.get('/verify-forgot-password-email', async (req, res) => {
        const verificationToken = req.query.resetToken;
        try {
            // Find the user in the database based on the verification token
            const user = await collection.findOne({ verificationToken: verificationToken });

            if (!user) {
                console.log('Invalid verification token from forgot password')
                // User not found or already verified
                return res.status(404).send('Invalid verification token');
            }
        
            console.log('entered verify token email for forgot password')
            // Update the user's status to "verified" in the database
            await collection.updateOne(
                { _id: user._id },
                { $set: { verified: true } }//resetToken: null, resetTokenExpiresAt: null
            );
            console.log('exit update email token to true for forgot password')
            res.status(200).json({ message: 'Email verified successfully for forgot password' });
        } 
        catch (error) {
          console.log(error);
          res.status(500).send('Error verifying email');
        }
    });

    // For the form inside About.js on the client side
    app.post('/submit-form', async (req, res) => {
        try {
            await collection.insertOne(req.body)
            res.status(200).send('Form data saved')  /* On the client-side, when making the Axios POST request 

to /submit-form, if the server responds with a status of 200 (OK), the client-side code enters the .then block. */
} catch (error) {
console.log(error)
res.status(500).send('Error saving form data')
}
})

    // Define the sendVerificationEmail function
    function sendVerificationEmail(email, verificationToken) {
        const mailOptions = {
        from: '[email protected]',
        to: email,
        subject: 'Account Verification',
        html: `<p>Hello,</p>
                <p>Thank you for registering. Please verify your email address by clicking the following link:</p>
                <a href="http://localhost:3000/verify?token=${verificationToken}">Verify Email</a>`,
        };
    
        transporter.sendMail(mailOptions, (error, info) => {
        if (error) {
            console.log(error);
            // Handle error while sending verification email
        } 
        else {
            console.log('Verification email sent - from nodemailer');
            // Handle successful sending of verification email
        }
        });
    }

    // For the form inside Register_Page.js on the client side
    app.post('/Register-Page-Form', async (req, res) => {
        const {text, email, password} = req.body
        try {
            let userExist = await collection.findOne({email})
            if(userExist){
                res.status(200).send({ message : 'This email already exists. Please Login'})
            }
            else{
                const hashedPassword = await bcrypt.hash(password, 10); 
                const verificationToken = generateVerificationToken();
                const user = {
                    username: text,
                    email: email,
                    password: hashedPassword,
                    verified: false,
                    verificationToken: verificationToken
                };
                await collection.insertOne(user)
                console.log('User in database')
                res.status(200).send({ message : 'User registered successfully. Please Login'})
                sendVerificationEmail(email, verificationToken);
            }
        } 
        catch (error) {
            console.log(error)
            res.status(500).send('Error saving form data')
        }
    })
    // Function to generate verification token
    function generateVerificationToken() {
        return crypto.randomBytes(20).toString('hex');
    }

    function forgotPasswordToken(email, resetToken){
        const mailOptions = {
            from: '[email protected]',
            to: email,
            subject: 'Account Verification',
            html: `<p>Hello,</p>
                    <p>Enter the new Password by clicking the following link:</p>
                    <a href="http://localhost:3000/verify-forgot-password-email?resetToken=${resetToken}">Verify Email</a>`,
            };
        
        transporter.sendMail(mailOptions, (error, info) => {
            if (error) {
                console.log(error);
                // Handle error while sending verification email
            } 
            else {
                console.log('Verification email sent- from nodemailer for forgot password');
                // Handle successful sending of verification email
            }
        });
    }

    app.post('/Forgot-Password', async(req, res) => {
        const {email} = req.body
        try{
            let userExist = await collection.findOne({email})
            if (!userExist) {
                console.log('Email not found in Forgot-Password snippet')
                // User with the provided email doesn't exist
                return res.status(404).send('User not found');
            }
            const resetToken = generateVerificationToken()
            console.log('Reset Token in Forgot-Password snippet = ', resetToken)
            // Save the reset token and its expiration in the user document in your database
            await collection.updateOne(
                { _id: userExist._id },
                {
                  $set: {
                    resetToken: resetToken,
                    resetTokenExpiresAt: Date.now() + 3600000,
                    verified: false,
                    verificationToken: resetToken
                  }
                }
            );
            console.log('In Forgot-Password successfully updated in Database')
            //console.log('resetTokenExpiresAt = ', resetTokenExpiresAt, 'Current Date = ', Date.now())
            forgotPasswordToken(email, resetToken)
            res.status(200).send({ email });
        }
        catch (error) {
            console.log(error)
            res.status(500).send('Error saving form data')
        }
    })

    app.post('/Forgot-Password-Form', async(req, res) => {
        const { resetToken, password, email } = req.body;
        try{
            const user = await collection.findOne({ verificationToken: resetToken });
            console.log('Hi i am Forgot-Password-Form')
            if (!user) {
                // User not found or the reset token is invalid
                console.log('User with the email not found in Forgot-Password-Form')
                return res.status(404).send('Invalid reset token');
            }
            console.log('User exists and Current Date = ', Date.now())
            // Check if the reset token has expired
            if (user.resetTokenExpiresAt < Date.now()) {
                // Reset token has expired
                console.log('Reset token has expired')
                return res.status(400).send('Reset token has expired');
            }
            console.log('Reset Token has not expired, Hurray !!!!!')
            const newPassword = await bcrypt.hash(password, 10); 
            console.log('Hashed Password done')
            await collection.updateOne(
                { _id: user._id },
                {
                  $set: {
                    password: newPassword,
                    resetToken: null,
                    verificationToken: null,
                    resetTokenExpiresAt: null
                  }
                }
            );
            console.log('Password reset successfully')
            // Redirect the user to the login page or send a success response
            res.sendStatus(200);
        }
        catch(error){
            console.log(error)
            res.status(500).send('Error Resetting Password')
        }
    })

// ! For the form inside Login_Page.js on the client side
app.post('/Login-Page-Form', async (req, res) => {
const {email, password} = req.body
try {
let userExist = await collection.findOne({email}) // returns the entire document and so userExist contains both email and password
if(userExist){
const isPasswordMatch = await bcrypt.compare(password, userExist.password);
console.log(password)
if(isPasswordMatch){
if(userExist.verified){
const token = jwt.sign({email}, jwtSecret, {expiresIn: '10h'})
console.log(token)
res.status(200).send({token})
return
}
else{
console.log('Please verify your email before logging in')
res.status(401).send({ message: 'Please verify your email before logging in' });
return;
}
}
else{
console.log('Invalid email or password')
res.status(401).send({ message: 'Invalid email or password' });
return
}
}
else{
console.log('Hmmmm')
res.redirect('/')
return
}
}
catch (error) {
console.log(error)
res.status(500).send('Error saving form data')
}
})
/
-------------------------------------------------------------------------------------------------------------- */

    app.listen(5000, () => {
        console.log('App is running')
    })
} 
catch (error) {
    console.log(error)
}

}
startServer()

from passport.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.