express-generator-typescript 2.3.0 → 2.3.2
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/lib/project-files/src/routes/AuthRoutes.ts +12 -9
- package/lib/project-files/src/routes/middleware/adminMw.ts +13 -16
- package/lib/project-files/src/routes/types/express/misc.ts +1 -1
- package/lib/project-files/src/services/AuthService.ts +5 -10
- package/lib/project-files/src/util/SessionUtil.ts +92 -0
- package/package.json +1 -1
- package/lib/project-files/src/util/JwtUtil.ts +0 -48
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
|
2
|
-
|
|
2
|
+
import SessionUtil from '@src/util/SessionUtil';
|
|
3
3
|
import AuthService from '@src/services/AuthService';
|
|
4
|
-
import EnvVars from '@src/constants/EnvVars';
|
|
5
|
-
import { IReq, IRes } from './types/express/misc';
|
|
6
4
|
|
|
5
|
+
import { IReq, IRes } from './types/express/misc';
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
// **** Types **** //
|
|
@@ -21,10 +20,15 @@ interface ILoginReq {
|
|
|
21
20
|
*/
|
|
22
21
|
async function login(req: IReq<ILoginReq>, res: IRes) {
|
|
23
22
|
const { email, password } = req.body;
|
|
24
|
-
//
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
// Login
|
|
24
|
+
const user = await AuthService.login(email, password);
|
|
25
|
+
// Setup Admin Cookie
|
|
26
|
+
await SessionUtil.addSessionData(res, {
|
|
27
|
+
id: user.id,
|
|
28
|
+
email: user.name,
|
|
29
|
+
name: user.name,
|
|
30
|
+
role: user.role,
|
|
31
|
+
});
|
|
28
32
|
// Return
|
|
29
33
|
return res.status(HttpStatusCodes.OK).end();
|
|
30
34
|
}
|
|
@@ -33,8 +37,7 @@ async function login(req: IReq<ILoginReq>, res: IRes) {
|
|
|
33
37
|
* Logout the user.
|
|
34
38
|
*/
|
|
35
39
|
function logout(_: IReq, res: IRes) {
|
|
36
|
-
|
|
37
|
-
res.clearCookie(Key, Options);
|
|
40
|
+
SessionUtil.clearCookie(res);
|
|
38
41
|
return res.status(HttpStatusCodes.OK).end();
|
|
39
42
|
}
|
|
40
43
|
|
|
@@ -8,14 +8,18 @@ import { JwtPayload } from 'jsonwebtoken';
|
|
|
8
8
|
import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
|
9
9
|
import EnvVars from '@src/constants/EnvVars';
|
|
10
10
|
|
|
11
|
-
import
|
|
11
|
+
import SessionUtil from '@src/util/SessionUtil';
|
|
12
12
|
import { ISessionUser, UserRoles } from '@src/models/User';
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
// **** Variables **** //
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
|
|
17
|
+
const USER_UNAUTHORIZED_ERR = 'User not authorized to perform this action';
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
// **** Types **** //
|
|
21
|
+
|
|
22
|
+
type TSessionData = ISessionUser & JwtPayload;
|
|
19
23
|
|
|
20
24
|
|
|
21
25
|
// **** Functions **** //
|
|
@@ -28,21 +32,14 @@ async function adminMw(
|
|
|
28
32
|
res: Response,
|
|
29
33
|
next: NextFunction,
|
|
30
34
|
) {
|
|
31
|
-
//
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
if (!jwt) {
|
|
35
|
-
return res
|
|
36
|
-
.status(HttpStatusCodes.UNAUTHORIZED)
|
|
37
|
-
.json({ error: JWT_NOT_PRESENT_ERR });
|
|
38
|
-
}
|
|
39
|
-
// Make sure user role is an admin
|
|
40
|
-
const clientData = await JwtUtil.decode<ISessionUser & JwtPayload>(jwt);
|
|
35
|
+
// Get session data
|
|
36
|
+
const sessionData = await SessionUtil.getSessionData<TSessionData>(req);
|
|
37
|
+
// Set session data to locals
|
|
41
38
|
if (
|
|
42
|
-
typeof
|
|
43
|
-
|
|
39
|
+
typeof sessionData === 'object' &&
|
|
40
|
+
sessionData?.role === UserRoles.Admin
|
|
44
41
|
) {
|
|
45
|
-
res.locals.sessionUser =
|
|
42
|
+
res.locals.sessionUser = sessionData;
|
|
46
43
|
return next();
|
|
47
44
|
// Return an unauth error if user is not an admin
|
|
48
45
|
} else {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import UserRepo from '@src/repos/UserRepo';
|
|
2
2
|
|
|
3
|
-
import JwtUtil from '@src/util/JwtUtil';
|
|
4
3
|
import PwdUtil from '@src/util/PwdUtil';
|
|
5
4
|
import { tick } from '@src/util/misc';
|
|
6
5
|
|
|
7
6
|
import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
|
8
7
|
import { RouteError } from '@src/other/classes';
|
|
8
|
+
import { IUser } from '@src/models/User';
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
// **** Variables **** //
|
|
@@ -22,7 +22,7 @@ export const Errors = {
|
|
|
22
22
|
/**
|
|
23
23
|
* Login a user.
|
|
24
24
|
*/
|
|
25
|
-
async function
|
|
25
|
+
async function login(email: string, password: string): Promise<IUser> {
|
|
26
26
|
// Fetch user
|
|
27
27
|
const user = await UserRepo.getOne(email);
|
|
28
28
|
if (!user) {
|
|
@@ -42,18 +42,13 @@ async function getJwt(email: string, password: string): Promise<string> {
|
|
|
42
42
|
Errors.Unauth,
|
|
43
43
|
);
|
|
44
44
|
}
|
|
45
|
-
//
|
|
46
|
-
return
|
|
47
|
-
id: user.id,
|
|
48
|
-
email: user.name,
|
|
49
|
-
name: user.name,
|
|
50
|
-
role: user.role,
|
|
51
|
-
});
|
|
45
|
+
// Return
|
|
46
|
+
return user;
|
|
52
47
|
}
|
|
53
48
|
|
|
54
49
|
|
|
55
50
|
// **** Export default **** //
|
|
56
51
|
|
|
57
52
|
export default {
|
|
58
|
-
|
|
53
|
+
login,
|
|
59
54
|
} as const;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
|
|
3
|
+
import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
|
4
|
+
import { RouteError } from '@src/other/classes';
|
|
5
|
+
import jsonwebtoken from 'jsonwebtoken';
|
|
6
|
+
|
|
7
|
+
import EnvVars from '../constants/EnvVars';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
// **** Variables **** //
|
|
11
|
+
|
|
12
|
+
// Errors
|
|
13
|
+
const Errors = {
|
|
14
|
+
ParamFalsey: 'Param is falsey',
|
|
15
|
+
Validation: 'JSON-web-token validation failed.',
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
// Options
|
|
19
|
+
const Options = {
|
|
20
|
+
expiresIn: EnvVars.Jwt.Exp,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
// **** Functions **** //
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get session data from request object (i.e. ISessionUser)
|
|
28
|
+
*/
|
|
29
|
+
function getSessionData<T>(req: Request): Promise<string | T | undefined> {
|
|
30
|
+
const { Key } = EnvVars.CookieProps,
|
|
31
|
+
jwt = req.signedCookies[Key];
|
|
32
|
+
return _decode(jwt);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Add a JWT to the response
|
|
37
|
+
*/
|
|
38
|
+
async function addSessionData(
|
|
39
|
+
res: Response,
|
|
40
|
+
data: string | object,
|
|
41
|
+
): Promise<Response> {
|
|
42
|
+
if (!res || !data) {
|
|
43
|
+
throw new RouteError(HttpStatusCodes.BAD_REQUEST, Errors.ParamFalsey);
|
|
44
|
+
}
|
|
45
|
+
// Setup JWT
|
|
46
|
+
const jwt = await _sign(data),
|
|
47
|
+
{ Key, Options } = EnvVars.CookieProps;
|
|
48
|
+
// Return
|
|
49
|
+
return res.cookie(Key, jwt, Options);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Remove cookie
|
|
54
|
+
*/
|
|
55
|
+
function clearCookie(res: Response): Response {
|
|
56
|
+
const { Key, Options } = EnvVars.CookieProps;
|
|
57
|
+
return res.clearCookie(Key, Options);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
// **** Helper Functions **** //
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Encrypt data and return jwt.
|
|
65
|
+
*/
|
|
66
|
+
function _sign(data: string | object | Buffer): Promise<string> {
|
|
67
|
+
return new Promise((res, rej) => {
|
|
68
|
+
jsonwebtoken.sign(data, EnvVars.Jwt.Secret, Options, (err, token) => {
|
|
69
|
+
return err ? rej(err) : res(token || '');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Decrypt JWT and extract client data.
|
|
76
|
+
*/
|
|
77
|
+
function _decode<T>(jwt: string): Promise<string | undefined | T> {
|
|
78
|
+
return new Promise((res, rej) => {
|
|
79
|
+
jsonwebtoken.verify(jwt, EnvVars.Jwt.Secret, (err, decoded) => {
|
|
80
|
+
return err ? rej(Errors.Validation) : res(decoded as T);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
// **** Export default **** //
|
|
87
|
+
|
|
88
|
+
export default {
|
|
89
|
+
addSessionData,
|
|
90
|
+
getSessionData,
|
|
91
|
+
clearCookie,
|
|
92
|
+
} as const;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-generator-typescript",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
4
4
|
"description": "Generate new Express applications similar to express-generate which but sets it up to use TypeScript instead",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"express-generator-typescript": "node bin/cli.js",
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import jsonwebtoken from 'jsonwebtoken';
|
|
2
|
-
import EnvVars from '../constants/EnvVars';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// **** Variables **** //
|
|
6
|
-
|
|
7
|
-
// Errors
|
|
8
|
-
const Errors = {
|
|
9
|
-
Validation: 'JSON-web-token validation failed.',
|
|
10
|
-
} as const;
|
|
11
|
-
|
|
12
|
-
// Options
|
|
13
|
-
const Options = {
|
|
14
|
-
expiresIn: EnvVars.Jwt.Exp,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// **** Functions **** //
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Encrypt data and return jwt.
|
|
22
|
-
*/
|
|
23
|
-
function sign(data: string | object | Buffer): Promise<string> {
|
|
24
|
-
return new Promise((res, rej) => {
|
|
25
|
-
jsonwebtoken.sign(data, EnvVars.Jwt.Secret, Options, (err, token) => {
|
|
26
|
-
return err ? rej(err) : res(token || '');
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Decrypt JWT and extract client data.
|
|
33
|
-
*/
|
|
34
|
-
function decode<T>(jwt: string): Promise<string | undefined | T> {
|
|
35
|
-
return new Promise((res, rej) => {
|
|
36
|
-
jsonwebtoken.verify(jwt, EnvVars.Jwt.Secret, (err, decoded) => {
|
|
37
|
-
return err ? rej(Errors.Validation) : res(decoded as T);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// **** Export default **** //
|
|
44
|
-
|
|
45
|
-
export default {
|
|
46
|
-
sign,
|
|
47
|
-
decode,
|
|
48
|
-
} as const;
|