parsony 1.2.1 → 2.0.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/index.js +0 -1
- package/lib/api/api.js +24 -26
- package/lib/api/gates/endpointValidation.js +76 -119
- package/lib/auth/persistence.js +25 -24
- package/lib/auth/session.js +48 -42
- package/lib/http/errors.js +5 -5
- package/lib/models/models.js +1 -1
- package/package.json +19 -20
package/index.js
CHANGED
package/lib/api/api.js
CHANGED
|
@@ -14,7 +14,7 @@ const {
|
|
|
14
14
|
endpointValidationGateAsync,
|
|
15
15
|
apiKeyGateAsync,
|
|
16
16
|
sessionAuthenticationGateAsync,
|
|
17
|
-
signedRequestGate
|
|
17
|
+
signedRequestGate,
|
|
18
18
|
} = require("./gates");
|
|
19
19
|
|
|
20
20
|
const {
|
|
@@ -26,27 +26,27 @@ const {
|
|
|
26
26
|
PARAMS,
|
|
27
27
|
AUTHENTICATION,
|
|
28
28
|
SESSION_TOKEN,
|
|
29
|
-
API_KEY
|
|
29
|
+
API_KEY,
|
|
30
30
|
},
|
|
31
31
|
REQUEST: { METHOD: REQUEST_METHOD, ARGS, HINT },
|
|
32
|
-
RESPONSE: { API_EXPECTS }
|
|
32
|
+
RESPONSE: { API_EXPECTS },
|
|
33
33
|
} = require("../enums");
|
|
34
34
|
|
|
35
35
|
const HTTP = {
|
|
36
36
|
GET: "get",
|
|
37
37
|
POST: "post",
|
|
38
38
|
PUT: "put",
|
|
39
|
-
DELETE: "delete"
|
|
39
|
+
DELETE: "delete",
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
const ABORT = {
|
|
43
43
|
METHOD: {
|
|
44
44
|
NOT_FOUND: "noMethodFound",
|
|
45
|
-
NOT_SUPPLIED: "noMethodSupplied"
|
|
45
|
+
NOT_SUPPLIED: "noMethodSupplied",
|
|
46
46
|
},
|
|
47
47
|
ARGS: {
|
|
48
|
-
MISSING: "noArgsSupplied"
|
|
49
|
-
}
|
|
48
|
+
MISSING: "noArgsSupplied",
|
|
49
|
+
},
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
let parsony;
|
|
@@ -60,7 +60,7 @@ let parsony;
|
|
|
60
60
|
const combineInterfaceContracts = (master, service) => {
|
|
61
61
|
const contracts = service.interface || [];
|
|
62
62
|
const combined = Object.assign({}, master);
|
|
63
|
-
contracts.forEach(endpoint => {
|
|
63
|
+
contracts.forEach((endpoint) => {
|
|
64
64
|
combined.contracts[endpoint[JSON_API]] = endpoint;
|
|
65
65
|
combined.mappings[endpoint[JSON_API]] = endpoint[JSON_API];
|
|
66
66
|
});
|
|
@@ -79,7 +79,7 @@ const combineInterfaceContracts = (master, service) => {
|
|
|
79
79
|
const bindRESTEndpointsToRoutes = (app, service) => {
|
|
80
80
|
const contracts = service.interface || [];
|
|
81
81
|
|
|
82
|
-
contracts.forEach(contract => {
|
|
82
|
+
contracts.forEach((contract) => {
|
|
83
83
|
const method = contract[INTERFACE_METHOD];
|
|
84
84
|
const url = contract[REST_URL];
|
|
85
85
|
|
|
@@ -124,7 +124,7 @@ const bindRESTEndpointsToRoutes = (app, service) => {
|
|
|
124
124
|
*/
|
|
125
125
|
function _restfulReq(req, res, contract) {
|
|
126
126
|
const method = req.route.path;
|
|
127
|
-
const args = {...req.body, ...req.query};
|
|
127
|
+
const args = { ...req.body, ...req.query };
|
|
128
128
|
_validateThenHandle(req, res, args, method, contract);
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -147,7 +147,7 @@ const bindJsonRpcToPostEndpoint = (app, master, apiEndpoint, debugMode) => {
|
|
|
147
147
|
const api = `/${apiEndpoint}`;
|
|
148
148
|
const {
|
|
149
149
|
METHOD: { NOT_SUPPLIED, NOT_FOUND },
|
|
150
|
-
ARGS: { MISSING }
|
|
150
|
+
ARGS: { MISSING },
|
|
151
151
|
} = ABORT;
|
|
152
152
|
|
|
153
153
|
app.post(api, (req, res) => {
|
|
@@ -178,7 +178,7 @@ const bindJsonRpcToPostEndpoint = (app, master, apiEndpoint, debugMode) => {
|
|
|
178
178
|
function _abortWithError(res, req, type, detail) {
|
|
179
179
|
const {
|
|
180
180
|
METHOD: { NOT_FOUND, NOT_SUPPLIED },
|
|
181
|
-
ARGS: { MISSING }
|
|
181
|
+
ARGS: { MISSING },
|
|
182
182
|
} = ABORT;
|
|
183
183
|
|
|
184
184
|
switch (type) {
|
|
@@ -187,9 +187,9 @@ function _abortWithError(res, req, type, detail) {
|
|
|
187
187
|
res,
|
|
188
188
|
makeStandardError(
|
|
189
189
|
errors.REQUEST.NO_METHOD_FOUND,
|
|
190
|
-
`The requested method: ${detail} was not found
|
|
190
|
+
`The requested method: ${detail} was not found.`,
|
|
191
191
|
),
|
|
192
|
-
req.body
|
|
192
|
+
req.body,
|
|
193
193
|
);
|
|
194
194
|
break;
|
|
195
195
|
|
|
@@ -197,7 +197,7 @@ function _abortWithError(res, req, type, detail) {
|
|
|
197
197
|
sendFailure(
|
|
198
198
|
res,
|
|
199
199
|
makeStandardError(errors.REQUEST.NO_METHOD_SUPPLIED),
|
|
200
|
-
req.body
|
|
200
|
+
req.body,
|
|
201
201
|
);
|
|
202
202
|
break;
|
|
203
203
|
|
|
@@ -240,8 +240,8 @@ function _validateThenHandle(req, res, args, method, contract) {
|
|
|
240
240
|
.then(({ data, sessionObj }) => {
|
|
241
241
|
_handleRequest(contract[HANDLER], sessionObj, data, res, method);
|
|
242
242
|
})
|
|
243
|
-
.catch(err => {
|
|
244
|
-
sendFailure(res, err, req.body,method,parsony.debugMode);
|
|
243
|
+
.catch((err) => {
|
|
244
|
+
sendFailure(res, err, req.body, method, parsony.debugMode);
|
|
245
245
|
});
|
|
246
246
|
}
|
|
247
247
|
|
|
@@ -262,9 +262,10 @@ function _validateThenHandle(req, res, args, method, contract) {
|
|
|
262
262
|
*/
|
|
263
263
|
async function _validateRequest(req, data, contract) {
|
|
264
264
|
let sessionObj;
|
|
265
|
+
|
|
265
266
|
if (isApiKeyRequired(contract)) {
|
|
266
267
|
await apiKeyGateAsync(req);
|
|
267
|
-
await signedRequestGate(req
|
|
268
|
+
await signedRequestGate(req);
|
|
268
269
|
}
|
|
269
270
|
if (isSessionTokenRequired(contract)) {
|
|
270
271
|
sessionObj = await sessionAuthenticationGateAsync(req);
|
|
@@ -272,7 +273,7 @@ async function _validateRequest(req, data, contract) {
|
|
|
272
273
|
await endpointValidationGateAsync(data, contract[PARAMS]);
|
|
273
274
|
return {
|
|
274
275
|
data,
|
|
275
|
-
sessionObj
|
|
276
|
+
sessionObj,
|
|
276
277
|
};
|
|
277
278
|
}
|
|
278
279
|
|
|
@@ -291,10 +292,10 @@ async function _validateRequest(req, data, contract) {
|
|
|
291
292
|
*/
|
|
292
293
|
function _handleRequest(handler, sessionObj, data, res, reqMethod) {
|
|
293
294
|
handler({ ...data, sessionObj })
|
|
294
|
-
.then(results => {
|
|
295
|
+
.then((results) => {
|
|
295
296
|
sendSuccess(res, results, reqMethod);
|
|
296
297
|
})
|
|
297
|
-
.catch(err => {
|
|
298
|
+
.catch((err) => {
|
|
298
299
|
err = err.code
|
|
299
300
|
? err
|
|
300
301
|
: makeStandardError(errors.SERVER_ERROR, err.message);
|
|
@@ -312,8 +313,6 @@ function _sendDebugHint(res, contract) {
|
|
|
312
313
|
sendSuccess(res, { [API_EXPECTS]: contract });
|
|
313
314
|
}
|
|
314
315
|
|
|
315
|
-
|
|
316
|
-
|
|
317
316
|
/**
|
|
318
317
|
* Does the contract require an API Key
|
|
319
318
|
* @param contract
|
|
@@ -336,8 +335,7 @@ function isSessionTokenRequired(contract) {
|
|
|
336
335
|
* Configs setter.
|
|
337
336
|
* @param {object} parsony - Parsony singleton
|
|
338
337
|
*/
|
|
339
|
-
const setParsony = withParsony => (parsony = withParsony);
|
|
340
|
-
|
|
338
|
+
const setParsony = (withParsony) => (parsony = withParsony);
|
|
341
339
|
|
|
342
340
|
module.exports = {
|
|
343
341
|
setParsony,
|
|
@@ -346,5 +344,5 @@ module.exports = {
|
|
|
346
344
|
JSONGate,
|
|
347
345
|
combineInterfaceContracts,
|
|
348
346
|
bindRESTEndpointsToRoutes,
|
|
349
|
-
bindJsonRpcToPostEndpoint
|
|
347
|
+
bindJsonRpcToPostEndpoint,
|
|
350
348
|
};
|
|
@@ -3,24 +3,26 @@
|
|
|
3
3
|
* @module /api/gates/endpointValidation
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
const { isURL, isJSON, validateEmail } = require("../../utils");
|
|
8
|
-
const { makeStandardError } = require(
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const { makeStandardError } = require("../../http");
|
|
8
|
+
const {
|
|
9
|
+
REQUEST: { MALFORMED_VALIDATION: MALFORMED },
|
|
10
|
+
} = require("../../errors/errors.json");
|
|
11
|
+
const {
|
|
12
|
+
INTERFACE: { VALIDATION },
|
|
13
|
+
} = require("../../enums");
|
|
12
14
|
|
|
13
15
|
const ERROR = {
|
|
14
|
-
MISSING_ARG
|
|
15
|
-
MAX_LENGTH
|
|
16
|
-
MIN_LENGTH
|
|
17
|
-
INVALID_EMAIL
|
|
18
|
-
ARG_MISMATCH
|
|
19
|
-
OUT_OF_RANGE
|
|
20
|
-
NOT_URL
|
|
21
|
-
NOT_JSON
|
|
22
|
-
NOT_ARRAY
|
|
23
|
-
REGEX
|
|
16
|
+
MISSING_ARG: "missing_arg",
|
|
17
|
+
MAX_LENGTH: "max_length_exceeded",
|
|
18
|
+
MIN_LENGTH: "min_length_not_met",
|
|
19
|
+
INVALID_EMAIL: "invalid_email",
|
|
20
|
+
ARG_MISMATCH: "argument_type_mismatch",
|
|
21
|
+
OUT_OF_RANGE: "argument_out_of_range",
|
|
22
|
+
NOT_URL: "argument_not_url",
|
|
23
|
+
NOT_JSON: "argument_not_json",
|
|
24
|
+
NOT_ARRAY: "argument_not_an_array",
|
|
25
|
+
REGEX: "argument_invalid_pattern",
|
|
24
26
|
};
|
|
25
27
|
|
|
26
28
|
/**
|
|
@@ -60,20 +62,19 @@ const ERROR = {
|
|
|
60
62
|
*/
|
|
61
63
|
const endpointValidationGateAsync = async (data, params) => {
|
|
62
64
|
const errors = [];
|
|
63
|
-
|
|
64
|
-
params.forEach( def => {
|
|
65
|
+
params.forEach((def) => {
|
|
65
66
|
const rules = Object.keys(def[VALIDATION]);
|
|
66
67
|
const param = def.param;
|
|
67
68
|
|
|
68
69
|
if (data.hasOwnProperty(param)) {
|
|
69
|
-
rules.forEach(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
} else if(def.required) {
|
|
70
|
+
rules.forEach((rule) => {
|
|
71
|
+
const arg = data[param];
|
|
72
|
+
const error = _validate(arg, def, rule);
|
|
73
|
+
if (error) {
|
|
74
|
+
errors.push(error);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
} else if (def.required) {
|
|
77
78
|
errors.push(_missingArgError(param));
|
|
78
79
|
}
|
|
79
80
|
});
|
|
@@ -81,13 +82,10 @@ const endpointValidationGateAsync = async (data, params) => {
|
|
|
81
82
|
if (errors.length === 0) {
|
|
82
83
|
return data;
|
|
83
84
|
} else {
|
|
84
|
-
throw makeStandardError(
|
|
85
|
-
MALFORMED,
|
|
86
|
-
errors);
|
|
85
|
+
throw makeStandardError(MALFORMED, errors);
|
|
87
86
|
}
|
|
88
87
|
};
|
|
89
88
|
|
|
90
|
-
|
|
91
89
|
/**
|
|
92
90
|
* Compares passed arg for param to validation rule
|
|
93
91
|
*
|
|
@@ -107,7 +105,7 @@ function _validate(arg, def, type) {
|
|
|
107
105
|
const error = validator.error;
|
|
108
106
|
|
|
109
107
|
if (!test(arg, comp)) {
|
|
110
|
-
return error(arg, param, comp)
|
|
108
|
+
return error(arg, param, comp);
|
|
111
109
|
} else {
|
|
112
110
|
return null;
|
|
113
111
|
}
|
|
@@ -116,48 +114,48 @@ function _validate(arg, def, type) {
|
|
|
116
114
|
const VALIDATIONS_MAP = {
|
|
117
115
|
max_length: {
|
|
118
116
|
test: _maxLength,
|
|
119
|
-
error: _maxLengthError
|
|
117
|
+
error: _maxLengthError,
|
|
120
118
|
},
|
|
121
119
|
min_length: {
|
|
122
120
|
test: _minLength,
|
|
123
|
-
error: _minLengthError
|
|
121
|
+
error: _minLengthError,
|
|
124
122
|
},
|
|
125
123
|
valid_email: {
|
|
126
124
|
test: _isEmail,
|
|
127
|
-
error: _emailError
|
|
125
|
+
error: _emailError,
|
|
128
126
|
},
|
|
129
127
|
is_type: {
|
|
130
128
|
test: _isType,
|
|
131
|
-
error: _typeError
|
|
129
|
+
error: _typeError,
|
|
132
130
|
},
|
|
133
131
|
in_set: {
|
|
134
132
|
test: _inSet,
|
|
135
|
-
error: _inSetError
|
|
133
|
+
error: _inSetError,
|
|
136
134
|
},
|
|
137
135
|
is_url: {
|
|
138
136
|
test: _isUrl,
|
|
139
|
-
error: _isUrlError
|
|
137
|
+
error: _isUrlError,
|
|
140
138
|
},
|
|
141
139
|
is_json: {
|
|
142
140
|
test: _isJSON,
|
|
143
|
-
error: _isJsonError
|
|
141
|
+
error: _isJsonError,
|
|
144
142
|
},
|
|
145
143
|
is_array: {
|
|
146
144
|
test: _isArray,
|
|
147
|
-
error: _isArrayError
|
|
145
|
+
error: _isArrayError,
|
|
148
146
|
},
|
|
149
147
|
regex: {
|
|
150
|
-
test
|
|
151
|
-
error: _isRegexError
|
|
152
|
-
}
|
|
148
|
+
test: _regexTest,
|
|
149
|
+
error: _isRegexError,
|
|
150
|
+
},
|
|
153
151
|
};
|
|
154
152
|
|
|
155
153
|
function _maxLength(arg, comp) {
|
|
156
|
-
return arg.split(
|
|
154
|
+
return arg.split("").length <= comp;
|
|
157
155
|
}
|
|
158
156
|
|
|
159
157
|
function _minLength(arg, comp) {
|
|
160
|
-
return arg.split(
|
|
158
|
+
return arg.split("").length >= comp;
|
|
161
159
|
}
|
|
162
160
|
|
|
163
161
|
function _isEmail(arg) {
|
|
@@ -165,16 +163,15 @@ function _isEmail(arg) {
|
|
|
165
163
|
}
|
|
166
164
|
|
|
167
165
|
function _isType(arg, comp) {
|
|
168
|
-
if (comp ===
|
|
166
|
+
if (comp === "date") {
|
|
169
167
|
return Date.parse(arg);
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
168
|
+
} else {
|
|
172
169
|
return typeof arg === comp;
|
|
173
170
|
}
|
|
174
171
|
}
|
|
175
172
|
|
|
176
173
|
function _inSet(arg, comp) {
|
|
177
|
-
return comp.indexOf(arg) > -1
|
|
174
|
+
return comp.indexOf(arg) > -1;
|
|
178
175
|
}
|
|
179
176
|
|
|
180
177
|
function _isUrl(arg) {
|
|
@@ -182,121 +179,81 @@ function _isUrl(arg) {
|
|
|
182
179
|
}
|
|
183
180
|
|
|
184
181
|
function _isJSON(arg) {
|
|
185
|
-
return isJSON(arg)
|
|
182
|
+
return isJSON(arg);
|
|
186
183
|
}
|
|
187
184
|
|
|
188
185
|
function _isArray(arg) {
|
|
189
|
-
return Array.isArray(arg)
|
|
186
|
+
return Array.isArray(arg);
|
|
190
187
|
}
|
|
191
188
|
|
|
192
|
-
function _regexTest(arg, comp){
|
|
189
|
+
function _regexTest(arg, comp) {
|
|
193
190
|
const regex = new RegExp(comp);
|
|
194
191
|
return regex.test(arg);
|
|
195
192
|
}
|
|
196
193
|
|
|
197
194
|
function _missingArgError(param) {
|
|
198
|
-
return _validationError(
|
|
199
|
-
ERROR.MISSING_ARG,
|
|
200
|
-
param,
|
|
201
|
-
null
|
|
202
|
-
);
|
|
195
|
+
return _validationError(ERROR.MISSING_ARG, param, null);
|
|
203
196
|
}
|
|
204
197
|
|
|
205
198
|
function _maxLengthError(arg, def, required) {
|
|
206
|
-
return _validationError(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
max: required,
|
|
211
|
-
sent: arg.split('').length
|
|
212
|
-
}
|
|
213
|
-
)
|
|
199
|
+
return _validationError(ERROR.MAX_LENGTH, def, {
|
|
200
|
+
max: required,
|
|
201
|
+
sent: arg.split("").length,
|
|
202
|
+
});
|
|
214
203
|
}
|
|
215
204
|
|
|
216
205
|
function _minLengthError(arg, def, required) {
|
|
217
|
-
return _validationError(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
min: required,
|
|
222
|
-
sent: arg.split('').length
|
|
223
|
-
}
|
|
224
|
-
)
|
|
206
|
+
return _validationError(ERROR.MIN_LENGTH, def, {
|
|
207
|
+
min: required,
|
|
208
|
+
sent: arg.split("").length,
|
|
209
|
+
});
|
|
225
210
|
}
|
|
226
211
|
|
|
227
212
|
function _emailError(arg, def) {
|
|
228
|
-
return _validationError(
|
|
229
|
-
ERROR.INVALID_EMAIL,
|
|
230
|
-
def,
|
|
231
|
-
arg
|
|
232
|
-
)
|
|
213
|
+
return _validationError(ERROR.INVALID_EMAIL, def, arg);
|
|
233
214
|
}
|
|
234
215
|
|
|
235
216
|
function _typeError(arg, def, required) {
|
|
236
|
-
return _validationError(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
expected_type: required,
|
|
241
|
-
provided_type: typeof arg
|
|
242
|
-
}
|
|
243
|
-
)
|
|
217
|
+
return _validationError(ERROR.ARG_MISMATCH, def, {
|
|
218
|
+
expected_type: required,
|
|
219
|
+
provided_type: typeof arg,
|
|
220
|
+
});
|
|
244
221
|
}
|
|
245
222
|
|
|
246
223
|
function _inSetError(arg, def, required) {
|
|
247
|
-
return _validationError(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
acceptable_set: required,
|
|
252
|
-
sent: arg
|
|
253
|
-
}
|
|
254
|
-
)
|
|
224
|
+
return _validationError(ERROR.OUT_OF_RANGE, def, {
|
|
225
|
+
acceptable_set: required,
|
|
226
|
+
sent: arg,
|
|
227
|
+
});
|
|
255
228
|
}
|
|
256
229
|
|
|
257
230
|
function _isUrlError(arg, def) {
|
|
258
|
-
return _validationError(
|
|
259
|
-
ERROR.NOT_URL,
|
|
260
|
-
def,
|
|
261
|
-
arg
|
|
262
|
-
)
|
|
231
|
+
return _validationError(ERROR.NOT_URL, def, arg);
|
|
263
232
|
}
|
|
264
233
|
|
|
265
234
|
function _isJsonError(arg, def) {
|
|
266
|
-
return _validationError(
|
|
267
|
-
ERROR.NOT_JSON,
|
|
268
|
-
def,
|
|
269
|
-
arg
|
|
270
|
-
)
|
|
235
|
+
return _validationError(ERROR.NOT_JSON, def, arg);
|
|
271
236
|
}
|
|
272
237
|
|
|
273
238
|
function _isArrayError(arg, def) {
|
|
274
|
-
return _validationError(
|
|
275
|
-
ERROR.NOT_ARRAY,
|
|
276
|
-
def,
|
|
277
|
-
arg
|
|
278
|
-
)
|
|
239
|
+
return _validationError(ERROR.NOT_ARRAY, def, arg);
|
|
279
240
|
}
|
|
280
241
|
|
|
281
242
|
function _isRegexError(arg, def, required) {
|
|
282
|
-
return _validationError(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
expected_pattern: required,
|
|
287
|
-
provided: arg
|
|
288
|
-
}
|
|
289
|
-
)
|
|
243
|
+
return _validationError(ERROR.REGEX, def, {
|
|
244
|
+
expected_pattern: required,
|
|
245
|
+
provided: arg,
|
|
246
|
+
});
|
|
290
247
|
}
|
|
291
248
|
|
|
292
249
|
function _validationError(code, param, opt) {
|
|
293
250
|
return {
|
|
294
251
|
code,
|
|
295
252
|
param,
|
|
296
|
-
opt_desc: opt
|
|
297
|
-
}
|
|
253
|
+
opt_desc: opt,
|
|
254
|
+
};
|
|
298
255
|
}
|
|
299
256
|
|
|
300
257
|
module.exports = {
|
|
301
|
-
endpointValidationGateAsync
|
|
302
|
-
};
|
|
258
|
+
endpointValidationGateAsync,
|
|
259
|
+
};
|
package/lib/auth/persistence.js
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
* @module auth/persistence
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
const cache = require("../cache").getCache();
|
|
8
|
-
const models
|
|
7
|
+
const models = require("../models").getModels();
|
|
9
8
|
const cachedAPIKeyPrefix = "APIKey:";
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -14,7 +13,7 @@ const cachedAPIKeyPrefix = "APIKey:";
|
|
|
14
13
|
* @param secret
|
|
15
14
|
* @return {Promise.<void>}
|
|
16
15
|
*/
|
|
17
|
-
const cacheApiKeyPair
|
|
16
|
+
const cacheApiKeyPair = async (apiKey, secret) => {
|
|
18
17
|
const cacheAPIKey = cachedAPIKeyPrefix + apiKey;
|
|
19
18
|
await cache.set(cacheAPIKey, secret);
|
|
20
19
|
};
|
|
@@ -24,7 +23,7 @@ const cacheApiKeyPair = async (apiKey, secret) =>{
|
|
|
24
23
|
* @param apiKey
|
|
25
24
|
* @return {Promise.<string>}
|
|
26
25
|
*/
|
|
27
|
-
const
|
|
26
|
+
const cachedApiKeyPair = async (apiKey) => {
|
|
28
27
|
const cacheAPIKey = cachedAPIKeyPrefix + apiKey;
|
|
29
28
|
return await cache.get(cacheAPIKey);
|
|
30
29
|
};
|
|
@@ -36,19 +35,19 @@ const cachedApiKeyPair = async (apiKey) => {
|
|
|
36
35
|
*/
|
|
37
36
|
const dbApiKeyPair = async (apiKey) => {
|
|
38
37
|
const { ApiKey } = models;
|
|
39
|
-
const keyPass = await ApiKey.
|
|
38
|
+
const keyPass = await ApiKey.findOne({
|
|
40
39
|
where: {
|
|
41
40
|
key: apiKey,
|
|
42
|
-
enabled:true,
|
|
43
|
-
}
|
|
41
|
+
enabled: true,
|
|
42
|
+
},
|
|
44
43
|
});
|
|
45
|
-
if(keyPass){
|
|
44
|
+
if (keyPass) {
|
|
46
45
|
return {
|
|
47
46
|
key: keyPass.key,
|
|
48
|
-
secret: keyPass.secret
|
|
47
|
+
secret: keyPass.secret,
|
|
49
48
|
};
|
|
50
|
-
} else{
|
|
51
|
-
return false
|
|
49
|
+
} else {
|
|
50
|
+
return false;
|
|
52
51
|
}
|
|
53
52
|
};
|
|
54
53
|
|
|
@@ -57,11 +56,11 @@ const dbApiKeyPair = async (apiKey) => {
|
|
|
57
56
|
* @param apiKey
|
|
58
57
|
* @return {Promise.<void>}
|
|
59
58
|
*/
|
|
60
|
-
const dbDeleteKey = async apiKey => {
|
|
59
|
+
const dbDeleteKey = async (apiKey) => {
|
|
61
60
|
await models.ApiKey.destroy({
|
|
62
61
|
where: {
|
|
63
|
-
key: apiKey
|
|
64
|
-
}
|
|
62
|
+
key: apiKey,
|
|
63
|
+
},
|
|
65
64
|
});
|
|
66
65
|
};
|
|
67
66
|
|
|
@@ -70,9 +69,9 @@ const dbDeleteKey = async apiKey => {
|
|
|
70
69
|
* @param apiKey
|
|
71
70
|
* @return {Promise.<void>}
|
|
72
71
|
*/
|
|
73
|
-
const unsetCachedApiKey = async apiKey => {
|
|
72
|
+
const unsetCachedApiKey = async (apiKey) => {
|
|
74
73
|
const cached = cachedAPIKeyPrefix + apiKey;
|
|
75
|
-
await cache.del(cached)
|
|
74
|
+
await cache.del(cached);
|
|
76
75
|
};
|
|
77
76
|
|
|
78
77
|
/**
|
|
@@ -82,21 +81,23 @@ const unsetCachedApiKey = async apiKey => {
|
|
|
82
81
|
* @return {Promise.<void>}
|
|
83
82
|
*/
|
|
84
83
|
const dbToggleKeyEnabled = async (apiKey, enabled) => {
|
|
85
|
-
await models.ApiKey.update(
|
|
86
|
-
|
|
84
|
+
await models.ApiKey.update(
|
|
85
|
+
{
|
|
86
|
+
enabled: enabled,
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
89
|
where: {
|
|
90
|
-
key: apiKey
|
|
91
|
-
}
|
|
92
|
-
}
|
|
90
|
+
key: apiKey,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
);
|
|
93
94
|
};
|
|
94
95
|
|
|
95
|
-
module.exports ={
|
|
96
|
+
module.exports = {
|
|
96
97
|
cacheApiKeyPair,
|
|
97
98
|
cachedApiKeyPair,
|
|
98
99
|
dbApiKeyPair,
|
|
99
100
|
dbDeleteKey,
|
|
100
101
|
unsetCachedApiKey,
|
|
101
|
-
dbToggleKeyEnabled
|
|
102
|
-
};
|
|
102
|
+
dbToggleKeyEnabled,
|
|
103
|
+
};
|
package/lib/auth/session.js
CHANGED
|
@@ -2,21 +2,19 @@
|
|
|
2
2
|
* Auth Module
|
|
3
3
|
* @module /auth/session
|
|
4
4
|
*/
|
|
5
|
-
const crypto = require(
|
|
5
|
+
const crypto = require("crypto");
|
|
6
6
|
const cache = require("../cache").getCache();
|
|
7
7
|
const { randomString } = require("../utils");
|
|
8
8
|
const { makeStandardError } = require("../http");
|
|
9
9
|
const {
|
|
10
10
|
INVALID_CREDENTIALS,
|
|
11
11
|
SERVER_ERROR,
|
|
12
|
-
SESSION
|
|
12
|
+
SESSION,
|
|
13
13
|
} = require("../errors/errors.json");
|
|
14
14
|
const models = require("../models").getModels();
|
|
15
15
|
|
|
16
16
|
const cachePrefix = "sessionToken:";
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
18
|
/**
|
|
21
19
|
* Checks provided credentials. Throws HTTP Error Obj if not, otherwise
|
|
22
20
|
* returns null;
|
|
@@ -26,14 +24,18 @@ const cachePrefix = "sessionToken:";
|
|
|
26
24
|
*/
|
|
27
25
|
const checkCredentials = async (username, password) => {
|
|
28
26
|
const { User } = models;
|
|
29
|
-
const user = await User.
|
|
27
|
+
const user = await User.findOne({
|
|
30
28
|
where: { username },
|
|
31
|
-
include: [models.UserAuth]
|
|
29
|
+
include: [models.UserAuth],
|
|
32
30
|
});
|
|
33
31
|
if (user) {
|
|
34
32
|
let equality = null;
|
|
35
33
|
try {
|
|
36
|
-
equality = _hashEquality(
|
|
34
|
+
equality = _hashEquality(
|
|
35
|
+
password,
|
|
36
|
+
user.UserAuth.passwordHash,
|
|
37
|
+
user.UserAuth.salt,
|
|
38
|
+
);
|
|
37
39
|
} catch (err) {
|
|
38
40
|
throw makeStandardError(SERVER_ERROR, err.message);
|
|
39
41
|
}
|
|
@@ -47,14 +49,14 @@ const checkCredentials = async (username, password) => {
|
|
|
47
49
|
}
|
|
48
50
|
};
|
|
49
51
|
|
|
50
|
-
function _hashEquality(value, hash, salt){
|
|
51
|
-
return _saltedHash(value,salt) === hash;
|
|
52
|
+
function _hashEquality(value, hash, salt) {
|
|
53
|
+
return _saltedHash(value, salt) === hash;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
function _saltedHash(string, salt){
|
|
55
|
-
const hash = crypto.createHmac(
|
|
56
|
+
function _saltedHash(string, salt) {
|
|
57
|
+
const hash = crypto.createHmac("sha256", salt);
|
|
56
58
|
hash.update(string);
|
|
57
|
-
return hash.digest(
|
|
59
|
+
return hash.digest("hex");
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
/**
|
|
@@ -63,7 +65,7 @@ function _saltedHash(string, salt){
|
|
|
63
65
|
* @param sessionToken
|
|
64
66
|
* @return {Promise.<object>}
|
|
65
67
|
*/
|
|
66
|
-
const getSession = async sessionToken => {
|
|
68
|
+
const getSession = async (sessionToken) => {
|
|
67
69
|
const cachedSession = await _cacheHasSession(sessionToken);
|
|
68
70
|
if (cachedSession) {
|
|
69
71
|
return cachedSession;
|
|
@@ -73,7 +75,7 @@ const getSession = async sessionToken => {
|
|
|
73
75
|
await _cacheSession(
|
|
74
76
|
dbSession.UserId,
|
|
75
77
|
dbSession.sessionToken,
|
|
76
|
-
dbSession.sessionStart
|
|
78
|
+
dbSession.sessionStart,
|
|
77
79
|
);
|
|
78
80
|
await _extendSessionInCache(dbSession.sessionToken, dbSession);
|
|
79
81
|
return dbSession;
|
|
@@ -87,14 +89,14 @@ const getSession = async sessionToken => {
|
|
|
87
89
|
* @param userId
|
|
88
90
|
* @return {Promise.<*>}
|
|
89
91
|
*/
|
|
90
|
-
const createSession = async userId => {
|
|
92
|
+
const createSession = async (userId) => {
|
|
91
93
|
const sessionToken = randomString(40);
|
|
92
94
|
const dbSession = await _storeSessionInDB(userId, sessionToken);
|
|
93
95
|
if (dbSession) {
|
|
94
96
|
const cachedSession = await _cacheSession(
|
|
95
97
|
userId,
|
|
96
98
|
dbSession.sessionToken,
|
|
97
|
-
dbSession.sessionStart
|
|
99
|
+
dbSession.sessionStart,
|
|
98
100
|
);
|
|
99
101
|
return cachedSession || dbSession;
|
|
100
102
|
} else {
|
|
@@ -108,9 +110,9 @@ const createSession = async userId => {
|
|
|
108
110
|
* @param options
|
|
109
111
|
* @return {Promise.<void>}
|
|
110
112
|
*/
|
|
111
|
-
const extendSession = async (sessionToken, options) =>{
|
|
113
|
+
const extendSession = async (sessionToken, options) => {
|
|
112
114
|
await _extendSessionInCache(sessionToken, options);
|
|
113
|
-
await _extendSessionInDB(sessionToken,options);
|
|
115
|
+
await _extendSessionInDB(sessionToken, options);
|
|
114
116
|
};
|
|
115
117
|
|
|
116
118
|
/**
|
|
@@ -118,29 +120,32 @@ const extendSession = async (sessionToken, options) =>{
|
|
|
118
120
|
* @param sessionToken
|
|
119
121
|
* @return {Promise.<null>}
|
|
120
122
|
*/
|
|
121
|
-
const destroySession = async sessionToken => {
|
|
123
|
+
const destroySession = async (sessionToken) => {
|
|
122
124
|
await Promise.all([
|
|
123
125
|
_deleteSessionFromDB(sessionToken),
|
|
124
|
-
_flushSessionFromCache(sessionToken)
|
|
126
|
+
_flushSessionFromCache(sessionToken),
|
|
125
127
|
]);
|
|
126
128
|
return null;
|
|
127
129
|
};
|
|
128
130
|
|
|
129
|
-
|
|
130
131
|
async function _dbHasSession(sessionToken) {
|
|
131
132
|
const { User, UserSessions } = models;
|
|
132
|
-
const session = await UserSessions.
|
|
133
|
+
const session = await UserSessions.findOne({
|
|
133
134
|
where: {
|
|
134
|
-
sessionToken
|
|
135
|
+
sessionToken,
|
|
135
136
|
},
|
|
136
|
-
include: [User]
|
|
137
|
+
include: [User],
|
|
137
138
|
});
|
|
138
139
|
return session
|
|
139
|
-
? Object.assign(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
? Object.assign(
|
|
141
|
+
{},
|
|
142
|
+
{
|
|
143
|
+
userId: session.UserId,
|
|
144
|
+
sessionToken: session.sessionToken,
|
|
145
|
+
sessionStart: session.sessionStart,
|
|
146
|
+
},
|
|
147
|
+
JSON.parse(session.options),
|
|
148
|
+
)
|
|
144
149
|
: false;
|
|
145
150
|
}
|
|
146
151
|
|
|
@@ -155,7 +160,7 @@ async function _cacheSession(userId, sessionToken, sessionStart) {
|
|
|
155
160
|
const sessionObj = {
|
|
156
161
|
userId,
|
|
157
162
|
sessionStart,
|
|
158
|
-
sessionToken
|
|
163
|
+
sessionToken,
|
|
159
164
|
};
|
|
160
165
|
await cache.set(cacheToken, JSON.stringify(sessionObj));
|
|
161
166
|
}
|
|
@@ -163,25 +168,26 @@ async function _cacheSession(userId, sessionToken, sessionStart) {
|
|
|
163
168
|
async function _extendSessionInCache(sessionToken, options) {
|
|
164
169
|
const cacheToken = cachePrefix + sessionToken;
|
|
165
170
|
const session = await cache.get(cacheToken);
|
|
166
|
-
if(session){
|
|
171
|
+
if (session) {
|
|
167
172
|
const sessionObj = JSON.parse(session);
|
|
168
173
|
const extendedSessionObj = Object.assign({}, sessionObj, options);
|
|
169
174
|
await cache.set(cacheToken, JSON.stringify(extendedSessionObj));
|
|
170
175
|
}
|
|
171
176
|
}
|
|
172
177
|
|
|
173
|
-
async function _extendSessionInDB(
|
|
178
|
+
async function _extendSessionInDB(sessionToken, options) {
|
|
174
179
|
const { UserSessions } = models;
|
|
175
180
|
try {
|
|
176
181
|
await UserSessions.update(
|
|
177
182
|
{
|
|
178
|
-
options:JSON.stringify(options)
|
|
183
|
+
options: JSON.stringify(options),
|
|
179
184
|
},
|
|
180
185
|
{
|
|
181
186
|
where: {
|
|
182
|
-
sessionToken
|
|
183
|
-
}
|
|
184
|
-
}
|
|
187
|
+
sessionToken,
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
);
|
|
185
191
|
} catch (err) {
|
|
186
192
|
throw makeStandardError(SESSION.DB_WRITE_ERROR);
|
|
187
193
|
}
|
|
@@ -193,12 +199,12 @@ async function _storeSessionInDB(userId, sessionToken) {
|
|
|
193
199
|
const session = await UserSessions.create({
|
|
194
200
|
UserId: userId,
|
|
195
201
|
sessionToken,
|
|
196
|
-
sessionStart: new Date()
|
|
202
|
+
sessionStart: new Date(),
|
|
197
203
|
});
|
|
198
204
|
return {
|
|
199
205
|
userId,
|
|
200
206
|
sessionToken,
|
|
201
|
-
sessionStart: session.sessionStart
|
|
207
|
+
sessionStart: session.sessionStart,
|
|
202
208
|
};
|
|
203
209
|
} catch (err) {
|
|
204
210
|
throw makeStandardError(SESSION.DB_WRITE_ERROR);
|
|
@@ -216,10 +222,10 @@ async function _flushSessionFromCache(sessionToken) {
|
|
|
216
222
|
|
|
217
223
|
async function _deleteSessionFromDB(sessionToken) {
|
|
218
224
|
const { UserSessions } = models;
|
|
219
|
-
const session = await UserSessions.
|
|
225
|
+
const session = await UserSessions.findOne({
|
|
220
226
|
where: {
|
|
221
|
-
sessionToken
|
|
222
|
-
}
|
|
227
|
+
sessionToken,
|
|
228
|
+
},
|
|
223
229
|
});
|
|
224
230
|
if (session) await session.destroy();
|
|
225
231
|
}
|
|
@@ -228,5 +234,5 @@ module.exports = {
|
|
|
228
234
|
getSession,
|
|
229
235
|
createSession,
|
|
230
236
|
destroySession,
|
|
231
|
-
extendSession
|
|
237
|
+
extendSession,
|
|
232
238
|
};
|
package/lib/http/errors.js
CHANGED
|
@@ -27,12 +27,12 @@ const makeError = (errCode, type, errMsg, detail) => {
|
|
|
27
27
|
* @param {Error} err
|
|
28
28
|
* @return {Error}
|
|
29
29
|
*/
|
|
30
|
-
const modelError = err => {
|
|
30
|
+
const modelError = (err) => {
|
|
31
31
|
return makeError(
|
|
32
32
|
MODEL_ERROR.code,
|
|
33
33
|
MODEL_ERROR.type,
|
|
34
34
|
MODEL_ERROR.msg,
|
|
35
|
-
err.message
|
|
35
|
+
err.message,
|
|
36
36
|
);
|
|
37
37
|
};
|
|
38
38
|
|
|
@@ -49,19 +49,19 @@ const modelError = err => {
|
|
|
49
49
|
* "msg": "An error has occurred."
|
|
50
50
|
* }
|
|
51
51
|
*/
|
|
52
|
-
const makeStandardError = (errorObj, optionalDesc) => {
|
|
52
|
+
const makeStandardError = (errorObj, optionalDesc = "") => {
|
|
53
53
|
const newErrorObj = Object.assign({}, SERVER_ERROR, errorObj);
|
|
54
54
|
newErrorObj.detail = optionalDesc || newErrorObj.detail;
|
|
55
55
|
return makeError(
|
|
56
56
|
newErrorObj.code,
|
|
57
57
|
newErrorObj.type,
|
|
58
58
|
newErrorObj.msg,
|
|
59
|
-
newErrorObj.detail
|
|
59
|
+
newErrorObj.detail,
|
|
60
60
|
);
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
module.exports = {
|
|
64
64
|
makeError,
|
|
65
65
|
modelError,
|
|
66
|
-
makeStandardError
|
|
66
|
+
makeStandardError,
|
|
67
67
|
};
|
package/lib/models/models.js
CHANGED
|
@@ -39,7 +39,7 @@ function _createAndAttachModels() {
|
|
|
39
39
|
return file.indexOf(".") !== 0;
|
|
40
40
|
})
|
|
41
41
|
.forEach(file => {
|
|
42
|
-
const model =
|
|
42
|
+
const model = require(join(modelsDirectory, file))(sequelize, Sequelize.DataTypes);
|
|
43
43
|
models[model.name] = model;
|
|
44
44
|
});
|
|
45
45
|
Object.keys(models).forEach(modelName => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "parsony",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "API Engine for Parsony Framework.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"JSON-RPC, API, Rapid Development"
|
|
@@ -11,30 +11,29 @@
|
|
|
11
11
|
},
|
|
12
12
|
"author": {
|
|
13
13
|
"name": "Eric Phelan",
|
|
14
|
-
"email": "
|
|
14
|
+
"email": "epcphelan@gmail.com",
|
|
15
15
|
"url": "http://ericphelan.com"
|
|
16
16
|
},
|
|
17
17
|
"license": "MIT",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"body-parser": "^
|
|
20
|
-
"chalk": "^
|
|
19
|
+
"body-parser": "^2.0.0",
|
|
20
|
+
"chalk": "^4.1.2",
|
|
21
21
|
"clear": "^0.1.0",
|
|
22
|
-
"compression": "^1.
|
|
22
|
+
"compression": "^1.8.0",
|
|
23
23
|
"continuation-local-storage": "^3.1.6",
|
|
24
|
-
"express": "^4.
|
|
25
|
-
"express-winston": "^2.
|
|
26
|
-
"figlet": "^1.
|
|
27
|
-
"handlebars": "^4.
|
|
28
|
-
"mysql": "^2.
|
|
29
|
-
"mysql2": "^
|
|
30
|
-
"node-cron": "^
|
|
31
|
-
"nodemailer": "^
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"sequelize": "^
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"winston": "^2.4.3"
|
|
24
|
+
"express": "^4.21.2",
|
|
25
|
+
"express-winston": "^4.2.0",
|
|
26
|
+
"figlet": "^1.8.0",
|
|
27
|
+
"handlebars": "^4.7.8",
|
|
28
|
+
"mysql": "^2.18.1",
|
|
29
|
+
"mysql2": "^3.12.0",
|
|
30
|
+
"node-cron": "^3.0.3",
|
|
31
|
+
"nodemailer": "^6.10.0",
|
|
32
|
+
"prettier": "^3.5.2",
|
|
33
|
+
"redis": "^3.1.2",
|
|
34
|
+
"sequelize": "^6.37.5",
|
|
35
|
+
"superagent": "^10.1.1",
|
|
36
|
+
"twilio": "^5.4.5",
|
|
37
|
+
"winston": "^3.17.0"
|
|
39
38
|
}
|
|
40
39
|
}
|