@cocreate/authorize 1.7.6 → 1.8.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/package.json +3 -3
  3. package/src/index.js +98 -181
package/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ # [1.8.0](https://github.com/CoCreate-app/CoCreate-authorize/compare/v1.7.6...v1.8.0) (2023-11-03)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * if organization_id does not exist error ([5dbdd8f](https://github.com/CoCreate-app/CoCreate-authorize/commit/5dbdd8f285418618575efc8a1e525dbde6ea81a1))
7
+ * improve authorization promise handling ([df00618](https://github.com/CoCreate-app/CoCreate-authorize/commit/df00618c03c129b20abb5878f73d6522dbec5401))
8
+ * Improve conditions ([689e6fa](https://github.com/CoCreate-app/CoCreate-authorize/commit/689e6fa95d8378f2d7bed22c1e2a2f29bc5c7be0))
9
+ * request.request param removed ([06a656d](https://github.com/CoCreate-app/CoCreate-authorize/commit/06a656d8b2a354ff473e8de1cfa5b44abc81bd89))
10
+ * update dependencies to the lates versions ([0a19463](https://github.com/CoCreate-app/CoCreate-authorize/commit/0a1946353c787a5dee1f54324e1fb2290c4b7a0f))
11
+
12
+
13
+ ### Features
14
+
15
+ * check if authoriztion keys has a query operator and apply query ([e2dfa5c](https://github.com/CoCreate-app/CoCreate-authorize/commit/e2dfa5c02bbb537454e2f5d9a9b07444dd60c3a6))
16
+ * support adding querires for crud methods ([9b68d24](https://github.com/CoCreate-app/CoCreate-authorize/commit/9b68d244982fe08f680043cd7f1a1b06cc6be301))
17
+
1
18
  ## [1.7.6](https://github.com/CoCreate-app/CoCreate-authorize/compare/v1.7.5...v1.7.6) (2023-10-26)
2
19
 
3
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/authorize",
3
- "version": "1.7.6",
3
+ "version": "1.8.0",
4
4
  "description": "A simple authorize component in vanilla javascript. Easily configured using HTML5 data-attributes and/or JavaScript API.",
5
5
  "keywords": [
6
6
  "authorize",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "main": "./src/index.js",
47
47
  "dependencies": {
48
- "@cocreate/crud-client": "^1.28.10",
49
- "@cocreate/utils": "^1.26.1"
48
+ "@cocreate/crud-client": "^1.28.12",
49
+ "@cocreate/utils": "^1.26.2"
50
50
  }
51
51
  }
package/src/index.js CHANGED
@@ -15,7 +15,7 @@
15
15
  }
16
16
  }(typeof self !== 'undefined' ? self : this, function (isBrowser, crud, { getValueFromObject, dotNotationToObject }) {
17
17
 
18
- const authorizations = new Map()
18
+ const organizations = {}
19
19
 
20
20
  if (isBrowser) {
21
21
  crud.listen('update.object', function (data) {
@@ -36,9 +36,9 @@
36
36
 
37
37
  if (array === 'keys' && object) {
38
38
  let authorization = object[0]
39
- if (authorization && authorization.key && hasAuthorization(authorization.key)) {
39
+ if (authorization && authorization.key && organizations[organization_id] && organizations[organization_id][authorization.key]) {
40
40
  let newAuthorization = await readAuthorization(authorization.key, organization_id)
41
- setAuthorization(authorization.key, newAuthorization)
41
+ organizations[organization_id][authorization.key] = newAuthorization
42
42
  }
43
43
  }
44
44
  }
@@ -48,44 +48,21 @@
48
48
 
49
49
  if (array === 'keys' && object) {
50
50
  let authorization = object[0]
51
- if (authorization && authorization.key && hasAuthorization(authorization.key)) {
52
- authorizations.delete(authorization.key)
51
+ if (authorization && authorization.key && organizations[organization_id] && organizations[organization_id][authorization.key]) {
52
+ delete organizations[organization_id][authorization.key]
53
53
  }
54
54
  }
55
55
  }
56
56
 
57
- function setAuthorization(key, authorization) {
58
- authorizations.set(key, authorization)
59
- }
60
-
61
- function hasAuthorization(key) {
62
- return authorizations.has(key)
63
- }
64
-
65
57
  async function getAuthorization(key, organization_id) {
66
- // Check if there is a value orpending promise for this key
67
- if (key && authorizations.has(key)) {
68
- // Return the value or pending promise
69
- return await authorizations.get(key);
70
- }
71
-
72
- // Create a new promise and store it
73
- const authorizationPromise = readAuthorization(key, organization_id);
74
- authorizations.set(key, authorizationPromise);
75
-
76
- try {
77
- // Wait for the authorization to be resolved
78
- const authorization = await authorizationPromise;
58
+ if (!organizations[organization_id])
59
+ organizations[organization_id] = {}
79
60
 
80
- // Once resolved, store the resolved authorization in the map
81
- authorizations.set(key, authorization);
61
+ if (!organizations[organization_id][key])
62
+ organizations[organization_id][key] = readAuthorization(key, organization_id);
82
63
 
83
- return authorization;
84
- } catch (error) {
85
- // Handle errors if necessary
86
- authorizations.delete(key);
87
- throw error;
88
- }
64
+ organizations[organization_id][key] = await organizations[organization_id][key]
65
+ return organizations[organization_id][key]
89
66
  }
90
67
 
91
68
  async function readAuthorization(key, organization_id) {
@@ -94,10 +71,10 @@
94
71
  return { error: 'An organization_id is required' };
95
72
 
96
73
  let request = {
97
- method: 'read.object',
74
+ method: 'object.read',
75
+ database: organization_id,
98
76
  array: 'keys',
99
77
  organization_id,
100
- object: {},
101
78
  $filter: {
102
79
  query: []
103
80
  }
@@ -124,20 +101,19 @@
124
101
  role_ids.push({ _id })
125
102
  })
126
103
 
127
- delete request.object.$filter
128
- delete request.request
104
+ delete request.$filter
105
+ delete request.isFilter
106
+
129
107
  request.object = role_ids
130
108
 
131
109
  let roles = await crud.send(request)
132
110
  roles = roles.object
133
111
 
134
- authorization = createAuthorization(authorization, roles)
112
+ authorization = await createAuthorization(authorization, roles)
135
113
  }
136
-
137
- }
138
-
139
- return authorization;
140
-
114
+ return authorization;
115
+ } else
116
+ return {}
141
117
  } catch (error) {
142
118
  console.log("authorization Error", error)
143
119
  return { error };
@@ -198,171 +174,111 @@
198
174
  }
199
175
 
200
176
  async function checkAuthorization({ key, data }) {
201
- // let method = data.method
202
- let { method, organization_id, endPoint } = data
203
- if (!organization_id)
204
- return { error: '' };
177
+ if (!data.organization_id)
178
+ return { error: 'organization_id is required' };
179
+ if (!data.method)
180
+ return { error: 'method is required' };
205
181
 
206
- let authorized = await getAuthorization(key, organization_id)
182
+ let authorized = await getAuthorization(key, data.organization_id)
207
183
  if (!authorized || authorized.error)
208
184
  return authorized
209
- if (authorized.organization_id !== organization_id)
185
+ if (authorized.organization_id !== data.organization_id)
210
186
  return false;
211
187
  if (authorized.host && authorized.host.length) {
212
188
  if (!authorized.host || (!authorized.host.includes(data.host) && !authorized.host.includes("*")))
213
189
  return false;
214
-
215
190
  }
216
- if (authorized.admin == 'true' || authorized.admin === true)
191
+ if (authorized.admin === 'true' || authorized.admin === true)
217
192
  return true;
218
193
 
219
- let status = await checkMethod(authorized.actions, method, endPoint, data)
194
+ let status = await checkMethod(data, authorized.actions, data.method)
195
+
196
+ // console.log(data.method, status)
220
197
 
221
- if (!status)
198
+ if (!status) {
222
199
  return false
200
+ }
223
201
 
224
202
  return { authorized: data };
225
203
  }
226
204
 
227
- async function checkMethod(autorized, method, endPoint, data) {
228
- if (!autorized || !method || !autorized[method] || autorized[method] == 'false') return false;
229
- if (autorized[method] === true || autorized[method] == 'true' || autorized[method] == '*') return true;
230
-
231
- let authorized = autorized[method].authorize
232
- if (authorized) {
233
- let status = await checkAthorized(authorized, method, endPoint, data)
234
- if (!status)
235
- return false
236
- else {
237
- let unauthorized = autorized[method].unauthorize
238
- if (unauthorized) {
239
- let status = await checkAthorized(unauthorized, method, endPoint, data, true)
240
- if (status)
241
- return false
242
- }
243
- return true
205
+ async function checkMethod(data, authorized, method) {
206
+ if (authorized[method]) {
207
+ return await checkMethodMatch(data, authorized[method], method)
208
+ } else if (method.includes('.')) {
209
+ let match = ''
210
+ let splitMethod = method.split('.')
211
+ for (let i = 0; i < splitMethod.length; i++) {
212
+ if (!match)
213
+ match = splitMethod[i]
214
+ else
215
+ match += '.' + splitMethod[i]
216
+ if (authorized[match]) {
217
+ return await checkMethodMatch(data, authorized[match], match)
218
+ } else if (i === splitMethod.length - 1)
219
+ return false
244
220
  }
245
221
  } else
246
- return false
222
+ return false;
247
223
  }
248
224
 
249
- async function checkAthorized(authorized, method, endPoint, data, unauthorize) {
250
- if (!Array.isArray(authorized))
251
- authorized = [authorized]
252
-
253
- let status = false
254
- for (let i = 0; i < authorized.length; i++) {
255
- // if authorized[i] is a booleaan
256
- if (authorized[i] === true)
225
+ async function checkMethodMatch(data, authorized, match) {
226
+ if (typeof authorized === 'boolean') {
227
+ return authorized
228
+ } else if (typeof authorized === 'string') {
229
+ if (authorized === 'false')
230
+ return false
231
+ else if (authorized === 'true')
257
232
  return true
258
-
259
- // if authorized[i] is a string or an array
260
- if (typeof authorized[i] === "string" || Array.isArray(authorized[i])) {
261
- if (authorized[i].includes(true) || authorized[i].includes('true') || authorized[i].includes('*'))
262
- return true
263
- else if (endPoint)
264
- return authorized.includes(endPoint)
265
- else
266
- return false
267
- }
268
-
269
- // if authorized[i] is an object
270
- for (const key of Object.keys(authorized[i])) {
271
- status = await checkAthorizedKey(authorized[i], method, endPoint, data, key, unauthorize)
233
+ else if (authorized === match)
234
+ return true // check string for match or mutate data
235
+ else
236
+ return true // check string for match or mutate data
237
+ } else if (typeof authorized === 'number') {
238
+ return !!authorized
239
+ } else {
240
+ let status = false
241
+ let newmatch = data.method.replace(match, '')
242
+
243
+ if (Array.isArray(authorized)) {
244
+ for (let i = 0; i < authorized.length; i++) {
245
+ status = await checkMethodMatch(data, authorized[i], newmatch)
246
+ }
247
+ } else if (typeof authorized === 'object') {
248
+ let keys = Object.keys(authorized);
249
+
250
+ for (const key of keys) {
251
+ if (key.includes('$'))
252
+ status = await checkMethodOperators(data, key, authorized[key])
253
+ else if (newmatch && (authorized[newmatch] || authorized['*'])) {
254
+ status = await checkMethodMatch(data, authorized[newmatch] || authorized['*'], newmatch)
255
+ }
256
+ }
272
257
  }
273
-
258
+ return status
274
259
  }
275
-
276
- return status
277
-
278
260
  }
279
261
 
280
- async function checkAthorizedKey(authorized, method, endPoint, data, key, unauthorize) {
281
- let status = false;
282
- let keyStatus = false;
283
-
284
- // if authorized[key] is a booleaan
285
- if (authorized[key] === true)
286
- keyStatus = true
287
-
288
- // if authorized[key] is a string or number
289
- else if (typeof authorized[key] === "string" || typeof authorized[key] === "number") {
290
- if (authorized[key] === true || authorized[key] === 'true' || authorized[key] === '*')
291
- keyStatus = true
292
- else if (data[key]) {
293
- keyStatus = await checkArray(authorized, data, key, unauthorize)
294
- if (await checkFilter(authorized, data, key, unauthorize))
295
- status = true
296
- }
297
- }
298
-
299
- // if authorized[key] is an array
300
- else if (Array.isArray(authorized[key])) {
301
- if (authorized[key].includes(true) || authorized[key].includes('true') || authorized[key].includes('*'))
302
- keyStatus = true
303
- else if (data[key]) {
304
- keyStatus = await checkArray(authorized, data, key, unauthorize)
305
- if (await checkFilter(authorized, data, key, unauthorize))
306
- status = true
307
- }
308
- }
309
-
310
- // if authorized[key] is an object
311
- else if (typeof authorized[key] === "object") {
312
- console.log('authorized[key] is an object', authorized[key])
313
- } else
314
- delete data[key]
315
-
316
- // if key status is false for unauthorized case
317
- if (!keyStatus || keyStatus && unauthorize) {
318
- if (!data.unauthorized || !data.unauthorized[method])
319
- data.unauthorized = { [method]: { [key]: [data[key]] } }
320
- else if (!data.unauthorized[method][key])
321
- data.unauthorized[method][key] = [data[key]]
262
+ async function checkMethodOperators(data, key, value) {
263
+ if (value === 'this.userId' && data.socket)
264
+ value = data.socket.user_id
265
+
266
+ let keys = key.split('.')
267
+ if (['$eq', '$ne', '$lt', '$lte', '$gt', '$gte', '$in', '$nin', '$or', '$and', '$not', '$nor', '$exists', '$type', '$mod', '$regex', '$text', '$where', '$all', '$elemMatch', '$size'].includes(keys[0])) {
268
+ // let keys = key.split('.')
269
+ let query = { key: keys[1], value, operator: keys[0] }
270
+ if (!data.$filter)
271
+ data.$filter = { query: [query] }
272
+ else if (!data.$filter.query)
273
+ data.$filter.query = [query]
322
274
  else
323
- data.unauthorized[method][key].push(data[key])
324
- } else
325
- status = true
326
- return status
327
- }
275
+ data.$filter.query.push(query)
328
276
 
329
- async function checkArray(authorized, data, key, unauthorize) {
330
- let keyStatus = false
331
- let authorizedValue = getValueFromObject(authorized, key);
332
- let dataValue = getValueFromObject(data, key);
333
-
334
- if (!authorizedValue && !unauthorize) {
335
- data = deleteKey(data, key)
336
- } else if (typeof dataValue == "string") {
337
- if (unauthorize && authorizedValue.includes(dataValue))
338
- data = deleteKey(data, key)
339
- else {
340
- if (!authorizedValue.includes(dataValue))
341
- data = deleteKey(data, key)
342
- else
343
- keyStatus = true
344
- }
345
- } else if (Array.isArray(dataValue)) {
346
- for (let i = 0; i < dataValue.length; i++) {
347
- keyStatus = await checkArray(authorized, data, `${key}[${i}]`, unauthorize)
348
- }
349
- } else if (typeof dataValue === "object") {
350
- let checkKeys = true
351
- if (dataValue['_id']) {
352
- if (authorized.object.includes(dataValue['_id']))
353
- checkKeys = true
354
- }
355
- if (checkKeys) {
356
- if (authorizedValue['*'] || authorizedValue['*'] == '')
357
- keyStatus = true
358
- else
359
- for (const k of Object.keys(dataValue)) {
360
- keyStatus = await checkArray(authorized, data, `${key}.${k}`, unauthorize)
361
- }
362
- }
277
+ } else {
278
+ // TODO: sanitize data by removing items user does not have access to.
279
+ // console.log('key is a query operator', key)
363
280
  }
364
-
365
- return keyStatus
281
+ return true
366
282
  }
367
283
 
368
284
  async function checkFilter(authorized, data, apikey, unauthorize) {
@@ -387,6 +303,7 @@
387
303
  }
388
304
  }
389
305
 
306
+
390
307
  function deleteKey(data, path) {
391
308
  if (!data || !path) return
392
309
  if (path.includes('._id'))