jxp 2.11.0 → 2.11.1
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/libs/docs.js +8 -4
- package/libs/jxp.js +22 -50
- package/libs/login.js +20 -22
- package/libs/security.js +5 -10
- package/libs/setup.js +1 -3
- package/package.json +3 -2
package/libs/docs.js
CHANGED
|
@@ -46,29 +46,32 @@ class Docs {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
metaModel(req, res) {
|
|
49
|
+
metaModel(req, res, next) {
|
|
50
50
|
try {
|
|
51
51
|
if (!req.Model) {
|
|
52
52
|
return res.send(404, { status: "error", error: "Model not found" })
|
|
53
53
|
}
|
|
54
54
|
res.send(req.Model.schema.paths);
|
|
55
|
+
next();
|
|
55
56
|
} catch (err) {
|
|
56
57
|
console.error(err);
|
|
57
58
|
return res.send(500, { status: "error", error: err, message: err.toString() });
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
dbDiagram(req, res) {
|
|
62
|
+
dbDiagram(req, res, next) {
|
|
62
63
|
try {
|
|
63
64
|
res.send(this.models);
|
|
65
|
+
next();
|
|
64
66
|
} catch(err) {
|
|
65
67
|
res.send(500, { status: "error", error: err, message: err.toString() });
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
frontPage(req, res) {
|
|
71
|
+
frontPage(req, res, next) {
|
|
70
72
|
try {
|
|
71
73
|
this.renderTemplate(res, "index", {});
|
|
74
|
+
next();
|
|
72
75
|
} catch(err) {
|
|
73
76
|
res.send(500, { status: "error", error: err, message: err.toString() });
|
|
74
77
|
}
|
|
@@ -84,7 +87,7 @@ class Docs {
|
|
|
84
87
|
}
|
|
85
88
|
}
|
|
86
89
|
|
|
87
|
-
model(req, res) {
|
|
90
|
+
model(req, res, next) {
|
|
88
91
|
try {
|
|
89
92
|
const model = this.models[req.params.modelname];
|
|
90
93
|
console.dir(model.schema.opts);
|
|
@@ -92,6 +95,7 @@ class Docs {
|
|
|
92
95
|
fields.sort();
|
|
93
96
|
const perms = model.schema.opts.perms;
|
|
94
97
|
this.renderTemplate(res, "model", { model, fields, perms });
|
|
98
|
+
next();
|
|
95
99
|
} catch(err) {
|
|
96
100
|
res.send(500, { status: "error", error: err, message: err.toString() });
|
|
97
101
|
}
|
package/libs/jxp.js
CHANGED
|
@@ -49,12 +49,13 @@ const middlewareCheckAdmin = (req, res, next) => {
|
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
// Outputs whatever is in res.result as JSON
|
|
52
|
-
const outputJSON = (req, res) => {
|
|
52
|
+
const outputJSON = (req, res, next) => {
|
|
53
53
|
res.send(res.result);
|
|
54
|
+
next();
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
// Outputs whatever is in res.result as CSV
|
|
57
|
-
const outputCSV = (req, res) => {
|
|
58
|
+
const outputCSV = (req, res, next) => {
|
|
58
59
|
const json2csv = require('json2csv').parse;
|
|
59
60
|
const opts = { "flatten": true };
|
|
60
61
|
if (!res.result.data) {
|
|
@@ -71,6 +72,7 @@ const outputCSV = (req, res) => {
|
|
|
71
72
|
});
|
|
72
73
|
const csv = json2csv(data, opts);
|
|
73
74
|
res.end(csv);
|
|
75
|
+
next();
|
|
74
76
|
} catch (err) {
|
|
75
77
|
console.error(err);
|
|
76
78
|
res.send(500, { status: "error", error: err, message: err.toString() });
|
|
@@ -78,7 +80,7 @@ const outputCSV = (req, res) => {
|
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
// Actions (verbs)
|
|
81
|
-
const actionGet = async (req, res
|
|
83
|
+
const actionGet = async (req, res) => {
|
|
82
84
|
const opname = `get ${req.modelname} ${ops++}`;
|
|
83
85
|
console.time(opname);
|
|
84
86
|
try {
|
|
@@ -184,7 +186,6 @@ const actionGet = async (req, res, next) => {
|
|
|
184
186
|
result.data = await q.exec();
|
|
185
187
|
res.result = result;
|
|
186
188
|
if (debug) console.timeEnd(opname);
|
|
187
|
-
next();
|
|
188
189
|
} catch(err) {
|
|
189
190
|
console.error(new Date(), err);
|
|
190
191
|
if (debug) console.timeEnd(opname);
|
|
@@ -213,7 +214,7 @@ const actionGetOne = async (req, res) => {
|
|
|
213
214
|
}
|
|
214
215
|
};
|
|
215
216
|
|
|
216
|
-
const actionPost = async (req, res
|
|
217
|
+
const actionPost = async (req, res) => {
|
|
217
218
|
const opname = `post ${req.modelname} ${ops++}`;
|
|
218
219
|
console.time(opname);
|
|
219
220
|
try {
|
|
@@ -236,7 +237,6 @@ const actionPost = async (req, res, next) => {
|
|
|
236
237
|
data: item
|
|
237
238
|
});
|
|
238
239
|
if (debug) console.timeEnd(opname);
|
|
239
|
-
next();
|
|
240
240
|
} catch (err) {
|
|
241
241
|
console.error(new Date(), err);
|
|
242
242
|
if (debug) console.timeEnd(opname);
|
|
@@ -244,7 +244,7 @@ const actionPost = async (req, res, next) => {
|
|
|
244
244
|
}
|
|
245
245
|
};
|
|
246
246
|
|
|
247
|
-
const actionPut = async (req, res
|
|
247
|
+
const actionPut = async (req, res) => {
|
|
248
248
|
const opname = `put ${req.modelname}/${req.params.item_id} ${ops++}`;
|
|
249
249
|
console.time(opname);
|
|
250
250
|
try {
|
|
@@ -273,7 +273,6 @@ const actionPut = async (req, res, next) => {
|
|
|
273
273
|
data: data
|
|
274
274
|
});
|
|
275
275
|
if (debug) console.timeEnd(opname);
|
|
276
|
-
next();
|
|
277
276
|
} catch (err) {
|
|
278
277
|
console.error(new Date(), err);
|
|
279
278
|
if (debug) console.timeEnd(opname);
|
|
@@ -282,24 +281,10 @@ const actionPut = async (req, res, next) => {
|
|
|
282
281
|
}
|
|
283
282
|
};
|
|
284
283
|
|
|
285
|
-
const actionUpdate = async (req, res
|
|
284
|
+
const actionUpdate = async (req, res) => {
|
|
286
285
|
const opname = `update ${req.modelname}/${req.params.item_id} ${ops++}`;
|
|
287
286
|
console.time(opname);
|
|
288
287
|
try {
|
|
289
|
-
// let item = await req.Model.findById(req.params.item_id);
|
|
290
|
-
// if (!item) {
|
|
291
|
-
// console.error(new Date(), "Document not found");
|
|
292
|
-
// res.send(404, { status: "error", message: "Document not found" });
|
|
293
|
-
// return;
|
|
294
|
-
// }
|
|
295
|
-
// _populateItem(item, datamunging.deserialize(req.body));
|
|
296
|
-
// _versionItem(item);
|
|
297
|
-
// if (res.user) {
|
|
298
|
-
// item.__user = res.user;
|
|
299
|
-
// item._updated_by_id = res.user._id;
|
|
300
|
-
// }
|
|
301
|
-
// const data = await item.save();
|
|
302
|
-
console.log({ body: req.body });
|
|
303
288
|
let body_data = datamunging.deserialize(req.body);
|
|
304
289
|
const data = await req.Model.update({ _id: req.params.item_id }, body_data);
|
|
305
290
|
let silence = req.params._silence;
|
|
@@ -314,7 +299,6 @@ const actionUpdate = async (req, res, next) => {
|
|
|
314
299
|
data
|
|
315
300
|
});
|
|
316
301
|
if (debug) console.timeEnd(opname);
|
|
317
|
-
next();
|
|
318
302
|
} catch (err) {
|
|
319
303
|
console.error(new Date(), err);
|
|
320
304
|
if (debug) console.timeEnd(opname);
|
|
@@ -323,7 +307,7 @@ const actionUpdate = async (req, res, next) => {
|
|
|
323
307
|
}
|
|
324
308
|
};
|
|
325
309
|
|
|
326
|
-
const actionDelete = async (req, res
|
|
310
|
+
const actionDelete = async (req, res) => {
|
|
327
311
|
const permaDelete = req.query._permaDelete;
|
|
328
312
|
const cascade = req.query._cascade;
|
|
329
313
|
let silence = req.query._silence || (req.body && req.body._silence);
|
|
@@ -394,7 +378,6 @@ const actionDelete = async (req, res, next) => {
|
|
|
394
378
|
message: `${req.modelname}/${ req.params.item_id } deleted`
|
|
395
379
|
});
|
|
396
380
|
if (debug) console.timeEnd(opname);
|
|
397
|
-
next();
|
|
398
381
|
} catch(err) {
|
|
399
382
|
console.error(new Date(), err);
|
|
400
383
|
if (debug) console.timeEnd(opname);
|
|
@@ -403,7 +386,7 @@ const actionDelete = async (req, res, next) => {
|
|
|
403
386
|
}
|
|
404
387
|
};
|
|
405
388
|
|
|
406
|
-
const actionCount = async (req, res
|
|
389
|
+
const actionCount = async (req, res) => {
|
|
407
390
|
const opname = `count ${req.modelname} ${ops++}`;
|
|
408
391
|
console.time(opname);
|
|
409
392
|
const parseSearch = function(search) {
|
|
@@ -432,7 +415,6 @@ const actionCount = async (req, res, next) => {
|
|
|
432
415
|
const count = await req.Model.countDocuments(filters).exec();
|
|
433
416
|
res.result = { count };
|
|
434
417
|
if (debug) console.timeEnd(opname);
|
|
435
|
-
next();
|
|
436
418
|
} catch(err) {
|
|
437
419
|
console.error(new Date(), err);
|
|
438
420
|
if (debug) console.timeEnd(opname);
|
|
@@ -453,29 +435,21 @@ const actionCall = async (req, res) => {
|
|
|
453
435
|
}
|
|
454
436
|
};
|
|
455
437
|
|
|
456
|
-
const actionCallItem = (req, res) => {
|
|
457
|
-
|
|
438
|
+
const actionCallItem = async (req, res) => {
|
|
439
|
+
try {
|
|
440
|
+
const item = req.Model.findById(req.params.item_id);
|
|
458
441
|
if (!item) {
|
|
459
442
|
res.send(404, "Document not found for " + req.params.method_name);
|
|
460
443
|
return;
|
|
461
444
|
}
|
|
462
|
-
if (err) {
|
|
463
|
-
console.trace(err);
|
|
464
|
-
res.send(500, { status: "error", message: err.toString() });
|
|
465
|
-
return;
|
|
466
|
-
}
|
|
467
445
|
req.params.__user = res.user || null;
|
|
468
|
-
req.Model[req.params.method_name](item)
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
res.send(500, { status: "error", message: err.toString() });
|
|
476
|
-
}
|
|
477
|
-
);
|
|
478
|
-
});
|
|
446
|
+
const result = await req.Model[req.params.method_name](item);
|
|
447
|
+
res.json(result);
|
|
448
|
+
|
|
449
|
+
} catch(err) {
|
|
450
|
+
console.trace(err);
|
|
451
|
+
res.send(500, { status: "error", message: err.toString() });
|
|
452
|
+
}
|
|
479
453
|
};
|
|
480
454
|
|
|
481
455
|
// Actions (verbs)
|
|
@@ -583,7 +557,7 @@ const actionAggregate = async (req, res) => {
|
|
|
583
557
|
};
|
|
584
558
|
|
|
585
559
|
// Actions (verbs)
|
|
586
|
-
const actionBulkWrite = async (req, res
|
|
560
|
+
const actionBulkWrite = async (req, res) => {
|
|
587
561
|
if (!req.body || !Array.isArray(req.body)) {
|
|
588
562
|
console.error("query missing or not of type array")
|
|
589
563
|
return res.send(500, { status: "error", message: "query missing or not of type array" });
|
|
@@ -598,7 +572,6 @@ const actionBulkWrite = async (req, res, next) => {
|
|
|
598
572
|
res.result = result;
|
|
599
573
|
if (debug) console.timeEnd(opname);
|
|
600
574
|
res.json(result);
|
|
601
|
-
next();
|
|
602
575
|
} catch (err) {
|
|
603
576
|
console.error(new Date(), err);
|
|
604
577
|
if (debug) console.timeEnd(opname);
|
|
@@ -838,8 +811,7 @@ const JXP = function(options) {
|
|
|
838
811
|
}
|
|
839
812
|
},
|
|
840
813
|
post_hooks: {
|
|
841
|
-
login: async (
|
|
842
|
-
next();
|
|
814
|
+
login: async () => {
|
|
843
815
|
},
|
|
844
816
|
},
|
|
845
817
|
cache_timeout: "5 minutes",
|
package/libs/login.js
CHANGED
|
@@ -83,7 +83,7 @@ const oauth = (req, res, next) => { // Log in through an OAuth2 provider, define
|
|
|
83
83
|
res.redirect(uri, next);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
const oauth_callback = async (req, res
|
|
86
|
+
const oauth_callback = async (req, res) => {
|
|
87
87
|
const provider = req.params.provider;
|
|
88
88
|
const provider_config = req.config.oauth[provider];
|
|
89
89
|
const code = req.query.code;
|
|
@@ -126,19 +126,19 @@ const oauth_callback = async (req, res, next) => {
|
|
|
126
126
|
var jwt_token = jwt.sign({ apikey: apikey.apikey, user: user }, req.config.shared_secret, {
|
|
127
127
|
expiresIn: "1m"
|
|
128
128
|
});
|
|
129
|
-
res.redirect(`${req.config.oauth.success_uri}?token=${jwt_token}
|
|
129
|
+
res.redirect(`${req.config.oauth.success_uri}?token=${jwt_token}`);
|
|
130
130
|
} catch (err) {
|
|
131
131
|
console.error(err);
|
|
132
132
|
if (typeof err === 'string' || err instanceof String) {
|
|
133
|
-
res.redirect(`${req.config.oauth.fail_uri}?error=${err}&provider=${provider}
|
|
133
|
+
res.redirect(`${req.config.oauth.fail_uri}?error=${err}&provider=${provider}`);
|
|
134
134
|
} else {
|
|
135
|
-
res.redirect(`${req.config.oauth.fail_uri}?error=unknown&provider=${provider}
|
|
135
|
+
res.redirect(`${req.config.oauth.fail_uri}?error=unknown&provider=${provider}`);
|
|
136
136
|
}
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
const login = async (req, res
|
|
141
|
+
const login = async (req, res) => {
|
|
142
142
|
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
|
143
143
|
let email = req.params.email || req.body.email;
|
|
144
144
|
let password = req.params.password || req.body.password;
|
|
@@ -170,7 +170,6 @@ const login = async (req, res, next) => {
|
|
|
170
170
|
refresh_token_expires: security.tokenExpires(refreshtoken),
|
|
171
171
|
provider: token.provider,
|
|
172
172
|
});
|
|
173
|
-
next();
|
|
174
173
|
} catch (err) {
|
|
175
174
|
res.send(401, { status: "fail", message: "Authentication failed", err });
|
|
176
175
|
console.error(new Date(), `Authentication failed`, ip, err);
|
|
@@ -178,7 +177,7 @@ const login = async (req, res, next) => {
|
|
|
178
177
|
}
|
|
179
178
|
}
|
|
180
179
|
|
|
181
|
-
const getJWT = (req, res) => {
|
|
180
|
+
const getJWT = async (req, res) => {
|
|
182
181
|
var user = null;
|
|
183
182
|
if (!res.user.admin) {
|
|
184
183
|
res.send(403, { status: "fail", message: "Unauthorized" });
|
|
@@ -189,27 +188,26 @@ const getJWT = (req, res) => {
|
|
|
189
188
|
res.send(400, { status: "fail", message: "Email required" });
|
|
190
189
|
return;
|
|
191
190
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
res.send(500, { status: "error", error: err });
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
191
|
+
try {
|
|
192
|
+
const result = await User.findOne({ email: email });
|
|
197
193
|
if (!result || !result._id) {
|
|
198
194
|
res.send(404, { status: "fail", message: "User not found" });
|
|
199
195
|
return;
|
|
200
196
|
}
|
|
201
197
|
user = result;
|
|
202
|
-
|
|
203
|
-
.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
});
|
|
207
|
-
res.send({ email: user.email, token: token });
|
|
208
|
-
}, function () {
|
|
209
|
-
res.send(403, { status: "fail", message: "Unauthorized" });
|
|
198
|
+
try {
|
|
199
|
+
const apikey = await security.generateApiKey(user._id)
|
|
200
|
+
var token = jwt.sign({ apikey: apikey.apikey, email: user.email, id: user._id }, req.config.shared_secret, {
|
|
201
|
+
expiresIn: "2d"
|
|
210
202
|
});
|
|
211
|
-
|
|
212
|
-
|
|
203
|
+
res.send({ email: user.email, token: token });
|
|
204
|
+
} catch (err) {
|
|
205
|
+
res.send(403, { status: "fail", message: "Unauthorized" });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
} catch (err) {
|
|
209
|
+
res.send(500, { status: "error", error: err });
|
|
210
|
+
}
|
|
213
211
|
}
|
|
214
212
|
|
|
215
213
|
const Login = {
|
package/libs/security.js
CHANGED
|
@@ -204,7 +204,7 @@ const revokeRefreshToken = async user_id => {
|
|
|
204
204
|
return true;
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
const refresh = async (req, res
|
|
207
|
+
const refresh = async (req, res) => {
|
|
208
208
|
try {
|
|
209
209
|
if(req.headers.authorization && req.headers.authorization.trim().toLowerCase().indexOf("bearer") === 0) {
|
|
210
210
|
const refresh_token = await RefreshToken.findOne({ refresh_token: bearerAuthData(req) }).exec();
|
|
@@ -221,27 +221,24 @@ const refresh = async (req, res, next) => {
|
|
|
221
221
|
refresh_token: new_refresh_token.refresh_token,
|
|
222
222
|
refresh_token_expires: tokenExpires(new_refresh_token)
|
|
223
223
|
});
|
|
224
|
-
next();
|
|
225
224
|
} else {
|
|
226
225
|
throw("Missing refresh token")
|
|
227
226
|
}
|
|
228
|
-
next();
|
|
229
227
|
} catch (err) {
|
|
230
228
|
console.error(err);
|
|
231
229
|
return fail(res, 403, err);
|
|
232
230
|
}
|
|
233
231
|
}
|
|
234
232
|
|
|
235
|
-
const login = async (req, res
|
|
233
|
+
const login = async (req, res) => {
|
|
236
234
|
try {
|
|
237
235
|
const authenticate_result = await authenticate(req);
|
|
238
236
|
if (!authenticate_result) {
|
|
239
237
|
res.user = null;
|
|
240
238
|
res.groups = [];
|
|
241
|
-
return
|
|
239
|
+
return;
|
|
242
240
|
}
|
|
243
241
|
res = Object.assign(res, authenticate_result);
|
|
244
|
-
next();
|
|
245
242
|
} catch(err) {
|
|
246
243
|
console.error(err);
|
|
247
244
|
return fail(res, 403, err);
|
|
@@ -282,7 +279,7 @@ const authenticate = async req => {
|
|
|
282
279
|
}
|
|
283
280
|
}
|
|
284
281
|
|
|
285
|
-
const auth = async (req, res
|
|
282
|
+
const auth = async (req, res) => {
|
|
286
283
|
// Check against model as to whether we're allowed to edit this model
|
|
287
284
|
if (!req.Model) {
|
|
288
285
|
console.error("Model missing");
|
|
@@ -304,7 +301,6 @@ const auth = async (req, res, next) => {
|
|
|
304
301
|
return fail(res, 500, "Unsupported operation: " + req.method);
|
|
305
302
|
}
|
|
306
303
|
await check_perms(res.user, res.groups, req.Model, method, req.params.item_id);
|
|
307
|
-
next();
|
|
308
304
|
} catch(err) {
|
|
309
305
|
console.error(err);
|
|
310
306
|
return fail(res, 403, { status: "Unauthorized", error: err });
|
|
@@ -312,13 +308,12 @@ const auth = async (req, res, next) => {
|
|
|
312
308
|
};
|
|
313
309
|
|
|
314
310
|
// Bulk auth requires all CRUD permissions
|
|
315
|
-
const bulkAuth = async (req, res,
|
|
311
|
+
const bulkAuth = async (req, res,) => {
|
|
316
312
|
try {
|
|
317
313
|
await check_perms(res.user, res.groups, req.Model, "c");
|
|
318
314
|
await check_perms(res.user, res.groups, req.Model, "r");
|
|
319
315
|
await check_perms(res.user, res.groups, req.Model, "u");
|
|
320
316
|
await check_perms(res.user, res.groups, req.Model, "d");
|
|
321
|
-
next();
|
|
322
317
|
} catch (err) {
|
|
323
318
|
console.error(err);
|
|
324
319
|
return fail(res, 403, { status: "Unauthorized", error: err });
|
package/libs/setup.js
CHANGED
|
@@ -9,14 +9,12 @@ const init = config => {
|
|
|
9
9
|
User = require(path.join(config.model_dir, "user_model"));
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
const checkUserDoesNotExist = async (req, res
|
|
12
|
+
const checkUserDoesNotExist = async (req, res) => {
|
|
13
13
|
try {
|
|
14
14
|
const count = await User.countDocuments();
|
|
15
15
|
if (count) {
|
|
16
|
-
const users = await User.find();
|
|
17
16
|
return res.send(403, { status: "failed", error: "Cannot setup if user exists" });
|
|
18
17
|
}
|
|
19
|
-
return next();
|
|
20
18
|
} catch(err) {
|
|
21
19
|
console.error(err);
|
|
22
20
|
res.send(500, { status: "error", error: err.message });
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jxp",
|
|
3
3
|
"description:": "An opinionated RESTful API library based on Mongoose and Restify. Make an API by just writing Mongoose models.",
|
|
4
|
-
"version": "2.11.
|
|
4
|
+
"version": "2.11.1",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "libs/jxp.js",
|
|
7
7
|
"scripts": {
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"chai": "^4.3.7",
|
|
60
60
|
"chai-http": "^4.3.0",
|
|
61
61
|
"mocha": "^10.1.0",
|
|
62
|
-
"should": "^13.2.3"
|
|
62
|
+
"should": "^13.2.3",
|
|
63
|
+
"moment": "^2.29.4"
|
|
63
64
|
}
|
|
64
65
|
}
|