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
package/README.md
CHANGED
|
@@ -36,24 +36,11 @@ and `_moduleAliases` in _package.json_ if you want to add/edit the relative path
|
|
|
36
36
|
|
|
37
37
|
## Sample-project
|
|
38
38
|
|
|
39
|
-
When you run _express-generator-typescript_, it sets up a
|
|
39
|
+
When you run _express-generator-typescript_, it sets up a simple application with routes for
|
|
40
40
|
adding, updating, deleting, and fetching user objects. This is just to demonstrate how routing is done
|
|
41
|
-
with express.
|
|
42
|
-
|
|
43
|
-
If you want a fully-secure application, you can pass the `--with-auth` option and you will have an
|
|
44
|
-
application which requires you to login before calling APIs on user objects. The app is
|
|
41
|
+
with express. You will have to login before calling APIs on user objects. The app is
|
|
45
42
|
configured with production quality client-side security and uses signed-cookies and jsonwebtokens
|
|
46
|
-
to store user-session data.
|
|
47
|
-
I highly encourage to use this option.
|
|
48
|
-
|
|
49
|
-
To have a chat app within your application, use the `--socket-io` option. This option will include
|
|
50
|
-
everything from the `--with-auth` option, plus will create a mini-chat app which displays the
|
|
51
|
-
sender name for the message of whoever the logged in user is. Without a login user we can't display
|
|
52
|
-
a sender name, that's why the `--socket-io` option must used in conjunction with `--with-auth`.
|
|
53
|
-
To create a socket-io sample app, you can pass `--socket-io` or `--with-auth --socket-io`; it won't
|
|
54
|
-
make a difference.
|
|
55
|
-
|
|
56
|
-
<img alt='chat-screenshot' src='https://github.com/seanpmaxwell/express-generator-typescript/raw/master/chat-screenshot.png' border='0'>
|
|
43
|
+
to store user-session data.
|
|
57
44
|
|
|
58
45
|
|
|
59
46
|
## Installation
|
|
@@ -75,14 +62,12 @@ Create the app:
|
|
|
75
62
|
|
|
76
63
|
```bash
|
|
77
64
|
$ npx express-generator-typescript "project name (default is express-gen-ts)"
|
|
78
|
-
with all options
|
|
79
|
-
$ npx express-generator-typescript --with-auth --socket-io --use-yarn "project name (default is express-gen-ts)"
|
|
80
65
|
```
|
|
81
66
|
|
|
82
67
|
Start your express-generator-typescript app in development mode at `http://localhost:3000/`:
|
|
83
68
|
|
|
84
69
|
```bash
|
|
85
|
-
$ cd "project name" && npm run
|
|
70
|
+
$ cd "project name" && npm run dev
|
|
86
71
|
```
|
|
87
72
|
|
|
88
73
|
|
|
@@ -106,6 +91,34 @@ This is located under `nodemonConfig:` in `package.json` for the server and `./s
|
|
|
106
91
|
unit-testing. For the `exec` property, replace `ts-node` with `node --inspect -r ts-node/register`.
|
|
107
92
|
|
|
108
93
|
|
|
94
|
+
## If you don't want authentication:
|
|
95
|
+
|
|
96
|
+
In previous version of __express-generator-typescript__ you could disregard authentication through the
|
|
97
|
+
command line options. But maintaining two separate project folders which contained and didn't contain
|
|
98
|
+
authentication started to get messy.
|
|
99
|
+
|
|
100
|
+
- Remove following modules from `package.json`:
|
|
101
|
+
- `jsonwebtoken`
|
|
102
|
+
- `@types/jsonwebtoken`
|
|
103
|
+
- `bcrypt`
|
|
104
|
+
- `@types/bcrypt`
|
|
105
|
+
|
|
106
|
+
- Delete the files:
|
|
107
|
+
- `src/routes/middleware.ts`
|
|
108
|
+
- `src/routes/auth-router.ts`
|
|
109
|
+
- `spec/tests/auth.spec.ts`
|
|
110
|
+
- `spec/support/login-agent.ts`
|
|
111
|
+
- `public/scripts/login.js`
|
|
112
|
+
- `public/stylesheets/login.css`
|
|
113
|
+
- `public/views/login.html`
|
|
114
|
+
|
|
115
|
+
- Update the files:
|
|
116
|
+
- In `src/routes/api`, delete the line: `apiRouter.use('/auth', authRouter);` and
|
|
117
|
+
remove the `adminMw,` from line 12. Remove the `adminMw` and `authRouter` imports as well.
|
|
118
|
+
- In `spec/tests/users.spec.ts`, remove all lines containing `loginAgent` and `setCookie`
|
|
119
|
+
- In `public/views/users.html` remove the `Logout` button.
|
|
120
|
+
|
|
121
|
+
|
|
109
122
|
## Note for VS-Code users
|
|
110
123
|
|
|
111
124
|
A lot of users have asked about _launch.json_ configurations for running this in VS-Code, so
|
|
@@ -136,13 +149,12 @@ VS-Code.
|
|
|
136
149
|
|
|
137
150
|
## Note for windows users
|
|
138
151
|
|
|
139
|
-
If you
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
the `node-gyp` module globally as well.
|
|
152
|
+
If you are on Windows, the `bcrypt` module tends to be fussy. To use this module on Windows you
|
|
153
|
+
need to make sure you have the node Windows build tools installed. I don't want to post instructions
|
|
154
|
+
because they might change frequently. I would search the Microsoft docs on how to setup Node for Windows.
|
|
155
|
+
To be able to debug in VSCODE on windows I also had to install the `node-gyp` module globally as well.
|
|
144
156
|
|
|
145
|
-
Happy web
|
|
157
|
+
Happy web deving :)
|
|
146
158
|
|
|
147
159
|
|
|
148
160
|
|
package/bin/cli.js
CHANGED
|
@@ -15,34 +15,21 @@ const expressGenTs = require('../lib/express-generator-typescript');
|
|
|
15
15
|
// const opts = processOptions(process.argv.slice(2));
|
|
16
16
|
// Process options
|
|
17
17
|
let destination = 'express-gen-ts';
|
|
18
|
-
let withAuth = false;
|
|
19
18
|
let useYarn = false;
|
|
20
|
-
let useSocketIo = false;
|
|
21
19
|
const args = process.argv.slice(2);
|
|
22
20
|
let idx = -1;
|
|
23
|
-
idx = args.indexOf('--with-auth');
|
|
24
|
-
if (idx > -1) {
|
|
25
|
-
withAuth = true;
|
|
26
|
-
args.splice(idx, 1);
|
|
27
|
-
}
|
|
28
21
|
idx = args.indexOf('--use-yarn');
|
|
29
22
|
if (idx > -1) {
|
|
30
23
|
useYarn = true;
|
|
31
24
|
args.splice(idx, 1);
|
|
32
25
|
}
|
|
33
|
-
idx = args.indexOf('--socket-io');
|
|
34
|
-
if (idx > -1) {
|
|
35
|
-
useSocketIo = true;
|
|
36
|
-
withAuth = true;
|
|
37
|
-
args.splice(idx, 1);
|
|
38
|
-
}
|
|
39
26
|
if (args.length > 0) {
|
|
40
27
|
destination = args[0];
|
|
41
28
|
}
|
|
42
29
|
destination = path.join(process.cwd(), destination);
|
|
43
30
|
// Creating new project finished
|
|
44
|
-
expressGenTs(destination,
|
|
31
|
+
expressGenTs(destination, useYarn).then(() => {
|
|
45
32
|
console.log('Project setup complete!');
|
|
46
33
|
});
|
|
47
|
-
|
|
34
|
+
})();
|
|
48
35
|
|
package/lib/cli.js
CHANGED
|
@@ -10,39 +10,25 @@ const path = require('path');
|
|
|
10
10
|
const expressGenTs = require('../lib/express-generator-typescript');
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
// Start
|
|
14
13
|
(() => {
|
|
15
14
|
console.log('Setting up new Express/TypeScript project...');
|
|
16
15
|
// const opts = processOptions(process.argv.slice(2));
|
|
17
16
|
// Process options
|
|
18
17
|
let destination = 'express-gen-ts';
|
|
19
|
-
let withAuth = false;
|
|
20
18
|
let useYarn = false;
|
|
21
|
-
let useSocketIo = false;
|
|
22
19
|
const args = process.argv.slice(2);
|
|
23
20
|
let idx = -1;
|
|
24
|
-
idx = args.indexOf('--with-auth');
|
|
25
|
-
if (idx > -1) {
|
|
26
|
-
withAuth = true;
|
|
27
|
-
args.splice(idx, 1);
|
|
28
|
-
}
|
|
29
21
|
idx = args.indexOf('--use-yarn');
|
|
30
22
|
if (idx > -1) {
|
|
31
23
|
useYarn = true;
|
|
32
24
|
args.splice(idx, 1);
|
|
33
25
|
}
|
|
34
|
-
idx = args.indexOf('--socket-io');
|
|
35
|
-
if (idx > -1) {
|
|
36
|
-
useSocketIo = true;
|
|
37
|
-
withAuth = true;
|
|
38
|
-
args.splice(idx, 1);
|
|
39
|
-
}
|
|
40
26
|
if (args.length > 0) {
|
|
41
27
|
destination = args[0];
|
|
42
28
|
}
|
|
43
29
|
destination = path.join(process.cwd(), destination);
|
|
44
30
|
// Creating new project finished
|
|
45
|
-
expressGenTs(destination,
|
|
31
|
+
expressGenTs(destination, useYarn).then(() => {
|
|
46
32
|
console.log('Project setup complete!');
|
|
47
33
|
});
|
|
48
34
|
})();
|
|
@@ -13,8 +13,12 @@ const fs = require('fs');
|
|
|
13
13
|
|
|
14
14
|
// **** Variables **** //
|
|
15
15
|
|
|
16
|
+
const prjFolder = './project-files';
|
|
17
|
+
|
|
16
18
|
const ncpOpts = {
|
|
17
|
-
filter:
|
|
19
|
+
filter: (fileName) => {
|
|
20
|
+
return !(fileName === 'package-lock.json' || fileName === 'node_modules');
|
|
21
|
+
},
|
|
18
22
|
};
|
|
19
23
|
|
|
20
24
|
|
|
@@ -23,12 +27,12 @@ const ncpOpts = {
|
|
|
23
27
|
/**
|
|
24
28
|
* Entry point
|
|
25
29
|
*/
|
|
26
|
-
async function expressGenTs(destination,
|
|
30
|
+
async function expressGenTs(destination, useYarn) {
|
|
27
31
|
try {
|
|
28
|
-
await copyProjectFiles(destination
|
|
32
|
+
await copyProjectFiles(destination);
|
|
29
33
|
updatePackageJson(destination);
|
|
30
34
|
await renameGitigoreFile(destination);
|
|
31
|
-
const depStrings = getDepStrings(
|
|
35
|
+
const depStrings = getDepStrings();
|
|
32
36
|
downloadNodeModules(destination, depStrings, useYarn);
|
|
33
37
|
} catch (err) {
|
|
34
38
|
console.error(err);
|
|
@@ -38,17 +42,10 @@ async function expressGenTs(destination, withAuth, useYarn, useSocketIo) {
|
|
|
38
42
|
/**
|
|
39
43
|
* Copy project files
|
|
40
44
|
*/
|
|
41
|
-
function copyProjectFiles(destination
|
|
42
|
-
let prjFolder = './project-files';
|
|
43
|
-
if (useSocketIo) {
|
|
44
|
-
prjFolder = './socket-io';
|
|
45
|
-
} else if (withAuth) {
|
|
46
|
-
prjFolder = './auth-proj';
|
|
47
|
-
}
|
|
45
|
+
function copyProjectFiles(destination) {
|
|
48
46
|
const source = path.join(__dirname, prjFolder);
|
|
49
|
-
// Return
|
|
50
47
|
return new Promise((res, rej) => {
|
|
51
|
-
ncp.limit =
|
|
48
|
+
ncp.limit = 16;
|
|
52
49
|
return ncp(source, destination, ncpOpts, (err) => {
|
|
53
50
|
return (!!err ? rej(err) : res());
|
|
54
51
|
});
|
|
@@ -81,21 +78,16 @@ function renameGitigoreFile(destination) {
|
|
|
81
78
|
/**
|
|
82
79
|
* Setup dependency strings. This way gets you the latest version of everything.
|
|
83
80
|
*/
|
|
84
|
-
function getDepStrings(
|
|
81
|
+
function getDepStrings() {
|
|
85
82
|
let dependencies = 'express dotenv http-status-codes morgan cookie-parser jet-logger ' +
|
|
86
|
-
'module-alias command-line-args express-async-errors helmet jsonfile'
|
|
83
|
+
'module-alias command-line-args express-async-errors helmet jsonfile bcrypt ' +
|
|
84
|
+
'jsonwebtoken';
|
|
87
85
|
let devDependencies = 'ts-node typescript nodemon find jasmine supertest ' +
|
|
88
86
|
'@types/node @types/express @types/jasmine @types/find @types/morgan ' +
|
|
89
87
|
'@types/cookie-parser @types/supertest fs-extra tsconfig-paths @types/jsonfile ' +
|
|
90
88
|
'@types/command-line-args @typescript-eslint/eslint-plugin @typescript-eslint/parser ' +
|
|
91
|
-
'eslint @types/fs-extra'
|
|
92
|
-
|
|
93
|
-
dependencies += ' bcrypt randomstring jsonwebtoken';
|
|
94
|
-
devDependencies += ' @types/bcrypt @types/randomstring @types/jsonwebtoken';
|
|
95
|
-
}
|
|
96
|
-
if (useSocketIo) {
|
|
97
|
-
dependencies += ' socket.io socket.io-client';
|
|
98
|
-
}
|
|
89
|
+
'eslint @types/fs-extra @types/bcrypt @types/jsonwebtoken ' +
|
|
90
|
+
'eslint-plugin-node';
|
|
99
91
|
// Return
|
|
100
92
|
return { dependencies, devDependencies };
|
|
101
93
|
}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
"extends": [
|
|
7
7
|
"eslint:recommended",
|
|
8
8
|
"plugin:@typescript-eslint/recommended",
|
|
9
|
-
"plugin:@typescript-eslint/recommended-requiring-type-checking"
|
|
9
|
+
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
|
10
|
+
"plugin:node/recommended"
|
|
10
11
|
],
|
|
11
12
|
"parserOptions": {
|
|
12
13
|
"project": "./tsconfig.json"
|
|
@@ -22,6 +23,18 @@
|
|
|
22
23
|
"no-extra-boolean-cast": 0,
|
|
23
24
|
"semi": 1,
|
|
24
25
|
"@typescript-eslint/no-misused-promises": 0,
|
|
25
|
-
"@typescript-eslint/no-floating-promises": 0
|
|
26
|
+
"@typescript-eslint/no-floating-promises": 0,
|
|
27
|
+
"node/no-process-env": 1,
|
|
28
|
+
"node/no-unsupported-features/es-syntax": [
|
|
29
|
+
"error",
|
|
30
|
+
{ "ignores" : ["modules"] }
|
|
31
|
+
],
|
|
32
|
+
"node/no-missing-import": 0,
|
|
33
|
+
"node/no-unpublished-import": 0
|
|
34
|
+
},
|
|
35
|
+
"settings": {
|
|
36
|
+
"node": {
|
|
37
|
+
"tryExtensions": [".js", ".json", ".node", ".ts"]
|
|
38
|
+
}
|
|
26
39
|
}
|
|
27
40
|
}
|
|
@@ -36,7 +36,7 @@ function remove(loc: string): Promise<void> {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* Copy file
|
|
39
|
+
* Copy file.
|
|
40
40
|
*/
|
|
41
41
|
function copy(src: string, dest: string): Promise<void> {
|
|
42
42
|
return new Promise((res, rej) => {
|
|
@@ -47,7 +47,7 @@ function copy(src: string, dest: string): Promise<void> {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* Do command line command.
|
|
51
51
|
*/
|
|
52
52
|
function exec(cmd: string, loc: string): Promise<void> {
|
|
53
53
|
return new Promise((res, rej) => {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "express-
|
|
2
|
+
"name": "express-typescript-example",
|
|
3
3
|
"version": "0.0.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "npx ts-node build.ts",
|
|
6
|
-
"lint": "eslint
|
|
6
|
+
"lint": "npx eslint --ext .ts src/",
|
|
7
|
+
"lint:tests": "npx eslint --ext .ts spec/",
|
|
7
8
|
"start": "node -r module-alias/register ./dist --env=production",
|
|
8
9
|
"dev": "nodemon",
|
|
9
10
|
"test": "nodemon --config ./spec/nodemon.json",
|
|
10
|
-
"test:no-reloading": "npx ts-node -r tsconfig-paths/register ./spec"
|
|
11
|
+
"test:no-reloading": "npx ts-node --files -r tsconfig-paths/register ./spec"
|
|
11
12
|
},
|
|
12
13
|
"nodemonConfig": {
|
|
13
14
|
"watch": [
|
|
@@ -17,7 +18,7 @@
|
|
|
17
18
|
"ignore": [
|
|
18
19
|
"src/public"
|
|
19
20
|
],
|
|
20
|
-
"exec": "./node_modules/.bin/ts-node -r tsconfig-paths/register ./src"
|
|
21
|
+
"exec": "./node_modules/.bin/ts-node --files -r tsconfig-paths/register ./src"
|
|
21
22
|
},
|
|
22
23
|
"_moduleAliases": {
|
|
23
24
|
"@services": "dist/services",
|
|
@@ -25,9 +26,14 @@
|
|
|
25
26
|
"@entities": "dist/entities",
|
|
26
27
|
"@shared": "dist/shared",
|
|
27
28
|
"@server": "dist/server",
|
|
28
|
-
"@routes": "dist/routes"
|
|
29
|
+
"@routes": "dist/routes",
|
|
30
|
+
"@util": "dist/util"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=8.10.0"
|
|
29
34
|
},
|
|
30
35
|
"dependencies": {
|
|
36
|
+
"bcrypt": "^5.0.1",
|
|
31
37
|
"command-line-args": "^5.2.1",
|
|
32
38
|
"cookie-parser": "^1.4.6",
|
|
33
39
|
"dotenv": "^16.0.2",
|
|
@@ -37,10 +43,12 @@
|
|
|
37
43
|
"http-status-codes": "^2.2.0",
|
|
38
44
|
"jet-logger": "^1.2.3",
|
|
39
45
|
"jsonfile": "^6.1.0",
|
|
46
|
+
"jsonwebtoken": "^8.5.1",
|
|
40
47
|
"module-alias": "^2.2.2",
|
|
41
48
|
"morgan": "^1.10.0"
|
|
42
49
|
},
|
|
43
50
|
"devDependencies": {
|
|
51
|
+
"@types/bcrypt": "^5.0.0",
|
|
44
52
|
"@types/command-line-args": "^5.2.0",
|
|
45
53
|
"@types/cookie-parser": "^1.4.3",
|
|
46
54
|
"@types/express": "^4.17.13",
|
|
@@ -48,12 +56,14 @@
|
|
|
48
56
|
"@types/fs-extra": "^9.0.13",
|
|
49
57
|
"@types/jasmine": "^4.3.0",
|
|
50
58
|
"@types/jsonfile": "^6.1.0",
|
|
59
|
+
"@types/jsonwebtoken": "^8.5.9",
|
|
51
60
|
"@types/morgan": "^1.9.3",
|
|
52
61
|
"@types/node": "^18.7.14",
|
|
53
62
|
"@types/supertest": "^2.0.12",
|
|
54
63
|
"@typescript-eslint/eslint-plugin": "^5.36.1",
|
|
55
64
|
"@typescript-eslint/parser": "^5.36.1",
|
|
56
65
|
"eslint": "^8.23.0",
|
|
66
|
+
"eslint-plugin-node": "^11.1.0",
|
|
57
67
|
"find": "^0.3.0",
|
|
58
68
|
"fs-extra": "^10.1.0",
|
|
59
69
|
"jasmine": "^4.3.0",
|
|
File without changes
|
|
@@ -31,7 +31,13 @@ const msgs = {
|
|
|
31
31
|
fallbackErr: `should return a response with a status of ${BAD_REQUEST} and a json with an error
|
|
32
32
|
for all other bad responses.`,
|
|
33
33
|
goodLogout: `should return a response with a status of ${OK}.`,
|
|
34
|
-
}
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
// Login credentials
|
|
37
|
+
const loginCreds = {
|
|
38
|
+
email: 'jsmith@gmail.com',
|
|
39
|
+
password: 'Password@1',
|
|
40
|
+
} as const;
|
|
35
41
|
|
|
36
42
|
|
|
37
43
|
// **** Types **** //
|
|
@@ -60,35 +66,25 @@ describe('auth-router', () => {
|
|
|
60
66
|
|
|
61
67
|
// Good login
|
|
62
68
|
it(msgs.goodLogin, (done) => {
|
|
63
|
-
// Setup Dummy Data
|
|
64
|
-
const creds = {
|
|
65
|
-
email: 'jsmith@gmail.com',
|
|
66
|
-
password: 'Password@1',
|
|
67
|
-
};
|
|
68
69
|
const role = UserRoles.Standard;
|
|
69
|
-
const pwdHash = hashPwd(
|
|
70
|
-
const loginUser = User.new('john smith',
|
|
70
|
+
const pwdHash = hashPwd(loginCreds.password);
|
|
71
|
+
const loginUser = User.new('john smith', loginCreds.email, role, pwdHash);
|
|
71
72
|
spyOn(userRepo, 'getOne').and.returnValue(Promise.resolve(loginUser));
|
|
72
73
|
// Call API
|
|
73
|
-
callApi(
|
|
74
|
+
callApi(loginCreds)
|
|
74
75
|
.end((err: Error, res: Response) => {
|
|
75
76
|
pErr(err);
|
|
76
77
|
expect(res.status).toBe(OK);
|
|
77
|
-
|
|
78
|
+
const cookie = res.headers['set-cookie'][0];
|
|
79
|
+
expect(cookie).toContain(envVars.cookieProps.key);
|
|
78
80
|
done();
|
|
79
81
|
});
|
|
80
82
|
});
|
|
81
83
|
|
|
82
84
|
// Email not found error
|
|
83
85
|
it(msgs.emailNotFound, (done) => {
|
|
84
|
-
// Setup Dummy Data
|
|
85
|
-
const creds = {
|
|
86
|
-
email: 'jsmith@gmail.com',
|
|
87
|
-
password: 'Password@1',
|
|
88
|
-
};
|
|
89
86
|
spyOn(userRepo, 'getOne').and.returnValue(Promise.resolve(null));
|
|
90
|
-
|
|
91
|
-
callApi(creds)
|
|
87
|
+
callApi(loginCreds)
|
|
92
88
|
.end((err: Error, res: Response) => {
|
|
93
89
|
pErr(err);
|
|
94
90
|
expect(res.status).toBe(UNAUTHORIZED);
|
|
@@ -99,17 +95,12 @@ describe('auth-router', () => {
|
|
|
99
95
|
|
|
100
96
|
// Password failed
|
|
101
97
|
it(msgs.pwdFailed, (done) => {
|
|
102
|
-
// Setup Dummy Data
|
|
103
|
-
const creds = {
|
|
104
|
-
email: 'jsmith@gmail.com',
|
|
105
|
-
password: 'someBadPassword',
|
|
106
|
-
};
|
|
107
98
|
const role = UserRoles.Standard;
|
|
108
|
-
const pwdHash = hashPwd('
|
|
109
|
-
const loginUser = User.new('john smith',
|
|
99
|
+
const pwdHash = hashPwd('bad password');
|
|
100
|
+
const loginUser = User.new('john smith', loginCreds.email, role, pwdHash);
|
|
110
101
|
spyOn(userRepo, 'getOne').and.returnValue(Promise.resolve(loginUser));
|
|
111
102
|
// Call API
|
|
112
|
-
callApi(
|
|
103
|
+
callApi(loginCreds)
|
|
113
104
|
.end((err: Error, res: Response) => {
|
|
114
105
|
pErr(err);
|
|
115
106
|
expect(res.status).toBe(UNAUTHORIZED);
|
|
@@ -120,14 +111,8 @@ describe('auth-router', () => {
|
|
|
120
111
|
|
|
121
112
|
// Fallback error
|
|
122
113
|
it(msgs.fallbackErr, (done) => {
|
|
123
|
-
// Setup Dummy Data
|
|
124
|
-
const creds = {
|
|
125
|
-
email: 'jsmith@gmail.com',
|
|
126
|
-
password: 'someBadPassword',
|
|
127
|
-
};
|
|
128
114
|
spyOn(userRepo, 'getOne').and.throwError('Database query failed.');
|
|
129
|
-
|
|
130
|
-
callApi(creds)
|
|
115
|
+
callApi(loginCreds)
|
|
131
116
|
.end((err: Error, res: Response) => {
|
|
132
117
|
pErr(err);
|
|
133
118
|
expect(res.status).toBe(BAD_REQUEST);
|
|
@@ -140,6 +125,7 @@ describe('auth-router', () => {
|
|
|
140
125
|
// Test logout
|
|
141
126
|
describe(`"GET:${logoutPath}"`, () => {
|
|
142
127
|
|
|
128
|
+
// Successful logout
|
|
143
129
|
it(msgs.goodLogout, (done) => {
|
|
144
130
|
agent.get(logoutPath)
|
|
145
131
|
.end((err: Error, res: Response) => {
|
|
@@ -7,6 +7,7 @@ import userRepo from '@repos/user-repo';
|
|
|
7
7
|
import User, { IUser } from '@models/user-model';
|
|
8
8
|
import { pErr } from '@shared/functions';
|
|
9
9
|
import { p as userPaths } from '@routes/user-router';
|
|
10
|
+
import loginAgent from '../support/login-agent';
|
|
10
11
|
import { ParamMissingError, UserNotFoundError } from '@shared/errors';
|
|
11
12
|
|
|
12
13
|
|
|
@@ -72,33 +73,40 @@ type TReqBody = string | object | undefined;
|
|
|
72
73
|
describe('user-router', () => {
|
|
73
74
|
|
|
74
75
|
let agent: SuperTest<Test>;
|
|
76
|
+
let jwtCookie: string;
|
|
75
77
|
|
|
76
78
|
|
|
77
79
|
// Run before all tests
|
|
78
80
|
beforeAll((done) => {
|
|
79
81
|
agent = supertest.agent(app);
|
|
80
|
-
|
|
82
|
+
loginAgent.login(agent, (cookie: string) => {
|
|
83
|
+
jwtCookie = cookie;
|
|
84
|
+
done();
|
|
85
|
+
});
|
|
81
86
|
});
|
|
82
87
|
|
|
83
|
-
// Test get users
|
|
88
|
+
// Test get users
|
|
84
89
|
describe(`"GET:${getUsersPath}"`, () => {
|
|
85
90
|
|
|
91
|
+
const callApi = () =>
|
|
92
|
+
agent.get(getUsersPath)
|
|
93
|
+
.set('Cookie', jwtCookie);
|
|
94
|
+
|
|
86
95
|
// Get all users
|
|
87
96
|
it(msgs.getUsersSuccess, (done) => {
|
|
88
97
|
const ret = Promise.resolve([...dummyGetAllUsers]);
|
|
89
98
|
spyOn(userRepo, 'getAll').and.returnValue(ret);
|
|
90
99
|
// Call API
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
});
|
|
100
|
+
callApi().end((err: Error, res: Response) => {
|
|
101
|
+
pErr(err);
|
|
102
|
+
expect(res.status).toBe(OK);
|
|
103
|
+
// Caste instance-objects to 'User' objects
|
|
104
|
+
const respUsers = res.body.users;
|
|
105
|
+
const retUsers = respUsers.map((user: IUser) => User.copy(user));
|
|
106
|
+
expect(retUsers).toEqual(dummyGetAllUsers);
|
|
107
|
+
expect(res.body.error).toBeUndefined();
|
|
108
|
+
done();
|
|
109
|
+
});
|
|
102
110
|
});
|
|
103
111
|
|
|
104
112
|
// Get all users bad
|
|
@@ -106,7 +114,7 @@ describe('user-router', () => {
|
|
|
106
114
|
const errMsg = 'Could not fetch users.';
|
|
107
115
|
spyOn(userRepo, 'getAll').and.throwError(errMsg);
|
|
108
116
|
// Call API
|
|
109
|
-
|
|
117
|
+
callApi()
|
|
110
118
|
.end((err: Error, res: Response) => {
|
|
111
119
|
pErr(err);
|
|
112
120
|
expect(res.status).toBe(BAD_REQUEST);
|
|
@@ -119,9 +127,10 @@ describe('user-router', () => {
|
|
|
119
127
|
// Test add user
|
|
120
128
|
describe(`"POST:${addUsersPath}"`, () => {
|
|
121
129
|
|
|
130
|
+
// Consts
|
|
122
131
|
const callApi = (reqBody: TReqBody) => {
|
|
123
|
-
return agent
|
|
124
|
-
.
|
|
132
|
+
return agent.post(addUsersPath)
|
|
133
|
+
.set('Cookie', jwtCookie)
|
|
125
134
|
.type('form').send(reqBody);
|
|
126
135
|
};
|
|
127
136
|
|
|
@@ -166,11 +175,10 @@ describe('user-router', () => {
|
|
|
166
175
|
// Test update users
|
|
167
176
|
describe(`"PUT:${updateUserPath}"`, () => {
|
|
168
177
|
|
|
169
|
-
const callApi = (reqBody: TReqBody) =>
|
|
170
|
-
|
|
171
|
-
.
|
|
172
|
-
.send(reqBody);
|
|
173
|
-
};
|
|
178
|
+
const callApi = (reqBody: TReqBody) =>
|
|
179
|
+
agent.put(updateUserPath)
|
|
180
|
+
.set('Cookie', jwtCookie)
|
|
181
|
+
.type('form').send(reqBody);
|
|
174
182
|
|
|
175
183
|
// Test updating a user success
|
|
176
184
|
it(msgs.updateSuccess, (done) => {
|
|
@@ -229,7 +237,8 @@ describe('user-router', () => {
|
|
|
229
237
|
|
|
230
238
|
const callApi = (id: number) => {
|
|
231
239
|
const path = deleteUserPath.replace(':id', id.toString());
|
|
232
|
-
return agent.delete(path)
|
|
240
|
+
return agent.delete(path)
|
|
241
|
+
.set('Cookie', jwtCookie);
|
|
233
242
|
};
|
|
234
243
|
|
|
235
244
|
// Delete user successful
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
// **** Types **** //
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export enum UserRoles {
|
|
4
|
+
Standard,
|
|
5
|
+
Admin,
|
|
6
|
+
}
|
|
7
|
+
|
|
4
8
|
export interface IUser {
|
|
5
9
|
id: number;
|
|
6
10
|
name: string;
|
|
7
11
|
email: string;
|
|
12
|
+
pwdHash: string;
|
|
13
|
+
role: UserRoles;
|
|
8
14
|
}
|
|
9
15
|
|
|
10
16
|
|
|
@@ -13,11 +19,18 @@ export interface IUser {
|
|
|
13
19
|
/**
|
|
14
20
|
* Get a new User object.
|
|
15
21
|
*/
|
|
16
|
-
function _new(
|
|
22
|
+
function _new(
|
|
23
|
+
name: string,
|
|
24
|
+
email: string,
|
|
25
|
+
role?: UserRoles,
|
|
26
|
+
pwdHash?: string,
|
|
27
|
+
): IUser {
|
|
17
28
|
return {
|
|
18
29
|
id: -1,
|
|
19
30
|
email,
|
|
20
31
|
name,
|
|
32
|
+
role: (role ?? UserRoles.Standard),
|
|
33
|
+
pwdHash: (pwdHash ?? ''),
|
|
21
34
|
};
|
|
22
35
|
}
|
|
23
36
|
|
|
@@ -29,6 +42,8 @@ function copy(user: IUser): IUser {
|
|
|
29
42
|
id: user.id,
|
|
30
43
|
email: user.email,
|
|
31
44
|
name: user.name,
|
|
45
|
+
role: user.role,
|
|
46
|
+
pwdHash: user.pwdHash,
|
|
32
47
|
};
|
|
33
48
|
}
|
|
34
49
|
|
|
@@ -12,3 +12,12 @@ JET_LOGGER_MODE=CONSOLE
|
|
|
12
12
|
JET_LOGGER_FILEPATH=jet-logger.log
|
|
13
13
|
JET_LOGGER_TIMESTAMP=TRUE
|
|
14
14
|
JET_LOGGER_FORMAT=LINE
|
|
15
|
+
|
|
16
|
+
## Authentication ##
|
|
17
|
+
COOKIE_DOMAIN=localhost
|
|
18
|
+
COOKIE_PATH=/
|
|
19
|
+
SECURE_COOKIE=false
|
|
20
|
+
JWT_SECRET=xxxxxxxxxxxxxx
|
|
21
|
+
COOKIE_SECRET=xxxxxxxxxxxxxx
|
|
22
|
+
# expires in 3 days
|
|
23
|
+
COOKIE_EXP=259200000
|