Token authentication on signup /user/ POST route working, started login and auth

This commit is contained in:
Ben
2018-09-04 16:34:58 +01:00
parent 9ecfa5204f
commit 29292603a5
19 changed files with 298 additions and 52 deletions

View File

@@ -1,3 +1,4 @@
export let Controllers = {};
Controllers.UserController = require('./user').UserController;
Controllers.UserController = require('./userController').UserController;
Controllers.LoginController = require('./loginController').LoginController;

View File

@@ -0,0 +1,55 @@
import {ControllerHandler} from './controllerHandler';
import {API} from '../models/api/api';
import {Database} from '../models/database/database'
import {User} from '../models/user/user';
export class LoginController extends ControllerHandler {
static async authenticate(req, res, next) {
let errors = new API.errors(res);
let ip = req.connection.remoteAddress;
if (ip.startsWith('::ffff:')) ip = ip.substring(7);
let username = req.body.username || undefined;
let email = req.body.email || undefined;
let password = req.body.password || undefined;
if (!password) errors.addError(400, 'Bad request', 'A password is required');
if (!username && !email) errors.addError(400, 'Bad request', 'A username or email is required');
if (errors.count() > 0) {
errors.endpoint();
next();
return;
}
let id;
if (!username /*If they're loging in with email*/) {
if (await Database.users.getID('email', email) == -1) errors.addError(422, 'Unprocessable entity', 'There is no user with that email');
id = await Database.users.getID('email', email);
} else {
if (await Database.users.getID('username', username) == -1) errors.addError(422, 'Unprocessable entity', 'There is no user with that username');
id = await Database.users.getID('username', username);
}
if (errors.count() > 0) {
errors.endpoint();
next();
return;
}
let user = await Database.users.getUserByID(id);
let match = await User.Password.compare(password, user.password);
if (!match) errors.addError(401, 'Unauthorized', 'Incorrect password for user');
if (errors.count() > 0) {
errors.endpoint();
next();
return;
}
res.end('Welcome')
next();
}
}

View File

@@ -12,7 +12,8 @@ export class RateLimits extends MiddleWare{
if (!buckets[ip]) {
Logger.debug(`New rate limiting bucket`);
RateLimits.newBucket(ip);
next();
MiddleWare.analytics(req, res, next);
return;
}
@@ -25,7 +26,7 @@ export class RateLimits extends MiddleWare{
}
buckets[ip].tokens.pop();
next();
MiddleWare.analytics(req, res, next);
}
static newBucket(ip) {

View File

@@ -12,12 +12,14 @@ export class Router {
app = Server.App;
app.get('/', [MiddleWare.RateLimits.request, MiddleWare.analytics, Router.frontPage]);
app.get('/', [MiddleWare.RateLimits.request, Router.frontPage]);
app.get('/user/:id', [MiddleWare.RateLimits.request, MiddleWare.analytics,]);
app.delete('/user/:id', [MiddleWare.RateLimits.request, MiddleWare.analytics,]);
app.post('/user', [MiddleWare.RateLimits.request, MiddleWare.analytics, Controllers.UserController.newUser]);
app.get('/user/:id', [MiddleWare.RateLimits.request]);
app.delete('/user/:id', [MiddleWare.RateLimits.request]);
app.post('/user', [MiddleWare.RateLimits.request, Controllers.UserController.newUser]);
app.post('/login', [MiddleWare.RateLimits.request, Controllers.LoginController.authenticate])
app.get('*', [MiddleWare.RateLimits.request, StatusCodes.pageNotFound]);
Logger.info('HTTP endpoints settup');
}

View File

@@ -3,7 +3,7 @@ import bcrypt from 'bcrypt';
import {Logger} from '../models/logger';
import {ControllerHandler} from './controllerHandler';
import {API} from '../models/api/api';
import {Database} from '../models/database/database';
import {Database} from '../models/database/database'
import {User} from '../models/user/user';
export class UserController extends ControllerHandler {
@@ -27,16 +27,27 @@ export class UserController extends ControllerHandler {
if (await Database.users.getID('username', username) != -1) errors.addError(422, 'Unprocessable entity', 'A user with that username allready exists');
if (await Database.users.getID('email', email) != -1) errors.addError(422, 'Unprocessable entity', 'A user with that email allready exists');
let id = new Date().getTime();
let token = "1234";
if (errors.count() > 0) {
errors.endpoint();
next();
return;
}
let response = new API.user(res, id, username, email, new Date().toLocaleString());
let user = new User(id, username, password, email, ip, 1234)
let encryptedPass = await User.Password.gen(password);
password = null; // Cleaning password from memory
console.log(encryptedPass);
let status = response.getStatus;
let id = new Date().getTime();
let token = await User.Token.gen(status, id, encryptedPass);
response.Token = token;
let user = new User(id, username, encryptedPass, email, ip, 1234);
let success = await user.insert();
if (success == -1) {
errors.addError(500, 'Internal server error').endpoint();
@@ -44,7 +55,7 @@ export class UserController extends ControllerHandler {
return;
}
new API.user(res, id, username, email, new Date().toLocaleString(), token).endpoint();
response.endpoint();
next();
}

View File

@@ -7,4 +7,4 @@ export class API extends BaseAPI {
}
API.errors = require('./APIErrors').APIErrors;
API.user = require('./userResponses').User;
API.user = require('./userResponses').UserAPI;

View File

@@ -31,5 +31,4 @@ export class APIErrors extends API {
this.res
.status(this.errors.status.code)
.end(JSON.stringify(this.errors, false, 4));
}
}
}}

View File

@@ -1,8 +1,15 @@
import {API} from './API';
import {User} from '../../models/user/user';
export class User extends API {
constructor(res, id, username, email, updated, token) {
export class UserAPI extends API {
get getStatus() {return this.response.status}
set Token(t) {this.response.data[0].token = t}
set Pass(p) {this.password = p}
constructor(res, id, username, email, updated) {
super();
this.res = res;
this.response = {
status: {
error: false,
@@ -19,12 +26,22 @@ export class User extends API {
email: email,
updated: updated
},
token: token
token: null
}
]
}
}
sign(password) {
if (password) {
return this.response.data[0].token = User.Token.gen(this.response.status, this.id, password);
} else if (this.password) {
return this.response.data[0].token = User.Token.gen(this.response.status, this.id, this.password);
} else {
return -1;
}
}
endpoint() {
this.res.status(200).end(JSON.stringify(this.response, false, 4));
}

View File

@@ -50,10 +50,8 @@ export class BaseDatabase {
primaryKey: true,
unique: true
},
selector: Sequelize.TEXT,
validator: Sequelize.TEXT,
uid: Sequelize.BIGINT,
expires: Sequelize.TEXT
token: Sequelize.TEXT,
passhash: Sequelize.TEXT
}, {
tableName: `auth`
});

View File

@@ -28,3 +28,4 @@ export class Database extends BaseDatabase {
}
Database.users = require('./users').UserTools;
Database.auth = require('./tokens').TokenTools;

View File

@@ -0,0 +1,29 @@
import {BaseDatabase} from './baseDatabase';
import {Logger} from '../logger';
export class TokenTools extends BaseDatabase {
static async listAll() {
let Auth = BaseDatabase.Auth;
return Auth.findAll();
}
static async newToken(id, token, passHash) {
}
static async getTokenByID(id) {
}
static async getIDByToken(token) {
}
static async getTokenByPassHash(hash) {
}
static async updateToken(id, newToken) {
}
}

View File

@@ -60,31 +60,29 @@ export class UserTools extends BaseDatabase {
let User = BaseDatabase.User;
try {
let user;
if (column == 'id') {
return search;
} else if (column == 'username') {
let user = await User.findOne({where: {username: search}});
user = await User.findOne({where: {username: search}});
if (user == null) return -1;
return user;
} else if (column == 'email') {
let user = await User.findOne({where: {email: search}});
user = await User.findOne({where: {email: search}});
if (user == null) return -1;
return user;
} else if (column == 'password') {
let user = await User.findOne({where: {password: search}});
user = await User.findOne({where: {password: search}});
if (user == null) return -1;
return user;
} else if (column == 'ip') {
let user = await User.findOne({where: {ip: search}});
user = await User.findOne({where: {ip: search}});
if (user == null) return -1;
return user;
} else if (column == 'authcode') {
let user = await User.findOne({where: {authcode: search}});
user = await User.findOne({where: {authcode: search}});
if (user == null) return -1;
return user;
} else {
return -1
}
return user.id;
} catch (e) {
Logger.error(`An error occured while querying the id of a user where ${column} is ${search}: ${e}`);
return -1;

View File

@@ -0,0 +1,25 @@
import sha256 from 'js-sha256';
import bcrypt from 'bcrypt';
import {User} from './user';
import {Logger} from '../logger';
export class Password extends User {
static async gen(passwordSecret) {
let salt = await bcrypt.genSaltSync(10);
let prehash = await sha256(passwordSecret)
let hash = await bcrypt.hashSync(prehash, salt);
return hash;
}
static async compare(password, hashToCompare) {
try {
let prehash = await sha256(password);
let res = await bcrypt.compareSync(prehash, hashToCompare);
return res;
} catch (e) {
Logger.error(`Somthing went wrong with comparing password hashes: ${e}`);
}
}
}

16
src/models/user/token.js Normal file
View File

@@ -0,0 +1,16 @@
import jwt from 'jsonwebtoken';
import {User} from './user';
export class Token extends User {
static async gen(status, clientID, clientSecret) {
let preGen = clientID + ':' + clientSecret;
let token = await jwt.sign(status, preGen);
return token;
}
static async check() {
}
}

View File

@@ -1,10 +0,0 @@
import {User} from './user';
class tokenGen extends User {
static async gen() {
let success = false;
}
}

View File

@@ -1,6 +1,7 @@
import {Logger} from '../logger';
import {BaseUser} from './baseUser';
import {Database} from '../database/database';
import { UserTools } from '../database/users';
export class User extends BaseUser {
constructor(id, username, password, email, ip, authcode) {
@@ -17,3 +18,6 @@ export class User extends BaseUser {
return this._instance.delete();
}
}
User.Token = require('./token').Token;
User.Password = require('./passwords').Password;