I am tring to make Static Model.findByCredentials. But it is not working for mongoose, Express login system? - express

userSchema.statics.findByCredentials = async (email, password) =>{
const user =await User.findOne({ email })
if(!user){
throw new Error("Unable to Login!")
}
const isMatch = await bcrypt.compare(password, user.password)
if (!isMatch){
throw new Error("Invalid to Login!!")
}
return user
}
const User = new mongoose.model("User",userSchema)
module.exports = User
In users i have set the routes properly too:
router.post("/users/login", async (req,res) => {
try{
const user = await User.findByCredentials(req.body.email, req.body.password)
res.send(user)
}
catch(err){
res.status(400).send()
}
})
But i get 400 Bad request error. The route is catching the error.
findByCredentials is not working?
What is my mistake??

Related

how to delete cookie without reloading the page using custom express server in next js

this is my routes file
const User = require("./schema");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const express = require("express");
const server2 = express();
const routes = (server,app) => {
// this route is for signup
server.post("/api/signup", async (req,res) => {
const { fullName, emailId, password }=req.body;
const signupData = new User({
fullName,
emailId,
password: await bcrypt.hash(password,10),
});
const token = await signupData.generateToken();
console.log(`token: ${token}`);
if (token != undefined) {
res.cookie("token",token,{
httpOnly: true,
secure: true,
sameSite: "strict",
path: "/",
maxAge: 1000*60*2
})
res.send({message:"signedup successfuly"});
res.end();
}
const saveUser = await signupData.save();
});
// this route is for user varification
server.get("/api", async (req,res) => {
const token = req.cookies.token;
console.log(`token: ${token}`);
if (token != undefined) {
const _id = jwt.verify(token,process.env.JWT_SECRET)._id;
const findUser = await User.findOne({ _id });
res.send(findUser);
} else {
res.send({fullName:""});
}
});
// this route is for logout
server.get("/api/logout",async (req, res) => {
try {
const token = req.cookies.token;
const _id = jwt.verify(token, process.env.JWT_SECRET)._id;
await User.updateOne({ _id }, { $pull: { tokens: { token }}});
res.clearCookie("token");
console.log(req.cookies.token)
res.send({message:""})
res.end();
} catch(err) {
console.log(err)
}
});
}
module.exports = routes;
When I do signup cookie is setting without reloading the page its working but that's not a problem the problem is when I do logout its not deleting cookie without reloading the page when I reload the page its working but without reloading the page its not working I am using custom express server in nextjs

Deleting user profile Mongoose and Express

I am creating a route from back end to be able to delete a profile once its been created but Ienter image description here am getting an error from postman saying it cant be done, please see screenshot attached
when I create the route i feel like i have done it right, my code is below, please let me know if you can help
const express = require('express');
const { defaultProxyHeaderWhiteList } = require('request/request');
// To use the express router
const router = express.Router();
const auth = require('../../middleware/auth');
const { check, validationResult } = require('express-validator');
const Profile = require('../../models/Profile');
const User = require('../../models/User');
const { normalizeType } = require('express/lib/utils');
const res = require('express/lib/response');
// #Route GET api/profile/me
// #description Get current users profile
// #access Private
router.get('/me', auth, async (req, res) => {
try {
// Pertains to Profile Model user id
const profile = await Profile.findOne({ user : req.user.id }).populate('user', ['name', 'avatar']);
if(!profile) {
return res.status(400).json({ msg: 'There is no profile for this user'});
}
// Returns the profile
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
// #Route POST api/profile
// #description Create or update user profile
// #access Private
router.post(
'/',
auth,
check('status', 'Status is required').notEmpty(),
check('skills', 'Skills is required').notEmpty(),
async (req, res) => {
const errors = validationResult(req);
// Check For Errors
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
company,
website,
location,
bio,
status,
githubusername,
skills,
youtube,
facebook,
twitter,
instagram,
linkedin
} = req.body;
// Build Profile Object
const profileFields = {};
profileFields.user = req.user.id;
if (company) profileFields.company = company;
if (website) profileFields.website = website;
if (location) profileFields.location = location;
if (bio) profileFields.bio = bio;
if (status) profileFields.status = status;
if (githubusername) profileFields.githubusername = githubusername;
if (skills) {
profileFields.skills = skills.split(',').map(skill => skill.trim());
};
// Build Social Media Object
profileFields.social = {};
if (youtube) profileFields.social.youtube = youtube;
if (twitter) profileFields.social.twitter = twitter;
if (facebook) profileFields.social.facebook = facebook;
if (linkedin) profileFields.social.linkedin = linkedin;
if (instagram) profileFields.social.instagram = instagram;
try {
let profile = await Profile.findOne({ user: req.user.id });
// Search for profile
if (profile) {
// Update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
);
return res.json(profile);
}
// Create Profile
profile = new Profile(profileFields);
await profile.save();
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
};
;});
// #Route GET api/profile
// #description Get all profiles
// #access Public
router.get('/', async (req, res) => {
try {
const profiles = await Profile.find().populate('user', ['name', 'avatar']);
res.json(profiles);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
// #Route GET api/profile/user/:user_id
// #description Get all profiles by user ID
// #access Public
router.get(
'/user/:user_id',
async (req, res) => {
try {
const profile = await Profile.findOne({ user: req.params.user_id }).populate('user', ['name', 'avatar']);
if (!profile)
return res.status(400).json({ msg: 'Profile not found1'});
res.json(profiles);
} catch (err) {
console.error(err.message);
if (err.kind == 'ObjectId') {
({ msg: 'Profile not found' });
}
res.status(500).send('Profile Not Found2')
}
});
// #Route DELETE api/profile/user/:user_id
// #description Delete Profile, User and Posts
// #access Private
router.get(
'/user/:user_id', auth, async (req, res) => {
try {
// Remove Profile
await Profile.findOneAndRemove({ user: req.user.id });
// Remove User
await User.findOneAndRemove({ _id: req.user.id });
res.json({ msg: 'User Deleted' });
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
module.exports = router;
Try replacing the route with this:
// #Route DELETE api/profile/user/:user_id
// #description Delete Profile, User and Posts
// #access Private
router.delete(
'/user/:user_id', auth, async(req, res) => {
try {
// Remove User
const data = await User.findByIdAndRemove(req.user.id);
if (!data) {
res.json({
success: false,
message: "user not found"
});
return;
}
// Remove Profile
const profile = await Profile.deleteOne({
user: mongoose.Types.ObjectId(req.user.id)
});
if (!profile) {
res.json({
success: false,
message: "profile not found"
});
return;
}
res.json({
success: true,
message: "User Deleted Successfully"
});
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});

How can I access the logged in user name on Netlify?

I'm having trouble understanding how handle functions on Netlify. In particular, I want to access the user's id when they login.
I have enabled identity on my netlify site and I can login and log out.
<button data-netlify-identity-button id="login"></button>
I have created a function identity-login that I think should handle the user's details, but I cannot see how to utilise it on the web-page
// functions/identity-login.js
exports.handler = async function (event, context) {
const { identity, user } = context.clientContext;
console.log(identity, user)
return {
statusCode: 200,
body: 'hello'
}
};
The function endpoint is
https://silly-parrot.netlify.app/.netlify/functions/identity-login
I have this in the script on my page, but I don't know how to call it or if it's correct
async function apiCall() {
const url = `/.netlify/functions/identity-login`;
try {
const response = await fetch(url);
const data = await response;
console.log(data)
return data;
} catch (err) {
console.log(err);
}
}
What should I do?
I now realise that I was taking the wrong approach. It is not necessary to use the Netlify identity-login event. The netlifyIdentity object provides the necessary functionality for identifying when the user logs in or logs out and to discover whether or not the user is logged in when the page loads (init). The user identity is contained in the user.token.access_token
The following code is within my main js script (you will of course need to access the netlifyIdentity object)
<script type="text/javascript" src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
And then setup async functions to handle the authorisation events
<script>
var token = '';
var logged_in = false;
async function started() {
logged_in = false;
netlifyIdentity.on('init', async user => {
if(user) {
token = user.token.access_token;
logged_in = true;
}
console.log('init', logged_in, token);
})
netlifyIdentity.on('login', user => {
if(user) {
logged_in = true;
token = user.token.access_token;
}
console.log('log in', logged_in, token);
})
netlifyIdentity.on('logout', () => {
token = '';
logged_in = false;
console.log('log out', logged_in, token);
})
}
started()
</script>

display data on page when user is auth, express , jwt, cookie-parser

I have simple application where user can register and login in his acc, now i want display user login on page, how i can get data from db about user that authinticated now
i also use mongodb and moongose as database
this register sistem
router.post('/register',async (req,res)=>{
const {login,mail,password} = req.body
bcrypt.hash(password, 10).then((hash) =>{
User({login:login,password:hash,mail:mail}).save()
})
res.redirect('/login')
})
this is login sistem
router.post('/',async (req,res)=>{
const {mail, password } = req.body
const user = req.body
console.log(user)
const isUserExist = await User.findOne({mail:mail})
const UserPwdCorrect = isUserExist.password
if(!isUserExist){
console.log('Логин гавно')
} else{
bcrypt.compare(password,UserPwdCorrect).then((match)=>{
if(!match){
console.log("Пароль говно")
} else{
const accessToken = createToken(user)
res.cookie("token",accessToken,{
maxAge:60*60*24*30*1000
})
res.redirect('/')
}
})
}
})
and this is what i did in jwt.js file
const {sign,verify} = require("jsonwebtoken")
const createToken = (user) =>{
const accessToken = sign({login: user.login, isAdmin:user.idAdmin,id:user.id},"jwt-secret")
return accessToken
}
const validateToken = (req,res,next) =>{
const accessToken = req.cookies["token"]
console.log(accessToken)
if(accessToken){
try {
const validtoken = verify(accessToken,"jwt-secret")
if(validtoken){
req.authenticated = true
return next()
} else{
return next()
}
} catch(err){
console.log(err)
}
}
}
Here's one solution:
Pass in userID in the JWT token. When the user clicks on the profile page, send a POST request to an endpoint that accepts the token (in a header). The backend verifies the token, extracts the userID, makes the DB call, and finally returns the response.
An advantage to this approach is that your profile route is authenticated (i.e, the route is secure).

Jest testing of async middleware for authentication

I'm using a static array to scaffold a user table, prior to refactoring with actual postgres db and some fetch()-ing code. At present, the tests work, but obviously they are working synchronously. Here's the placeholder API code:
// UserAPI.js
let findUserById = (credentials = {}) => {
const { userId } = credentials
if (userId) {
const foundUser = users.find(user => user.id === userId)
if (foundUser !== undefined) {
const { password: storedpassword, ...user } = foundUser
return user
}
}
return null
}
exports.byId = findUserById
And an example test as follows:
// excerpt from TokenAuth.test.js
const UserAPI = require('../lib/UserAPI')
describe('With TokenAuth middleware', () => {
beforeEach(() => {
setStatus(0)
})
it('should add user to req on authorised requests', () => {
const token = createToken(fakeUser)
const authReq = { headers: { authorization: 'Bearer ' + token } }
const myMiddleware = TokenAuth(UserAPI.byId)
myMiddleware(authReq, fakeRes, fakeNext)
// expect(authReq.user).toStrictEqual({ id: 1, username: 'smith#example.com' });
expect(authReq.user.username).toStrictEqual('smith#example.com')
expect(authReq.user.id).toStrictEqual(1)
})
})
This runs fine, and along with other tests gives me the coverage I want. However, I now want to check that the tests will deal with the async/await nature of the fetch() code I'm going to use for the proper UserAPI.js file. So I re-write the placeholder code as:
// UserAPI.js with added async/await pauses ;-)
let findUserById = async (credentials = {}) => {
const { userId } = credentials
// simulate url resolution
await new Promise(resolve => setTimeout(() => resolve(), 100)) // avoid jest open handle error
if (userId) {
const foundUser = users.find(user => user.id === userId)
if (foundUser !== undefined) {
const { password: storedpassword, ...user } = foundUser
return user
}
}
return null
}
exports.byId = findUserById
... at which point I start getting some lovely failures, due I think it's returning unresolved promises.
My problem is two-fold:
How should I alter the UserAPI.test.js tests to deal with the new async nature of findUserByCredentials() ?
Am I ok in my assumption that ExpressJS is happy with async functions as request handlers? Specifically, due to the async nature ofUserAPI.findUserByCredentials is this ok?
Main App.js uses curried UserAPI.byId() for the findUserById.
// App.js (massively simplified)
const express = require('express')
const TokenAuth = require('./middleware/TokenAuth')
const RequireAuth = require('./middleware/RequireAuth')
const UserAPI = require('./lib/UserAPI')
let router = express.Router()
const app = express()
app.use(TokenAuth(UserAPI.byId))
app.use(RequireAuth)
app.use('/users', UserRouter)
module.exports = app
My TokenAuth middleware would now run along these lines:
// TokenAuth.js (simplified)
const jwt = require('jsonwebtoken')
require('dotenv').config()
const signature = process.env.SIGNATURE
let TokenAuth = findUserById => async (req, res, next) => {
let header = req.headers.authorization || ''
let [type, token] = header.split(' ')
if (type === 'Bearer') {
let payload
try {
payload = jwt.verify(token, signature)
} catch (err) {
res.sendStatus(401)
return
}
let user = await findUserById(payload)
if (user) {
req.user = user
} else {
res.sendStatus(401)
return
}
}
next()
}
module.exports = TokenAuth
A partial answer us simply to add an async/await on the middleware call:
it('should add user to req on authorised requests', async () => {
const token = createToken(fakeUser)
const authReq = { headers: { authorization: 'Bearer ' + token } }
const myMiddleware = TokenAuth(UserAPI.byId)
await myMiddleware(authReq, fakeRes, fakeNext)
// expect(authReq.user).toStrictEqual({ id: 1, username: 'smith#example.com' });
expect(authReq.user.username).toStrictEqual('smith#example.com')
expect(authReq.user.id).toStrictEqual(1)
})