express-generator-typescript 1.10.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -25
- package/bin/cli.js +2 -15
- package/lib/cli.js +1 -15
- package/lib/express-generator-typescript.js +15 -23
- package/lib/project-files/.eslintrc.json +15 -2
- package/lib/project-files/build.ts +2 -2
- package/lib/project-files/package.json +15 -5
- package/lib/project-files/spec/nodemon.json +1 -1
- package/lib/{auth-proj → project-files}/spec/support/login-agent.ts +0 -0
- package/lib/{auth-proj → project-files}/spec/tests/auth.spec.ts +18 -32
- package/lib/project-files/spec/tests/users.spec.ts +31 -22
- package/lib/project-files/spec/types/supertest/index.d.ts +14 -0
- package/lib/project-files/src/models/user-model.ts +17 -2
- package/lib/project-files/src/pre-start/env/development.env +9 -0
- package/lib/project-files/src/pre-start/env/production.env +10 -0
- package/lib/project-files/src/pre-start/env/test.env +9 -0
- package/lib/{auth-proj → project-files}/src/public/scripts/http.js +0 -0
- package/lib/{auth-proj → project-files}/src/public/scripts/login.js +0 -0
- package/lib/{auth-proj → project-files}/src/public/scripts/users.js +0 -0
- package/lib/{auth-proj → project-files}/src/public/stylesheets/login.css +0 -0
- package/lib/{auth-proj → project-files}/src/public/stylesheets/users.css +0 -0
- package/lib/project-files/src/repos/user-repo.ts +7 -7
- package/lib/project-files/src/routes/api.ts +9 -6
- package/lib/{auth-proj → project-files}/src/routes/auth-router.ts +11 -4
- package/lib/{auth-proj → project-files}/src/routes/middleware.ts +7 -8
- package/lib/project-files/src/routes/user-router.ts +12 -16
- package/lib/project-files/src/server.ts +82 -73
- package/lib/{auth-proj → project-files}/src/services/auth-service.ts +0 -0
- package/lib/project-files/src/services/user-service.ts +8 -8
- package/lib/project-files/src/shared/env-vars.ts +18 -0
- package/lib/project-files/src/shared/errors.ts +11 -0
- package/lib/project-files/src/types/express/index.d.ts +27 -5
- package/lib/{auth-proj → project-files}/src/util/jwt-util.ts +4 -9
- package/lib/{auth-proj → project-files}/src/views/login.html +0 -0
- package/lib/{auth-proj → project-files}/src/views/users.html +0 -0
- package/lib/project-files/tsconfig.json +3 -0
- package/package.json +1 -1
- package/chat-screenshot.png +0 -0
- package/lib/auth-proj/.eslintignore +0 -1
- package/lib/auth-proj/.eslintrc.json +0 -27
- package/lib/auth-proj/build.ts +0 -64
- package/lib/auth-proj/gitignore +0 -3
- package/lib/auth-proj/package.json +0 -73
- package/lib/auth-proj/spec/index.ts +0 -57
- package/lib/auth-proj/spec/loadEnv.ts +0 -10
- package/lib/auth-proj/spec/nodemon.json +0 -6
- package/lib/auth-proj/spec/support/jasmine.json +0 -11
- package/lib/auth-proj/spec/tests/users.spec.ts +0 -283
- package/lib/auth-proj/src/index.ts +0 -14
- package/lib/auth-proj/src/models/user-model.ts +0 -56
- package/lib/auth-proj/src/pre-start/env/development.env +0 -23
- package/lib/auth-proj/src/pre-start/env/production.env +0 -24
- package/lib/auth-proj/src/pre-start/env/test.env +0 -23
- package/lib/auth-proj/src/pre-start/index.ts +0 -28
- package/lib/auth-proj/src/repos/database.json +0 -1
- package/lib/auth-proj/src/repos/mock-orm.ts +0 -41
- package/lib/auth-proj/src/repos/user-repo.ts +0 -88
- package/lib/auth-proj/src/routes/api.ts +0 -17
- package/lib/auth-proj/src/routes/user-router.ts +0 -78
- package/lib/auth-proj/src/server.ts +0 -82
- package/lib/auth-proj/src/services/user-service.ts +0 -52
- package/lib/auth-proj/src/shared/env-vars.ts +0 -20
- package/lib/auth-proj/src/shared/errors.ts +0 -45
- package/lib/auth-proj/src/shared/functions.ts +0 -18
- package/lib/auth-proj/src/types/express/index.d.ts +0 -23
- package/lib/auth-proj/tsconfig.json +0 -100
- package/lib/auth-proj/tsconfig.prod.json +0 -11
- package/lib/project-files/src/public/scripts/index.js +0 -183
- package/lib/project-files/src/public/stylesheets/style.css +0 -33
- package/lib/project-files/src/views/index.html +0 -31
- package/lib/socket-io/.eslintignore +0 -1
- package/lib/socket-io/.eslintrc.json +0 -27
- package/lib/socket-io/build.ts +0 -64
- package/lib/socket-io/gitignore +0 -3
- package/lib/socket-io/package.json +0 -75
- package/lib/socket-io/spec/index.ts +0 -57
- package/lib/socket-io/spec/loadEnv.ts +0 -10
- package/lib/socket-io/spec/nodemon.json +0 -6
- package/lib/socket-io/spec/support/jasmine.json +0 -11
- package/lib/socket-io/spec/support/login-agent.ts +0 -49
- package/lib/socket-io/spec/tests/auth.spec.ts +0 -159
- package/lib/socket-io/spec/tests/chat.spec.ts +0 -150
- package/lib/socket-io/spec/tests/users.spec.ts +0 -283
- package/lib/socket-io/src/index.ts +0 -14
- package/lib/socket-io/src/models/user-model.ts +0 -56
- package/lib/socket-io/src/pre-start/env/development.env +0 -23
- package/lib/socket-io/src/pre-start/env/production.env +0 -24
- package/lib/socket-io/src/pre-start/env/test.env +0 -23
- package/lib/socket-io/src/pre-start/index.ts +0 -28
- package/lib/socket-io/src/public/scripts/chat.js +0 -87
- package/lib/socket-io/src/public/scripts/http.js +0 -24
- package/lib/socket-io/src/public/scripts/index.js +0 -16
- package/lib/socket-io/src/public/scripts/login.js +0 -17
- package/lib/socket-io/src/public/scripts/users.js +0 -148
- package/lib/socket-io/src/public/stylesheets/chat.css +0 -43
- package/lib/socket-io/src/public/stylesheets/index.css +0 -13
- package/lib/socket-io/src/public/stylesheets/login.css +0 -20
- package/lib/socket-io/src/public/stylesheets/users.css +0 -40
- package/lib/socket-io/src/repos/database.json +0 -38
- package/lib/socket-io/src/repos/mock-orm.ts +0 -41
- package/lib/socket-io/src/repos/user-repo.ts +0 -88
- package/lib/socket-io/src/routes/api.ts +0 -19
- package/lib/socket-io/src/routes/auth-router.ts +0 -67
- package/lib/socket-io/src/routes/chat-router.ts +0 -88
- package/lib/socket-io/src/routes/middleware.ts +0 -55
- package/lib/socket-io/src/routes/user-router.ts +0 -76
- package/lib/socket-io/src/server.ts +0 -100
- package/lib/socket-io/src/services/auth-service.ts +0 -38
- package/lib/socket-io/src/services/user-service.ts +0 -52
- package/lib/socket-io/src/shared/env-vars.ts +0 -20
- package/lib/socket-io/src/shared/errors.ts +0 -56
- package/lib/socket-io/src/shared/functions.ts +0 -18
- package/lib/socket-io/src/types/express/index.d.ts +0 -23
- package/lib/socket-io/src/util/jwt-util.ts +0 -52
- package/lib/socket-io/src/views/chat.html +0 -51
- package/lib/socket-io/src/views/login.html +0 -35
- package/lib/socket-io/src/views/users.html +0 -47
- package/lib/socket-io/tsconfig.json +0 -100
- package/lib/socket-io/tsconfig.prod.json +0 -11
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import authService from '@services/auth-service';
|
|
3
|
-
import { ParamMissingError } from '@shared/errors';
|
|
4
|
-
import { Request, Response, Router } from 'express';
|
|
5
|
-
import StatusCodes from 'http-status-codes';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// **** Variables **** //
|
|
9
|
-
|
|
10
|
-
// Misc
|
|
11
|
-
const router = Router();
|
|
12
|
-
const { OK } = StatusCodes;
|
|
13
|
-
|
|
14
|
-
// Paths
|
|
15
|
-
export const p = {
|
|
16
|
-
login: '/login',
|
|
17
|
-
logout: '/logout',
|
|
18
|
-
} as const;
|
|
19
|
-
|
|
20
|
-
// Cookie Properties
|
|
21
|
-
export const cookieProps = Object.freeze({
|
|
22
|
-
key: 'ExpressGeneratorTs',
|
|
23
|
-
secret: process.env.COOKIE_SECRET,
|
|
24
|
-
options: {
|
|
25
|
-
httpOnly: true,
|
|
26
|
-
signed: true,
|
|
27
|
-
path: (process.env.COOKIE_PATH),
|
|
28
|
-
maxAge: Number(process.env.COOKIE_EXP),
|
|
29
|
-
domain: (process.env.COOKIE_DOMAIN),
|
|
30
|
-
secure: (process.env.SECURE_COOKIE === 'true'),
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// **** Routes **** //
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Login a user.
|
|
39
|
-
*/
|
|
40
|
-
router.post(p.login, async (req: Request, res: Response) => {
|
|
41
|
-
// Check email and password present
|
|
42
|
-
const { email, password } = req.body;
|
|
43
|
-
if (!(email && password)) {
|
|
44
|
-
throw new ParamMissingError();
|
|
45
|
-
}
|
|
46
|
-
// Get jwt
|
|
47
|
-
const jwt = await authService.login(email, password);
|
|
48
|
-
// Add jwt to cookie
|
|
49
|
-
const { key, options } = cookieProps;
|
|
50
|
-
res.cookie(key, jwt, options);
|
|
51
|
-
// Return
|
|
52
|
-
return res.status(OK).end();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Logout the user.
|
|
57
|
-
*/
|
|
58
|
-
router.get(p.logout, (_: Request, res: Response) => {
|
|
59
|
-
const { key, options } = cookieProps;
|
|
60
|
-
res.clearCookie(key, options);
|
|
61
|
-
return res.status(OK).end();
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// **** Export router **** //
|
|
66
|
-
|
|
67
|
-
export default router;
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import SocketIO from 'socket.io';
|
|
2
|
-
import StatusCodes from 'http-status-codes';
|
|
3
|
-
import { Router, Request, Response } from 'express';
|
|
4
|
-
|
|
5
|
-
import { ParamMissingError, RoomNotFoundError } from '@shared/errors';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// **** Variables **** //
|
|
9
|
-
|
|
10
|
-
// Chat router
|
|
11
|
-
const router = Router();
|
|
12
|
-
const { OK } = StatusCodes;
|
|
13
|
-
|
|
14
|
-
// Paths
|
|
15
|
-
export const p = {
|
|
16
|
-
connect: '/connect-socket-room/:socketId',
|
|
17
|
-
emit: '/emit-message',
|
|
18
|
-
} as const;
|
|
19
|
-
|
|
20
|
-
export const socketRoomName = 'jet-logger-chat-room';
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// **** Routes **** //
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Connect to socket room.
|
|
27
|
-
*/
|
|
28
|
-
router.get(p.connect, async (req: Request, res: Response) => {
|
|
29
|
-
const { socketId } = req.params;
|
|
30
|
-
// Check params
|
|
31
|
-
if (!socketId) {
|
|
32
|
-
throw new ParamMissingError();
|
|
33
|
-
}
|
|
34
|
-
// Get socket
|
|
35
|
-
const socket = getSocket(req, socketId);
|
|
36
|
-
// Connect
|
|
37
|
-
await Promise.all([
|
|
38
|
-
socket.leave(socketRoomName),
|
|
39
|
-
socket.join(socketRoomName),
|
|
40
|
-
]);
|
|
41
|
-
// Return
|
|
42
|
-
return res.status(OK).end();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Send a chat message.
|
|
47
|
-
*/
|
|
48
|
-
router.post(p.emit, (req: Request, res: Response) => {
|
|
49
|
-
const { sessionUser } = res.locals;
|
|
50
|
-
const { message, socketId } = req.body;
|
|
51
|
-
// Check params
|
|
52
|
-
if (!socketId || !message) {
|
|
53
|
-
throw new ParamMissingError();
|
|
54
|
-
}
|
|
55
|
-
// Get socket
|
|
56
|
-
const socket = getSocket(req, socketId);
|
|
57
|
-
// Connect
|
|
58
|
-
const room = socket.to(socketRoomName);
|
|
59
|
-
room.emit('emit-msg', {
|
|
60
|
-
timestamp: Date.now(),
|
|
61
|
-
content: message,
|
|
62
|
-
senderName: sessionUser.name,
|
|
63
|
-
});
|
|
64
|
-
// Return
|
|
65
|
-
return res.status(OK).json({
|
|
66
|
-
senderName: sessionUser.name,
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// **** Helpers **** //
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Get the socket from the Express request object.
|
|
75
|
-
*/
|
|
76
|
-
function getSocket(req: Request, socketId: string): SocketIO.Socket {
|
|
77
|
-
const io = req.app.get('socketio') as SocketIO.Server;
|
|
78
|
-
const socket = io.sockets.sockets.get(socketId);
|
|
79
|
-
if (!socket) {
|
|
80
|
-
throw new RoomNotFoundError();
|
|
81
|
-
}
|
|
82
|
-
return socket;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// **** Export default **** //
|
|
87
|
-
|
|
88
|
-
export default router;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import StatusCodes from 'http-status-codes';
|
|
2
|
-
import { Request, Response, NextFunction } from 'express';
|
|
3
|
-
import { JwtPayload } from 'jsonwebtoken';
|
|
4
|
-
|
|
5
|
-
import { cookieProps } from '@routes/auth-router';
|
|
6
|
-
import { IUser } from '@models/user-model';
|
|
7
|
-
import jwtUtil from '@util/jwt-util';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// **** Variables **** //
|
|
11
|
-
|
|
12
|
-
const { UNAUTHORIZED } = StatusCodes;
|
|
13
|
-
const jwtNotPresentErr = 'JWT not present in signed cookie.';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// **** Types **** //
|
|
17
|
-
|
|
18
|
-
export interface ISessionUser extends JwtPayload {
|
|
19
|
-
id: number;
|
|
20
|
-
email: string;
|
|
21
|
-
name: string;
|
|
22
|
-
role: IUser['role'];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// **** Functions **** //
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Middleware to verify if user is an admin.
|
|
30
|
-
*/
|
|
31
|
-
export async function authMw(req: Request, res: Response, next: NextFunction) {
|
|
32
|
-
try {
|
|
33
|
-
// Get json-web-token
|
|
34
|
-
const jwt = req.signedCookies[cookieProps.key];
|
|
35
|
-
if (!jwt) {
|
|
36
|
-
throw Error(jwtNotPresentErr);
|
|
37
|
-
}
|
|
38
|
-
// Make sure user role is an admin
|
|
39
|
-
const clientData = await jwtUtil.decode(jwt);
|
|
40
|
-
if (!!clientData && typeof clientData !== 'string') {
|
|
41
|
-
res.locals.sessionUser = clientData as ISessionUser;
|
|
42
|
-
next();
|
|
43
|
-
} else {
|
|
44
|
-
throw Error(jwtNotPresentErr);
|
|
45
|
-
}
|
|
46
|
-
} catch (err) {
|
|
47
|
-
let error;
|
|
48
|
-
if (typeof err === 'string') {
|
|
49
|
-
error = err;
|
|
50
|
-
} else if (err instanceof Error) {
|
|
51
|
-
error = err.message;
|
|
52
|
-
}
|
|
53
|
-
return res.status(UNAUTHORIZED).json({ error });
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import StatusCodes from 'http-status-codes';
|
|
2
|
-
import { Request, Response, Router } from 'express';
|
|
3
|
-
|
|
4
|
-
import userService from '@services/user-service';
|
|
5
|
-
import { ParamMissingError } from '@shared/errors';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// **** Variables **** //
|
|
9
|
-
|
|
10
|
-
// Constants
|
|
11
|
-
const router = Router();
|
|
12
|
-
const { CREATED, OK } = StatusCodes;
|
|
13
|
-
|
|
14
|
-
// Paths
|
|
15
|
-
export const p = {
|
|
16
|
-
get: '/all',
|
|
17
|
-
add: '/add',
|
|
18
|
-
update: '/update',
|
|
19
|
-
delete: '/delete/:id',
|
|
20
|
-
} as const;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// **** Routes **** //
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Get all users.
|
|
27
|
-
*/
|
|
28
|
-
router.get(p.get, async (_: Request, res: Response) => {
|
|
29
|
-
const users = await userService.getAll();
|
|
30
|
-
return res.status(OK).json({users});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Add one user.
|
|
35
|
-
*/
|
|
36
|
-
router.post(p.add, async (req: Request, res: Response) => {
|
|
37
|
-
const { user } = req.body;
|
|
38
|
-
if (!user) {
|
|
39
|
-
throw new ParamMissingError();
|
|
40
|
-
}
|
|
41
|
-
// Fetch data
|
|
42
|
-
await userService.addOne(user);
|
|
43
|
-
return res.status(CREATED).end();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Update one user.
|
|
48
|
-
*/
|
|
49
|
-
router.put(p.update, async (req: Request, res: Response) => {
|
|
50
|
-
const { user } = req.body;
|
|
51
|
-
if (!user) {
|
|
52
|
-
throw new ParamMissingError();
|
|
53
|
-
}
|
|
54
|
-
// Fetch data
|
|
55
|
-
await userService.updateOne(user);
|
|
56
|
-
return res.status(OK).end();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Delete one user.
|
|
62
|
-
*/
|
|
63
|
-
router.delete(p.delete, async (req: Request, res: Response) => {
|
|
64
|
-
const { id } = req.params;
|
|
65
|
-
if (!id) {
|
|
66
|
-
throw new ParamMissingError();
|
|
67
|
-
}
|
|
68
|
-
// Fetch data
|
|
69
|
-
await userService.delete(Number(id));
|
|
70
|
-
return res.status(OK).end();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// **** Export default **** //
|
|
75
|
-
|
|
76
|
-
export default router;
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import cookieParser from 'cookie-parser';
|
|
2
|
-
import morgan from 'morgan';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import http from 'http';
|
|
5
|
-
import helmet from 'helmet';
|
|
6
|
-
import StatusCodes from 'http-status-codes';
|
|
7
|
-
import { Server as SocketIo } from 'socket.io';
|
|
8
|
-
import express, { NextFunction, Request, Response } from 'express';
|
|
9
|
-
|
|
10
|
-
import 'express-async-errors';
|
|
11
|
-
|
|
12
|
-
import BaseRouter from './routes/api';
|
|
13
|
-
import logger from 'jet-logger';
|
|
14
|
-
import envVars from '@shared/env-vars';
|
|
15
|
-
import { CustomError } from '@shared/errors';
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// **** Init express **** //
|
|
19
|
-
|
|
20
|
-
const app = express();
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// **** Set basic express settings **** //
|
|
24
|
-
|
|
25
|
-
app.use(express.json());
|
|
26
|
-
app.use(express.urlencoded({extended: true}));
|
|
27
|
-
app.use(cookieParser(envVars.cookieProps.secret));
|
|
28
|
-
|
|
29
|
-
// Show routes called in console during development
|
|
30
|
-
if (envVars.nodeEnv === 'development') {
|
|
31
|
-
app.use(morgan('dev'));
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Security
|
|
35
|
-
if (envVars.nodeEnv === 'production') {
|
|
36
|
-
app.use(helmet());
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Add APIs
|
|
40
|
-
app.use('/api', BaseRouter);
|
|
41
|
-
|
|
42
|
-
// Error handling
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
44
|
-
app.use((err: Error | CustomError, req: Request, res: Response, _: NextFunction) => {
|
|
45
|
-
logger.err(err, true);
|
|
46
|
-
const status = (err instanceof CustomError ? err.HttpStatus : StatusCodes.BAD_REQUEST);
|
|
47
|
-
return res.status(status).json({
|
|
48
|
-
error: err.message,
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// **** Serve front-end content **** //
|
|
54
|
-
|
|
55
|
-
const viewsDir = path.join(__dirname, 'views');
|
|
56
|
-
app.set('views', viewsDir);
|
|
57
|
-
const staticDir = path.join(__dirname, 'public');
|
|
58
|
-
app.use(express.static(staticDir));
|
|
59
|
-
|
|
60
|
-
// Login page
|
|
61
|
-
app.get('/', (_: Request, res: Response) => {
|
|
62
|
-
return res.sendFile('login.html', {root: viewsDir});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// Users page
|
|
66
|
-
app.get('/users', (req: Request, res: Response) => {
|
|
67
|
-
const jwt = req.signedCookies[envVars.cookieProps.key];
|
|
68
|
-
if (!jwt) {
|
|
69
|
-
return res.redirect('/');
|
|
70
|
-
} else {
|
|
71
|
-
return res.sendFile('users.html', {root: viewsDir});
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// Chat page
|
|
76
|
-
app.get('/chat', (req: Request, res: Response) => {
|
|
77
|
-
const jwt = req.signedCookies[envVars.cookieProps.key];
|
|
78
|
-
if (!jwt) {
|
|
79
|
-
return res.redirect('/');
|
|
80
|
-
} else {
|
|
81
|
-
return res.sendFile('chat.html', {root: viewsDir});
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// **** Setup Socket.io **** //
|
|
87
|
-
|
|
88
|
-
// Tutorial used for this: https://www.valentinog.com/blog/socket-react/
|
|
89
|
-
|
|
90
|
-
const server = http.createServer(app);
|
|
91
|
-
const io = new SocketIo(server);
|
|
92
|
-
|
|
93
|
-
io.sockets.on('connect', () => {
|
|
94
|
-
return app.set('socketio', io);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// **** Export default **** //
|
|
99
|
-
|
|
100
|
-
export default server;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import bcrypt from 'bcrypt';
|
|
2
|
-
|
|
3
|
-
import userRepo from '@repos/user-repo';
|
|
4
|
-
import jwtUtil from '@util/jwt-util';
|
|
5
|
-
import { UnauthorizedError } from '@shared/errors';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// **** Functions **** //
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Login
|
|
12
|
-
*/
|
|
13
|
-
async function login(email: string, password: string): Promise<string> {
|
|
14
|
-
// Fetch user
|
|
15
|
-
const user = await userRepo.getOne(email);
|
|
16
|
-
if (!user) {
|
|
17
|
-
throw new UnauthorizedError();
|
|
18
|
-
}
|
|
19
|
-
// Check password
|
|
20
|
-
const pwdPassed = await bcrypt.compare(password, user.pwdHash);
|
|
21
|
-
if (!pwdPassed) {
|
|
22
|
-
throw new UnauthorizedError();
|
|
23
|
-
}
|
|
24
|
-
// Setup Admin Cookie
|
|
25
|
-
return jwtUtil.sign({
|
|
26
|
-
id: user.id,
|
|
27
|
-
email: user.name,
|
|
28
|
-
name: user.name,
|
|
29
|
-
role: user.role,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// **** Export default **** //
|
|
35
|
-
|
|
36
|
-
export default {
|
|
37
|
-
login,
|
|
38
|
-
} as const;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import userRepo from '@repos/user-repo';
|
|
2
|
-
import { IUser } from '@models/user-model';
|
|
3
|
-
import { UserNotFoundError } from '@shared/errors';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// **** Functions **** //
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Get all users.
|
|
10
|
-
*/
|
|
11
|
-
function getAll(): Promise<IUser[]> {
|
|
12
|
-
return userRepo.getAll();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Add one user
|
|
17
|
-
*/
|
|
18
|
-
function addOne(user: IUser): Promise<void> {
|
|
19
|
-
return userRepo.add(user);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Update one user
|
|
24
|
-
*/
|
|
25
|
-
async function updateOne(user: IUser): Promise<void> {
|
|
26
|
-
const persists = await userRepo.persists(user.id);
|
|
27
|
-
if (!persists) {
|
|
28
|
-
throw new UserNotFoundError();
|
|
29
|
-
}
|
|
30
|
-
return userRepo.update(user);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Delete a user by their id.
|
|
35
|
-
*/
|
|
36
|
-
async function _delete(id: number): Promise<void> {
|
|
37
|
-
const persists = await userRepo.persists(id);
|
|
38
|
-
if (!persists) {
|
|
39
|
-
throw new UserNotFoundError();
|
|
40
|
-
}
|
|
41
|
-
return userRepo.delete(id);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// **** Export default **** //
|
|
46
|
-
|
|
47
|
-
export default {
|
|
48
|
-
getAll,
|
|
49
|
-
addOne,
|
|
50
|
-
updateOne,
|
|
51
|
-
delete: _delete,
|
|
52
|
-
} as const;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
nodeEnv: (process.env.NODE_ENV ?? ''),
|
|
3
|
-
port: (process.env.PORT ?? 0),
|
|
4
|
-
cookieProps: {
|
|
5
|
-
key: 'ExpressGeneratorTs',
|
|
6
|
-
secret: (process.env.COOKIE_SECRET ?? ''),
|
|
7
|
-
options: {
|
|
8
|
-
httpOnly: true,
|
|
9
|
-
signed: true,
|
|
10
|
-
path: (process.env.COOKIE_PATH ?? ''),
|
|
11
|
-
maxAge: Number(process.env.COOKIE_EXP ?? 0),
|
|
12
|
-
domain: (process.env.COOKIE_DOMAIN ?? ''),
|
|
13
|
-
secure: (process.env.SECURE_COOKIE === 'true'),
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
jwt: {
|
|
17
|
-
secret: (process.env.JWT_SECRET ?? ''),
|
|
18
|
-
exp: (process.env.COOKIE_EXP ?? ''), // exp at the same time as the cookie
|
|
19
|
-
},
|
|
20
|
-
} as const;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import HttpStatusCodes from 'http-status-codes';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export abstract class CustomError extends Error {
|
|
5
|
-
|
|
6
|
-
public readonly HttpStatus = HttpStatusCodes.BAD_REQUEST;
|
|
7
|
-
|
|
8
|
-
constructor(msg: string, httpStatus: number) {
|
|
9
|
-
super(msg);
|
|
10
|
-
this.HttpStatus = httpStatus;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export class ParamMissingError extends CustomError {
|
|
16
|
-
|
|
17
|
-
public static readonly Msg = 'One or more of the required parameters was missing.';
|
|
18
|
-
public static readonly HttpStatus = HttpStatusCodes.BAD_REQUEST;
|
|
19
|
-
|
|
20
|
-
constructor() {
|
|
21
|
-
super(ParamMissingError.Msg, ParamMissingError.HttpStatus);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export class UserNotFoundError extends CustomError {
|
|
27
|
-
|
|
28
|
-
public static readonly Msg = 'A user with the given id does not exists in the database.';
|
|
29
|
-
public static readonly HttpStatus = HttpStatusCodes.NOT_FOUND;
|
|
30
|
-
|
|
31
|
-
constructor() {
|
|
32
|
-
super(UserNotFoundError.Msg, UserNotFoundError.HttpStatus);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
export class UnauthorizedError extends CustomError {
|
|
38
|
-
|
|
39
|
-
public static readonly Msg = 'Login failed';
|
|
40
|
-
public static readonly HttpStatus = HttpStatusCodes.UNAUTHORIZED;
|
|
41
|
-
|
|
42
|
-
constructor() {
|
|
43
|
-
super(UnauthorizedError.Msg, UnauthorizedError.HttpStatus);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
export class RoomNotFoundError extends CustomError {
|
|
49
|
-
|
|
50
|
-
public static readonly Msg = 'socket room not found on socket server.';
|
|
51
|
-
public static readonly HttpStatus = HttpStatusCodes.BAD_REQUEST;
|
|
52
|
-
|
|
53
|
-
constructor() {
|
|
54
|
-
super(RoomNotFoundError.Msg, RoomNotFoundError.HttpStatus);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import logger from 'jet-logger';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Print an error object if it's truthy. Useful for testing.
|
|
6
|
-
*/
|
|
7
|
-
export function pErr(err?: Error): void {
|
|
8
|
-
if (!!err) {
|
|
9
|
-
logger.err(err);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Get a random number between 1 and 1,000,000,000,000.
|
|
15
|
-
*/
|
|
16
|
-
export function getRandomInt(): number {
|
|
17
|
-
return Math.floor(Math.random() * 1_000_000_000_000);
|
|
18
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { IUser } from '@models/user-model';
|
|
2
|
-
import { ISessionUser } from '@routes/middleware';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
declare module 'express' {
|
|
6
|
-
|
|
7
|
-
export interface Request {
|
|
8
|
-
signedCookies: Record<string, string>,
|
|
9
|
-
body: {
|
|
10
|
-
user?: IUser
|
|
11
|
-
email?: string;
|
|
12
|
-
password?: string;
|
|
13
|
-
message?: string;
|
|
14
|
-
socketId?: string;
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface Response {
|
|
19
|
-
locals: {
|
|
20
|
-
sessionUser: ISessionUser;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import randomString from 'randomstring';
|
|
2
|
-
import jsonwebtoken, { JwtPayload } from 'jsonwebtoken';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// **** Variables **** //
|
|
6
|
-
|
|
7
|
-
// Errors
|
|
8
|
-
const errors = {
|
|
9
|
-
validation: 'JSON-web-token validation failed.',
|
|
10
|
-
} as const;
|
|
11
|
-
|
|
12
|
-
// Misc
|
|
13
|
-
const secret = (process.env.JWT_SECRET || randomString.generate(100));
|
|
14
|
-
const options = {expiresIn: process.env.COOKIE_EXP};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// **** Types **** //
|
|
18
|
-
|
|
19
|
-
type TDecoded = string | JwtPayload | undefined;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// **** Functions **** //
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Encrypt data and return jwt.
|
|
26
|
-
*/
|
|
27
|
-
function sign(data: JwtPayload): Promise<string> {
|
|
28
|
-
return new Promise((resolve, reject) => {
|
|
29
|
-
jsonwebtoken.sign(data, secret, options, (err, token) => {
|
|
30
|
-
err ? reject(err) : resolve(token || '');
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Decrypt JWT and extract client data.
|
|
37
|
-
*/
|
|
38
|
-
function decode(jwt: string): Promise<TDecoded> {
|
|
39
|
-
return new Promise((res, rej) => {
|
|
40
|
-
jsonwebtoken.verify(jwt, secret, (err, decoded) => {
|
|
41
|
-
return err ? rej(errors.validation) : res(decoded);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// **** Export default **** //
|
|
48
|
-
|
|
49
|
-
export default {
|
|
50
|
-
sign,
|
|
51
|
-
decode,
|
|
52
|
-
};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<title>Users</title>
|
|
6
|
-
<link rel="stylesheet" type="text/css" href="/stylesheets/index.css" />
|
|
7
|
-
<link rel="stylesheet" type="text/css" href="/stylesheets/chat.css" />
|
|
8
|
-
<script
|
|
9
|
-
src="https://cdn.socket.io/3.1.3/socket.io.min.js"
|
|
10
|
-
integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh"
|
|
11
|
-
crossorigin="anonymous"
|
|
12
|
-
></script>
|
|
13
|
-
<script
|
|
14
|
-
src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"
|
|
15
|
-
integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ=="
|
|
16
|
-
crossorigin="anonymous"
|
|
17
|
-
referrerpolicy="no-referrer"
|
|
18
|
-
></script>
|
|
19
|
-
<script src="scripts/http.js"></script>
|
|
20
|
-
</head>
|
|
21
|
-
<body>
|
|
22
|
-
|
|
23
|
-
<!-- Header -->
|
|
24
|
-
<div class="main-header">
|
|
25
|
-
<button class="header-button nav-users-btn">
|
|
26
|
-
Users
|
|
27
|
-
</button>
|
|
28
|
-
<button class="header-button nav-chat-btn">
|
|
29
|
-
Chat
|
|
30
|
-
</button>
|
|
31
|
-
<button class="header-button logout-btn">
|
|
32
|
-
Logout
|
|
33
|
-
</button>
|
|
34
|
-
</div>
|
|
35
|
-
|
|
36
|
-
<!-- Chat Window -->
|
|
37
|
-
<div id="window-wrapper">
|
|
38
|
-
Chat Window
|
|
39
|
-
<div id="chat-window"></div>
|
|
40
|
-
|
|
41
|
-
<div id="send-msg-wrapper">
|
|
42
|
-
<input id="send-msg-input"/>
|
|
43
|
-
<button id="send-msg-btn">
|
|
44
|
-
Send
|
|
45
|
-
</button>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
</body>
|
|
49
|
-
<script src="scripts/index.js"></script>
|
|
50
|
-
<script src="scripts/chat.js"></script>
|
|
51
|
-
</html>
|