‫So in this lecture,
‫we're gonna manage our users passwords in the database.
‫And by that I mean to first validate
‫if the inputted password is equal to the confirmed password
‫and then also to encrypt the password in the database
‫in order to secure it against attacks.
‫And so the first thing that we're gonna do
‫is to validate if the two inputted passwords are the same.
‫And the best place to do that is here
‫in the confirm password, okay?
‫And so let's write our custom validator for that, all right?
‫So remember, we use the validate property
‫and then since we want to create a function
‫and also an error message, let's open a new object here
‫and then in there create validator,
‫which is gonna be the function
‫and let's actually start with this one.
‫So, remember, all we need here is to specify
‫a simple callback function which is then gonna be called
‫when the new document is created.
‫So, function,
‫and here again, we cannot use an arrow function
‫because we actually need to use the disk keyword.
‫Okay?
‫So, remember that from the validator function
‫we return either true or false
‫and if the return value is false,
‫then it means that we're gonna get a validation error, okay?
‫And, of course, if it's true, then not.
‫And so what we want here is to say that the current element
‫so, password confirm, is equal to this dot password,
‫and that's actually it!
‫So, for example, if password confirm is A-B-C,
‫and password is also A-B-C,
‫then this will of course return true, all right?
‫And so then the validation is passed
‫and no error will occur.
‫But, if the initial password is, let's say, X-Y-Z,
‫well then of course this is gonna return false
‫and we're gonna have a validation error, okay?
‫So, very simple, but we need to keep in mind
‫that this is only gonna work on save, okay?
‫So I talked about that before
‫when we used the custom validator on the tour model, right?
‫But I'm reminding you of that here again
‫because this is absolutely crucial here in this point, okay?
‫So let me actually write it down here for you.
‫(keyboard clicking)
‫On
‫save.
‫Okay?
‫And for this reason, whenever we want to update a user,
‫we will always have to use save as well
‫and not, for example, find one and update
‫like we did with our tours, okay?
‫So let's keep this in mind when we write
‫the rest of the code throughout the rest of the section
‫and especially for updating, okay?
‫Because let's say that we updated the user's password
‫simply with a regular update.
‫Then in that case, this password confirm validation
‫that we have here would no longer work, okay?
‫And of course that cannot happen, okay?
‫And so, again, keep in mind that this will only work
‫when we create a new object, so on dot create, or on save.
‫Okay?
‫So, on create and save,
‫All right?
‫So we create new object using create, right?
‫So, right here, used a dot create
‫but remember how I also showed you
‫that we can use a user dot save,
‫like this, right?
‫And in fact, we can also use a user dot save
‫in order to update the user, all right?
‫But again, more about it a bit later.
‫Okay?
‫So let's now actually try out this validation here, okay?
‫So first of all, let's actually
‫just try to create a new user
‫with this data here which should not work
‫because we already have a user with this email address
‫and we said that this one should be unique
‫and so it should not work.
‫Okay, and so of course our duplicate key error, right?
‫Now if you were in production, then of course
‫we already would get our nicely formatted error
‫that we created in the last section, right?
‫But right now we are in development and so that's the error
‫that we defined we want to see.
‫Okay?
‫So let's simply use another email here
‫and since we're working on the email here,
‫let's also see how the email address validation works.
‫So let's say that we specified this as our email.
‫And so, we see the error, "please provide a valid email."
‫Okay?
‫So let's test it just like this because I think that this
‫should also not be valid.
‫Maybe it is, but let's see.
‫And yeah, actually it's not because
‫there are no domain names with only one letter, okay?
‫And so this validator is pretty specific
‫so it's really good.
‫Now if we do it like this, then of course it should work.
‫But anyway, what we wanted to test here
‫is these different passwords, okay?
‫And I remember now that we actually
‫didn't create an error message, I believe.
‫And yeah, we didn't.
‫And so, let's add that here as well.
‫So message,
‫are not
‫the same.
‫Okay.
‫So let's add something here, doesn't matter.
‫And so now, passwords are not the same, okay?
‫So perfect.
‫And now of course our validation should be passed.
‫And indeed, it is and we created our new user.
‫Let's head over to Compass here,
‫take a look, and then actually delete it
‫so that I can later create more users with the same email.
‫All right?
‫And we don't want all this junk here anyway
‫so all these test users, okay?
‫But now, the next step is to actually encrypt
‫these plain passwords that we are storing
‫in our database right now.
‫So, as I mentioned in the last video,
‫when we are working with authentication,
‫one of the most fundamental principles
‫is to never ever store plain passwords in a database, okay?
‫So that is something that's absolutely not acceptable, okay?
‫So we should really always encrypt user's passwords
‫because imagine that for some reason,
‫a hacker gets access to the database.
‫If then the passwords are stored in plain text in there,
‫then he can simply login as any user
‫and then do whatever he really wants
‫and cause a lot of damage in some cases, okay?
‫And so we need to absolutely prevent that.
‫And so let's now go ahead and implement this.
‫Now, where is the best place to actually do that?
‫Well, I would argue that the model is always the best place
‫to do this kind of functionality.
‫So in this case, the encryption
‫because it really has to do with the data itself
‫and so it should be on the model
‫and not in the controller, okay?
‫So again, keep the fat models, thin controllers
‫philosophy in mind here.
‫All right?
‫So how are we gonna now implement this encryption?
‫Well, this is another perfect use case
‫for using Mongoose middleware.
‫And the one that we're gonna use
‫is a pre-save middleware.
‫So basically document middleware, okay?
‫So, remember that we defined that on the schema, okay?
‫And in this case, we want to set a pre-hook,
‫so a pre-middleware on save, all right?
‫And the reason why we're doing it like this
‫is that the middleware function
‫that we're gonna specify here, so the encryption,
‫is then gonna be happened between the moment
‫that we receive that data and the moment
‫where it's actually persisted to the database, okay?
‫So that's where the pre-save middleware runs.
‫Between getting the data and saving it to the database.
‫And so that's the perfect time to manipulate the data.
‫All right?
‫So,
‫a function, and then remember we have access
‫to the next function in order to call the next middleware.
‫Okay, now we actually only want to encrypt the password
‫if the password field has actually been updated, okay?
‫So basically only when really the password is changed
‫or also when it's created new, all right?
‫Because imagine the user is only updating the email.
‫Then in that case, of course,
‫we do not want to encrypt the password again, right?
‫And so we can do that with Mongoose.
‫And so we're gonna say, if and then this,
‫which refers to the current document, right?
‫And so in this case, to the current user
‫and then is modified.
‫Okay?
‫So we have a method on all documents which we can use
‫if a certain field has been modified.
‫And so here, we need to pass in the name of the field,
‫so "password."
‫Okay?
‫And so basically, what we want to do here
‫is to say that if the password has not been modified,
‫so not, then in that case, let's simply
‫return from this function and not run
‫any of the other code that's in here
‫and then call the next middleware.
‫Okay?
‫So again, if the password has not been modified,
‫then let's just exit this function
‫and call the next middleware.
‫Otherwise we will then run the code
‫that I'm gonna put in here.
‫And so now it's finally time to actually encrypt,
‫or as we can also say, to hash the password, okay?
‫So you will see the term "hash" or "hashing" all the time
‫and so that basically means encryption as well, okay?
‫Now we are gonna do this encryption, or hashing,
‫using a very well-known and well-studied
‫and very popular hashing algorithm called bcrypt.
‫Okay?
‫So this algorithm will first salt then hash our password
‫in order to make it really strong to protect it
‫against bruteforce attacks, all right?
‫And so that's the whole reason
‫why encryption needs to be really strong.
‫Because bruteforce attacks could try to guess
‫a certain passwords if it's not really strong encrypted.
‫And remember how I said that bcrypt will salt our password
‫and that just means that it's gonna add a random string
‫to the password so that two equal passwords
‫do not generate the same hash, okay?
‫Make sense?
‫Now I'm not gonna go into all the cryptographic details
‫on how this really works behind the scenes
‫and why we need such a complex system, okay?
‫But of course you can read all you want about bcrypt online.
‫There's really a ton of interesting stuff
‫to discover there, all right?
‫Anyway, let's now go ahead and use the bcrypt js package
‫in order to use this algorithm.
‫So,
‫so npm install
‫bcryptjs.
‫Okay?
‫And so this basically is a bcrypt implementation
‫for Javascript.
‫Okay?
‫Let's go back to our main terminal
‫and then go ahead and import it here.
‫And this one is by default only called bcrypt, okay?
‫And not bcryptjs.
‫(keyboard clicking)
‫All right.
‫And now, let's actually use it.
‫So, we want to say that this dot password,
‫so the current password in this document
‫should be equal to bcrypt dot hash
‫and then our current password.
‫Okay?
‫And then in here we need to specify a cost parameter, okay?
‫And we could actually do this in two ways.
‫So the first way will to be manually generating the salt,
‫so that random string basically,
‫that is gonna be added to our password
‫and then use that salt here in this hash function.
‫All right?
‫But instead, to make it a bit easier,
‫we can also simply pass a cost parameter
‫into this function here.
‫And so that is basically a measure
‫of how CPU intensive this operation will be, all right?
‫And the default value here I believe is 10,
‫but right now it's a bit better actually to use 12
‫because computers have become more and more powerful.
‫So like 20 years ago, you could have used eight here
‫and then a bit later than 10,
‫but right now at this point in time, it's best to use 12.
‫And so the higher this cost here,
‫basically the more CPU intensive the process will be
‫and the better the password will be encrypted, okay?
‫And of course we could go even higher,
‫but then it would take way too long, all right?
‫And I will show that to you in a second.
‫Okay?
‫But for now, let's actually finish this
‫because there is one thing left here.
‫So this hash here is actually the asynchronous version,
‫but there also is a synchronous version.
‫But as you already know, we do not want to use
‫the synchronous version because
‫that will block the event loop and then prevent other users
‫from using the application.
‫So just like we learned in the beginning.
‫And so of course we want to use
‫the asynchronous version which is this one.
‫And this will then return a promise
‫and that promise, of course, we need to await.
‫And so, we need to use await and then say that this function
‫is an async function, just like this.
‫So, let's recap that here.
‫So, we want to set our current password
‫basically to encrypt this version of the original password
‫with a cost of 12, not to make it too easy
‫to break the password, but also not to make the application
‫take too long for encrypting the password, all right?
‫So with this, we encrypted our password
‫and now in the end, what we need to do
‫is to basically delete the confirm password, all right?
‫Because at this point in time,
‫we only have the real password hashed, right?
‫So, this dot password confirm,
‫and how we basically delete the field,
‫so not to be persisted in the database
‫is to set it to undefined.
‫All right?
‫So, we really only need this password confirm here
‫for the validation that we implemented before.
‫So just to make sure that the user
‫actually inputted two equal passwords
‫so that he doesn't make any mistakes with his password.
‫Right?
‫And so after this validation was successful,
‫we actually no longer need this field
‫so we really do not want to persist it to the database.
‫And so that's why we simply set it here to undefined.
‫All right?
‫Now you might wonder why this works
‫because we actually set password confirm
‫to a required, right?
‫But that simply means that it's a required input,
‫not that it's required to actually be persisted
‫to the database, okay?
‫Now, just to finish, we of course need to also call next.
‫Okay?
‫Let's give it a save.
‫And actually I'm gonna add some comments here
‫to make it really clear for you.
‫So basically what this does, is to only run
‫this function
‫if password
‫was actually modified.
‫Then here,
‫hash the password with cost of 12.
‫And then,
‫delete the password confirm field.
‫Okay.
‫And now, let's go ahead and test this.
‫And I will now create a new user with exactly this data
‫and let's now take a look at the result.
‫And indeed, we now get this very weird looking password
‫which indeed is the encrypted version of pass1234.
‫And also, as you see, password confirm is no longer here.
‫Okay?
‫And so just like this, we now stored users
‫in a secure way in our database.
‫Let me now just show you how it will work
‫if we, for example, set it to 16 here.
‫And I need to change the email here.
‫And so that should now take a lot of time
‫and I'm not sure if I can even wait.
‫Oh, actually it took like four and a half seconds.
‫But that's still a bit too much I believe, okay?
‫So,
‫let's set it back to 12
‫and so that should be better, okay?
‫And now let's just, again, delete
‫these users here that we just created.
‫And actually I need to get rid of this first one
‫because this one still has the password in plain text.
‫And so this user is not gonna work
‫when we start to actually login users
‫based on their password.
‫Okay?
‫So let's get rid of this.
‫Okay?
‫And also what I wanted to show you here
‫is that we put in the exact same password
‫for these two users that we created, right?
‫But you see that the encrypted password
‫is actually very different, right?
‫And so that's the power of salting the password
‫before hashing it.
‫All right?
‫So just like this, we, again, implemented a very secure
‫and good password management.