JSON Parse error: Unexpected identifier "Not found" - node.js

fetch('http://192.168.120.100:8080/login', {
method: 'POST',
body: JSON.stringify(SignInData),
headers: {
'Content-Type': 'application/json'
}
})
.then((response)=>response.json())
.then((user)=>{
if(user.status=="success"){
alert("success")
console.log("success");
}else{
alert("error")
console.log("fail");
}
})
.catch((error)=>{
console.log("Error, with message::",error)
});
}
and my server code is
router.post('/login', function (req, res) {
User.findOne({ email: req.body.email }).then((user) => {
console.log('testing' + JSON.stringify(user));
if (!user) return res.status(404).send("Not found");
//check password matches
if (user.password == req.body.password) {
user.status = "Success";
res.status(200).send('success');
} else {
res.status(404).send('Invalid Password');
}
})
.catch((err) => {
res.status(500).send(err);
});
});
});
i am working on signin form and my backend is working fine but while running on react native i am getting an error JSON Parse error: Unexpected identifier "Not".is it a json error ?

Looks like the problem is when you are passing the "Not found" in the case user not found , well for that matter even 'success'
On the UI side when you call .then((response)=>response.json()) It tries to change the response to a json format, whereas your API is returning String "Not Found" which does not conform to json structure.
as for solution you can pass JSON in all scenarios, you might need to change your UI accordingly.
router.post('/login', function (req, res) {
User.findOne({ email: req.body.email }).then((user) => {
console.log('testing' + JSON.stringify(user));
var result = {};
if (!user) {
result.message = "Not Found"
return res.status(404).send(result);
}
//check password matches
if (user.password == req.body.password) {
user.status = "Success";
result.message = "Success"
res.status(200).send(user);
} else {
result.message = "Invalid Password";
res.status(404).send(result);
}
})
.catch((err) => {
res.status(500).send(err);
});
});
});

Related

Getting error while logging in 402 (Payment Required)

I don't understand it. I am not able to login. User is already in my database, and when I log in, it simply says:
POST http://localhost:3000/api/v1/users/login 402 (Payment Required)
When I register for the first time, and then login, login is successful. If I logout, and then try to log in with that same email and password, it's throwing me the above error. I'm not even using someone's API. It's my own created one. It's sending me a response of "incorrect password"
Here's the controller:
loginUser: (req, res, next) => {
const { email, password } = req.body
if (!email || !password) {
return res.status(400).json({ message: "Email and password are must" })
}
User.findOne({ email }, (err, user) => {
if (err) {
return next(err)
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invalid email" })
} else if (!user) {
return res.status(402).json({ error: "User not found" })
} else if (!user.confirmPassword(password)) {
return res.status(402).json({ error: "incorrect password" })
}
})
}
User model
const mongoose = require("mongoose")
const bcrypt = require("bcrypt")
const Schema = mongoose.Schema
const userSchema = new Schema({
username: { type: String, required: true },
email: { type: String, reuired: true },
password: { type: String, required: true },
posts:[{ type: Schema.Types.ObjectId, ref: "Post" }]
}, { timestamps: true })
userSchema.pre("save", function (next) {
if (this.password) {
const salt = bcrypt.genSaltSync(10)
this.password = bcrypt.hashSync(this.password, salt)
}
next()
})
userSchema.methods.confirmPassword = function (password) {
return bcrypt.compareSync(password, this.password)
}
const User = mongoose.model("User", userSchema)
module.exports = User
registration controller
registerUser: (req, res) => {
const { username, email, password } = req.body
User.create(req.body, (err, createdUser) => {
if (err) {
return res.status(500).json({ error: "Server error occurred" })
} else if (!username || !email || !password) {
return res.status(400).json({ message: "Username, email and password are must" })
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invaid email" })
} else if (password.length < 6) {
return res.status(400).json({ message: "Password should be of at least 6 characters" })
}
else {
return res.status(200).json({ user: createdUser })
}
})
}
Edit
loginUser: async (req, res, next) => {
const { email, password } = req.body
if (!email || !password) {
return res.status(400).json({ message: "Email and password are must" })
}
await User.findOne({ email }, (err, user) => {
if (err) {
return next(err)
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invalid email" })
} else if (!user) {
return res.status(402).json({ error: "User not found" })
} else if (!user.confirmPassword(password)) {
return res.status(402).json({ error: "incorrect password" })
}
})
}
new post controller
newPost: (req, res) => {
const data = {
title: req.body.title,
content: req.body.content,
user: req.user.userId
}
Post.create(data, (err, newPost) => {
if (err) {
return res.status(500).json({ error: err })
} else if (!newPost) {
return res.status(400).json({ message: "No Post found" })
} else if (newPost) {
User.findById(req.user.userId, (err, user) => {
user.posts.push(newPost._id) //pushing posts documnet objectid to the post array of the user document
user
.save()
.then(() => {
return res.json(200).json({ user })
})
.catch(err => {
return res.status(500).json({ error: err })
})
})
}
})
}
You might want to refactor your code so that you do the bcrypt operations in controller not in the model. You are checking this.password after the user is updated (creating new posts) and since this is the user, the below code is being met each time you update the user object.
if (this.password) {
const salt = bcrypt.genSaltSync(10)
this.password = bcrypt.hashSync(this.password, salt)
}
So your hashing it every time you update the user (create a post). Instead, remove the above code from the userSchema.pre(...) and try doing the bcrypt hashing only when the user first registers.
registerUser: (req, res) => {
var { username, email, password } = req.body
if (password) {
const salt = bcrypt.genSaltSync(10)
password = bcrypt.hashSync(password, salt)
}
User.create(req.body, (err, createdUser) => {
if (err) {
return res.status(500).json({ error: "Server error occurred" })
} else if (!username || !email || !password) {
return res.status(400).json({ message: "Username, email and password are must" })
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invaid email" })
} else if (password.length < 6) {
return res.status(400).json({ message: "Password should be of at least 6 characters" })
}
else {
return res.status(200).json({ user: createdUser })
}
})
}
This way the hashing occurs only once at the creation of the user and should remain consistent throughout other operations.
As for the Can't set headers after they are sent error, you might be sending a response twice, since the error appears to come from the posts controller. You are likely sending the user response and the post response. Maybe don't send the posts response since you will be sending it along in the user response.
More info on the error here.

Post request sends undefined data inn flutter app

I was working on a simple app with login functionality , but im unable to send username and password properly to nodejs server. I have tried encoding it, putting it as Map and FormData, but nothing seems to workout. I console logged the request body and it prints "undefind"
I'm using Dio dart package for making http requests and Redux and redux thunk to dispatch actions .
//Code on My flutter app
ThunkAction<AppState> login(LoginData data) {
return (Store<AppState> store) async {
store.dispatch(IsLoading(true));
try {
Response response = await Dio().post(
"http://10.0.2.2:4000/api/user/login",
data: json.encode({"phone": data.phone, "password": data.password}));
if (response.statusCode == 200) {
print(json.decode(response.data));
store.dispatch(IsLoading(false));
}
} catch (e) {
print("Error :(");
}
};
}
// Code on My nodejs
router.post("/login", (req, res) => {
//this log prints undefined
console.log("Login route: " + req.body.phone);
var cred = {
phone: req.body.phone,
password: req.body.password
};
User.findOne({ phone: cred.phone })
.then(result => {
if (!result) {
res.status(400).json({ msg: "no user" });
} else {
bcrypt.compare(req.body.password, result.password, (err, isMatch) => {
if (isMatch) {
const payload = { id: result._id };
console.log("Logged in :" + payload);
jwt.sign(
payload,
keys.secretOrKey,
{ expiresIn: 7200 },
(err, token) => {
res.status(200).json({
success: true,
token: "Bearer " + token
});
}
);
} else {
res.status(400).json({ msg: err });
}
});
}
})
.catch(err => {
res.status(400).json({ msg: err });
});
});
To access parameter in server side add this header to you request:
HttpHeaders.contentTypeHeader: 'application/x-www-form-urlencoded'

Getting 400 Bad Request despite catching the err in angular2+

I have designed a login page where login is successful when i put a correct login and password and Login doesn't happen when I put an incorrect username or password which is correct. However, I get this error:
POST http://localhost:3003/login/authenticate 400 (Bad Request)
ERROR HttpErrorResponse {headers: HttpHeaders, status: 400, statusText: "Bad Request", url: "http://localhost:3003/login/authenticate", ok: false, …}
Everything works properly however, I get the error in the console. Like this:
I want the 400 bad request error to not appear in the console. How to do that?
login.component.ts
login(data) {
console.log("Inside Login");
this.authenticateObj = {
username: data.username,
password: data.password
}
this.http.post("http://localhost:3003/login/authenticate",
this.authenticateObj)
.map(Response => Response)
.catch((err) => {
console.log("err =", err)
alert('Login Failed. Username or Password
is incorrect');
return Observable.throw(err);
})
.subscribe((res: Response) => {
console.log("Inside login authenticate subscribe");
this.info = res;
if (this.info.message == 'Login Successful.') {
console.log("test after login = ", this.info);
if (localStorage.getItem('username') &&
localStorage.getItem('token')) {
alert('Login Successful');
this.router.navigate(['/file-upload/wsdl']);
} else {
this.notification.Error('Unauthorized');
}
}
if (this.info.message == 'error') {
alert('Login Failed');
}
else if (this.info.status == 400) {
alert('Login Failed');
}
})
}
login.controller.js
function authenticateUser(req, res, next) {
console.log("Inside authenticateUser = ", req.body)
LoginService.authenticate(req,req.body)
.then(function (token) {
if (token) {
res.setHeader("authorization",token.token);
res.send({
message: 'Login Successful.',
response: token
});
} else if(res.message == 'Username or Password is
incorrect'){
res.status(401).send({
message: 'Unauthorized. '
});
}
else {
console.log("inside controller, else res.status-400");
res.status(400).send({
message: 'Username or password is incorrect'
});
}
})
.catch(function (err) {
console.log("inside controller, catch res.status 400")
// res.status(400).send(err);
res.status(400).send({
message: 'Username or password is incorrect'
});
});
}
In order to handle errors from server properly, you have to catch them in the subcribe() method of the Observable returned by http.post from Rxjs:
this.http.post("http://localhost:3003/login/authenticate", this.authenticateObj)
.subscribe(
(res: Response) => {
// code when no error...
},
err => {
// error handling...
},
() => {
// finally...
}
);
IMO Bad request is an incorrect response by your server for incorrect username/password combination. You can return a "401" or a "200" itself depending on your requirement.
Now if you want the error not to appear in the console then add an error callback in your subscribe().
this.http.post("http://localhost:3003/login/authenticate", this.authenticateObj)
...
// rest of the code
.subscribe((res: Response) => {
// your code
}, (error) => {
// handle the error here, show some alerts, warnings, etc
console.log(error)
})

Add test data for mocha test using before()

I am trying to add test data for my test:
const chai = require("chai");
const expect = require("chai").expect;
chai.use(require("chai-http"));
const app = require("../server.js"); // Our app
const user = require("../app/controllers/user.controller.js");
describe("API endpoint /users", function() {
this.timeout(5000); // How long to wait for a response (ms)
before(function() {
const users = [
{
email: "ssss#ss.com",
givenName: "eee",
familyName: "www2"
},
{
email: "ssss#ss.com",
givenName: "eee",
familyName: "www2"
}
];
user.create(users);
done();
});
// GET - List all data
it("should return all users", function() {
return chai.request(app).get("/users").then(function(res) {
expect(res).to.have.status(200);
expect(res).to.be.json;
expect(res.body).to.be.an("array");
});
});
});
I get the error:
1) API endpoint /users
"before all" hook:
TypeError: Cannot destructure property email of 'undefined' or 'null'.
at Object.exports.create (app\controllers\user.controller.js:5:13)
How can I add test data?
Controller:
const user = require("../models/user.model.js");
const validator = require("email-validator");
// Create and Save a new user
exports.create = (req, res) => {
const { query: { email, givenName, familyName } } = req;
// Validate request
if (!validator.validate(email) || !givenName || !familyName) {
return res.status(400).send({
message:
"Please use a valid email address, given name and family name."
});
}
// Create a user
const User = new user({
email,
givenName,
familyName
});
// Save user in the database
User.save()
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Error occurred while creating the user."
});
});
};
// Retrieve and return all users from the database.
exports.findAll = (req, res) => {
user
.find()
.then(users => {
res.send(users);
})
.catch(err => {
res.status(500).send({
message:
err.message || "An error occurred while retrieving users."
});
});
};
// Find a single user with a userId
exports.findOne = (req, res) => {
user
.findById(req.params.userId)
.then(user => {
if (!user) {
return res.status(404).send({
message: "user not found with id " + req.params.userId
});
}
res.send(user);
})
.catch(err => {
if (err.kind === "ObjectId") {
return res.status(404).send({
message: "user not found with id " + req.params.userId
});
}
return res.status(500).send({
message: "Error retrieving user with id " + req.params.userId
});
});
};
// Update a user identified by the userId in the request
exports.update = (req, res) => {
// Validate Request
if (!req.body.content) {
return res.status(400).send({
message: "user content can not be empty"
});
}
// Find user and update it with the request body
user
.findByIdAndUpdate(
req.params.userId,
{
title: req.body.title || "Untitled user",
content: req.body.content
},
{ new: true }
)
.then(user => {
if (!user) {
return res.status(404).send({
message: "user not found with id " + req.params.userId
});
}
res.send(user);
})
.catch(err => {
if (err.kind === "ObjectId") {
return res.status(404).send({
message: "user not found with id " + req.params.userId
});
}
return res.status(500).send({
message: "Error updating user with id " + req.params.userId
});
});
};
// Delete a user with the specified userId in the request
exports.delete = (req, res) => {
user
.findByIdAndRemove(req.params.userId)
.then(user => {
if (!user) {
return res.status(404).send({
message: "user not found with id " + req.params.userId
});
}
res.send({ message: "user deleted successfully!" });
})
.catch(err => {
if (err.kind === "ObjectId" || err.name === "NotFound") {
return res.status(404).send({
message: "user not found with id " + req.params.userId
});
}
return res.status(500).send({
message: "Could not delete user with id " + req.params.userId
});
});
};
create function expects a single user while it receives an array of users as an argument. The problem with it is that it's a middleware, it doesn't return a promise, so it cannot be efficiently chained. It also causes side effects and calls res.send while this is not needed for what it's used here.
Mongoose model should be used directly here, its create accepts an array. The block should return a promise in order to not cause race conditions in tests:
const User = require(".../user.model.js");
...
before(function() {
const users = [...];
return User.create(users);
});

passport local strategy's not getting called

I'm currently making app with vue & express.
I adopted passport as authentication library and I've used it several times.
so I know that when I make login request, passport middleware authenticates user by 'xx strategy'.
The problem is register request works well but login isn't.
I constantly get 'false' for response.data.
I can't even guess where the false comes from.
There is no return statements that returns false.
follow is my code.
passport.deserializeUser((authId, done) => {
let hasUser
let users = User.findOneByAuthId(authId)
.then(results => (hasUser = results.length))
if (hasUser) {
console.log('deserialize!')
done(null, users[0])
} else {
console.log('no user')
done(null, { message: 'no user' })
}
})
passport.use(new LocalStrategy(
(username, password, done) => {
let hasUser
let users = User.findOneByEmail(username)
.then(results => (hasUser = results.length))
if (hasUser) {
let user = users[0]
let { hash } = user
if (User.checkPassword(password, hash)) {
done(null, { message: 'success' })
} else {
done(null, { message: 'wrong password' })
}
} else {
done(null, { message: 'wrong email' })
}
}
))
router.post('/register', (req, res) => {
if (!fun.emailChecker(req.body.username)) {
return res.status(403).json({
message: 'Invalid Email'
})
}
if (!fun.passwordChecker(req.body.password)) {
return res.status(403).json({
message: 'Invalid Password'
})
}
let hasUser
User.findOneByEmail(req.body.username)
.then(results => (hasUser = results.length))
if (hasUser) {
return res.status(409).json({
message: 'Email Exist'
})
} else {
let user = {
authId: 'local: ' + req.body.username,
email: req.body.username,
hash: User.hashPassword(req.body.password),
displayName: req.body.displayName
}
User.create(user)
.then(results => {
if (!results) {
throw new Error('user creation error')
} else {
req.login(user, err => {
if (!err) {
req.session.save(() => {
return res.json({ success: true })
})
}
})
}
})
}
})
router.post('/login', (req, res) => {
passport.authenticate('local', (err, result) => {
if (!err) {
return res.json(result)
}
})(req, res)
})
// vue component
methods: {
onSubmit () {
axios.post('http://localhost:3001/auth/login', {
email: this.email,
password: this.password
}).then(response => console.log(response.data))
},
There are various issues with your code.
Starting with incorrect promise handling:
let hasUser
let users = User.findOneByAuthId(authId)
.then(results => (hasUser = results.length))
if (hasUser) { ... }
You are trying to make asynchronous code synchronous here. The code that depends on the result of the asynchronous query has to be moved to inside the then handler (both in deserializeUser and the strategy verification handler):
User.findOneByAuthId(authId).then(users => {
let hasUser = users.length;
if (hasUser) {
console.log('deserialize!')
done(null, users[0]);
} else {
console.log('no user')
done(Error('no user'));
}
});
(I'm not quite sure why your method findOneByAuthId, whose name implies that there will be at most one result, could result in an array)
Also, you're not using the correct convention for passing user data and login errors back to Passport:
if (User.checkPassword(password, hash)) {
done(null, { message: 'success' })
} else {
done(null, { message: 'wrong password' })
}
This should look like this (and obviously, other places where done is called incorrectly should be fixed too):
if (User.checkPassword(password, hash)) {
done(null, user);
} else {
done(null, false, { message: 'wrong password' })
}
(documented here under "Verify Callback")
Finally, you're using passport.authenticate() incorrectly, which is probably the cause of the false being returned. Instead, try this:
router.post('/login', passport.authenticate('local'), (req, res) => {
return res.json(req.user); // or whatever you want to return in case of login success
})
(documented here; if you want to use a custom callback, look for "Custom Callback" on that page)

Resources