diff options
| author | Jan Tuomi <jan.tuomi@eficode.com> | 2020-02-05 19:25:36 +0200 |
|---|---|---|
| committer | Jan Tuomi <jan.tuomi@eficode.com> | 2020-02-05 19:25:36 +0200 |
| commit | 71d9490d0988c97b8b023a70e0b61c65f32ad3b9 (patch) | |
| tree | df6f3db2c1f3c3ef9339843431a79197b465a74c /backend/src/authn.js | |
| parent | 48a60c896d86de9bf76806ca60da35ef9f77259e (diff) | |
Implement permissions
Diffstat (limited to 'backend/src/authn.js')
| -rw-r--r-- | backend/src/authn.js | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/backend/src/authn.js b/backend/src/authn.js new file mode 100644 index 0000000..c6c4a2e --- /dev/null +++ b/backend/src/authn.js @@ -0,0 +1,139 @@ +const base64 = require('base-64'); +const sha512 = require('js-sha512'); +const shortid = require('shortid'); +const db = require('./db'); + +const buildSessionCookie = ({ username, sessionToken, isLogout }) => { + if (!isLogout) { + const tokenData = { + username, + sessionToken, + }; + const tokenDataStr = JSON.stringify(tokenData); + const encodedToken = base64.encode(tokenDataStr); + return `sessionCookie=${encodedToken}; Domain=localhost; HttpOnly; SameSite=strict;`; + } else { + return `sessionCookie=deleted; Domain=localhost; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=strict;`; + } +}; + +const authMiddleware = async (req, res, next) => { + const cookies = req.cookies; + const encodedCookie = cookies.sessionCookie; + + if (!encodedCookie) { + res.status(403); + return res.json({ + message: 'Log in first!', + }); + } + const sessionCookieStr = base64.decode(encodedCookie); + const sessionCookie = JSON.parse(sessionCookieStr); + + const { username, sessionToken } = sessionCookie; + + const user = await db('users').where({ username }).first(); + if (!user) { + res.status(400); + res.set('Set-Cookie', buildSessionCookie({ isLogout: true })); + return res.json({ + message: 'Invalid session token.', + sessionCookie, + }); + } + + const salt = user.salt; + + const sessionTokenHash = sha512(salt + sessionToken); + const token = await db('tokens').where({ type: 'session', value: sessionTokenHash }); + if (!token) { + res.status(400); + res.set('Set-Cookie', buildSessionCookie({ isLogout: true })); + return res.json({ + message: 'Invalid session token.', + sessionCookie, + }); + } + + req.sessionTokenHash = sessionTokenHash; + req.user = user; + + next(); +}; + +const registerRoute = async (req, res) => { + const { username, password } = req.body; + if (!username || !password) { + res.status(400); + return res.json({ + error: 'Username or password missing.', + }); + } + + const existingUser = await db('users').where({ username }).first(); + if (existingUser) { + res.status(400); + return res.json({ + error: 'Username already taken.', + }); + } + + const salt = shortid.generate(); + const pwHash = sha512(salt + password); + + const sessionToken = shortid.generate(); + const sessionTokenHash = sha512(salt + sessionToken); + + const user = (await db('users').insert({ username, password: pwHash, salt }).returning('*'))[0]; + await db('tokens').insert({ user_id: user.id, type: 'session', value: sessionTokenHash }); + + res.set('Set-Cookie', buildSessionCookie({ username, sessionToken, remember: false, isLogout: false })); + return res.json({ + username, + }); +}; + +const loginRoute = async (req, res) => { + const { username, password, remember } = req.body; + if (!username || !password) { + res.status(400); + return res.json({ + error: 'Username or password missing.', + }); + } + + const user = await db('users').where({ username }).first(); + + if (user) { + const sessionToken = shortid.generate(); + const sessionTokenHash = sha512(user.salt + sessionToken); + + await db('tokens').insert({ user_id: user.id, type: 'session', value: sessionTokenHash }); + + res.set('Set-Cookie', buildSessionCookie({ username, sessionToken, remember, isLogout: false })); + + return res.json({ + username, + }); + } + + res.status(403); + res.json({ + error: 'Wrong username or password', + }); +}; + +const logoutRoute = async (req, res) => { + await db('tokens').where({ type: 'session', user_id: req.user.id, value: req.sessionTokenHash }).delete(); + res.status(204); + res.set('Set-Cookie', buildSessionCookie({ isLogout: true })); + res.send(); +}; + +module.exports = { + buildSessionCookie, + authMiddleware, + registerRoute, + loginRoute, + logoutRoute, +}; |
