How do I add a password checking middleware in node js express

Viewed 439

I am trying to make a middleware which displays a form which asks for a password to enter a route.

The problem is that I am in a get route and there is no way for me to pass the data in a get request because I do not want to pass the password in the url. So I tried to make a middleware which displays a form with hidden info like the id of what chat the customer wants to access which submits to another route (post). In the post route it checks if the password is correct and if it is goes back to the original route (get) and displays the chat.

Here's what I've done so far:

The GET route:

router.get('/chats/:id', middleware.isLoggedIn, middleware.isAllowed, catchAsync(async (req, res, next) => {
    const foundChat = await Chat.findOne({
      _id: req.params.id
    })
    console.log('here', foundChat)
    res.render('chat/show', {
      chat: foundChat
    })
}))

The POST route

router.post('/chats/password', middleware.askForPassword)

The middlewares

middleware.isAllowed = async function (req, res, next) {
  if (req.cookies.allowed) {
    if (req.cookies.allowed.includes(req.params.id)) {
      req.body.password = null
      return next()
    }
  } else {
    res.redirect('/chats/password')
  }
}
middleware.askForPassword = async function (req, res, next) {
  try {
    const hashedDBPassword = await Chat.findById(req.params.id)
    const password = req.body.password
    const passwordHashed = hashedDBPassword.password
    const cookieName = encodeURIComponent(hashedDBPassword.name)
    const resultCompare = await bcrypt.compare(password, passwordHashed)
    let value
    if (req.cookies.allowed === undefined) {
      res.cookie('allowed', [], {
        maxAge: 30000,
        httpOnly: true
      })
    }
    if (resultCompare === true) {
      value = req.cookies.allowed
      value.push(passwordHashed)
      res.cookie('allowed', value, {
        maxAge: 30000,
        httpOnly: true
      })
      res.redirect('/chats/' + req.body.id)
    } else {
      global.nextMiddleware = true
      res.render('chat/password', {
        id: req.body.id
      })
    }
  } catch (err) {
    console.log(err)
    res.redirect('/chats')
  }
}

The form

<% layout("layouts/boilerplate.ejs") %>
<form action="/chats/password" method="post">
<input type="password" name="password" id="password">
<input type="hidden" name="id" value="<%= id %>">
<input type="submit" value="Go!">
</form>
1 Answers

If you want your code to be RESTful, then routes might look like this:

POST /auth
GET /auth
GET /auth/:sessionId
DELETE /auth/:sessionId
GET /chat/:chatId

Method POST /auth, should set authorization cookie and return sessionId to the client. Client can put sessionId into localStorage. Also there could be optional parameter redirect, which could redirect successful request to specified URL. But you should use it carefully, and not allow to redirect to external hosts.

Method GET /auth lists all live sessions opened by current user. It might be helpful when you need to close sessions on other devices.

Method GET /auth/:sessionId returns session by its ID. It can contain information about session, like last activity, device (browser or mobile), etc.

Method DELETE /auth/:sessionId receives sessionId from route, verify session ownership with authorization cookie, marks session closed in DB (if you store sessions in DB), and removes authorization cookie.

Method GET /chat/:chatId relies on HTTP only authorization cookie (work like it works now).

You can send POST request via XHR from the frontend, receive a successful response and then navigate to the chat.

Related