Issues populating mongoose document after model query - javascript

First time on SO so I'm hoping this goes well.
I'm using Mongoose on a current project and until now I haven't had any issues. As the title states, after querying for a document and verifying that document actually exists in the database using a simple console.log, I can't get my document's object references to populate when I use the populate method.
I'm working on a simple authentication route. My client document is broken into two object references, login and user profiles. In my query I'm searching for a client document where the login profile object reference id matches a previously queried login profile's id. Then I want to populate both the user profile and login profile on the client document, then return the client document.
My console log is showing the client document but the population methods don't seem to be executing. Code is below.
const login = await LoginProfile.findOne({ email });
if (login === null) {
console.log("Account doesn't exist.");
} else {
let validPassword = await bcrypt.compare(password, login.password);
if (!validPassword) {
console.log("Email or Password is incorrect");
} else {
const clientDoc = await Client.findOne({
loginProfile: login,
});
console.log(clientDoc.populate("userProfile").populate("loginProfile");
}
}
I'm probably doing this all wrong but I'm self taught and I'm trying. Thanks for whatever solutions you may have. If you have other ways of implementing this, please share! Thanks!

Welcome to Stack Overflow, MrGeonDeaux
Instead of :
console.log(clientDoc.populate("userProfile").populate("loginProfile"));
You could populate the documents on finding, here's the full snippet:
const login = await LoginProfile.findOne({ email });
if (login === null) {
console.log('Account doesn\'t exist.');
} else {
const validPassword = await bcrypt.compare(password, login.password);
if (!validPassword) {
console.log('Email or Password is incorrect');
} else {
const clientDoc = await Client.findOne({
loginProfile: login
}).populate('userProfile loginProfile');
console.log(clientDoc);
}
}

Related

Trying to use fetchSignInMethodForEmail

I am trying to discover how to make a statement appear when someone registering to the form that I was made but the email address was already used. I am using firebase. I am not familiar with fetchSignInForEmail and am wondering how to use it and implement it.
I am thinking I can use an if statement
if(email exists) {
push firebase user to directed page
} else {
statement.style.display === block
}
I am also curious on how to do this with passwords as well.
Thank you
Listen for that error. However, I prefer to merge the accounts and let the user sign in. Below is an example snippet. I've got this done for you, provided you want to allow email link authentication (no password required). Firebase offers a pre-rolled one as well that supports passwords and federation/oAuth (twitter, facebook, etc).
} catch (error) {
if(error.code === "auth/email-already-in-use"){
// REMEMBER AUTH CURRENT USER OBJECT
previousUser = firebase.auth().currentUser;
// WE MUST HANDLE DB READ AND DELETE WHILE SIGNED IN AS PREVIOUS USER PER FIRESTORE SECURITY RULES
if(localUserDoc){
if(localUserDoc.data().apples){
apples = localUserDoc.data().apples;
}
}
//DELETE CURRENT USER RECORD WHILE STILL SIGNED IN
await firebase.firestore().collection("users").doc(previousUser.uid).delete();
// CLEAN UP DONE. NOW SIGN IN USING EMAIL LINK CREDENTIAL
try {
var firebaseUserObj = await firebase.auth().signInAndRetrieveDataWithCredential(credential);
// FIRESTORE USER RECORD FOR EMAIL LINK USER WAS CREATED WHEN THEY ADDED APPLE TO CART
try {
var doc = await firebase.firestore().collection("users").doc(firebaseUserObj.user.uid).get();
if (doc.exists) {
if(doc.data().apples){
apples = apples + doc.data().apples;
}
}
await firebase.firestore().collection("users").doc(firebaseUserObj.user.uid).update({
apples: apples
});
} catch(error) {
console.log("Error getting document:", error);
}
previousUser.delete();
} catch (error) {
console.log(".signInWithCredential err ", error);
}
}
}

Unable to use mongoose model

I am coding a simple registration form using mongoose.
I have use a javascript file to process the values of the registration form.
Here is my registrationButtonAction.js
window.onload = function() {
var User = require('/models/Mongoose Database/user_database');
// this line is causing the problem
var registerButton = document.getElementById("registerMe");
var firstName = document.getElementById("firstName");
var lastName = document.getElementById("lastName");
var usernameRegister = document.getElementById("usernameRegister");
var passwordRegister = document.getElementById("passwordRegister");
var repasswordRegister = document.getElementById("repasswordRegister");
registerButton.onclick = function () {
if(!firstName.value || !passwordRegister.value || !repasswordRegister.value || !usernameRegister.value){
alert("Enter all required fields");
}else if (passwordRegister.value != repasswordRegister.value){
alert("Passwords must match");
}else {
var newUser = new User({
username : usernameRegister.value,
password : passwordRegister.value
});
User.find({username:usernameRegister.value}, function (error, user) {
if (error) throw error;
if(user){
window.location("/register");
}else {
newUser.save(function (error) {
if(error) throw error;
});
window.location("/login");
}
// user.comparePassword(passwordRegister.value, function (error, isMatch) {
// if (error) throw error;
//
// return 1;
//})
});
}
}
}
When I comment the var User = require('/models/Mongoose Database/user_database');, all the checks are working fine inside the onclick function. But when I uncomment it, it is not recognizing the button click.
I want to know whether this is a correct way of taking values from the registration page and storing them in a mongoose database.
You are mixing server and client code. Mongoose models and Node.js functions are not accessible inside window.onload on your client.
To put it simply, you need to create a REST API to perform database operations on the server. You have all the right tools aready, just need to reorder them.
The flow would be as such :
get the values entered in the browser
call an endpoint on your server (for example /api/createUser)
in the express router, have a route called /api/createUser in which you can access your User model and perform creation/deletion/update, etc.
My suggestion would be for you to go through this tutorial which should remove your confusion and bring you up to speed in no time. Good Luck!
Also, Passport can help you with authentication, but I believe you should first learn how to build a basic API. Authentication is a tricky beast ;)

password-hash-and-salt password verification fails

I'm using the nodeJS password-hash-and-salt library to encrypt password which I then store in a DB. This works fine. The problem comes in when I try to verify the password. Looking at the documentation, it should be simple... The example works flawlessly, but verifying a hash which was previously stored in a DB is failing. I've verified that the hash is not changing in-database, and that the hash is been returned when queried... I've also hashed a string and then tried to verify that string using the same string in-code (with no variables). I must be doing SOMETHING wrong... Anyone have any ideas? (Code below, library link here https://github.com/florianheinemann/password-hash-and-salt)
verifyPassword = function(user,pw){
// Connect to db
myuser = {};
var con = connect();
// Run query
con.query('SELECT UID,password FROM users WHERE username = ?', user, function(err,res){
if(err){ throw err; }
else {
myuser.userID = res[0].UID;
myuser.pswdV = res[0].password;
// Verifying hash
//console.log(pw);
//console.log(myuser.pswdV);
password(pw).verifyAgainst(myuser.pswdV, function(error, verified) {
//console.log(verified);
if(error)
throw new Error('Something went wrong!');
if(!verified) {
//socket.emit('popError','Invalid username or password. Please check your password and try again.');
//return {err:'Invalid username or password. Please check your password and try again.'}
console.log('Not verified');
} else {
var token = crypto.randomBytes(64);
token = buf.toString('hex');
myuser.secret = token;
delete myuser.pswdV;
con.query('UPDATE users SET magicSecret = ? WHERE username = ?', [token,user], function(err,res){
if(err) {
socket.emit('popError','Failed to login, this is a server problem.');
//return {err:'Failed to login, this is a server problem.'}
}
else {
socket.emit('login_success',myuser);
// return {err:myuser}
}
});
}
});
}
});
con.end(function(err) {
// The connection is terminated gracefully
// Ensures all previously enqueued queries are still
// before sending a COM_QUIT packet to the MySQL server.
});
};
Please excuse the debugging code... This should give you an idea of what I'm trying to do. If you see why it's failing please let me know.

Parse sessionToken revoked on user password update

My mobile hybrid app uses an expressJS server as the backend to proxy requests to parse.com via the REST API. I also use express for my own user authentication with an SSO provider. I've followed this tutorial and modified the approach a bit to work for my own setup (not using CloudCode, also not authenticating with GitHub). I'm also using the newish Revokable Sessions that came about earlier this year (March 2015?) Essentially the tutorial and my auth approach can be boiled down to doing the following on a remote backend (ExpressJS / CloudCode):
Login As User to Obtain Session Token
Create a new user if username doesn't already exist, and then continue
Create a new random password for the user (update the users password with masterKey)
With new password, log in as the user to generate the Parse sessionToken
Pass back the sessionToken to the client app
This all works fine, it seems to be the 'approach' for logging in with third-party authentication providers.
Problem is that each time my user logs in, the sessionToken essentially is re-created (as in, it destroys the old and creates a new token). I can see this in the dataBrowser as the session objectId is different. Also, and the main problem is that my user may have logged in on other devices, or on the web app, and essentially each time a user switches devices, the session token is invalidated on the other devices. Returning to that device then requires another login.
The new enhance session blog post mentions that the new revokable sessions provides for 'unique sessions' per device, however from my experience this doesn't seem to be working for users logging in over the REST API from my express backend. Perhaps this unique session would only work if the app itself was communicating to parse and thus would be able to pass along an installationId to distinguish the different devices.
I've posted my authentication code below, the parse object is from this npm parse library
upsertUser function:
/**
* This function checks to see if this user has logged in before.
* If the user is found, update their password in order to 'become' them and then return
* the user's Parse session token. If not found, createNewUser
*/
exports.upsertUser = function(ssoData, deferred) {
var userCreated = (typeof deferred != "undefined") ? true : false;
var deferred = deferred || q.defer();
var query = {
where: {username: ssoData.uid.trim()}
};
// set masterKey
parse.masterKey = parseConfig.MASTER_KEY;
// find existing user by username
parse.getUsers( query, function (err, res, body, success) {
if ( body.length ) {
var userId = body[0].objectId;
var username = body[0].username;
var password = new Buffer(24);
_.times(24, function (i) {
password.set(i, _.random(0, 255));
});
password = password.toString('base64');
parse.updateUser(userId, {password: password}, function (err, res, body, success) {
if ( typeof body.updatedAt != 'undefined' ) {
console.log('user update at: ', body.updatedAt);
parse.loginUser(username, password, function (err, res, body, success) {
deferred.resolve( body.sessionToken );
});
}
});
} else if ( userCreated === false ) {
console.log('object not found, create new user');
self.createNewUser(ssoData, deferred);
} else {
deferred.resolve();
}
});
return deferred.promise;
}
createNewUser function:
/**
* This function creates a Parse User with a random login and password, and
* Once completed, this will return upsertUser.
*/
exports.createNewUser = function(ssoData, deferred) {
// Generate a random username and password.
var password = new Buffer(24);
_.times(24, function(i) {
password.set(i, _.random(0, 255));
});
var newUser = {
username: ssoData.uid,
password: password.toString('base64'),
};
// Sign up the new User
parse.createUser(newUser, function(err, res, body, success) {
if (err) {
console.log('new parse user err', err)
}
if (typeof body.sessionToken != "undefined") {
self.upsertUser(ssoData, deferred);
} else {
deferred.resolve();
}
});
}
Any ideas how I can avoid invalidating sessionTokens upon subsequent logins?
Shoot, it seems there's a toggle on the settings page that I missed:
Revoke existing session tokens when user changes password
Simple as that i guess ;-) Still, I don't think I'll get unique sessions across devices.

Verify user password in Meteor

There are some irreversible actions that user can do in my app. To add a level of security, I'd like to verify that the person performing such an action is actually the logged in user. How can I achieve it?
For users with passwords, I'd like a prompt that would ask for entering user password again. How can I later verify this password, without sending it over the wire?
Is a similar action possible for users logged via external service? If yes, how to achieve it?
I can help with the first question. As of this writing, meteor doesn't have a checkPassword method, but here's how you can do it:
On the client, I'm going to assume you have a form with an input called password and a button called check-password. The event code could look something like this:
Template.userAccount.events({
'click #check-password': function() {
var digest = Package.sha.SHA256($('#password').val());
Meteor.call('checkPassword', digest, function(err, result) {
if (result) {
console.log('the passwords match!');
}
});
}
});
Then on the server, we can implement the checkPassword method like so:
Meteor.methods({
checkPassword: function(digest) {
check(digest, String);
if (this.userId) {
var user = Meteor.user();
var password = {digest: digest, algorithm: 'sha-256'};
var result = Accounts._checkPassword(user, password);
return result.error == null;
} else {
return false;
}
}
});
For more details, please see my blog post. I will do my best to keep it up to date.
I haven't done this before, but I think you will need something like this on your server
Accounts.registerLoginHandler(function(loginRequest) {
console.log(loginRequest)
var userId = null;
var username = loginRequest.username;
// I'M NOT SURE HOW METEOR PASSWORD IS HASHED...
// SO YOU NEED TO DO A BIT MORE RESEARCH ON THAT SIDE
// BUT LET'S SAY YOU HAVE IT NOW
var password = loginRequest.password;
var user = Meteor.users.findOne({
$and: [
{username: username},
{password: password}
]
});
if(!user) {
// ERROR
} else {
// VERIFIED
}
});
then you can call this function from the client side like this:
// FETCH THE USERNAME AND PASSWORD SOMEHOW
var loginRequest = {username: username, password: password};
Accounts.callLoginMethod({
methodArguments: [loginRequest]
});
I have a project on github for different purpose, but you can get a sense of how it is structured: https://github.com/534N/apitest
Hope this helps,
I have found the best way to validate the users password is to use the Accounts.changePassword command and
pass in the same password for old and new password. https://docs.meteor.com/api/passwords.html#Accounts-changePassword
Accounts.changePassword(this.password, this.password, (error) => {
if(error) {
//The password provided was incorrect
}
})
If the password provided is wrong, you will get an error back and the users password will not be changed.
If the password is correct, the users password will be updated with the same password as is currently set.

Categories

Resources