summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--backend/migrations/20200201145548_password-salt.js11
-rw-r--r--backend/package-lock.json5
-rw-r--r--backend/package.json1
-rw-r--r--backend/src/routes.js68
-rw-r--r--frontend/src/App.js2
5 files changed, 61 insertions, 26 deletions
diff --git a/backend/migrations/20200201145548_password-salt.js b/backend/migrations/20200201145548_password-salt.js
new file mode 100644
index 0000000..217b02b
--- /dev/null
+++ b/backend/migrations/20200201145548_password-salt.js
@@ -0,0 +1,11 @@
+exports.up = function(knex) {
+ return knex.schema.table('users', function(table) {
+ table.string('salt').notNullable();
+ });
+};
+
+exports.down = function(knex) {
+ return knex.schema.table('users', function(table) {
+ table.dropColumn('salt');
+ });
+};
diff --git a/backend/package-lock.json b/backend/package-lock.json
index ab6d9bf..6d7cd28 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -154,6 +154,11 @@
}
}
},
+ "base-64": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
+ "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs="
+ },
"basic-auth": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
diff --git a/backend/package.json b/backend/package.json
index 0883c00..e6b64b3 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -12,6 +12,7 @@
"author": "",
"license": "ISC",
"dependencies": {
+ "base-64": "^0.1.0",
"body-parser": "^1.19.0",
"cookie-parser": "^1.4.4",
"express": "^4.17.1",
diff --git a/backend/src/routes.js b/backend/src/routes.js
index a762d3a..b0f3660 100644
--- a/backend/src/routes.js
+++ b/backend/src/routes.js
@@ -1,20 +1,21 @@
const express = require('express');
const sha512 = require('js-sha512');
const shortid = require('shortid');
-
-const salt = 'suola';
+const base64 = require('base-64');
const db = require('./db');
-const buildSessionCookie = ({ sessionId, isLogout, remember }) => {
+const buildSessionCookie = ({ username, sessionToken, isLogout, remember }) => {
if (!isLogout) {
+ const joinedToken = `${username}&${sessionToken}`;
+ const encodedToken = base64.encode(joinedToken);
if (remember) {
- return `sessionId=${sessionId}; Domain=localhost; HttpOnly; SameSite=strict;`;
+ return `sessionCookie=${encodedToken}; Domain=localhost; HttpOnly; SameSite=strict;`;
} else {
- return `sessionId=${sessionId}; Domain=localhost; HttpOnly; SameSite=strict; Max-Age=86400;`;
+ return `sessionCookie=${encodedToken}; Domain=localhost; HttpOnly; SameSite=strict; Max-Age=86400;`;
}
} else {
- return `sessionId=deleted; Domain=localhost; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=strict;`;
+ return `sessionCookie=deleted; Domain=localhost; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=strict;`;
}
};
@@ -23,29 +24,42 @@ const authedRouter = express.Router();
authedRouter.use(async (req, res, next) => {
const cookies = req.cookies;
- const { sessionId } = cookies;
+ const encodedCookie = cookies.sessionCookie;
- if (!sessionId) {
+ if (!encodedCookie) {
res.status(403);
return res.json({
message: 'Log in first!',
});
}
+ const sessionCookie = base64.decode(encodedCookie);
- const token = await db('tokens').where('value', sessionId).first();
+ const [ username, sessionToken ] = sessionCookie.split('&');
- if (!token) {
+ 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.',
- sessionId,
+ sessionCookie,
});
}
- const user = await db('users').where({ id: token.user_id }).first();
+ const salt = user.salt;
- req.sessionId = sessionId;
+ 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();
@@ -66,20 +80,24 @@ normalRouter.post('/register', async (req, res) => {
});
}
- const existingUuser = await db('users').where({ username }).first();
- if (existingUuser) {
+ 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 sessionId = shortid.generate();
- const user = (await db('users').insert({ username, password: pwHash }).returning('*'))[0];
- await db('tokens').insert({ user_id: user.id, type: 'session', value: sessionId });
- res.set('Set-Cookie', buildSessionCookie({ sessionId, remember: false, isLogout: false }));
+ 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,
});
@@ -97,10 +115,12 @@ normalRouter.post('/login', async (req, res) => {
const user = await db('users').where({ username }).first();
if (user) {
- const sessionId = shortid.generate();
- await db('tokens').insert({ user_id: user.id, type: 'session', value: sessionId });
+ 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({ sessionId, remember, isLogout: false }));
+ res.set('Set-Cookie', buildSessionCookie({ username, sessionToken, remember, isLogout: false }));
return res.json({
username,
@@ -114,9 +134,7 @@ normalRouter.post('/login', async (req, res) => {
});
authedRouter.post('/logout', async (req, res) => {
- if (req.user && req.sessionId) {
- await db('tokens').where({ value: req.sessionId }).delete();
- }
+ 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();
diff --git a/frontend/src/App.js b/frontend/src/App.js
index 19e3426..89f3e1c 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect } from 'react';
import { Router } from '@reach/router';
import Login from './Login';