Category: Week 6

Never hash passwords synchronously

In our group project this week we used the bcrypt.js Node.js module to hash our users passwords before storing them in our database, specifically using the .hashSync() method:

const bcrypt = require("bcryptjs");

const salt = bcrypt.genSaltSync(10);
user.password = bcrypt.hashSync(user.password, salt);

In our code review our course leader pointed out that hashing is designed to take a long time for security purposes, so using the synchronous method of hashing will block our server code until the process is finished.

Instead we should do it asynchronously using promises:

const bcrypt = require("bcryptjs");

bcrypt.genSalt(10).then((salt) => bcrypt.hash(user.password, salt));

Finding unique items in arrays using the Set object

If we take the following array:
const arr = [4, 5, 4, 6, 3, 4, 5, 2, 23, 1, 4, 4, 4];

Instead of using filter on an array to find its unique values:

const unique = arr.filter((n, i, arr) => arr.indexOf(n) === i);

JavaScript has the Set object which stores unique values.

We can use Array.from to create a new array from the Set:

const unique = Array.from(new Set(arr));

Or we can use the spread operator to create a copy of the array:

const unique = [...new Set(arr)]

All of these evaluate to the same array of unique values:
console.log(unique); // [4, 5, 6, 3, 2, 23, 1]

Spread operator for objects

I’ve seen the spread operator many times, but haven’t needed to use it until today. This was the syntax:

function addNewProperty(object) { 
  return fetch("url")
    .then((property) => {
      const newObject = {...object}; 
      newObject.newProperty = property;
      return newObject; 
    })
}

{…object} creates a copy of the object passed into the addNewProperty() function. Then the property resolved from the promise is added to the copy and a new object is returned.

Advanced form validation

Until today I have only thought of form validation in terms of putting the required attribute on my <input> elements. This lets the native constraint validation behaviour of HTML5 do the work of checking that the user inputs are filled in and in the correct format.

Today we learned about the disadvantages of relying on this method, namely that the error messages are not accessible to screen readers and cannot be styled, and that inputs are invalid by default before the user has even had the chance to interact with them.

We can add custom validation with JavaScript, firstly we need to override the default form behaviour and prevent the in-built errors from appearing:
document.querySelector("form").setAttribute("novalidate", "");

Using the .checkValidity() method we can display custom error messages for invalid inputs. These error messages can now be styled in a meaningful way to the user, and aria labels can be added to make them accessible.

However, it is still good practice to have HTML constraint validation in case the JavaScript does not load or breaks.

Cookies in Node.js 🍪

In Node.js you can attach cookies to the server response using the Set-Cookie header in your router.js file:

response.writeHead(302, {
  'Set-Cookie': 'loggedin=true; HttpOnly; Max-Age=9000'});

You can set multiple cookies in an array:

response.writeHead(302, {
  'Set-Cookie': ['cookie1=example'], ['cookie2=example']});

You can remove the cookie by overwriting the values you’ve set or setting the Max-Age to 0:

response.writeHead(302, {
  'Set-Cookie': 'loggedin=0; HttpOnly; Max-Age=0'});

You can view cookies on the Chrome Dev Tools in the Application tab.