New users can now be created.
- Note: Login is buggy with a brand new account
This commit is contained in:
@@ -11,7 +11,7 @@ import * as winston from 'winston';
|
||||
import { config } from './config';
|
||||
import { GetBeat, GetBeatStats } from './endpoints/beat';
|
||||
import { GetPhone, PostPhone } from './endpoints/phone';
|
||||
import { DeleteUser, GetUser, LoginRabbitUser, LoginUser, MW_User, PatchUser, Resource, Topic, VHost } from './endpoints/user';
|
||||
import { DeleteUser, GetUser, LoginRabbitUser, LoginUser, MW_User, PatchUser, PostUser, Resource, Topic, VHost } from './endpoints/user';
|
||||
import { hashPassword, randomPepper, randomString } from './lib/crypto';
|
||||
import { RabbitMQ } from './lib/rabbit';
|
||||
import { UserType } from './models/user/user.interface';
|
||||
@@ -147,6 +147,7 @@ async function run() {
|
||||
|
||||
// Basic user actions
|
||||
app.get('/user/', MW_User, (req, res) => GetUser(req, res));
|
||||
app.post('/user/', MW_User, (req, res) => PostUser(req, res));
|
||||
app.get('/user/:id', MW_User, (req, res) => GetUser(req, res));
|
||||
app.patch('/user/:id', MW_User, (req, res) => PatchUser(req, res));
|
||||
app.delete('/user/:id', MW_User, (req, res) => DeleteUser(req, res));
|
||||
|
||||
@@ -22,8 +22,11 @@ export async function GetBeatStats(req: LivebeatRequest, res: Response) {
|
||||
export async function GetBeat(req: LivebeatRequest, res: Response) {
|
||||
const from: number = Number(req.query.from);
|
||||
const to: number = Number(req.query.to);
|
||||
const limit: number = Number(req.query.limit || 10000);
|
||||
const sort: number = Number(req.query.sort || 1); // Either -1 or 1
|
||||
const phoneId = req.query.phoneId;
|
||||
|
||||
// Grab default phone if non was provided.
|
||||
const phone = req.query.phone === undefined ? await Phone.findOne({ user: req.user?._id }) : await Phone.findOne({ _id: phoneId, user: req.user?._id });
|
||||
let beats: IBeat[] = []
|
||||
|
||||
@@ -35,7 +38,7 @@ export async function GetBeat(req: LivebeatRequest, res: Response) {
|
||||
$gte: new Date((from | 0) * 1000),
|
||||
$lte: new Date((to | Date.now() /1000) * 1000)
|
||||
}
|
||||
}).sort({ _id: 1 });
|
||||
}).sort({ _id: sort }).limit(limit);
|
||||
res.status(200).send(beats);
|
||||
} else {
|
||||
res.status(404).send({ message: 'Phone not found' });
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
import { Request, Response } from "express";
|
||||
import { verifyPassword } from "../lib/crypto";
|
||||
import { User } from "../models/user/user.model";
|
||||
import { sign, decode, verify } from 'jsonwebtoken';
|
||||
import { JWT_SECRET, logger, RABBITMQ_URI } from "../app";
|
||||
import { Request, Response } from 'express';
|
||||
import { decode, sign, verify } from 'jsonwebtoken';
|
||||
|
||||
import { JWT_SECRET, logger, RABBITMQ_URI } from '../app';
|
||||
import * as jwt from 'jsonwebtoken';
|
||||
import { config } from '../config';
|
||||
import { hashPassword, randomPepper, randomString, verifyPassword } from '../lib/crypto';
|
||||
import { LivebeatRequest } from '../lib/request';
|
||||
import { SchemaTypes } from "mongoose";
|
||||
import { Phone } from "../models/phone/phone.model";
|
||||
import { UserType } from "../models/user/user.interface";
|
||||
import { UserType } from '../models/user/user.interface';
|
||||
import { User } from '../models/user/user.model';
|
||||
|
||||
export async function GetUser(req: LivebeatRequest, res: Response) {
|
||||
let user: any = req.user;
|
||||
let user: any = req.params.id === undefined ? req.user : await User.findById(req.params.id);
|
||||
|
||||
if (user === null) {
|
||||
res.status(404).send();
|
||||
return;
|
||||
}
|
||||
|
||||
user.password = undefined;
|
||||
user.salt = undefined;
|
||||
user.__v = undefined;
|
||||
@@ -17,6 +24,54 @@ export async function GetUser(req: LivebeatRequest, res: Response) {
|
||||
res.status(200).send(user);
|
||||
}
|
||||
|
||||
export async function PostUser(req: LivebeatRequest, res: Response) {
|
||||
// Only admin can create new users
|
||||
if (req.user?.type !== UserType.ADMIN) {
|
||||
res.status(401).send({ message: 'Only admins can create new users.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const name = req.body.name;
|
||||
const password = req.body.password;
|
||||
const type = req.body.type;
|
||||
|
||||
if (name === undefined || password === undefined || type === undefined) {
|
||||
res.status(400).send();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Object.values(UserType).includes(type)) {
|
||||
res.status(400).send({ message: 'The user type can only be \'guest\', \'user\', \'admin\'.' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (await User.countDocuments({ name }) === 1) {
|
||||
res.status(409).send();
|
||||
return;
|
||||
}
|
||||
|
||||
const salt = randomString(config.authentification.salt_length);
|
||||
const brokerToken = randomString(16);
|
||||
const hashedPassword = await hashPassword(password + salt + randomPepper()).catch(error => {
|
||||
res.status(400).send({ message: 'Provided password is too weak and cannot be used.' });
|
||||
return;
|
||||
}) as string;
|
||||
|
||||
const newUser = await User.create({
|
||||
name,
|
||||
password: hashedPassword,
|
||||
salt,
|
||||
brokerToken,
|
||||
type,
|
||||
lastLogin: new Date(0)
|
||||
});
|
||||
|
||||
// Create setup token that the new user can use to change his password.
|
||||
const setupToken = jwt.sign({ setupForUser: newUser._id }, JWT_SECRET, { expiresIn: '1d' });
|
||||
|
||||
res.status(200).send({ setupToken });
|
||||
}
|
||||
|
||||
export async function DeleteUser(req: Request, res: Response) {
|
||||
|
||||
}
|
||||
@@ -72,15 +127,16 @@ export async function LoginUser(req: Request, res: Response) {
|
||||
export async function LoginRabbitUser(req: Request, res: Response) {
|
||||
const username = req.query.username;
|
||||
const password = req.query.password;
|
||||
res.status(200);
|
||||
|
||||
if (username === undefined || password === undefined) {
|
||||
res.status(200).send('deny');
|
||||
res.send('deny');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if request comes from backend. Basicly, we permitting ourself to connect with RabbitMQ.
|
||||
if (username === "backend" && password === RABBITMQ_URI.split(':')[2].split('@')[0]) {
|
||||
res.status(200).send('allow administrator');
|
||||
res.send('allow administrator');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -89,22 +145,22 @@ export async function LoginRabbitUser(req: Request, res: Response) {
|
||||
|
||||
// If we are here, it means we have a non-admin user.
|
||||
if (user === null) {
|
||||
res.status(200).send('deny');
|
||||
res.send('deny');
|
||||
return;
|
||||
}
|
||||
|
||||
// Auth token for message broker is stored in plain text since it's randomly generated and only grants access to the broker.
|
||||
if (user.brokerToken === password.toString()) {
|
||||
if (user.type === UserType.ADMIN) {
|
||||
res.status(200).send('allow administrator');
|
||||
res.send('allow administrator');
|
||||
} else {
|
||||
// Not an admin, grant user privilieges
|
||||
res.status(200).send('allow user')
|
||||
res.send('allow user')
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200).send('deny');
|
||||
res.send('deny');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user