not-node 5.1.44 → 6.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/.eslintrc.json +32 -38
- package/index.js +6 -0
- package/package.json +12 -11
- package/src/app.js +2 -2
- package/src/auth/index.js +0 -2
- package/src/auth/routes.js +25 -61
- package/src/auth/rules.js +8 -7
- package/src/common.js +19 -0
- package/src/identity/exceptions.js +17 -0
- package/src/identity/identity.js +61 -0
- package/src/identity/index.js +35 -0
- package/src/identity/providers/session.js +137 -0
- package/src/identity/providers/token.js +255 -0
- package/src/manifest/result.filter.js +268 -0
- package/src/manifest/route.js +6 -36
- package/static2.js +24 -0
- package/test/auth/identity.js +0 -0
- package/test/auth/routes.js +1 -1
- package/test/auth.js +427 -229
- package/test/env.js +20 -20
- package/test/fields.js +3 -2
- package/test/identity/identity.js +1 -0
- package/test/identity/index.js +12 -0
- package/test/identity/providers/session.js +227 -0
- package/test/identity/providers/token.js +244 -0
- package/test/identity.js +5 -0
- package/test/init/app.js +359 -365
- package/test/init/bodyparser.js +37 -39
- package/test/init/compression.js +29 -31
- package/test/init/cors.js +38 -39
- package/test/init/db.js +60 -64
- package/test/init/env.js +109 -114
- package/test/init/express.js +50 -47
- package/test/init/fileupload.js +30 -32
- package/test/init/http.js +258 -240
- package/test/init/informer.js +20 -24
- package/test/init/methodoverride.js +29 -31
- package/test/init/middleware.js +56 -58
- package/test/init/modules.js +19 -19
- package/test/init/monitoring.js +22 -22
- package/test/init/routes.js +185 -171
- package/test/init/security.js +77 -103
- package/test/init/sessions/mongoose.js +56 -57
- package/test/init/sessions/redis.js +59 -61
- package/test/init/sessions.js +84 -79
- package/test/init/static.js +108 -113
- package/test/init/template.js +46 -41
- package/test/notInit.js +217 -217
- package/test/notManifest.js +232 -191
- package/test/notRoute.js +1022 -799
- package/test/result.filter.js +422 -0
- package/src/auth/session.js +0 -151
- package/test/auth/session.js +0 -266
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
const { error, log } = require("not-log")(module, "Identity//Token");
|
|
2
|
+
const { notRequestError } = require("not-error");
|
|
3
|
+
const CONST = require("../../auth/const");
|
|
4
|
+
const ROLES = require("../../auth/roles");
|
|
5
|
+
const { objHas } = require("../../common");
|
|
6
|
+
const phrase = require("not-locale").modulePhrase("not-node");
|
|
7
|
+
|
|
8
|
+
const JWT = require("jsonwebtoken");
|
|
9
|
+
|
|
10
|
+
module.exports = class IdentityProviderToken {
|
|
11
|
+
#tokenContent = null;
|
|
12
|
+
#token = null;
|
|
13
|
+
|
|
14
|
+
static #options = {};
|
|
15
|
+
|
|
16
|
+
static setOptions(options = {}) {
|
|
17
|
+
this.#options = options;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static #getOptions() {
|
|
21
|
+
return this.#options;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
constructor(req) {
|
|
25
|
+
this.req = req;
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static getTokenFromRequest(req) {
|
|
30
|
+
const auth = req.get("Authorization");
|
|
31
|
+
if (auth && auth.length) {
|
|
32
|
+
const [, token] = auth.split(" ");
|
|
33
|
+
return token;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#extractToken(req) {
|
|
39
|
+
const token = this.getTokenFromRequest(req);
|
|
40
|
+
if (token) {
|
|
41
|
+
this.#token = token;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#updateToken() {
|
|
46
|
+
this.#token = this.#encodeTokenContent();
|
|
47
|
+
return this.#token;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#decodeTokenContent() {
|
|
51
|
+
try {
|
|
52
|
+
if (this.#token) {
|
|
53
|
+
const secret = this.#getOptions().secret;
|
|
54
|
+
JWT.verify(this.#token, secret);
|
|
55
|
+
return JWT.decode(this.#token, secret);
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
} catch (e) {
|
|
59
|
+
error(e.message);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#encodeTokenContent() {
|
|
65
|
+
try {
|
|
66
|
+
if (this.#token) {
|
|
67
|
+
const secret = this.#getOptions().secret;
|
|
68
|
+
return JWT.sign(this.#tokenContent, secret);
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
} catch (e) {
|
|
72
|
+
error(e.message);
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#extractTokenContent(req) {
|
|
78
|
+
this.#tokenContent = this.#decodeTokenContent(req);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get tokenContent() {
|
|
82
|
+
return this.#tokenContent;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get token() {
|
|
86
|
+
return this.#token;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static #validateSecretForToken({ secret, context }) {
|
|
90
|
+
if (
|
|
91
|
+
!secret ||
|
|
92
|
+
typeof secret === "undefined" ||
|
|
93
|
+
secret === null ||
|
|
94
|
+
secret === ""
|
|
95
|
+
) {
|
|
96
|
+
throw new notRequestError(phrase("user_token_secret_not_valid"), {
|
|
97
|
+
...context,
|
|
98
|
+
code: 500,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static #validateTTLForToken(tokenTTL) {
|
|
104
|
+
if (tokenTTL <= 0 || isNaN(tokenTTL)) {
|
|
105
|
+
log(phrase("user_token_ttl_not_set"));
|
|
106
|
+
tokenTTL = CONST.TOKEN_TTL;
|
|
107
|
+
}
|
|
108
|
+
return tokenTTL;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static #composeUserTokenPayload({ user, additionalFields = [] }) {
|
|
112
|
+
const addons = {};
|
|
113
|
+
if (Array.isArray(additionalFields)) {
|
|
114
|
+
additionalFields.forEach((fieldName) => {
|
|
115
|
+
if (objHas(user, fieldName)) {
|
|
116
|
+
addons[fieldName] = user[fieldName];
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
_id: user._id,
|
|
122
|
+
role: user.role,
|
|
123
|
+
active: user.active,
|
|
124
|
+
username: user.username,
|
|
125
|
+
...addons,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static #composeGuestTokenPayload() {
|
|
130
|
+
return {
|
|
131
|
+
_id: false,
|
|
132
|
+
role: CONST.DEFAULT_USER_ROLE_FOR_GUEST,
|
|
133
|
+
active: true,
|
|
134
|
+
username: phrase("user_role_guest"),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static createToken({
|
|
139
|
+
ip,
|
|
140
|
+
user,
|
|
141
|
+
additionalFields = ["emailConfirmed", "telephoneConfirmed"],
|
|
142
|
+
}) {
|
|
143
|
+
const context = { ip };
|
|
144
|
+
const secret = this.#getOptions().secret;
|
|
145
|
+
this.#validateSecretForToken({ secret, context });
|
|
146
|
+
let payload = {};
|
|
147
|
+
if (user) {
|
|
148
|
+
payload = this.#composeUserTokenPayload({ user, additionalFields });
|
|
149
|
+
} else {
|
|
150
|
+
payload = this.#composeGuestTokenPayload();
|
|
151
|
+
}
|
|
152
|
+
this.#setTokenExpiration(payload);
|
|
153
|
+
return JWT.sign(payload, secret);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static #setTokenExpiration(payload) {
|
|
157
|
+
const tokenTTL = this.#validateTTLForToken(this.#getOptions().ttl);
|
|
158
|
+
if (!objHas(payload, "exp")) {
|
|
159
|
+
payload.exp = Date.now() / 1000 + tokenTTL;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Checks if user is authenticated
|
|
165
|
+
* @return {boolean} true - authenticated, false - guest
|
|
166
|
+
**/
|
|
167
|
+
isUser() {
|
|
168
|
+
return !!this.tokenContent?._id;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Returns user role from token object
|
|
173
|
+
* @return user role
|
|
174
|
+
**/
|
|
175
|
+
getRole() {
|
|
176
|
+
return this.tokenContent?.role ?? CONST.DEFAULT_USER_ROLE_FOR_GUEST;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Set user role for active session
|
|
181
|
+
* @param {Array<string>} role array of roles
|
|
182
|
+
**/
|
|
183
|
+
setRole(role) {
|
|
184
|
+
if (this.tokenContent) {
|
|
185
|
+
this.#tokenContent.role = [...role];
|
|
186
|
+
this.#updateToken();
|
|
187
|
+
}
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Set user id for active session
|
|
193
|
+
* @param {string} _id user id
|
|
194
|
+
**/
|
|
195
|
+
setUserId(_id) {
|
|
196
|
+
if (this.tokenContent) {
|
|
197
|
+
this.#tokenContent._id = _id;
|
|
198
|
+
this.#updateToken();
|
|
199
|
+
}
|
|
200
|
+
return this;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
isRoot() {
|
|
204
|
+
return (
|
|
205
|
+
this.isUser() &&
|
|
206
|
+
ROLES.compareRoles(
|
|
207
|
+
this.getRole(),
|
|
208
|
+
CONST.DEFAULT_USER_ROLE_FOR_ADMIN
|
|
209
|
+
)
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Get user id for active session
|
|
215
|
+
**/
|
|
216
|
+
getUserId() {
|
|
217
|
+
return this.#tokenContent?._id;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* returns token
|
|
222
|
+
**/
|
|
223
|
+
getSessionId() {
|
|
224
|
+
return this.token;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Set auth data in session, user id and role
|
|
229
|
+
* @param {string} id user id
|
|
230
|
+
* @param {string} role user role
|
|
231
|
+
**/
|
|
232
|
+
setAuth(id, role) {
|
|
233
|
+
this.setUserId(id);
|
|
234
|
+
this.setRole(role);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Set auth data in token to Guest
|
|
239
|
+
**/
|
|
240
|
+
setGuest() {
|
|
241
|
+
this.setAuth(null, [CONST.DEFAULT_USER_ROLE_FOR_GUEST]);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Reset session
|
|
246
|
+
* @param {object} req Express Request
|
|
247
|
+
**/
|
|
248
|
+
cleanse() {
|
|
249
|
+
this.setGuest();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
static test(req) {
|
|
253
|
+
return !!this.getTokenFromRequest(req);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
const notPath = require("not-path");
|
|
2
|
+
const { objHas, copyObj } = require("../common");
|
|
3
|
+
|
|
4
|
+
const PROP_NAME_RETURN_ROOT = "returnRoot"; //path to object to filter
|
|
5
|
+
const PROP_NAME_RETURN_RULE = "return"; //filtering rule
|
|
6
|
+
const PROP_NAME_RETURN_STRICT = "returnStrict"; //if filtering should be strict
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @const {boolean} DEFAULT_STRICT_MODE
|
|
10
|
+
* active only in complex rules presented as objects
|
|
11
|
+
* defines if filtering should exclude any not mentioned property and sub property in map object
|
|
12
|
+
* Example:
|
|
13
|
+
* target structure =
|
|
14
|
+
* {
|
|
15
|
+
* id,
|
|
16
|
+
* user:{
|
|
17
|
+
* id,
|
|
18
|
+
* username,
|
|
19
|
+
* aliases: [
|
|
20
|
+
* {id, title, createdAt},
|
|
21
|
+
* {id, title, createdAt, banned}
|
|
22
|
+
* ],
|
|
23
|
+
* createdAt
|
|
24
|
+
* },
|
|
25
|
+
* clean
|
|
26
|
+
* }
|
|
27
|
+
* rule object =
|
|
28
|
+
* {
|
|
29
|
+
* id,
|
|
30
|
+
* 'user.aliases': ['id', 'title', 'banned']
|
|
31
|
+
* }
|
|
32
|
+
* in strict==true
|
|
33
|
+
* filtered target structure =
|
|
34
|
+
* {
|
|
35
|
+
* id,
|
|
36
|
+
* user:{
|
|
37
|
+
* aliases: [
|
|
38
|
+
* {id, title},
|
|
39
|
+
* {id, title, banned}
|
|
40
|
+
* ]
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* in strict==false
|
|
44
|
+
* filtered target structure = {
|
|
45
|
+
* id,
|
|
46
|
+
* user:{
|
|
47
|
+
* id,
|
|
48
|
+
* username,
|
|
49
|
+
* aliases: [
|
|
50
|
+
* {id, title},
|
|
51
|
+
* {id, title, banned}
|
|
52
|
+
* ],
|
|
53
|
+
* createdAt
|
|
54
|
+
* }
|
|
55
|
+
* }
|
|
56
|
+
*/
|
|
57
|
+
const DEFAULT_STRICT_MODE = false;
|
|
58
|
+
|
|
59
|
+
module.exports = class notManifestRouteResultFilter {
|
|
60
|
+
/**
|
|
61
|
+
* Removes fields from result object acctoding to actionData.return array
|
|
62
|
+
* if presented
|
|
63
|
+
* @param {object} notRouteData request rules and preferencies
|
|
64
|
+
* @param {object} result result returned by main action processor
|
|
65
|
+
*/
|
|
66
|
+
static filter(notRouteData, result) {
|
|
67
|
+
if (!(result && typeof result === "object")) return;
|
|
68
|
+
const filteringRule = this.getFilteringRule(notRouteData);
|
|
69
|
+
if (!filteringRule) return;
|
|
70
|
+
const filteringTarget = this.getFilteringTarget(result, notRouteData);
|
|
71
|
+
if (!filteringTarget) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.filterByRule(
|
|
75
|
+
filteringTarget,
|
|
76
|
+
filteringRule,
|
|
77
|
+
this.getFilteringStrictMode(notRouteData)
|
|
78
|
+
);
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* modifies target according to rule
|
|
84
|
+
* @param {object} target object which properties should be filtered
|
|
85
|
+
* @param {array} rule filtering rule
|
|
86
|
+
* @param {boolean} strict filtering mode
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
static filterByRule(target, rule, strict = DEFAULT_STRICT_MODE) {
|
|
90
|
+
if (!rule || !target) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (Array.isArray(rule)) {
|
|
94
|
+
this.filterByArrayRule(target, rule); //flat map always strict==true
|
|
95
|
+
} else if (typeof rule === "object") {
|
|
96
|
+
this.filterByMapRule(target, rule, strict); //object map strict could vary
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* filters target by rule.
|
|
102
|
+
* Rule form: {pathToProperty: filteringRuleArray, pathToProperty: filteringRuleMap }
|
|
103
|
+
* pathToProperty should be in notPath notation except starting symbol (default: ':')
|
|
104
|
+
* if pathToProperty targets array in target, each item of array will be filtered by
|
|
105
|
+
* @param {object} target
|
|
106
|
+
* @param {object} rule map of properties.
|
|
107
|
+
* @param {boolean} strict filtering mode
|
|
108
|
+
* example:
|
|
109
|
+
* {
|
|
110
|
+
* 'user': ['username', 'id', 'email'], //filtering properties of object target.user
|
|
111
|
+
* 'posts': ['id', 'title'], //filtering properties of array of objects target.posts
|
|
112
|
+
* 'friends.list': ['id', 'username'] //filtering props of array of objects target.friends.list by path.
|
|
113
|
+
* //if strict==false: will not drop any from friends.*, only friends.list cotent will be processed
|
|
114
|
+
* //if strict==true: will drop all properties of friends except list
|
|
115
|
+
* 'friends': { //this will clear friends sub-object from any properties except 'list' in any strict mode
|
|
116
|
+
* 'list': ['id', 'username'] //and filter 'list' items
|
|
117
|
+
* },
|
|
118
|
+
* 'storage': { //filtering complex sub object by map
|
|
119
|
+
* 'files':{
|
|
120
|
+
* 'cloud': ['id','title'],
|
|
121
|
+
* 'local': ['id', 'title', 'size']
|
|
122
|
+
* }
|
|
123
|
+
* }
|
|
124
|
+
* }
|
|
125
|
+
*/
|
|
126
|
+
static filterByMapRule(target, rule, strict = DEFAULT_STRICT_MODE) {
|
|
127
|
+
//to form ['id', 'user.username', 'files']
|
|
128
|
+
const filteringArray = Object.keys(rule);
|
|
129
|
+
//filtering direct chilren if in strict mode
|
|
130
|
+
if (strict) {
|
|
131
|
+
this.filterStrict(target, filteringArray);
|
|
132
|
+
}
|
|
133
|
+
//filter properties
|
|
134
|
+
for (let filteringTargetName of filteringArray) {
|
|
135
|
+
const subTarget = notPath.get(
|
|
136
|
+
`${notPath.PATH_START_OBJECT}${filteringTargetName}`,
|
|
137
|
+
target
|
|
138
|
+
);
|
|
139
|
+
//if sub target Array filtering each item individualy
|
|
140
|
+
if (Array.isArray(subTarget)) {
|
|
141
|
+
subTarget.forEach((subTargetItem) => {
|
|
142
|
+
this.filterByRule(
|
|
143
|
+
subTargetItem,
|
|
144
|
+
rule[filteringTargetName],
|
|
145
|
+
strict
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
} else if (typeof subTarget == "object") {
|
|
149
|
+
this.filterByRule(subTarget, rule[filteringTargetName], strict);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
static filterStrict(target, filteringArray) {
|
|
155
|
+
console.log(target, filteringArray);
|
|
156
|
+
//to form ['id', 'user', 'files']
|
|
157
|
+
const filteringArrayDirectChildren = filteringArray.map(
|
|
158
|
+
(propName) => propName.split(notPath.PATH_SPLIT)[0]
|
|
159
|
+
);
|
|
160
|
+
//filter strict direct children
|
|
161
|
+
this.filterByArrayRule(target, filteringArrayDirectChildren);
|
|
162
|
+
//filter strict each level in props paths in filteringArray
|
|
163
|
+
for (let path of filteringArray) {
|
|
164
|
+
let pathParts = path.split(notPath.PATH_SPLIT);
|
|
165
|
+
if (pathParts.length === 1) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
//property name in which we will clean content except pathParts[1]
|
|
169
|
+
const directPropName = pathParts.shift();
|
|
170
|
+
//
|
|
171
|
+
const subTarget = target[directPropName];
|
|
172
|
+
if (Array.isArray(subTarget)) continue;
|
|
173
|
+
const subFilteringArray = [pathParts.join(notPath.PATH_SPLIT)];
|
|
174
|
+
this.filterStrict(subTarget, subFilteringArray);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* filters target properties by rule, all properties which names are not presented in rule
|
|
180
|
+
* array will be removed from target
|
|
181
|
+
* @param {object} target object to filter
|
|
182
|
+
* @param {Array} rule list of enabled properties. example: ['id', 'title', 'createdAt']
|
|
183
|
+
*/
|
|
184
|
+
static filterByArrayRule(target, rule) {
|
|
185
|
+
const presented = Object.keys(target);
|
|
186
|
+
presented.forEach((fieldName) => {
|
|
187
|
+
if (!rule.includes(fieldName)) {
|
|
188
|
+
delete target[fieldName];
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* returns filtering rule object or undefined
|
|
195
|
+
* @param {object} notRouteData
|
|
196
|
+
* @returns {object|Array|undefined} rule to filter result object properties
|
|
197
|
+
*/
|
|
198
|
+
static getFilteringRule(notRouteData) {
|
|
199
|
+
if (objHas(notRouteData.rule, PROP_NAME_RETURN_RULE)) {
|
|
200
|
+
return copyObj(notRouteData.rule[PROP_NAME_RETURN_RULE]);
|
|
201
|
+
} else if (objHas(notRouteData.actionData, PROP_NAME_RETURN_RULE)) {
|
|
202
|
+
return copyObj(notRouteData.actionData[PROP_NAME_RETURN_RULE]);
|
|
203
|
+
} else {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Returns path to sub object which properties should be filtered
|
|
210
|
+
* @param {object} notRouteData
|
|
211
|
+
* @returns {string} path of sub object in notPath notation
|
|
212
|
+
*/
|
|
213
|
+
static getFilteringTargetPath(notRouteData) {
|
|
214
|
+
let path = notPath.PATH_START_OBJECT;
|
|
215
|
+
if (notRouteData) {
|
|
216
|
+
if (objHas(notRouteData.rule, PROP_NAME_RETURN_ROOT)) {
|
|
217
|
+
path += notRouteData.rule[PROP_NAME_RETURN_ROOT];
|
|
218
|
+
} else if (objHas(notRouteData.actionData, PROP_NAME_RETURN_ROOT)) {
|
|
219
|
+
path += notRouteData.actionData[PROP_NAME_RETURN_ROOT];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return path;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Returns object which properties should be filtered
|
|
227
|
+
* @param {object} result request result
|
|
228
|
+
* @param {object} notRouteData request route rules and prefs
|
|
229
|
+
* @returns {object} object to filter
|
|
230
|
+
*/
|
|
231
|
+
static getFilteringTarget(result, notRouteData) {
|
|
232
|
+
if (result && typeof result == "object") {
|
|
233
|
+
const returnListRoot = this.getFilteringTargetPath(notRouteData);
|
|
234
|
+
return notPath.get(returnListRoot, result);
|
|
235
|
+
} else {
|
|
236
|
+
return result;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
static getFilteringStrictMode(notRouteData) {
|
|
241
|
+
if (notRouteData) {
|
|
242
|
+
if (objHas(notRouteData.rule, PROP_NAME_RETURN_STRICT)) {
|
|
243
|
+
return !!notRouteData.rule[PROP_NAME_RETURN_STRICT];
|
|
244
|
+
} else if (
|
|
245
|
+
objHas(notRouteData.actionData, PROP_NAME_RETURN_STRICT)
|
|
246
|
+
) {
|
|
247
|
+
return !!notRouteData.actionData[PROP_NAME_RETURN_STRICT];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return this.DEFAULT_STRICT_MODE;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
static get PROP_NAME_RETURN_ROOT() {
|
|
254
|
+
return PROP_NAME_RETURN_ROOT;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
static get PROP_NAME_RETURN_RULE() {
|
|
258
|
+
return PROP_NAME_RETURN_RULE;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
static get PROP_NAME_RETURN_STRICT() {
|
|
262
|
+
return PROP_NAME_RETURN_STRICT;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
static get DEFAULT_STRICT_MODE() {
|
|
266
|
+
return DEFAULT_STRICT_MODE;
|
|
267
|
+
}
|
|
268
|
+
};
|
package/src/manifest/route.js
CHANGED
|
@@ -2,10 +2,13 @@ const CONST_BEFORE_ACTION = "before";
|
|
|
2
2
|
const CONST_AFTER_ACTION = "after";
|
|
3
3
|
|
|
4
4
|
const obsoleteWarning = require("../obsolete");
|
|
5
|
+
|
|
6
|
+
const notAppIdentity = require("../identity");
|
|
5
7
|
const Auth = require("../auth"),
|
|
6
8
|
HttpError = require("../error").Http;
|
|
7
9
|
|
|
8
|
-
const
|
|
10
|
+
const notManifestRouteResultFilter = require("./result.filter");
|
|
11
|
+
const { copyObj, executeObjectFunction } = require("../common");
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Route representation
|
|
@@ -67,7 +70,7 @@ class notRoute {
|
|
|
67
70
|
* @return {object} rule or null
|
|
68
71
|
*/
|
|
69
72
|
selectRule(req) {
|
|
70
|
-
const user =
|
|
73
|
+
const user = notAppIdentity.extractAuthData(req);
|
|
71
74
|
if (this.actionData) {
|
|
72
75
|
return notRoute.actionAvailableByRule(this.actionData, user);
|
|
73
76
|
}
|
|
@@ -171,39 +174,6 @@ class notRoute {
|
|
|
171
174
|
);
|
|
172
175
|
}
|
|
173
176
|
|
|
174
|
-
extractReturn(notRouteData) {
|
|
175
|
-
if (objHas(notRouteData.rule, "return")) {
|
|
176
|
-
return [...notRouteData.rule.return];
|
|
177
|
-
} else if (objHas(notRouteData.actionData, "return")) {
|
|
178
|
-
return [...notRouteData.actionData.return];
|
|
179
|
-
} else {
|
|
180
|
-
return undefined;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Removes fields from result object acctoding to actionData.return array
|
|
186
|
-
* if presented
|
|
187
|
-
* @param {ExpressRequest} req request object
|
|
188
|
-
* @param {object} result result returned by main action processor
|
|
189
|
-
*/
|
|
190
|
-
filterResultByReturnRule(req, result) {
|
|
191
|
-
const returnList = this.extractReturn(req.notRouteData);
|
|
192
|
-
if (
|
|
193
|
-
result &&
|
|
194
|
-
typeof result === "object" &&
|
|
195
|
-
returnList &&
|
|
196
|
-
Array.isArray(returnList)
|
|
197
|
-
) {
|
|
198
|
-
let presented = Object.keys(result);
|
|
199
|
-
presented.forEach((fieldName) => {
|
|
200
|
-
if (!returnList.includes(fieldName)) {
|
|
201
|
-
delete result[fieldName];
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
177
|
async executeRoute(modRoute, actionName, { req, res, next }) {
|
|
208
178
|
try {
|
|
209
179
|
//waiting preparation
|
|
@@ -220,7 +190,7 @@ class notRoute {
|
|
|
220
190
|
prepared,
|
|
221
191
|
]);
|
|
222
192
|
//filter result IF actionData.return specified
|
|
223
|
-
|
|
193
|
+
notManifestRouteResultFilter.filter(req.notRouteData, result);
|
|
224
194
|
//run after with results, continue without waiting when it finished
|
|
225
195
|
return this.executeFunction(modRoute, CONST_AFTER_ACTION, [
|
|
226
196
|
req,
|
package/static2.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class Parent {
|
|
2
|
+
static getOptions() {
|
|
3
|
+
return this.#options;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
static setOptions(opts) {
|
|
7
|
+
this.#options = opts;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class Child extends Parent {
|
|
12
|
+
static #options = {};
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
run() {
|
|
18
|
+
Child.getOptions();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
Parent.setOptions({ 1: "1" });
|
|
23
|
+
|
|
24
|
+
console.log(new Child().run());
|
|
File without changes
|
package/test/auth/routes.js
CHANGED
|
@@ -3,7 +3,7 @@ const {
|
|
|
3
3
|
HttpExceptionForbidden,
|
|
4
4
|
} = require("../../src/exceptions/http");
|
|
5
5
|
|
|
6
|
-
module.exports = ({ Auth,
|
|
6
|
+
module.exports = ({ Auth, expect }) => {
|
|
7
7
|
describe("Routes", () => {
|
|
8
8
|
describe("getIP", () => {
|
|
9
9
|
it("req.header[x-forwarded-for]", () => {
|