@azteam/express 1.2.151 → 1.2.154
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/package.json +2 -3
- package/src/AdminController.js +39 -45
- package/src/Controller.js +2 -3
- package/src/Server.js +38 -66
- package/src/SocketServer.js +13 -25
- package/src/constant.js +1 -1
- package/src/index.js +2 -6
- package/src/middleware/authMiddleware.js +5 -9
- package/src/middleware/cacheMiddleware.js +26 -5
- package/src/middleware/etagMiddleware.js +4 -4
- package/src/middleware/index.js +0 -1
- package/src/middleware/limitRequestMiddleware.js +9 -8
- package/src/middleware/paginateMiddleware.js +11 -20
- package/src/middleware/roleMiddleware.js +6 -7
- package/src/middleware/signMiddleware.js +6 -9
- package/src/middleware/validateMiddleware.js +11 -13
- package/src/validate.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@azteam/express",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.154",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -26,8 +26,6 @@
|
|
|
26
26
|
"@azteam/crypto": "latest",
|
|
27
27
|
"@azteam/error": "latest",
|
|
28
28
|
"@azteam/http-client": "latest",
|
|
29
|
-
"@azteam/rabbitmq-async": "latest",
|
|
30
|
-
"@azteam/redis-async": "latest",
|
|
31
29
|
"@grpc/grpc-js": "1.6.7",
|
|
32
30
|
"@grpc/proto-loader": "0.6.12",
|
|
33
31
|
"body-parser": "1.19.0",
|
|
@@ -41,6 +39,7 @@
|
|
|
41
39
|
"fastest-validator": "1.8.0",
|
|
42
40
|
"helmet": "3.21.2",
|
|
43
41
|
"jsonwebtoken": "8.2.1",
|
|
42
|
+
"lodash": "4.17.21",
|
|
44
43
|
"method-override": "3.0.0",
|
|
45
44
|
"morgan": "1.10.0",
|
|
46
45
|
"socket.io": "4.4.1",
|
package/src/AdminController.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {NOT_EXISTS} from '@azteam/error';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import {REQUEST_TYPE, USER_LEVEL} from './constant';
|
|
4
|
+
import {paginateMiddleware, roleMiddleware, validateMiddleware} from './middleware';
|
|
5
|
+
import {rulesID} from './validate';
|
|
6
6
|
import Controller from './Controller';
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
class AdminController extends Controller {
|
|
10
9
|
constructor(pathName, repository, options = {}) {
|
|
11
10
|
super(pathName, repository, {
|
|
@@ -15,7 +14,7 @@ class AdminController extends Controller {
|
|
|
15
14
|
UPDATE: 3,
|
|
16
15
|
DELETE: 4,
|
|
17
16
|
RESTORE: 5,
|
|
18
|
-
DESTROY: 6
|
|
17
|
+
DESTROY: 6,
|
|
19
18
|
}, // system roles
|
|
20
19
|
|
|
21
20
|
paginateOptions: {},
|
|
@@ -25,7 +24,7 @@ class AdminController extends Controller {
|
|
|
25
24
|
guardResponse: {},
|
|
26
25
|
allowResponse: {},
|
|
27
26
|
|
|
28
|
-
...options
|
|
27
|
+
...options,
|
|
29
28
|
});
|
|
30
29
|
}
|
|
31
30
|
|
|
@@ -39,10 +38,10 @@ class AdminController extends Controller {
|
|
|
39
38
|
const paginateData = await this.repository.find(req.query, req.paginate);
|
|
40
39
|
|
|
41
40
|
return res.success(paginateData, this.options.guardResponse, this.options.allowResponse);
|
|
42
|
-
}
|
|
43
|
-
]
|
|
41
|
+
},
|
|
42
|
+
],
|
|
44
43
|
};
|
|
45
|
-
}
|
|
44
|
+
}
|
|
46
45
|
|
|
47
46
|
getPaginateTrash() {
|
|
48
47
|
return {
|
|
@@ -54,10 +53,10 @@ class AdminController extends Controller {
|
|
|
54
53
|
const paginateData = await this.repository.findTrash(req.query, req.paginate);
|
|
55
54
|
|
|
56
55
|
return res.success(paginateData, this.options.guardResponse, this.options.allowResponse);
|
|
57
|
-
}
|
|
58
|
-
]
|
|
56
|
+
},
|
|
57
|
+
],
|
|
59
58
|
};
|
|
60
|
-
}
|
|
59
|
+
}
|
|
61
60
|
|
|
62
61
|
getOnePublic() {
|
|
63
62
|
return {
|
|
@@ -69,11 +68,10 @@ class AdminController extends Controller {
|
|
|
69
68
|
const item = await this.repository.findOneById(req.params.id);
|
|
70
69
|
if (!item) return res.error(NOT_EXISTS);
|
|
71
70
|
return res.success(item, this.options.guardResponse, this.options.allowResponse);
|
|
72
|
-
}
|
|
73
|
-
]
|
|
71
|
+
},
|
|
72
|
+
],
|
|
74
73
|
};
|
|
75
|
-
|
|
76
|
-
};
|
|
74
|
+
}
|
|
77
75
|
|
|
78
76
|
getOneTrash() {
|
|
79
77
|
return {
|
|
@@ -85,20 +83,18 @@ class AdminController extends Controller {
|
|
|
85
83
|
const item = await this.repository.findOneTrashById(req.params.id);
|
|
86
84
|
if (!item) return res.error(NOT_EXISTS);
|
|
87
85
|
return res.success(item, this.options.guardResponse, this.options.allowResponse);
|
|
88
|
-
}
|
|
89
|
-
]
|
|
86
|
+
},
|
|
87
|
+
],
|
|
90
88
|
};
|
|
91
|
-
|
|
92
|
-
};
|
|
93
|
-
|
|
89
|
+
}
|
|
94
90
|
|
|
95
91
|
async beforeCreate(data, user) {
|
|
96
92
|
return data;
|
|
97
|
-
}
|
|
93
|
+
}
|
|
98
94
|
|
|
99
95
|
async afterCreate(item, user) {
|
|
100
96
|
return item;
|
|
101
|
-
}
|
|
97
|
+
}
|
|
102
98
|
|
|
103
99
|
postCreatePublic() {
|
|
104
100
|
return {
|
|
@@ -107,7 +103,6 @@ class AdminController extends Controller {
|
|
|
107
103
|
roleMiddleware([this.options.roles.CREATE], USER_LEVEL.ADMIN),
|
|
108
104
|
validateMiddleware(REQUEST_TYPE.BODY, this.options.rulesCreate),
|
|
109
105
|
async (req, res) => {
|
|
110
|
-
|
|
111
106
|
const data = await this.beforeCreate(req.body, req.user);
|
|
112
107
|
|
|
113
108
|
let item = await this.repository.createByUser(req.user.id, data);
|
|
@@ -115,18 +110,18 @@ class AdminController extends Controller {
|
|
|
115
110
|
item = await this.afterCreate(item, req.user);
|
|
116
111
|
|
|
117
112
|
return res.success(item, this.options.guardResponse, this.options.allowResponse);
|
|
118
|
-
}
|
|
119
|
-
]
|
|
113
|
+
},
|
|
114
|
+
],
|
|
120
115
|
};
|
|
121
|
-
}
|
|
122
|
-
|
|
116
|
+
}
|
|
123
117
|
|
|
124
118
|
async beforeModify(data, user) {
|
|
125
119
|
return data;
|
|
126
|
-
}
|
|
120
|
+
}
|
|
121
|
+
|
|
127
122
|
async afterModify(item, user) {
|
|
128
123
|
return item;
|
|
129
|
-
}
|
|
124
|
+
}
|
|
130
125
|
|
|
131
126
|
putModifyPublic() {
|
|
132
127
|
return {
|
|
@@ -136,7 +131,6 @@ class AdminController extends Controller {
|
|
|
136
131
|
validateMiddleware(REQUEST_TYPE.PARAMS, rulesID),
|
|
137
132
|
validateMiddleware(REQUEST_TYPE.BODY, this.options.rulesModify),
|
|
138
133
|
async (req, res) => {
|
|
139
|
-
|
|
140
134
|
let item = await this.repository.findOneById(req.params.id);
|
|
141
135
|
if (!item) return res.error(NOT_EXISTS);
|
|
142
136
|
|
|
@@ -147,10 +141,10 @@ class AdminController extends Controller {
|
|
|
147
141
|
item = await this.afterModify(item, req.user);
|
|
148
142
|
|
|
149
143
|
return res.success(item, this.options.guardResponse, this.options.allowResponse);
|
|
150
|
-
}
|
|
151
|
-
]
|
|
144
|
+
},
|
|
145
|
+
],
|
|
152
146
|
};
|
|
153
|
-
}
|
|
147
|
+
}
|
|
154
148
|
|
|
155
149
|
deletePublic() {
|
|
156
150
|
return {
|
|
@@ -164,10 +158,10 @@ class AdminController extends Controller {
|
|
|
164
158
|
|
|
165
159
|
await this.repository.deleteByUser(req.user.id, item);
|
|
166
160
|
return res.success(true);
|
|
167
|
-
}
|
|
168
|
-
]
|
|
161
|
+
},
|
|
162
|
+
],
|
|
169
163
|
};
|
|
170
|
-
}
|
|
164
|
+
}
|
|
171
165
|
|
|
172
166
|
postRestoreTrash() {
|
|
173
167
|
return {
|
|
@@ -181,10 +175,10 @@ class AdminController extends Controller {
|
|
|
181
175
|
|
|
182
176
|
await this.repository.restoreByUser(req.user.id, item);
|
|
183
177
|
return res.success(true);
|
|
184
|
-
}
|
|
185
|
-
]
|
|
178
|
+
},
|
|
179
|
+
],
|
|
186
180
|
};
|
|
187
|
-
}
|
|
181
|
+
}
|
|
188
182
|
|
|
189
183
|
deleteDestroyTrash() {
|
|
190
184
|
return {
|
|
@@ -198,10 +192,10 @@ class AdminController extends Controller {
|
|
|
198
192
|
|
|
199
193
|
await this.repository.destroy(item);
|
|
200
194
|
return res.success(true);
|
|
201
|
-
}
|
|
202
|
-
]
|
|
195
|
+
},
|
|
196
|
+
],
|
|
203
197
|
};
|
|
204
|
-
}
|
|
198
|
+
}
|
|
205
199
|
}
|
|
206
200
|
|
|
207
|
-
export default AdminController;
|
|
201
|
+
export default AdminController;
|
package/src/Controller.js
CHANGED
|
@@ -4,7 +4,7 @@ class Controller {
|
|
|
4
4
|
this.repository = repository;
|
|
5
5
|
|
|
6
6
|
this.options = {
|
|
7
|
-
...options
|
|
7
|
+
...options,
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -13,7 +13,6 @@ class Controller {
|
|
|
13
13
|
let result = [];
|
|
14
14
|
|
|
15
15
|
while (Object.getPrototypeOf(child.__proto__)) {
|
|
16
|
-
|
|
17
16
|
const data = Object.getOwnPropertyNames(Object.getPrototypeOf(child));
|
|
18
17
|
|
|
19
18
|
data.map((methodName) => {
|
|
@@ -29,7 +28,7 @@ class Controller {
|
|
|
29
28
|
result.push({
|
|
30
29
|
type: matches[0],
|
|
31
30
|
name: methodName,
|
|
32
|
-
path
|
|
31
|
+
path,
|
|
33
32
|
});
|
|
34
33
|
}
|
|
35
34
|
});
|
package/src/Server.js
CHANGED
|
@@ -12,15 +12,13 @@ import _ from 'lodash';
|
|
|
12
12
|
import 'express-async-errors';
|
|
13
13
|
import {errorCatch, ErrorException, NOT_FOUND, UNKNOWN} from '@azteam/error';
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
const RES_TYPE = {
|
|
17
16
|
ARRAY: 'ARRAY',
|
|
18
17
|
OBJECT: 'OBJECT',
|
|
19
|
-
DOCS: 'DOCS'
|
|
18
|
+
DOCS: 'DOCS',
|
|
20
19
|
};
|
|
21
20
|
|
|
22
21
|
function omitItem(item, guard, allows) {
|
|
23
|
-
|
|
24
22
|
if (_.isArray(guard)) {
|
|
25
23
|
guard = _.difference(guard, allows);
|
|
26
24
|
}
|
|
@@ -37,7 +35,6 @@ function omitItem(item, guard, allows) {
|
|
|
37
35
|
return item;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
|
|
41
38
|
class Server {
|
|
42
39
|
constructor(currentDir = '', options = {}) {
|
|
43
40
|
this.redis = null;
|
|
@@ -51,7 +48,7 @@ class Server {
|
|
|
51
48
|
secure: process.env.NODE_ENV !== 'development',
|
|
52
49
|
httpOnly: true,
|
|
53
50
|
signed: true,
|
|
54
|
-
sameSite: 'Lax'
|
|
51
|
+
sameSite: 'Lax',
|
|
55
52
|
};
|
|
56
53
|
|
|
57
54
|
this.middlewares = [];
|
|
@@ -62,7 +59,6 @@ class Server {
|
|
|
62
59
|
this.initController(currentDir);
|
|
63
60
|
}
|
|
64
61
|
|
|
65
|
-
|
|
66
62
|
setMessageQueue(messageQueue) {
|
|
67
63
|
this.messageQueue = messageQueue;
|
|
68
64
|
return this;
|
|
@@ -76,7 +72,7 @@ class Server {
|
|
|
76
72
|
setCookieOptions(cookieOptions) {
|
|
77
73
|
this.cookieOptions = {
|
|
78
74
|
...this.cookieOptions,
|
|
79
|
-
...cookieOptions
|
|
75
|
+
...cookieOptions,
|
|
80
76
|
};
|
|
81
77
|
return this;
|
|
82
78
|
}
|
|
@@ -100,7 +96,7 @@ class Server {
|
|
|
100
96
|
this.controllers.push({
|
|
101
97
|
name,
|
|
102
98
|
version,
|
|
103
|
-
controller
|
|
99
|
+
controller,
|
|
104
100
|
});
|
|
105
101
|
return this;
|
|
106
102
|
}
|
|
@@ -128,19 +124,17 @@ class Server {
|
|
|
128
124
|
return this;
|
|
129
125
|
}
|
|
130
126
|
|
|
131
|
-
|
|
132
127
|
startAPI(port) {
|
|
133
|
-
|
|
134
128
|
if (!_.isEmpty(this.controllers)) {
|
|
135
|
-
|
|
136
129
|
const WHITE_LIST = this.whiteList;
|
|
137
130
|
const COOKIE_OPTIONS = this.cookieOptions;
|
|
138
131
|
|
|
139
|
-
|
|
140
132
|
const app = express();
|
|
141
|
-
app.use(
|
|
142
|
-
|
|
143
|
-
|
|
133
|
+
app.use(
|
|
134
|
+
helmet({
|
|
135
|
+
frameguard: false,
|
|
136
|
+
})
|
|
137
|
+
);
|
|
144
138
|
|
|
145
139
|
app.use(methodOverride());
|
|
146
140
|
app.use(bodyParser.urlencoded({limit: '5mb', extended: true}));
|
|
@@ -150,31 +144,29 @@ class Server {
|
|
|
150
144
|
|
|
151
145
|
app.use(cookieParser(process.env.SECRET_KEY));
|
|
152
146
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}));
|
|
147
|
+
app.use(
|
|
148
|
+
cors({
|
|
149
|
+
credentials: true,
|
|
150
|
+
origin: function (origin, callback) {
|
|
151
|
+
if (!origin || !WHITE_LIST.length || WHITE_LIST.some((re) => origin.endsWith(re))) {
|
|
152
|
+
callback(null, true);
|
|
153
|
+
} else {
|
|
154
|
+
callback(new Error(`${origin} Not allowed by CORS`));
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
})
|
|
158
|
+
);
|
|
166
159
|
|
|
167
160
|
if (this.debug) {
|
|
168
161
|
app.use(morgan('dev'));
|
|
169
162
|
}
|
|
170
163
|
|
|
171
|
-
app.get('/robots.txt', function(req, res) {
|
|
164
|
+
app.get('/robots.txt', function (req, res) {
|
|
172
165
|
res.type('text/plain');
|
|
173
166
|
res.send('User-agent: *\nDisallow: /');
|
|
174
167
|
});
|
|
175
168
|
app.get('/favicon.ico', (req, res) => res.status(204).json({}));
|
|
176
169
|
|
|
177
|
-
|
|
178
170
|
const {redis} = this;
|
|
179
171
|
|
|
180
172
|
if (redis) {
|
|
@@ -182,13 +174,11 @@ class Server {
|
|
|
182
174
|
app.response.redis = redis;
|
|
183
175
|
}
|
|
184
176
|
|
|
185
|
-
|
|
186
|
-
app.response.error = function(code, errors = []) {
|
|
177
|
+
app.response.error = function (code, errors = []) {
|
|
187
178
|
throw new ErrorException(code, errors);
|
|
188
179
|
};
|
|
189
180
|
|
|
190
|
-
app.response.success = function(data = {}, guard = [], allows = []) {
|
|
191
|
-
|
|
181
|
+
app.response.success = function (data = {}, guard = [], allows = []) {
|
|
192
182
|
let guardData = data;
|
|
193
183
|
if (data) {
|
|
194
184
|
let resType = null;
|
|
@@ -202,31 +192,17 @@ class Server {
|
|
|
202
192
|
}
|
|
203
193
|
|
|
204
194
|
if (_.isArray(guard)) {
|
|
205
|
-
guard = [
|
|
206
|
-
...guard,
|
|
207
|
-
'__v',
|
|
208
|
-
'_id',
|
|
209
|
-
'deleted_at',
|
|
210
|
-
'updated_at',
|
|
211
|
-
'created_id',
|
|
212
|
-
'modified_id'
|
|
213
|
-
];
|
|
195
|
+
guard = [...guard, '__v', '_id', 'deleted_at', 'updated_at', 'created_id', 'modified_id'];
|
|
214
196
|
if (resType === RES_TYPE.ARRAY || resType === RES_TYPE.DOCS) {
|
|
215
|
-
guard = [
|
|
216
|
-
...guard,
|
|
217
|
-
'metadata_disable',
|
|
218
|
-
'metadata_keywords',
|
|
219
|
-
'metadata_description',
|
|
220
|
-
'metadata_image_url'
|
|
221
|
-
];
|
|
197
|
+
guard = [...guard, 'metadata_disable', 'metadata_keywords', 'metadata_description', 'metadata_image_url'];
|
|
222
198
|
}
|
|
223
199
|
}
|
|
224
200
|
if (resType === RES_TYPE.DOCS) {
|
|
225
|
-
guardData.docs = _.map(data.docs, item => {
|
|
201
|
+
guardData.docs = _.map(data.docs, (item) => {
|
|
226
202
|
return omitItem(item, guard, allows);
|
|
227
203
|
});
|
|
228
204
|
} else if (resType === RES_TYPE.ARRAY) {
|
|
229
|
-
guardData = _.map(data, item => {
|
|
205
|
+
guardData = _.map(data, (item) => {
|
|
230
206
|
return omitItem(item, guard, allows);
|
|
231
207
|
});
|
|
232
208
|
} else if (resType === RES_TYPE.OBJECT) {
|
|
@@ -237,43 +213,43 @@ class Server {
|
|
|
237
213
|
const resData = {
|
|
238
214
|
success: true,
|
|
239
215
|
data: guardData,
|
|
240
|
-
options: this.resOptions
|
|
216
|
+
options: this.resOptions,
|
|
241
217
|
};
|
|
242
218
|
|
|
243
219
|
if (this.redis && this.cache) {
|
|
244
|
-
this.redis.set(this.cache.key, resData, this.ttl);
|
|
220
|
+
this.redis.set(this.cache.key, resData, this.cache.ttl);
|
|
245
221
|
}
|
|
246
222
|
|
|
247
223
|
return this.json(resData);
|
|
248
224
|
};
|
|
249
225
|
|
|
250
|
-
app.response.cleanCookie = function(data) {
|
|
226
|
+
app.response.cleanCookie = function (data) {
|
|
251
227
|
_.map(data, (name) => {
|
|
252
228
|
this.clearCookie(name, {
|
|
253
|
-
domain: COOKIE_OPTIONS.domain
|
|
229
|
+
domain: COOKIE_OPTIONS.domain,
|
|
254
230
|
});
|
|
255
231
|
});
|
|
256
232
|
};
|
|
257
233
|
|
|
258
|
-
app.response.addCookie = function(data) {
|
|
234
|
+
app.response.addCookie = function (data) {
|
|
259
235
|
_.map(data, (value, key) => {
|
|
260
236
|
const maxAge = 86400000 * 365; // 1 year
|
|
261
237
|
this.cookie(key, value, {
|
|
262
238
|
...COOKIE_OPTIONS,
|
|
263
239
|
maxAge,
|
|
264
|
-
expires: new Date(Date.now() + maxAge)
|
|
240
|
+
expires: new Date(Date.now() + maxAge),
|
|
265
241
|
});
|
|
266
242
|
});
|
|
267
243
|
};
|
|
268
244
|
|
|
269
|
-
app.use(async function(req, res, next) {
|
|
245
|
+
app.use(async function (req, res, next) {
|
|
270
246
|
delete res.cache;
|
|
271
247
|
|
|
272
248
|
req.trackDevice = {
|
|
273
249
|
ip: req.ip,
|
|
274
250
|
device: req.get('X-DEVICE') || req.get('User-Agent'),
|
|
275
251
|
device_id: req.get('X-DEVICE-ID') || 'web',
|
|
276
|
-
os: req.get('X-OS') || 'web'
|
|
252
|
+
os: req.get('X-OS') || 'web',
|
|
277
253
|
};
|
|
278
254
|
|
|
279
255
|
next();
|
|
@@ -306,7 +282,7 @@ class Server {
|
|
|
306
282
|
version: controllerVersion,
|
|
307
283
|
type,
|
|
308
284
|
method: name,
|
|
309
|
-
path: router.path
|
|
285
|
+
path: router.path,
|
|
310
286
|
});
|
|
311
287
|
app[type](router.path, ...router.method);
|
|
312
288
|
});
|
|
@@ -347,9 +323,7 @@ class Server {
|
|
|
347
323
|
throw error;
|
|
348
324
|
}
|
|
349
325
|
|
|
350
|
-
let bind = typeof port === 'string' ?
|
|
351
|
-
'Pipe ' + port :
|
|
352
|
-
'Port ' + port;
|
|
326
|
+
let bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
|
|
353
327
|
|
|
354
328
|
switch (error.code) {
|
|
355
329
|
case 'EACCES':
|
|
@@ -368,7 +342,6 @@ class Server {
|
|
|
368
342
|
server.listen(port);
|
|
369
343
|
|
|
370
344
|
return server;
|
|
371
|
-
|
|
372
345
|
} else {
|
|
373
346
|
throw Error('No controllers in use API');
|
|
374
347
|
}
|
|
@@ -377,7 +350,6 @@ class Server {
|
|
|
377
350
|
|
|
378
351
|
startSocket(port) {
|
|
379
352
|
if (!_.isEmpty(this.controllers)) {
|
|
380
|
-
|
|
381
353
|
} else {
|
|
382
354
|
throw Error('No controllers in use SOCKET');
|
|
383
355
|
}
|
package/src/SocketServer.js
CHANGED
|
@@ -5,17 +5,15 @@ import socketIO from 'socket.io';
|
|
|
5
5
|
import bodyParser from 'body-parser';
|
|
6
6
|
import cookieParser from 'cookie-parser';
|
|
7
7
|
import redisAdapter from 'socket.io-redis';
|
|
8
|
-
import cors from 'cors';
|
|
9
8
|
import _ from 'lodash';
|
|
10
9
|
|
|
11
|
-
const wrap = middleware => (socket, next) => middleware(socket.request, {}, next);
|
|
10
|
+
const wrap = (middleware) => (socket, next) => middleware(socket.request, {}, next);
|
|
12
11
|
|
|
13
12
|
class SocketServer {
|
|
14
|
-
|
|
15
13
|
constructor(currentDir = '', options = {}) {
|
|
16
14
|
this.options = {
|
|
17
15
|
redisConfig: null,
|
|
18
|
-
...options
|
|
16
|
+
...options,
|
|
19
17
|
};
|
|
20
18
|
|
|
21
19
|
this.middlewares = [];
|
|
@@ -44,7 +42,7 @@ class SocketServer {
|
|
|
44
42
|
this.controllers.push({
|
|
45
43
|
name,
|
|
46
44
|
version,
|
|
47
|
-
controller
|
|
45
|
+
controller,
|
|
48
46
|
});
|
|
49
47
|
return this;
|
|
50
48
|
}
|
|
@@ -74,7 +72,6 @@ class SocketServer {
|
|
|
74
72
|
|
|
75
73
|
startPort(port) {
|
|
76
74
|
if (!_.isEmpty(this.controllers)) {
|
|
77
|
-
|
|
78
75
|
const WHITE_LIST = this.whiteList;
|
|
79
76
|
|
|
80
77
|
const server = http.Server(express());
|
|
@@ -82,23 +79,20 @@ class SocketServer {
|
|
|
82
79
|
const io = socketIO(server, {
|
|
83
80
|
wsEngine: 'eiows',
|
|
84
81
|
perMessageDeflate: {
|
|
85
|
-
threshold: 32768
|
|
82
|
+
threshold: 32768,
|
|
86
83
|
},
|
|
87
84
|
cors: {
|
|
88
85
|
credentials: true,
|
|
89
|
-
origin: function(origin, callback) {
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
WHITE_LIST.some(re => origin.endsWith(re))) {
|
|
93
|
-
callback(null, true)
|
|
86
|
+
origin: function (origin, callback) {
|
|
87
|
+
if (!origin || !WHITE_LIST.length || WHITE_LIST.some((re) => origin.endsWith(re))) {
|
|
88
|
+
callback(null, true);
|
|
94
89
|
} else {
|
|
95
90
|
callback(new Error(`${origin} Not allowed by CORS`));
|
|
96
91
|
}
|
|
97
92
|
},
|
|
98
|
-
}
|
|
93
|
+
},
|
|
99
94
|
});
|
|
100
95
|
|
|
101
|
-
|
|
102
96
|
if (this.options.redisConfig) {
|
|
103
97
|
io.adapter(redisAdapter(this.options.redisConfig));
|
|
104
98
|
}
|
|
@@ -114,26 +108,24 @@ class SocketServer {
|
|
|
114
108
|
|
|
115
109
|
const middlewares = [...this.middlewares, ...(item.middlewares || [])];
|
|
116
110
|
|
|
117
|
-
nsp.use(wrap(bodyParser.urlencoded({
|
|
118
|
-
nsp.use(wrap(bodyParser.json({
|
|
111
|
+
nsp.use(wrap(bodyParser.urlencoded({limit: '5mb', extended: true})));
|
|
112
|
+
nsp.use(wrap(bodyParser.json({limit: '5mb'})));
|
|
119
113
|
nsp.use(wrap(cookieParser(process.env.SECRET_KEY)));
|
|
120
114
|
|
|
121
115
|
_.map(middlewares, (middleware) => {
|
|
122
116
|
nsp.use(wrap(middleware));
|
|
123
117
|
});
|
|
124
118
|
|
|
125
|
-
|
|
126
119
|
if (item.schedule) {
|
|
127
120
|
item.schedule(io);
|
|
128
121
|
}
|
|
129
122
|
|
|
130
123
|
if (item.connection) {
|
|
131
|
-
nsp.on('connection', socket => {
|
|
124
|
+
nsp.on('connection', (socket) => {
|
|
132
125
|
item.connection(io, socket);
|
|
133
126
|
});
|
|
134
127
|
}
|
|
135
128
|
|
|
136
|
-
|
|
137
129
|
msg.push({
|
|
138
130
|
controller: obj.name,
|
|
139
131
|
version: obj.version,
|
|
@@ -144,7 +136,6 @@ class SocketServer {
|
|
|
144
136
|
|
|
145
137
|
console.table(msg);
|
|
146
138
|
|
|
147
|
-
|
|
148
139
|
server.on('listening', () => {
|
|
149
140
|
this._alert('listening', `Server start at http://localhost:${server.address().port}`);
|
|
150
141
|
});
|
|
@@ -154,9 +145,7 @@ class SocketServer {
|
|
|
154
145
|
throw error;
|
|
155
146
|
}
|
|
156
147
|
|
|
157
|
-
let bind = typeof port === 'string' ?
|
|
158
|
-
'Pipe ' + port :
|
|
159
|
-
'Port ' + port;
|
|
148
|
+
let bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
|
|
160
149
|
|
|
161
150
|
switch (error.code) {
|
|
162
151
|
case 'EACCES':
|
|
@@ -175,7 +164,6 @@ class SocketServer {
|
|
|
175
164
|
server.listen(port);
|
|
176
165
|
|
|
177
166
|
return server;
|
|
178
|
-
|
|
179
167
|
} else {
|
|
180
168
|
throw Error('No controllers in use');
|
|
181
169
|
}
|
|
@@ -196,4 +184,4 @@ class SocketServer {
|
|
|
196
184
|
}
|
|
197
185
|
}
|
|
198
186
|
|
|
199
|
-
export default SocketServer;
|
|
187
|
+
export default SocketServer;
|
package/src/constant.js
CHANGED
package/src/index.js
CHANGED
|
@@ -3,14 +3,10 @@ import Server from './Server';
|
|
|
3
3
|
import Controller from './Controller';
|
|
4
4
|
import AdminController from './AdminController';
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
export * from './middleware';
|
|
8
7
|
export * from './constant';
|
|
9
8
|
export * from './validate';
|
|
10
9
|
|
|
11
|
-
export {
|
|
12
|
-
Controller,
|
|
13
|
-
AdminController,
|
|
14
|
-
}
|
|
10
|
+
export {Controller, AdminController};
|
|
15
11
|
|
|
16
|
-
export default Server;
|
|
12
|
+
export default Server;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ErrorException } from '@azteam/error';
|
|
2
1
|
import jwt from 'jsonwebtoken';
|
|
3
2
|
|
|
4
3
|
function systemLogin(userData = null) {
|
|
@@ -11,10 +10,9 @@ function systemLogin(userData = null) {
|
|
|
11
10
|
return user;
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
export default function(cbRefreshToken, cbLoginAPI) {
|
|
15
|
-
return async function(req, res, next) {
|
|
16
|
-
|
|
17
|
-
const { headers, signedCookies } = req;
|
|
13
|
+
export default function (cbRefreshToken, cbLoginAPI) {
|
|
14
|
+
return async function (req, res, next) {
|
|
15
|
+
const {headers, signedCookies} = req;
|
|
18
16
|
|
|
19
17
|
if (headers['x-app-secret'] === process.env.SECRET_KEY) {
|
|
20
18
|
req.user = systemLogin(headers['x-app-user']);
|
|
@@ -43,7 +41,7 @@ export default function(cbRefreshToken, cbLoginAPI) {
|
|
|
43
41
|
if (data) {
|
|
44
42
|
jwtData = jwt.decode(data.access_token);
|
|
45
43
|
res.addCookie({
|
|
46
|
-
|
|
44
|
+
access_token: data.access_token,
|
|
47
45
|
});
|
|
48
46
|
res.set('Auth-Token', data.access_token);
|
|
49
47
|
}
|
|
@@ -57,8 +55,6 @@ export default function(cbRefreshToken, cbLoginAPI) {
|
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
57
|
|
|
60
|
-
|
|
61
58
|
return next();
|
|
62
59
|
};
|
|
63
|
-
|
|
64
|
-
}
|
|
60
|
+
}
|
|
@@ -1,14 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import qs from 'querystring';
|
|
3
|
+
|
|
4
|
+
export default function (key, options = {}) {
|
|
5
|
+
options = {
|
|
6
|
+
ttl: 300,
|
|
7
|
+
limitPage: 5,
|
|
8
|
+
...options,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
return async function (req, res, next) {
|
|
3
12
|
const {redis} = req;
|
|
4
13
|
if (redis) {
|
|
5
|
-
|
|
14
|
+
let cacheKey = key;
|
|
15
|
+
|
|
16
|
+
if (options.query) {
|
|
17
|
+
cacheKey += `${cacheKey}:${_.get(req, options.query)}`;
|
|
18
|
+
}
|
|
19
|
+
if (req.paginate) {
|
|
20
|
+
if (_.isEmpty(req.query) && req.paginate.page <= options.limitPage) {
|
|
21
|
+
cacheKey = `${cacheKey}:${qs.stringify(req.paginate)}`;
|
|
22
|
+
} else {
|
|
23
|
+
return next();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const cacheData = await redis.get(cacheKey);
|
|
6
27
|
if (cacheData) {
|
|
7
28
|
return res.json(cacheData);
|
|
8
29
|
} else {
|
|
9
30
|
res.cache = {
|
|
10
|
-
key,
|
|
11
|
-
ttl
|
|
31
|
+
key: cacheKey,
|
|
32
|
+
ttl: options.ttl,
|
|
12
33
|
};
|
|
13
34
|
}
|
|
14
35
|
}
|
|
@@ -6,8 +6,8 @@ function floorToMinute(time, minutes) {
|
|
|
6
6
|
return time;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export default function(mTimeout = 5) {
|
|
10
|
-
return async function(req, res, next) {
|
|
9
|
+
export default function (mTimeout = 5) {
|
|
10
|
+
return async function (req, res, next) {
|
|
11
11
|
if (req.method === 'GET') {
|
|
12
12
|
const etag_hash = etag(req.url + floorToMinute(Math.floor(Date.now() / 1000), mTimeout));
|
|
13
13
|
if (req.headers['if-none-match'] === etag_hash) {
|
|
@@ -16,5 +16,5 @@ export default function(mTimeout = 5) {
|
|
|
16
16
|
res.setHeader('ETag', etag_hash);
|
|
17
17
|
}
|
|
18
18
|
return next();
|
|
19
|
-
}
|
|
20
|
-
}
|
|
19
|
+
};
|
|
20
|
+
}
|
package/src/middleware/index.js
CHANGED
|
@@ -6,4 +6,3 @@ export {default as paginateMiddleware} from './paginateMiddleware';
|
|
|
6
6
|
export {default as validateMiddleware} from './validateMiddleware';
|
|
7
7
|
export {default as limitRequestMiddleware} from './limitRequestMiddleware';
|
|
8
8
|
export {default as cacheMiddleware} from './cacheMiddleware';
|
|
9
|
-
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import rateLimit from 'express-rate-limit';
|
|
2
|
-
import {
|
|
2
|
+
import {BLOCKED} from '@azteam/error';
|
|
3
3
|
|
|
4
4
|
export default function limitRequest(max = 10, seconds = 30) {
|
|
5
5
|
return rateLimit({
|
|
@@ -7,11 +7,12 @@ export default function limitRequest(max = 10, seconds = 30) {
|
|
|
7
7
|
windowMs: seconds * 1000, // default 30 seconds
|
|
8
8
|
message: {
|
|
9
9
|
success: false,
|
|
10
|
-
errors: [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
errors: [
|
|
11
|
+
{
|
|
12
|
+
code: BLOCKED,
|
|
13
|
+
message: 'Too many request',
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
},
|
|
15
17
|
});
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
function omitData(data) {
|
|
5
|
-
Object.keys(data).map(function(key, index) {
|
|
4
|
+
Object.keys(data).map(function (key, index) {
|
|
6
5
|
let value = data[key];
|
|
7
6
|
if (typeof value === 'string') {
|
|
8
7
|
value = value.trim();
|
|
@@ -20,30 +19,24 @@ function omitData(data) {
|
|
|
20
19
|
return data;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
export default function(options = {}) {
|
|
22
|
+
export default function (options = {}) {
|
|
25
23
|
options = {
|
|
26
24
|
limit: 20,
|
|
27
25
|
searchFields: [],
|
|
28
|
-
sortFields: [
|
|
29
|
-
|
|
30
|
-
'modified_at',
|
|
31
|
-
'status'
|
|
32
|
-
],
|
|
33
|
-
...options
|
|
26
|
+
sortFields: ['created_at', 'modified_at', 'status'],
|
|
27
|
+
...options,
|
|
34
28
|
};
|
|
35
29
|
|
|
36
|
-
return async function(req, res, next) {
|
|
30
|
+
return async function (req, res, next) {
|
|
37
31
|
req.query = omitData(req.query);
|
|
38
32
|
|
|
39
33
|
res.resOptions = options;
|
|
40
34
|
req.paginate = {
|
|
41
|
-
limit: options.limit
|
|
35
|
+
limit: options.limit,
|
|
42
36
|
};
|
|
43
37
|
if (req.query.limit) {
|
|
44
38
|
req.paginate.limit = Number(req.query.limit);
|
|
45
39
|
delete req.query.limit;
|
|
46
|
-
|
|
47
40
|
}
|
|
48
41
|
|
|
49
42
|
req.paginate.page = req.query.page ? Number(req.query.page) : 1;
|
|
@@ -51,10 +44,9 @@ export default function(options = {}) {
|
|
|
51
44
|
|
|
52
45
|
delete req.query.page;
|
|
53
46
|
|
|
54
|
-
|
|
55
47
|
if (req.query.sort_by && options.sortFields.includes(req.query.sort_by)) {
|
|
56
48
|
req.paginate.sort = {
|
|
57
|
-
[req.query.sort_by]: req.query.sort_type === 'asc' ? 'asc' : 'desc'
|
|
49
|
+
[req.query.sort_by]: req.query.sort_type === 'asc' ? 'asc' : 'desc',
|
|
58
50
|
};
|
|
59
51
|
|
|
60
52
|
delete req.query.sort_by;
|
|
@@ -70,18 +62,17 @@ export default function(options = {}) {
|
|
|
70
62
|
|
|
71
63
|
req.query[newKey] = {
|
|
72
64
|
...req.query[newKey],
|
|
73
|
-
$gte: value
|
|
65
|
+
$gte: value,
|
|
74
66
|
};
|
|
75
67
|
} else if (key.endsWith('_end')) {
|
|
76
68
|
const newKey = key.replace('_end', '');
|
|
77
69
|
|
|
78
70
|
req.query[newKey] = {
|
|
79
71
|
...req.query[newKey],
|
|
80
|
-
$lt: value
|
|
72
|
+
$lt: value,
|
|
81
73
|
};
|
|
82
74
|
}
|
|
83
75
|
|
|
84
|
-
|
|
85
76
|
if (!options.searchFields.includes(key)) {
|
|
86
77
|
delete req.query[key];
|
|
87
78
|
}
|
|
@@ -96,8 +87,8 @@ export default function(options = {}) {
|
|
|
96
87
|
req.query = {
|
|
97
88
|
...req.query,
|
|
98
89
|
$text: {
|
|
99
|
-
$search: keywords
|
|
100
|
-
}
|
|
90
|
+
$search: keywords,
|
|
91
|
+
},
|
|
101
92
|
};
|
|
102
93
|
}
|
|
103
94
|
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {ErrorException, PERMISSION, UNAUTHORIZED} from '@azteam/error';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return async function(req, res, next) {
|
|
3
|
+
export default function (roles = null, minLevel = 1) {
|
|
4
|
+
return async function (req, res, next) {
|
|
6
5
|
if (!req.user) {
|
|
7
6
|
return next(new ErrorException(UNAUTHORIZED));
|
|
8
7
|
}
|
|
9
8
|
if (req.user.level < minLevel) {
|
|
10
9
|
return next(new ErrorException(PERMISSION));
|
|
11
10
|
}
|
|
12
|
-
if (!roles || req.user.level === 100 || req.user.roles.some(r => roles.includes(r))) {
|
|
11
|
+
if (!roles || req.user.level === 100 || req.user.roles.some((r) => roles.includes(r))) {
|
|
13
12
|
return next();
|
|
14
13
|
}
|
|
15
14
|
return next(new ErrorException(PERMISSION));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {isValidSign} from '@azteam/crypto';
|
|
2
|
+
import {ErrorException, SIGNATURE_FAILED} from '@azteam/error';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export default function(secretKey, mTimeout = 5) {
|
|
8
|
-
return async function(req, res, next) {
|
|
4
|
+
export default function (secretKey, mTimeout = 5) {
|
|
5
|
+
return async function (req, res, next) {
|
|
9
6
|
if (req.query.sign) {
|
|
10
7
|
let url = `${req.protocol}://${req.hostname}${req.originalUrl}`;
|
|
11
8
|
if (isValidSign(url, secretKey, mTimeout)) {
|
|
@@ -13,5 +10,5 @@ export default function(secretKey, mTimeout = 5) {
|
|
|
13
10
|
}
|
|
14
11
|
}
|
|
15
12
|
return next(new ErrorException(SIGNATURE_FAILED));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {ErrorException, VALIDATE} from '@azteam/error';
|
|
2
2
|
import Validator from 'fastest-validator';
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
const v = new Validator({
|
|
6
5
|
messages: {
|
|
7
|
-
jsonString: "The '{field}' field must be an json string! Actual: {actual}"
|
|
8
|
-
}
|
|
6
|
+
jsonString: "The '{field}' field must be an json string! Actual: {actual}",
|
|
7
|
+
},
|
|
9
8
|
});
|
|
10
9
|
|
|
11
|
-
v.add(
|
|
10
|
+
v.add('json', function ({schema, messages}, path, context) {
|
|
12
11
|
return {
|
|
13
12
|
source: `
|
|
14
13
|
try {
|
|
15
14
|
JSON.parse(value);
|
|
16
15
|
} catch (e) {
|
|
17
|
-
${this.makeError({
|
|
16
|
+
${this.makeError({type: 'jsonString', actual: 'value', messages})}
|
|
18
17
|
return;
|
|
19
18
|
}
|
|
20
19
|
return value;
|
|
21
|
-
|
|
20
|
+
`,
|
|
22
21
|
};
|
|
23
22
|
});
|
|
24
23
|
|
|
25
|
-
|
|
26
24
|
/* remove empty field or not have validate field */
|
|
27
25
|
function omitData(data, inKeys = []) {
|
|
28
|
-
Object.keys(data).map(function(key, index) {
|
|
26
|
+
Object.keys(data).map(function (key, index) {
|
|
29
27
|
if (inKeys.includes(key)) {
|
|
30
28
|
let value = data[key];
|
|
31
29
|
if (typeof value === 'string') {
|
|
@@ -47,8 +45,8 @@ function omitData(data, inKeys = []) {
|
|
|
47
45
|
return data;
|
|
48
46
|
}
|
|
49
47
|
|
|
50
|
-
export default function(type, rules) {
|
|
51
|
-
return async function(req, res, next) {
|
|
48
|
+
export default function (type, rules) {
|
|
49
|
+
return async function (req, res, next) {
|
|
52
50
|
const reqData = omitData(req[type], Object.keys(rules));
|
|
53
51
|
|
|
54
52
|
/* validate field */
|
|
@@ -58,5 +56,5 @@ export default function(type, rules) {
|
|
|
58
56
|
return next(new ErrorException(VALIDATE, errors));
|
|
59
57
|
}
|
|
60
58
|
return next();
|
|
61
|
-
}
|
|
62
|
-
}
|
|
59
|
+
};
|
|
60
|
+
}
|