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):
(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
):
- Use the
/info
interface to get and then print the club name. - Use the
/activities
interface to get the activities and print out the number of activities. - 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:
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:
- Get initial activities and print the total number of activities
- Add a new activity (this will be via post)
- Get activities (see if there is one more) print the new number of activities
- deleting a single activity (this will be via delete) print the new number of activities.
The output from my test program looks like:
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:
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.
Good email, good password
Bad email (user not found)
Good email, incorrect password
Show your test code here and a screen shot of the output. I get something like: