CS 651 Fall 2021 Homework 9

Start Club Server and Security

Dr. Greg M. Bernstein

Due Wednesday, October 27th, 2021 by 11:59PM, 50 points.

General Instructions

Create and Use a new Branch hw9

We will create a new git branch called hw9 for use in this assignment. The branch you create must exactly match the one I’ve given you for you to receive any credit for this homework.

Prior to creating this new branch make sure your working directory is “clean”, i.e., consistent with the last commit you did when you turned in homework 8. Follow the procedures in GitHub for Classroom Use to create the new branch, i.e., git checkout -b hw9. Review the section on submission for using push with a new branch.

Use README.md for Answers

You will modify the README.md file to contain the answers to this homework.

# Homework #9 Solution
**Your name**
**NetID: yourNetID**

Questions

Question 1. (15 pts) Club Server

Create a top level directory clubServer to hold the server code for your club. This server will be primarily serving up data in JSON format for use by a front end app.

(a) Create clubServer.mjs file

Create a new server in the file clubServer.mjs in the clubServer directory. Add a handler for a “GET” method on a path /info which returns an JSON object with the following contents:

{"clubName": "Your club name",
 "ownerName": "Your Name",
 "ownerNetId": "Your NetId}

Visit this server and path with your browser and take a screen shot. Mine looks like (yours may be different depending on browser and plugins):

JSON club info

(b) Create a get activities path/method

Using your club event/activities JSON file read this information into a variable on your server and have your server return this information in response to a “GET” on the path “/activities”.

Hint: You can use the following to read and convert a JSON file to a JavaScript array/object:

import { readFile } from 'fs/promises'; 
const activities = JSON.parse(await readFile(new URL('./eventData.json',
    import.meta.url))); // activities will be an array of JS objects

Show your server code at this point here.

(c) Create a get members path/method

We will get “practice” club member data from the file clubUsers3NoPW.json. Download this into your server directory and read it into a global variable like you did in part (b). Create a “get interface” that returns just the first and last names of all the club members in JSON format.

Show the code for this interface (only).

(d) Test with node-fetch

Write a separate program called testInfoActsMems.mjs that uses node-fetch to test the above server interfaces in the following order (you should be using async/await with node-fetch):

  1. Use the /info interface to get and then print the club name.
  2. Use the /activities interface to get the activities and print out the number of activities.
  3. Use the /members interface to get member names and print out the number of members.

Take a screenshot of this test program’s output. I get:

Info test

Question 2. (15 pts) Add/Delete Activities

(a) Add Activity path/method

Create a handler to add an activity to the list of events/activities when a “POST” method is received on the path /activities. Note that this will be receiving a JSON object and you will add it to the array variable you initialized with your JSON file of events. Return the updated list of activities in the response. Note: Don’t write/update the events array! We will use a database for that later we are just learning to receive JSON based data at this point.

Show the code for handling (just) this request here.

(b) Delete Activity

Implement a “delete activity” by using a delete method on the /activities path. Assume that the activities are just kept in an array for now any you will identify them by their index in the array. This will later become a unique key in the database that we will be using. After you delete the activity from the activities array on the server return the updated array to the client via JSON. Don’t worry about bad index values after testing in part (c) show the code for this interface only here. Hint: use a “route” parameter to get the index value to be deleted and use the array method splice to remove the array entry. Do not worry that this is crude, we will use a database for this later!

(c) Test with node-fetch

Write a separate Node.js program called addDelActivityTest.mjs to test the interfaces in parts (a) and (b) by running the following tests in order:

  1. Get initial activities and print the total number of activities
  2. Add a new activity (this will be via post)
  3. Get activities (see if there is one more) print the new number of activities
  4. deleting a single activity (this will be via delete) print the new number of activities.

The output from my test program looks like:

Add/Delete test

Show your code here.

Question 3. (10 pts) Securing User Passwords

For this question you will need the mock user data I generated: clubUsers3.json. Put all work in your clubServer directory. DO NOT attach this file to your server in any way since it has plaintext passwords!!!

(a) Hash user passwords

To emulate server side storage of user information including passwords, write a Node.js program that reads in the clubUsers3.json data, hashes the password field with bcrypt, and saves the data to a new file clubUsers3Hash.json without the plaintext passwords.

Hint you can use the following code to get you started if you like.

import bcrypt from 'bcryptjs';
import { readFile, writeFile } from 'fs/promises';
const users = JSON.parse(await readFile(new URL('./clubUsers3.json',
    import.meta.url)));

let nRounds = 10;
let hashedUsers = [];
let start = new Date(); // timing code
console.log(`Starting password hashing with nRounds = ${nRounds}, ${start}`);
// Your code here to process the passwords

let elapsed = new Date() - start; // timing code
console.log(`Finished password hashing, ${elapsed/1000} seconds.`);
writeFile("clubUsers3Hash.json", JSON.stringify(hashedUsers, null, 2));

Show your code here along with a couple of entries from the clubUsers3Hash.json file.

(b) bcrypt work

By changing the “rounds” parameter to bcrypt we can make it harder (in terms of computation) to compute the password hash and thus increase our defenses a bit. Using the program from part (a) increase the number rounds (default is 10) parameter to bcrypt until it takes at least 15 seconds to run. Take a screen shot of the timing results. I get something like:

bcryptjs timing for 40 users

Question 4. (10pts) Basic Login Interface and Test

(a) Login interface and handler

Now instead of reading te clubUsers3NoPW.json file into your server use the file with the hashed passwords you created in the previous question. Add a server API with path /login and method POST to your clubServer.mjs code. This API receives a JSON message of the form: {"email": "user@email.com", "password": "Not123456!!!"}

If the email and hash of the password correctly you will return the user information (not including password hash) in JSON format. If either the password is incorrect or the user is not in the “user database” you will respond with the code “401” and a JSON message of the form: {"error": true, "message": "User/Password error" }

After you have finished testing this API in part (b) put the code for just this addition to your server here.

(b) Test Login Interface

Create a Node.js program file called loginTest.mjs within your clubServer directory. Have it perform the following login tests in order. Pick any user from the clubUsers3.json file to test with.

  1. Good email, good password

  2. Bad email (user not found)

  3. Good email, incorrect password

Show your test code here and a screen shot of the output. I get something like:

Test results screenshot