API-9: PartyPlaner Login endpoint #5
|
@ -1,4 +1,5 @@
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
|
||||||
export abstract class CommonRoutesConfig {
|
export abstract class CommonRoutesConfig {
|
||||||
app: express.Application;
|
app: express.Application;
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -8,8 +9,10 @@ export abstract class CommonRoutesConfig {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.configureRoutes();
|
this.configureRoutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
getName() {
|
||||||
return this.name;
|
return this.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract configureRoutes(): express.Application;
|
abstract configureRoutes(): express.Application;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as appRoot from "app-root-path";
|
import * as appRoot from 'app-root-path';
|
||||||
import * as winston from "winston";
|
import * as winston from 'winston';
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
file_info: {
|
file_info: {
|
||||||
|
@ -34,7 +34,7 @@ const options = {
|
||||||
handleExceptions: true,
|
handleExceptions: true,
|
||||||
json: false,
|
json: false,
|
||||||
colorize: true
|
colorize: true
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
const logger: winston.Logger = winston.createLogger({
|
const logger: winston.Logger = winston.createLogger({
|
||||||
format: winston.format.combine(
|
format: winston.format.combine(
|
||||||
|
@ -47,6 +47,6 @@ const logger: winston.Logger = winston.createLogger({
|
||||||
new winston.transports.File(options.file_debug),
|
new winston.transports.File(options.file_debug),
|
||||||
new winston.transports.Console(options.console)
|
new winston.transports.Console(options.console)
|
||||||
],
|
],
|
||||||
exitOnError: false, // do not exit on handled exceptions
|
exitOnError: false // do not exit on handled exceptions
|
||||||
});
|
});
|
||||||
export default logger;
|
export default logger;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
import express, {Request, Response} from 'express';
|
import express, {Request, Response} from 'express';
|
||||||
import {generalInfoRouter} from './generalInfo/GeneralInfo.router';
|
import {generalInfoRouter} from './generalInfo/GeneralInfo.router';
|
||||||
import logger from "../../middleware/logger";
|
import logger from '../../middleware/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router Definition
|
* Router Definition
|
||||||
|
@ -20,4 +20,4 @@ dhbwServiceRouter.get('/', async (req: Request, res: Response) => {
|
||||||
logger.error('Error handling a request: ' + e.message);
|
logger.error('Error handling a request: ' + e.message);
|
||||||
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Required External Modules and Interfaces
|
* Required External Modules and Interfaces
|
||||||
*/
|
*/
|
||||||
import express, {Request, Response} from 'express';
|
import express, {Request, Response} from 'express';
|
||||||
import logger from "../../../middleware/logger";
|
import logger from '../../../middleware/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router Definition
|
* Router Definition
|
||||||
|
@ -16,7 +16,7 @@ generalInfoRouter.get('/', async (req: Request, res: Response) => {
|
||||||
logger.error('Error handling a request: ' + e.message);
|
logger.error('Error handling a request: ' + e.message);
|
||||||
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
generalInfoRouter.post('/', async (req: Request, res: Response) => {
|
generalInfoRouter.post('/', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
|
@ -25,4 +25,4 @@ generalInfoRouter.post('/', async (req: Request, res: Response) => {
|
||||||
logger.error('Error handling a request: ' + e.message);
|
logger.error('Error handling a request: ' + e.message);
|
||||||
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
import express, {Request, Response} from 'express';
|
import express, {Request, Response} from 'express';
|
||||||
import {dataRouter} from './data/Data.router';
|
import {dataRouter} from './data/Data.router';
|
||||||
import {registerRouter} from './register/Register.router';
|
import {registerRouter} from './register/Register.router';
|
||||||
import logger from "../../middleware/logger";
|
import logger from '../../middleware/logger';
|
||||||
|
import {loginRouter} from './login/Login.router';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router Definition
|
* Router Definition
|
||||||
|
@ -14,6 +15,7 @@ export const partyPlanerRouter = express.Router();
|
||||||
// Sub-Endpoints
|
// Sub-Endpoints
|
||||||
partyPlanerRouter.use('/data', dataRouter);
|
partyPlanerRouter.use('/data', dataRouter);
|
||||||
partyPlanerRouter.use('/register', registerRouter);
|
partyPlanerRouter.use('/register', registerRouter);
|
||||||
|
partyPlanerRouter.use('/login', loginRouter);
|
||||||
|
|
||||||
partyPlanerRouter.get('/', async (req: Request, res: Response) => {
|
partyPlanerRouter.get('/', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
|
@ -22,4 +24,4 @@ partyPlanerRouter.get('/', async (req: Request, res: Response) => {
|
||||||
logger.error('Error handling a request: ' + e.message);
|
logger.error('Error handling a request: ' + e.message);
|
||||||
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Required External Modules and Interfaces
|
* Required External Modules and Interfaces
|
||||||
*/
|
*/
|
||||||
import express, {Request, Response} from 'express';
|
import express, {Request, Response} from 'express';
|
||||||
import logger from "../../../middleware/logger";
|
import logger from '../../../middleware/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router Definition
|
* Router Definition
|
||||||
|
@ -16,7 +16,7 @@ dataRouter.get('/', async (req: Request, res: Response) => {
|
||||||
logger.error('Error handling a request: ' + e.message);
|
logger.error('Error handling a request: ' + e.message);
|
||||||
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
dataRouter.post('/', async (req: Request, res: Response) => {
|
dataRouter.post('/', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
|
@ -25,4 +25,4 @@ dataRouter.post('/', async (req: Request, res: Response) => {
|
||||||
logger.error('Error handling a request: ' + e.message);
|
logger.error('Error handling a request: ' + e.message);
|
||||||
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
51
src/models/partyplaner/login/Login.router.ts
Normal file
51
src/models/partyplaner/login/Login.router.ts
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
* Required External Modules and Interfaces
|
||||||
|
*/
|
||||||
|
import express, {Request, Response} from 'express';
|
||||||
|
import * as UserService from '../userService/user.service';
|
||||||
|
import logger from '../../../middleware/logger';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Router Definition
|
||||||
|
*/
|
||||||
|
export const loginRouter = express.Router();
|
||||||
|
|
||||||
|
loginRouter.post('/:isDevCall', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
let username: string = '';
|
||||||
|
let email: string = '';
|
||||||
|
let firstName: string = '';
|
||||||
|
let lastName: string = '';
|
||||||
|
let password: string = '';
|
||||||
|
let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD
|
||||||
|
|
||||||
|
// API accepts both JSON in body and HTTP parameters
|
||||||
|
if (req.headers['content-type'] === 'application/json') {
|
||||||
|
username = req.body.username;
|
||||||
|
email = req.body.email;
|
||||||
|
password = req.body.password;
|
||||||
|
} else if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
|
||||||
|
username = (req.query.username ?? '').toString();
|
||||||
|
email = (req.query.email ?? '').toString();
|
||||||
|
password = (req.query.password ?? '').toString();
|
||||||
|
}
|
||||||
|
let userIP = req.socket.remoteAddress ?? '';
|
||||||
|
let deviceInfo = req.headers['user-agent'] ?? '';
|
||||||
|
|
||||||
|
if ((username === '' && email === '') || password === '') {
|
||||||
|
res.status(400).send({
|
||||||
|
'status': 'WRONG_PARAMS',
|
||||||
|
'message': 'Missing or wrong parameters'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check password and create session
|
||||||
|
let session = await UserService.loginUser(useDev, username, email, password, userIP, deviceInfo);
|
||||||
|
|
||||||
|
res.status(200).send(session);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('Error handling a request: ' + e.message);
|
||||||
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
|
}
|
||||||
|
});
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
import express, {Request, Response} from 'express';
|
import express, {Request, Response} from 'express';
|
||||||
import * as UserService from '../userService/user.service';
|
import * as UserService from '../userService/user.service';
|
||||||
import logger from "../../../middleware/logger";
|
import logger from '../../../middleware/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router Definition
|
* Router Definition
|
||||||
|
@ -65,4 +65,4 @@ registerRouter.post('/:isDevCall', async (req: Request, res: Response) => {
|
||||||
logger.error('Error handling a request: ' + e.message);
|
logger.error('Error handling a request: ' + e.message);
|
||||||
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
|
@ -20,6 +20,11 @@ const dev_pool = mariadb.createPool({
|
||||||
connectionLimit: 5
|
connectionLimit: 5
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all usernames and emails from the database and returns them in an object
|
||||||
|
* @param useDev If the dev or prod database should be used
|
||||||
|
* @return any An object with a list of usernames and emails
|
||||||
|
*/
|
||||||
export const getExistingUsernamesAndEmails = async (useDev: boolean): Promise<any> => {
|
export const getExistingUsernamesAndEmails = async (useDev: boolean): Promise<any> => {
|
||||||
let conn;
|
let conn;
|
||||||
try {
|
try {
|
||||||
|
@ -52,7 +57,7 @@ export const getExistingUsernamesAndEmails = async (useDev: boolean): Promise<an
|
||||||
conn.end();
|
conn.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used in the registerUser and loginUser methods as return value
|
* Used in the registerUser and loginUser methods as return value
|
||||||
|
@ -63,6 +68,17 @@ export interface Session {
|
||||||
sessionKey: string;
|
sessionKey: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new user and a new session
|
||||||
|
* @param useDev If the dev or prod database should be used
|
||||||
|
* @param username The username of the new user
|
||||||
|
* @param email The email address of the new user
|
||||||
|
* @param firstName The first name of the new user
|
||||||
|
* @param lastName The last name of the new user
|
||||||
|
* @param password The password of the new user
|
||||||
|
* @param ip The IP Address of the new user
|
||||||
|
* @param deviceInfo The user agent of the new user
|
||||||
|
*/
|
||||||
export const registerUser = async (useDev: boolean, username: string, email: string, firstName: string, lastName: string, password: string, ip: string, deviceInfo: string): Promise<Session> => {
|
export const registerUser = async (useDev: boolean, username: string, email: string, firstName: string, lastName: string, password: string, ip: string, deviceInfo: string): Promise<Session> => {
|
||||||
let conn;
|
let conn;
|
||||||
try {
|
try {
|
||||||
|
@ -122,8 +138,92 @@ export const registerUser = async (useDev: boolean, username: string, email: str
|
||||||
conn.end();
|
conn.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks credentials of a user and creates a new session if they are correct
|
||||||
|
* @param useDev If the dev or prod database should be used
|
||||||
|
* @param username The username of the new user
|
||||||
|
* @param email The email address of the new user
|
||||||
|
* @param password The password of the new user
|
||||||
|
* @param ip The IP Address of the new user
|
||||||
|
* @param deviceInfo The user agent of the new user
|
||||||
|
*/
|
||||||
|
export const loginUser = async (useDev: boolean, username: string, email: string, password: string, ip: string, deviceInfo: string): Promise<Session> => {
|
||||||
|
let conn;
|
||||||
|
try {
|
||||||
|
if (useDev) {
|
||||||
|
conn = await dev_pool.getConnection();
|
||||||
|
} else {
|
||||||
|
conn = await prod_pool.getConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let query_result;
|
||||||
|
|
||||||
|
// Get the saved hash
|
||||||
|
if (username !== '') {
|
||||||
|
query_result = await conn.query('SELECT user_id, password_hash FROM users WHERE username = ?', username);
|
||||||
|
} else {
|
||||||
|
query_result = await conn.query('SELECT user_id, password_hash FROM users WHERE email = ?', email);
|
||||||
|
}
|
||||||
|
|
||||||
|
let passwordHash: string = '';
|
||||||
|
let userId: string = '';
|
||||||
|
|
||||||
|
for (let row in query_result) {
|
||||||
|
if (row !== 'meta') {
|
||||||
|
passwordHash = query_result[row].password_hash;
|
||||||
|
userId = query_result[row].user_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrong password
|
||||||
|
if (!bcrypt.compareSync(password, passwordHash)) {
|
||||||
|
return {} as Session;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update user last login
|
||||||
|
await conn.query('UPDATE users SET last_login = NOW() WHERE user_id = ?', userId);
|
||||||
|
await conn.commit();
|
||||||
|
|
||||||
|
// Create session
|
||||||
|
const sessionKey = Guid.create().toString();
|
||||||
|
const sessionKeyHash = bcrypt.hashSync(sessionKey, 10);
|
||||||
|
|
||||||
|
let deviceType = 'unknown';
|
||||||
|
if (deviceInfo.includes('PartyPlaner') || deviceInfo.includes('Dart')) {
|
||||||
|
deviceType = 'mobile';
|
||||||
|
} else {
|
||||||
|
deviceType = 'desktop';
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessionQuery = 'INSERT INTO sessions (user_id, session_key_hash, created_Date, last_login, valid_until, valid_days, last_ip, device_info, type) VALUES (?,?,NOW(),NOW(),DATE_ADD(NOW(), INTERVAL 365 DAY),365,?, ?, ?) RETURNING session_id';
|
||||||
|
const sessionIdRes = await conn.query(sessionQuery, [userId, sessionKeyHash, ip, deviceInfo, deviceType]);
|
||||||
|
await conn.commit();
|
||||||
|
|
||||||
|
// Get session id of the created session
|
||||||
|
let sessionId: number = -1;
|
||||||
|
for (const row in sessionIdRes) {
|
||||||
|
if (row !== 'meta' && sessionIdRes[row].session_id != null) {
|
||||||
|
sessionId = sessionIdRes[row].session_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'userId': userId.toString(),
|
||||||
|
'sessionId': sessionId.toString(),
|
||||||
|
'sessionKey': sessionKey
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
if (conn) {
|
||||||
|
conn.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used in the checkUsernameAndEmail method as return value
|
* Used in the checkUsernameAndEmail method as return value
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
import express, {Request, Response} from 'express';
|
import express, {Request, Response} from 'express';
|
||||||
import {addHighlightRouter} from './addHighlight/AddHighlight.router';
|
import {addHighlightRouter} from './addHighlight/AddHighlight.router';
|
||||||
import logger from "../../middleware/logger";
|
import logger from '../../middleware/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router Definition
|
* Router Definition
|
||||||
|
@ -19,4 +19,4 @@ highlightMarkerRouter.get('/', async (req: Request, res: Response) => {
|
||||||
logger.error('Error handling a request: ' + e.message);
|
logger.error('Error handling a request: ' + e.message);
|
||||||
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
import express, {Request, Response} from 'express';
|
import express, {Request, Response} from 'express';
|
||||||
import * as AddHighlightService from './addHighlights.service';
|
import * as AddHighlightService from './addHighlights.service';
|
||||||
import logger from "../../../middleware/logger";
|
import logger from '../../../middleware/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router Definition
|
* Router Definition
|
||||||
|
@ -17,7 +17,7 @@ addHighlightRouter.get('/', (req: Request, res: Response) => {
|
||||||
logger.error('Error handling a request: ' + e.message);
|
logger.error('Error handling a request: ' + e.message);
|
||||||
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
addHighlightRouter.post('/', (req: Request, res: Response) => {
|
addHighlightRouter.post('/', (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
|
@ -43,4 +43,4 @@ addHighlightRouter.post('/', (req: Request, res: Response) => {
|
||||||
logger.error('Error handling a request: ' + e.message);
|
logger.error('Error handling a request: ' + e.message);
|
||||||
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
res.status(500).send({'message': 'Internal Server Error. Try again later.'});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
|
@ -11,6 +11,10 @@ const pool = mariadb.createPool({
|
||||||
connectionLimit: 5
|
connectionLimit: 5
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new highlight entry in SQL
|
||||||
|
* @param req_body The request body
|
||||||
|
*/
|
||||||
export const createHighlightEntry = async (req_body: any) => {
|
export const createHighlightEntry = async (req_body: any) => {
|
||||||
let conn;
|
let conn;
|
||||||
try {
|
try {
|
||||||
|
@ -35,4 +39,4 @@ export const createHighlightEntry = async (req_body: any) => {
|
||||||
conn.end();
|
conn.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user