summaryrefslogtreecommitdiffstats
path: root/backend/src/authn.js
diff options
context:
space:
mode:
authorJan Tuomi <jan.tuomi@eficode.com>2020-02-05 19:25:36 +0200
committerJan Tuomi <jan.tuomi@eficode.com>2020-02-05 19:25:36 +0200
commit71d9490d0988c97b8b023a70e0b61c65f32ad3b9 (patch)
treedf6f3db2c1f3c3ef9339843431a79197b465a74c /backend/src/authn.js
parent48a60c896d86de9bf76806ca60da35ef9f77259e (diff)
Implement permissions
Diffstat (limited to 'backend/src/authn.js')
-rw-r--r--backend/src/authn.js139
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,
+};