Description
In this project, you will extend your work on Project #6 by adding the ability for users to login, comment on photos, and upload new photos. Note that these new feature additions are full stack in that you will need to modify both the front end (React app) and the back end (Node web server and MongoDB database).
Problem 1: Simple Login
Extend your photo app to have the notion of an user being logged in. If a user is logged in, the toolbar should include a small message “Hi < rstname>” where < rstname> is the rst name of the logged-in user. The toolbar should also contain a button displaying “Logout” that will log the user out.
If there is no user logged in, the toolbar should display “Please Login” and the main view of your application should display an new view component named LoginRegister . The LoginRegister view should provide a way for a user to login and, as part of Problem #4 below, register as a new user. All attempts to navigate to a di erent view (e.g. deep links) should result in the display being redirected to the LoginRegister view if no user is logged in. (See the hints section if you are unsure how to implement this.) In addition, the user list on the left should not be populated if the current user is not logged in. (See the section below about modifying the server endpoints to return a status of 401 (Unauthorized)).
When a user logs in successfully the view should switch to displaying the user’s details. If the user login fails (e.g. no user with the login_name) the view should report an appropriate error message and let the user try again.
Extend your backend implementation to support the photo app’s notion of logged in users. In making this change you will need to change both the database schema and the web server API.
Extend the Mongoose schema for User to add a new property login_name . This property is a string containing the identi er the user will type when logging in (their “login name”).
Modify the web server API to support 2 new REST API calls for logging in and out a user. Like in the previous assignment we will use HTTP requests with JSON-encoded bodies to transmit model data. The API uses POST requests to:
/admin/login – Provides a way for the photo app’s LoginRegister view to login in a user. The POST request JSON-encoded body should include a property login_name (no passwords for now) and reply with information needed by your app for logged in user. An HTTP status of 400 (Bad request) should be returned if the login failed (e.g. login_name is not a valid account). A parameter in the request body is accessed using request.body.parameter_name . Note the login register handler should ensure that there exists a user with the given login_name . If so, it stores
some information in the Express session where it can be checked by other request handlers that need to know whether a user is logged in.
/admin/logout – A POST request with an empty body to this URL will logout the user by clearing the information stored in the session. An HTTP status of 400 (Bad request) should be returned in the user is not currently logged in.
As part of updating the web server to handle login/logout you need to update all requests (except to /admin/login and /admin/logout ) to reject the request with a status of 401 (Unauthorized) if the session state does not report a user is logged in.
Problem 2: New Comments
Once you have implemented user login, the next step is to implement the ability to add comments to photos. In the photo detail view where you display the comments of a photo, add the ability for the currently logged in user to add a comment to the photo. You get to design the user interface (e.g.
popup dialog, input eld, etc.) for this feature. It should be obvious how to use it and what photo the comment is about. The display of the photo and its comments should be updated immediately to re ect the newly added comment.
For the backend support extend the web server API with the following HTTP POST API:
/commentsOfPhoto/:photo_id – Add a comment to the photo whose id is photo_id . The body of the POST requests should be a JSON-encoded body with a single property comment that contains the comment’s text. The comment object created on the photo must include the identi er of the logged in user and the time when the comment was created. Your implementation should reject any empty comments with a status of 400 (Bad request).
Problem 3: Photo Uploading
Allow users to add new photos. When a user is logged in, the main toolbar should have a button labelled “Add Photo” that allows the current logged in user to upload a photo to the app. We will provide you with an example of how to upload les using HTML in the Hint section below.
Extend the web server to support POST requests to the URL:
/photos/new – Upload a photo for the current user. The body of the POST request should be the le (see hint below). The uploaded les should be placed in the images directory under an unique name you generated. The unique name, along with the creation data and logged in user id, should be placed in the new Photo object you create. A response status of 400 should be returned if there is no le in the POST request. See the Hint section for help with this.
Problem 4: Registration and Passwords
Enhance the LoginRegister view component to support new-user registration and passwords. Extend the login portion to add a password eld. Add a registration section that allows all the elds of the User object to be lled in. To reduce the chance that the user typos that password the view should contain a an additional copy of the password eld and the view should only allow the user to be created if the two password elds are identical. Good security practice requires that the passwords typed by the user shouldn’t be visible in the view. Registration should be triggered by a button at the bottom of the page labelled “Register Me”. When the button is pushed either an error should be reported explaining *speci cally* why it didn’t work or a success message should be reported and the register form input elds should be cleared.
For the backend extend the User object schema with a string eld password that will store the password. This is horribly insecure. See the Extra Credit below if you can’t bring yourself to implement something so insecure.
Extend the web server to support POST requests to the URL:
/user to allow a user to register. The registration POST takes a JSON-encoded body with the following properties: ( login_name, password, first_name, last_name, location, description, occupation ). The post request handler must make sure that the new login_name is speci ed and doesn’t already exist. The rst_name, last_name, and password must be non-empty strings as well. If the information is valid, then a
new user is created in the database. If there is an error, the response should return status 400 and a string indicating the error.
Enhance the LoginRegister view to support logging in with a password and check it as part of the post request to /admin/login .
Extra Credit #1: Salted Passwords
Enhance the security of your password mechanism by implementing salting. The salting mechanism is described in the next few paragraphs. The problem with the clear text password mechanism we implemented for Problem 4 is if someone is able to read the database (for example, a rogue system administrator) they can easily retrieve all of the passwords for all users.
A better approach is to apply a message digest function such as SHA-1 to each password, and store only the message digest in the database. SHA-1 takes a string such as a password as input and produces a 40-character string of hex digits (called a message digest) as output. The output has two interesting properties: rst, the digest provides a unique signature for the input string (there is no known way to produce two di erent strings with the same digest); second, given a message digest, there is no known way to produce a string that will generate that digest. When a user sets their password, you must invoke Node crypto (https://nodejs.org/api/crypto.html) package’s createHash
(https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm) function to generate the SHA-1 digest corresponding to that password, and store only the digest in the database; once this is done you can discard the password. When a user enters a password to login, invoke createHash function to compute the digest, and compare that digest to what is stored in the database. With this approach, you can make sure that a user types the correct password when logging in, but if someone reads the digests from the database they cannot use that information to log in.
However, the approach of the previous paragraph has one remaining aw. Suppose an attacker gets a copy of the database containing the digests. Since the SHA-1 function is public, they can employ a fast dictionary attack to guess common passwords. To do this, the attacker takes each word from a dictionary and computes its digest using SHA-1. Then the attacker checks each digest in the database against the digests in the dictionary (this can be done very quickly by putting all of the dictionary digests in a hash table). If any user has chosen a simple dictionary word as their password, the attacker can guess it quickly.
In order to make dictionary attacks more di cult, you must use password salting. When a user sets their password, compute a random number and concatenate it with the password before computing the SHA-1 digest (the crypto package randomBytes
(https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) function with a length of 8 will return a suitable random number. The random number is called a salt. Then store both the salt and the digest in the database. When checking passwords during login, retrieve the salt from the database, concatenate it to the password typed by the user, and compute the digest of this string for comparison with the digest in the database. With this approach an attacker who has gained access to the login database cannot use the simple dictionary attack described above; the digest of a dictionary word would need to include the salt for a particular account, which means that the attacker would need to recompute all of the dictionary digests for every distinct account in the database. This makes dictionary attacks more expensive.
To implement this, remove the password property from the User schema and replace it with two new string properties: password_digest and salt . Update the user register and login to use this mechanism.
You should create and write your implementation in a node module le named cs142password.js . This module should export two functions:
and
We provide a Mocha test le test/cs142passwordTest.js that tests this interface. Please make sure that you pass the tests within this le before submitting. You will need to change the package.json scripts test line to mocha serverApiTest.js sessionInputApiTest.js cs142passwordTest.js so that running npm test runs these tests too. Changing this line also serves as indication that you’ve done this extra credit. You will also need to update the loadDatabase.js script to require cs142password.js and use it to generate the correct password properties in the new user objects that the script creates.
Extra Credit #2: Handle Browser Refresh
For simplicity in the regular parts of this assignment we allow you to keep the application’s session state in JavaScript memory. Although this makes implementation easier it means that a browser refresh causes the application to forget who is logged in.
Extend your application to handle browser refresh like it did before you added the login session support. Your scheme should allow a user to do a browser refresh yet stay logged in. You are free to use whatever implemention techniques you want but they must:
Maintain backward compatibility with the other parts of this assignment, including the Mocha tests.
Not mess up the security of the application.




