fix(curriculum): Convert blockquote elements to triple backtick syntax for Information Security And Quality Assurance (#35997)

* fix: converted blockquotes

* fix: added extra line before triple backtick syntax

Co-Authored-By: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* fix: corrected misc issues

* fix: properly closed em element

Co-Authored-By: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Randell Dawson
2019-05-14 04:58:09 -07:00
committed by Tom
parent df8659ab8c
commit 46411ca1cd
21 changed files with 298 additions and 219 deletions

View File

@ -11,18 +11,20 @@ Many chat rooms are able to annouce when a user connects or disconnects and then
<hr>Change the event name to 'user' and as the data pass an object along containing fields 'name', 'currentUsers', and boolean 'connected' (to be true if connection, or false for disconnection of the user sent). Be sure to make the change to both points we had the 'user count' event and set the disconnect one to sent false for field 'connected' instead of true like the event emitted on connect. <code>io.emit('user', {name: socket.request.user.name, currentUsers, connected: true});</code>
Now your client will have all the necessary information to correctly display the current user count and annouce when a user connects or disconnects! To handle this event on the client side we should listen for 'user' and then update the current user count by using jQuery to change the text of <code>#num-users</code> to '{NUMBER} users online', as well as append a <code>&#60;li&#62;</code> to the unordered list with id 'messages' with '{NAME} has {joined/left} the chat.'.
An implementation of this could look like the following:<br>
<blockquote>
socket.on('user', function(data){<br>
&nbsp;&nbsp;$('#num-users').text(data.currentUsers+' users online');<br>
&nbsp;&nbsp;var message = data.name;<br>
&nbsp;&nbsp;if(data.connected) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;message += ' has joined the chat.';<br>
&nbsp;&nbsp;} else {<br>
&nbsp;&nbsp;&nbsp;&nbsp;message += ' has left the chat.';<br>
&nbsp;&nbsp;}<br>
&nbsp;&nbsp;$('#messages').append($('&#60;li&#62;').html('&#60;b&#62;'+ message +'&#60;\/b&#62;'));<br>
```js
socket.on('user', function(data){
$('#num-users').text(data.currentUsers+' users online');
var message = data.name;
if(data.connected) {
message += ' has joined the chat.';
} else {
message += ' has left the chat.';
}
$('#messages').append($('<li>').html('<b>'+ message +'<\/b>'));
});
</blockquote>
```
Submit your page when you think you've got it right.
</section>

View File

@ -10,19 +10,21 @@ As a reminder, this project is being built upon the following starter project on
A strategy is a way of authenticating a user. You can use a strategy for allowing users to authenticate based on locally saved information (if you have them register first) or from a variety of providers such as Google or GitHub. For this project we will set up a local strategy. To see a list of the 100's of strategies, visit Passports site <a href='http://passportjs.org/'>here</a>.
Add <em>passport-local</em> as a dependency and add it to your server as follows: <code>const LocalStrategy = require('passport-local');</code>
Now you will have to tell passport to <b>use</b> an instantiated LocalStartegy object with a few settings defined. Make sure this as well as everything from this point on is encapsulated in the database connection since it relies on it!
<blockquote>
passport.use(new LocalStrategy(<br>
&nbsp;&nbsp;function(username, password, done) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;db.collection('users').findOne({ username: username }, function (err, user) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log('User '+ username +' attempted to log in.');<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (err) { return done(err); }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!user) { return done(null, false); }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (password !== user.password) { return done(null, false); }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return done(null, user);<br>
&nbsp;&nbsp;&nbsp;&nbsp;});<br>
&nbsp;&nbsp;}<br>
```js
passport.use(new LocalStrategy(
function(username, password, done) {
db.collection('users').findOne({ username: username }, function (err, user) {
console.log('User '+ username +' attempted to log in.');
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (password !== user.password) { return done(null, false); }
return done(null, user);
});
}
));
</blockquote><br>
```
This is defining the process to take when we try to authenticate someone locally. First it tries to find a user in our database with the username entered, then it checks for the password to match, then finally if no errors have popped up that we checked for, like an incorrect password, the users object is returned and they are authenticated.
Many strategies are set up using different settings, general it is easy to set it up based on the README in that strategies repository though. A good example of this is the GitHub strategy where we don't need to worry about a username or password because the user will be sent to GitHub's auth page to authenticate and as long as they are logged in and agree then GitHub returns their profile for us to use.
In the next step we will set up how to actually call the authentication strategy to validate a user based on form data! Submit your page when you think you've got it right up to this point.

View File

@ -10,14 +10,16 @@ As a reminder, this project is being built upon the following starter project on
Currently, you cannot determine who is connected to your web socket. While 'req.user' containers the user object, thats only when your user interacts with the web server and with web sockets you have no req (request) and therefor no user data. One way to solve the problem of knowing who is connected to your web socket is by parsing and decoding the cookie that contains the passport session then deserializing it to obtain the user object. Luckily, there is a package on NPM just for this that turns a once complex task into something simple!
<hr>Add 'passport.socketio' as a dependency and require it as 'passportSocketIo'.
Now we just have to tell Socket.IO to use it and set the options. Be sure this is added before the existing socket code and not in the existing connection listener. For your server it should look as follows:
<blockquote>
io.use(passportSocketIo.authorize({<br>
&nbsp;&nbsp;cookieParser: cookieParser,<br>
&nbsp;&nbsp;key: 'express.sid',<br>
&nbsp;&nbsp;secret: process.env.SESSION_SECRET,<br>
&nbsp;&nbsp;store: sessionStore<br>
```js
io.use(passportSocketIo.authorize({
cookieParser: cookieParser,
key: 'express.sid',
secret: process.env.SESSION_SECRET,
store: sessionStore
}));
</blockquote>
```
You can also optionally pass 'success' and 'fail' with a function that will be called after the authentication process completes when a client trys to connect.
The user object is now accessible on your socket object as <code>socket.request.user</code>. For example, now you can add the following: <code>console.log('user ' + socket.request.user.name + ' connected');</code> and it will log to the server console who has connected!
Submit your page when you think you've got it right. If you're running into errors, you can check out the project up to this point <a href='https://gist.github.com/JosephLivengood/a9e69ff91337500d5171e29324e1ff35'>here</a>.

View File

@ -10,11 +10,13 @@ As a reminder, this project is being built upon the following starter project on
Right now everything you have is in your server.js file. This can lead to hard to manage code that isn't very expandable.
Create 2 new files: Routes.js and Auth.js
Both should start with the following code:
<blockquote>
module.exports = function (app, db) {<br>
<br>
```js
module.exports = function (app, db) {
}
</blockquote>
```
Now in the top of your server file, require these files like such: <code>const routes = require('./routes.js');</code>
Right after you establish a successful connect with the database instantiate each of them like such: <code>routes(app, db)</code>
Finally, take all of the routes in your server and paste them into your new files and remove them from your server file. Also take the ensureAuthenticated since we created that middleware function for routing specifically. You will have to now correctly add the dependencies in that are used, such as <code>const passport = require('passport');</code>, at the very top above the export line in your routes.js file.

View File

@ -12,11 +12,13 @@ As a reminder, this project is being built upon the following starter project on
Now when someone connects you should increment the count before emitting the count so you will want to add the incrementer within the connection listener. <code>++currentUsers;</code>
Finally after incrementing the count, you should emit the event(still within the connection listener). The event should be named 'user count' and the data should just be the 'currentUsers'. <code>io.emit('user count', currentUsers);</code>
<hr>Now you can implement a way for your client to listen for this event! Similarly to listening for a connection on the server you will use the <em>on</em> keyword.
<blockquote>
socket.on('user count', function(data){<br>
&nbsp;&nbsp;console.log(data);<br>
```js
socket.on('user count', function(data){
console.log(data);
});
</blockquote>
```
Now try loading up your app and authenticate and you should see in your client console '1' representing the current user count! Try loading more clients up and authenticating to see the number go up.
Submit your page when you think you've got it right.
</section>

View File

@ -9,22 +9,26 @@ challengeType: 2
As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.
As in, any user can just go to /profile whether they authenticated or not by typing in the url. We want to prevent this by checking if the user is authenticated first before rendering the profile page. This is the perfect example of when to create a middleware.
The challenge here is creating the middleware function <code>ensureAuthenticated(req, res, next)</code>, which will check if a user is authenticated by calling passports isAuthenticated on the <em>request</em> which in turn checks for <em>req.user</em> is to be defined. If it is then <em>next()</em> should be called, otherwise we can just respond to the request with a redirect to our homepage to login. An implementation of this middleware is:
<blockquote>
function ensureAuthenticated(req, res, next) {<br>
&nbsp;&nbsp;if (req.isAuthenticated()) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;return next();<br>
&nbsp;&nbsp;}<br>
&nbsp;&nbsp;res.redirect('/');<br>
```js
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/');
};
</blockquote>
```
Now add <em>ensureAuthenticated</em> as a middleware to the request for the profile page before the argument to the get request containing the function that renders the page.
<blockquote>
app<br>
&nbsp;.route('/profile')<br>
&nbsp;.get(ensureAuthenticated, (req,res) => {<br>
&nbsp;&nbsp;res.render(process.cwd() + '/views/pug/profile');<br>
&nbsp;});
</blockquote>
```js
app
.route('/profile')
.get(ensureAuthenticated, (req,res) => {
res.render(process.cwd() + '/views/pug/profile');
});
```
Submit your page when you think you've got it right.
</section>

View File

@ -10,17 +10,19 @@ As a reminder, this project is being built upon the following starter project on
Right now we're not loading an actual user object since we haven't set up our database. This can be done many different ways, but for our project we will connect to the database once when we start the server and keep a persistent connection for the full life-cycle of the app.
To do this, add MongoDB as a dependency and require it in your server. (<code>const mongo = require('mongodb').MongoClient;</code>)
Now we want to the connect to our database then start listening for requests. The purpose of this is to not allow requests before our database is connected or if there is a database error. To accomplish you will want to encompass your serialization and your app listener in the following:
<blockquote>
mongo.connect(process.env.DATABASE, (err, db) => {<br>
&nbsp;&nbsp;if(err) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;console.log('Database error: ' + err);<br>
&nbsp;&nbsp;} else {<br>
&nbsp;&nbsp;&nbsp;&nbsp;console.log('Successful database connection');<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;//serialization and app.listen<br>
<br>
}});
</blockquote>
```js
mongo.connect(process.env.DATABASE, (err, db) => {
if(err) {
console.log('Database error: ' + err);
} else {
console.log('Successful database connection');
//serialization and app.listen
}
});
```
You can now uncomment the block in deserializeUser and remove your <code>done(null, null)</code>. Be sure to set <em>DATABASE</em> in your .env file to your database's connection string (for example: <code>DATABASE=mongodb://admin:pass@mlab.com:12345/my-project</code>). You can set up a free database on <a href='https://mlab.com/welcome/'>mLab</a>. Congratulations- you've finished setting up serialization!
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/e192e809a1d27cb80dc2c6d3467b7477'>here</a>.
</section>

View File

@ -10,18 +10,20 @@ As a reminder, this project is being built upon the following starter project on
The last part of setting up your GitHub authentication is to create the strategy itself. For this, you will need to add the dependency of 'passport-github' to your project and require it as GithubStrategy like <code>const GitHubStrategy = require('passport-github').Strategy;</code>.
To set up the GitHub strategy, you have to tell <b>passport</b> to <b>use</b> an instantiated <b>GitHubStrategy</b>, which accepts 2 arguments: An object (containing <em>clientID</em>, <em>clientSecret</em>, and <em>callbackURL</em>) and a function to be called when a user is successfully authenticated which we will determine if the user is new and what fields to save initially in the user's database object. This is common across many strategies but some may require more information as outlined in that specific strategy's github README; for example, Google requires a <em>scope</em> as well which determines what kind of information your request is asking returned and asks the user to approve such access. The current strategy we are implementing has its usage outlined <a>here</a>, but we're going through it all right here on freeCodeCamp!
Here's how your new strategy should look at this point:
<blockquote>
passport.use(new GitHubStrategy({<br>
&nbsp;&nbsp;clientID: process.env.GITHUB_CLIENT_ID,<br>
&nbsp;&nbsp;clientSecret: process.env.GITHUB_CLIENT_SECRET,<br>
&nbsp;&nbsp;callbackURL: /*INSERT CALLBACK URL ENTERED INTO GITHUB HERE*/<br>
},<br>
&nbsp;&nbsp;function(accessToken, refreshToken, profile, cb) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;console.log(profile);<br>
&nbsp;&nbsp;&nbsp;&nbsp;//Database logic here with callback containing our user object<br>
&nbsp;&nbsp;}<br>
```js
passport.use(new GitHubStrategy({
clientID: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
callbackURL: /*INSERT CALLBACK URL ENTERED INTO GITHUB HERE*/
},
function(accessToken, refreshToken, profile, cb) {
console.log(profile);
//Database logic here with callback containing our user object
}
));
</blockquote>
```
Your authentication won't be successful yet, and actually throw an error, without the database logic and callback, but it should log to your console your GitHub profile if you try it!
Submit your page when you think you've got it right.
</section>

View File

@ -8,28 +8,30 @@ challengeType: 2
<section id='description'>
As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a>.
The final part of the strategy is handling the profile returned from GitHub. We need to load the user's database object if it exists, or create one if it doesn't, and populate the fields from the profile, then return the user's object. GitHub supplies us a unique <em>id</em> within each profile which we can use to search with to serialize the user with (already implemented). Below is an example implementation you can use in your project- it goes within the function that is the second argument for the new strategy, right below the <code>console.log(profile);</code> currently is:
<blockquote>
db.collection('socialusers').findAndModify(<br>
&nbsp;&nbsp;{id: profile.id},<br>
&nbsp;&nbsp;{},<br>
&nbsp;&nbsp;{$setOnInsert:{<br>
&nbsp;&nbsp;&nbsp;&nbsp;id: profile.id,<br>
&nbsp;&nbsp;&nbsp;&nbsp;name: profile.displayName || 'John Doe',<br>
&nbsp;&nbsp;&nbsp;&nbsp;photo: profile.photos[0].value || '',<br>
&nbsp;&nbsp;&nbsp;&nbsp;email: profile.emails[0].value || 'No public email',<br>
&nbsp;&nbsp;&nbsp;&nbsp;created_on: new Date(),<br>
&nbsp;&nbsp;&nbsp;&nbsp;provider: profile.provider || ''<br>
&nbsp;&nbsp;},$set:{<br>
&nbsp;&nbsp;&nbsp;&nbsp;last_login: new Date()<br>
&nbsp;&nbsp;},$inc:{<br>
&nbsp;&nbsp;&nbsp;&nbsp;login_count: 1<br>
&nbsp;&nbsp;}},<br>
&nbsp;&nbsp;{upsert:true, new: true},<br>
&nbsp;&nbsp;(err, doc) => {<br>
&nbsp;&nbsp;&nbsp;&nbsp;return cb(null, doc.value);<br>
&nbsp;&nbsp;}<br>
```js
db.collection('socialusers').findAndModify(
{id: profile.id},
{},
{$setOnInsert:{
id: profile.id,
name: profile.displayName || 'John Doe',
photo: profile.photos[0].value || '',
email: profile.emails[0].value || 'No public email',
created_on: new Date(),
provider: profile.provider || ''
},$set:{
last_login: new Date()
},$inc:{
login_count: 1
}},
{upsert:true, new: true},
(err, doc) => {
return cb(null, doc.value);
}
);
</blockquote>
```
With a findAndModify, it allows you to search for an object and update it, as well as insert the object if it doesn't exist and receive the new object back each time in our callback function. In this example, we always set the last_login as now, we always increment the login_count by 1, and only when we insert a new object(new user) do we populate the majority of the fields. Something to notice also is the use of default values. Sometimes a profile returned won't have all the information filled out or it will have been chosen by the user to remain private; so in this case we have to handle it to prevent an error.
You should be able to login to your app now- try it! Submit your page when you think you've got it right. If you're running into errors, you can check out an example of this mini-project's finished code <a href='https://glitch.com/#!/project/guttural-birch'>here</a>.
</section>

View File

@ -9,15 +9,17 @@ challengeType: 2
As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a>.
The basic path this kind of authentication will follow in your app is: <ol><li>User clicks a button or link sending them to our route to authenticate using a specific strategy (EG. GitHub)</li><li>Your route calls <code>passport.authenticate('github')</code> which redirects them to GitHub.</li><li>The page the user lands on, on GitHub, allows them to login if they aren't already. It then asks them to approve access to their profile from our app.</li><li>The user is then returned to our app at a specific callback url with their profile if they are approved.</li><li>They are now authenticated and your app should check if it is a returning profile, or save it in your database if it is not.</li></ol>
Strategies with OAuth require you to have at least a <em>Client ID</em> and a <em>Client Secret</em> which is a way for them to verify who the authentication request is coming from and if it is valid. These are obtained from the site you are trying to implement authentication with, such as GitHub, and are unique to your app- <b>THEY ARE NOT TO BE SHARED</b> and should never be uploaded to a public repository or written directly in your code. A common practice is to put them in your <em>.env</em> file and reference them like: <code>process.env.GITHUB_CLIENT_ID</code>. For this challenge we're going to use the GitHub strategy.
Obtaining your <em>Client ID and Secret<em> from GitHub is done in your account profile settings under 'developer settings', then '<a href='https://github.com/settings/developers'>OAuth applications</a>'. Click 'Register a new application', name your app, paste in the url to your glitch homepage (<b>Not the project code's url</b>), and lastly for the callback url, paste in the same url as the homepage but with '/auth/github/callback' added on. This is where users will be redirected to for us to handle after authenticating on GitHub. Save the returned information as 'GITHUB_CLIENT_ID' and 'GITHUB_CLIENT_SECRET' in your .env file.
Obtaining your <em>Client ID and Secret</em> from GitHub is done in your account profile settings under 'developer settings', then '<a href='https://github.com/settings/developers'>OAuth applications</a>'. Click 'Register a new application', name your app, paste in the url to your glitch homepage (<b>Not the project code's url</b>), and lastly for the callback url, paste in the same url as the homepage but with '/auth/github/callback' added on. This is where users will be redirected to for us to handle after authenticating on GitHub. Save the returned information as 'GITHUB_CLIENT_ID' and 'GITHUB_CLIENT_SECRET' in your .env file.
On your remixed project, create 2 routes accepting GET requests: /auth/github and /auth/github/callback. The first should only call passport to authenticate 'github' and the second should call passport to authenticate 'github' with a failure redirect to '/' and then if that is successful redirect to '/profile' (similar to our last project).
An example of how '/auth/github/callback' should look is similar to how we handled a normal login in our last project:
<blockquote>
app.route('/login')<br>
&nbsp;&nbsp;.post(passport.authenticate('local', { failureRedirect: '/' }), (req,res) => {<br>
&nbsp;&nbsp;&nbsp;&nbsp;res.redirect('/profile');<br>
&nbsp;&nbsp;});
</blockquote>
```js
app.route('/login')
.post(passport.authenticate('local', { failureRedirect: '/' }), (req,res) => {
res.redirect('/profile');
});
```
Submit your page when you think you've got it right. If you're running into errors, you can check out the project up to this point <a href='https://gist.github.com/JosephLivengood/28ea2cae7e1dc6a53d7f0c42d987313b'>here</a>.
</section>

View File

@ -9,21 +9,25 @@ challengeType: 2
As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.
Creating the logout logic is easy. The route should just unauthenticate the user and redirect to the home page instead of rendering any view.
In passport, unauthenticating a user is as easy as just calling <code>req.logout();</code> before redirecting.
<blockquote>
app.route('/logout')<br>
&nbsp;&nbsp;.get((req, res) => {<br>
&nbsp;&nbsp;&nbsp;&nbsp;req.logout();<br>
&nbsp;&nbsp;&nbsp;&nbsp;res.redirect('/');<br>
```js
app.route('/logout')
.get((req, res) => {
req.logout();
res.redirect('/');
});
</blockquote>
```
You may have noticed that we're not handling missing pages (404), the common way to handle this in Node is with the following middleware. Go ahead and add this in after all your other routes:
<blockquote>
app.use((req, res, next) => {<br>
&nbsp;&nbsp;res.status(404)<br>
&nbsp;&nbsp;&nbsp;&nbsp;.type('text')<br>
&nbsp;&nbsp;&nbsp;&nbsp;.send('Not Found');<br>
```js
app.use((req, res, next) => {
res.status(404)
.type('text')
.send('Not Found');
});
</blockquote>
```
Submit your page when you think you've got it right.
</section>

View File

@ -10,36 +10,38 @@ As a reminder, this project is being built upon the following starter project on
Now we need to allow a new user on our site to register an account. On the res.render for the home page add a new variable to the object passed along- <code>showRegistration: true</code>. When you refresh your page, you should then see the registration form that was already created in your index.pug file! This form is set up to <b>POST</b> on <em>/register</em> so this is where we should set up to accept the POST and create the user object in the database.
The logic of the registration route should be as follows: Register the new user > Authenticate the new user > Redirect to /profile
The logic of step 1, registering the new user, should be as follows: Query database with a findOne command > if user is returned then it exists and redirect back to home <em>OR</em> if user is undefined and no error occurs then 'insertOne' into the database with the username and password and as long as no errors occur then call <em>next</em> to go to step 2, authenticating the new user, which we've already written the logic for in our POST /login route.
<blockquote>
app.route('/register')<br>
&nbsp;&nbsp;.post((req, res, next) => {<br>
&nbsp;&nbsp;&nbsp;&nbsp;db.collection('users').findOne({ username: req.body.username }, function(err, user) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (err) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next(err);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else if (user) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.redirect('/');<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.collection('users').insertOne({<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;username: req.body.username,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password: req.body.password<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(err, doc) => {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (err) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.redirect('/');<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next(null, user);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;})<br>
&nbsp;&nbsp;},<br>
&nbsp;&nbsp;&nbsp;&nbsp;passport.authenticate('local', { failureRedirect: '/' }),<br>
&nbsp;&nbsp;&nbsp;&nbsp;(req, res, next) => {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.redirect('/profile');<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;);
</blockquote>
```js
app.route('/register')
.post((req, res, next) => {
db.collection('users').findOne({ username: req.body.username }, function(err, user) {
if (err) {
next(err);
} else if (user) {
res.redirect('/');
} else {
db.collection('users').insertOne({
username: req.body.username,
password: req.body.password
},
(err, doc) => {
if (err) {
res.redirect('/');
} else {
next(null, user);
}
}
)
}
})
},
passport.authenticate('local', { failureRedirect: '/' }),
(req, res, next) => {
res.redirect('/profile');
}
);
```
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/6c47bee7df34df9f11820803608071ed'>here</a>.
</section>

View File

@ -10,19 +10,21 @@ As a reminder, this project is being built upon the following starter project on
Serialization and deserialization are important concepts in regards to authentication. To serialize an object means to convert its contents into a small <em>key</em> essentially that can then be deserialized into the original object. This is what allows us to know whos communicated with the server without having to send the authentication data like username and password at each request for a new page.
To set this up properly, we need to have a serialize function and a deserialize function. In passport we create these with <code>passport.serializeUser( OURFUNCTION )</code> and <code>passport.deserializeUser( OURFUNCTION )</code>
The serializeUser is called with 2 arguments, the full user object and a callback used by passport. Returned in the callback should be a unique key to identify that user- the easiest one to use being the users _id in the object as it should be unique as it generated by MongoDb. Similarly deserializeUser is called with that key and a callback function for passport as well, but this time we have to take that key and return the users full object to the callback. To make a query search for a Mongo _id you will have to create <code>const ObjectID = require('mongodb').ObjectID;</code>, and then to use it you call <code>new ObjectID(THE_ID)</code>. Be sure to add MongoDB as a dependency. You can see this in the examples below:
<blockquote>
passport.serializeUser((user, done) => {<br>
&nbsp;&nbsp;done(null, user._id);<br>
});<br>
passport.deserializeUser((id, done) => {<br>
&nbsp;&nbsp;db.collection('users').findOne(<br>
&nbsp;&nbsp;&nbsp;&nbsp;{_id: new ObjectID(id)},<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(err, doc) => {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;done(null, doc);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;);<br>
```js
passport.serializeUser((user, done) => {
done(null, user._id);
});
</blockquote>
passport.deserializeUser((id, done) => {
db.collection('users').findOne(
{_id: new ObjectID(id)},
(err, doc) => {
done(null, doc);
}
);
});
```
NOTE: This deserializeUser will throw an error until we set up the DB in the next step so comment out the whole block and just call <code>done(null, null)</code> in the function deserializeUser.
Submit your page when you think you've got it right.
</section>

View File

@ -12,13 +12,15 @@ To set up Passport for use in your project, you will need to add it as a depende
In addition, add Express-session as a dependency now as well. Express-session has a ton of advanced features you can use but for now we're just going to use the basics! <code>"express-session": "^1.15.0"</code>
You will need to set up the session settings now and initialize Passport. Be sure to first create the variables 'session' and 'passport' to require 'express-session' and 'passport' respectively.
To set up your express app to use use the session we'll define just a few basic options. Be sure to add 'SESSION_SECRET' to your .env file and give it a random value. This is used to compute the hash used to encrypt your cookie!
<blockquote>
app.use(session({<br>
&nbsp;&nbsp;secret: process.env.SESSION_SECRET,<br>
&nbsp;&nbsp;resave: true,<br>
&nbsp;&nbsp;saveUninitialized: true,<br>
```js
app.use(session({
secret: process.env.SESSION_SECRET,
resave: true,
saveUninitialized: true,
}));
</blockquote>
```
As well you can go ahead and tell your express app to <b>use</b> 'passport.initialize()' and 'passport.session()'. (For example, <code>app.use(passport.initialize());</code>)
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/338a9c5a326923c3826a666d430e65c3'>here</a>.
</section>

View File

@ -10,15 +10,20 @@ As a reminder, this project is being built upon the following starter project on
Add Socket.IO as a dependency and require/instantiate it in your server defined as 'io' with the http server as an argument. <code>const io = require('socket.io')(http);</code>
The first thing needing to be handled is listening for a new connection from the client. The <dfn>on</dfn> keyword does just that- listen for a specific event. It requires 2 arguments: a string containing the title of the event thats emitted, and a function with which the data is passed though. In the case of our connection listener, we use <em>socket</em> to define the data in the second argument. A socket is an individual client who is connected.
For listening for connections on our server, add the following between the comments in your project:
<blockquote>
io.on('connection', socket => {<br>
&nbsp;&nbsp;console.log('A user has connected');<br>
```js
io.on('connection', socket => {
console.log('A user has connected');
});
</blockquote>
```
Now for the client to connect, you just need to add the following to your client.js which is loaded by the page after you've authenticated:
<blockquote>/*global io*/<br>
```js
/*global io*/
var socket = io();
</blockquote>
```
The comment suppresses the error you would normally see since 'io' is not defined in the file. We've already added a reliable CDN to the Socket.IO library on the page in chat.pug.
Now try loading up your app and authenticate and you should see in your server console 'A user has connected'!
<strong>Note</strong><br><code>io()</code> works only when connecting to a socket hosted on the same url/server. For connecting to an external socket hosted elsewhere, you would use <code>io.connect('URL');</code>.

View File

@ -9,20 +9,22 @@ challengeType: 2
As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.
<code>app.use(helmet())</code> will automatically include all the middleware introduced above, except <code>noCache()</code>, and <code>contentSecurityPolicy()</code>, but these can be enabled if necessary. You can also disable or configure any other middleware individually, using a configuration object.
<h3>Example:</h3>
<blockquote>
app.use(helmet({<br>
&nbsp;&nbsp;frameguard: { // configure<br>
&nbsp;&nbsp;&nbsp;&nbsp;action: 'deny'<br>
&nbsp;&nbsp;},<br>
&nbsp;&nbsp;contentSecurityPolicy: { // enable and configure<br>
&nbsp;&nbsp;&nbsp;&nbsp;directives: {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;defaultSrc: ["self"],<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;styleSrc: ['style.com'],<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;},<br>
&nbsp;&nbsp;dnsPrefetchControl: false // disable<br>
```js
app.use(helmet({
frameguard: { // configure
action: 'deny'
},
contentSecurityPolicy: { // enable and configure
directives: {
defaultSrc: ["self"],
styleSrc: ['style.com'],
}
},
dnsPrefetchControl: false // disable
}))
</blockquote>
```
We introduced each middleware separately for teaching purposes and for ease of testing. Using the parent <code>helmet()</code> middleware is easy to implement in a real project.
</section>

View File

@ -7,26 +7,40 @@ challengeType: 2
## Description
<section id='description'>
As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-bcrypt/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-bcrypt/'>GitHub</a>.
As hashing is designed to be computationally intensive, it is recommended to do so asyncronously on your server as to avoid blocking incoming connections while you hash. All you have to do to hash a password asynchronous is call <blockquote>bcrypt.hash(myPlaintextPassword, saltRounds, (err, hash) => {<br>
&nbsp;&nbsp;/*Store hash in your db*/<br>
});</blockquote>
As hashing is designed to be computationally intensive, it is recommended to do so asyncronously on your server as to avoid blocking incoming connections while you hash. All you have to do to hash a password asynchronous is call
```js
bcrypt.hash(myPlaintextPassword, saltRounds, (err, hash) => {
/*Store hash in your db*/
});
```
</section>
## Instructions
<section id='instructions'>
Add this hashing function to your server(we've already defined the variables used in the function for you to use) and log it to the console for you to see! At this point you would normally save the hash to your database.
Now when you need to figure out if a new input is the same data as the hash you would just use the compare function <blockquote>bcrypt.compare(myPlaintextPassword, hash, (err, res) => {<br>
&nbsp;&nbsp;/*res == true or false*/<br>
});</blockquote>. Add this into your existing hash function(since you need to wait for the hash to complete before calling the compare function) after you log the completed hash and log 'res' to the console within the compare. You should see in the console a hash then 'true' is printed! If you change 'myPlaintextPassword' in the compare function to 'someOtherPlaintextPassword' then it should say false.
<blockquote>
bcrypt.hash('passw0rd!', 13, (err, hash) => {<br>
&nbsp;&nbsp;console.log(hash);<br>
&nbsp;&nbsp;//$2a$12$Y.PHPE15wR25qrrtgGkiYe2sXo98cjuMCG1YwSI5rJW1DSJp0gEYS<br>
&nbsp;&nbsp;bcrypt.compare('passw0rd!', hash, (err, res) => {<br>
&nbsp;&nbsp;&nbsp;&nbsp;console.log(res); //true<br>
&nbsp;&nbsp;});<br>
});<br>
</blockquote>
Now when you need to figure out if a new input is the same data as the hash you would just use the compare function.
```js
bcrypt.compare(myPlaintextPassword, hash, (err, res) => {
/*res == true or false*/
});
```
Add this into your existing hash function(since you need to wait for the hash to complete before calling the compare function) after you log the completed hash and log 'res' to the console within the compare. You should see in the console a hash then 'true' is printed! If you change 'myPlaintextPassword' in the compare function to 'someOtherPlaintextPassword' then it should say false.
```js
bcrypt.hash('passw0rd!', 13, (err, hash) => {
console.log(hash);
//$2a$12$Y.PHPE15wR25qrrtgGkiYe2sXo98cjuMCG1YwSI5rJW1DSJp0gEYS
bcrypt.compare('passw0rd!', hash, (err, res) => {
console.log(res); //true
});
});
```
Submit your page when you think you've got it right.
</section>

View File

@ -7,9 +7,20 @@ challengeType: 2
## Description
<section id='description'>
As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-bcrypt/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-bcrypt/'>GitHub</a>.
Hashing synchronously is just as easy to do but can cause lag if using it server side with a high cost or with hashing done very often. Hashing with this method is as easy as calling <blockquote>var hash = bcrypt.hashSync(myPlaintextPassword, saltRounds);</blockquote>
Hashing synchronously is just as easy to do but can cause lag if using it server side with a high cost or with hashing done very often. Hashing with this method is as easy as calling
```js
var hash = bcrypt.hashSync(myPlaintextPassword, saltRounds);
```
Add this method of hashing to your code and then log the result to the console. Again, the variables used are already defined in the server so you wont need to adjust them. You may notice even though you are hashing the same password as in the async function, the result in the console is different- this is due to the salt being randomly generated each time as seen by the first 22 characters in the third string of the hash.
Now to compare a password input with the new sync hash, you would use the compareSync method: <blockquote>var result = bcrypt.compareSync(myPlaintextPassword, hash);</blockquote> with the result being a boolean true or false.
Now to compare a password input with the new sync hash, you would use the compareSync method:
```js
var result = bcrypt.compareSync(myPlaintextPassword, hash);
```
with the result being a boolean true or false.
</section>
## Instructions

View File

@ -9,15 +9,21 @@ challengeType: 2
As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.
In the next example we'll see how to send data in a request payload (body).
We are going to test a PUT request. The <code>'/travellers'</code> endpoint accepts a JSON object taking the structure :
<blockquote>
{<br>
&nbsp;surname: [last name of a traveller of the past]<br>
} </blockquote>
```json
{
"surname": [last name of a traveller of the past]
}
```
The route responds with :
<blockquote>
{<br>
&nbsp;name: [first name], surname:[last name], dates: [birth - death years]<br>
}</blockquote>
```json
{
"name": [first name], "surname": [last name], "dates": [birth - death years]
}
```
See the server code for more details.
</section>
@ -25,10 +31,13 @@ See the server code for more details.
## Instructions
<section id='instructions'>
Send <br>
<blockquote>
{<br>
&nbsp;surname: 'Colombo'<br>
}</blockquote>
```json
{
"surname": "Colombo"
}
```
Replace <code>assert.fail()</code> and make the test pass.
Check for 1) <code>status</code>, 2) <code>type</code>, 3) <code>body.name</code>, 4) <code>body.surname</code>.
Follow the assertion order above, We rely on it.

View File

@ -13,11 +13,15 @@ This exercise is similar to the preceding. Look at it for the details.
## Instructions
<section id='instructions'>
Send <br>
<blockquote>
{<br>
&nbsp;surname: 'da Verrazzano'<br>
}</blockquote>. Replace <code>assert.fail()</code> and make the test pass.
Send
```json
{
"surname": "da Verrazzano"
}
```
Replace <code>assert.fail()</code> and make the test pass.
Check for 1) <code>status</code>, 2) <code>type</code>, 3) <code>body.name</code>, 4) <code>body.surname</code>.
Follow the assertion order above, We rely on it.
</section>

View File

@ -9,11 +9,13 @@ challengeType: 2
As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.
<code>isTrue()</code> will test for the boolean value true and <code>isNotTrue()</code> will pass when given anything but the boolean value of true.
<blockquote>
assert.isTrue(true, 'this will pass with the boolean value true');
assert.isTrue('true', 'this will NOT pass with the string value 'true');
```js
assert.isTrue(true, 'this will pass with the boolean value true');
assert.isTrue('true', 'this will NOT pass with the string value 'true');
assert.isTrue(1, 'this will NOT pass with the number value 1');
</blockquote>
```
<code>isFalse()</code> and <code>isNotFalse()</code> also exist and behave similary to their true counterparts except they look for the boolean value of false.
</section>