@cocreate/authorize 1.7.5 → 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 +24 -0
  2. package/package.json +3 -3
  3. package/src/index.js +102 -186
package/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
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
+
18
+ ## [1.7.6](https://github.com/CoCreate-app/CoCreate-authorize/compare/v1.7.5...v1.7.6) (2023-10-26)
19
+
20
+
21
+ ### Bug Fixes
22
+
23
+ * await key to resolve, update filters ([f69bdb7](https://github.com/CoCreate-app/CoCreate-authorize/commit/f69bdb72fe8c4b7ce8a2993699c8611442373e12))
24
+
1
25
  ## [1.7.5](https://github.com/CoCreate-app/CoCreate-authorize/compare/v1.7.4...v1.7.5) (2023-10-25)
2
26
 
3
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/authorize",
3
- "version": "1.7.5",
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 (authorizations.has(key)) {
68
- // Return the value or pending promise
69
- return 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,20 +71,19 @@
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
- $filter: {
102
- query: []
103
- }
78
+ $filter: {
79
+ query: []
104
80
  }
105
81
  }
106
82
 
107
83
  if (key)
108
- request.object.$filter.query.push({ key: 'key', value: key, operator: '$eq' })
84
+ request.$filter.query.push({ key: 'key', value: key, operator: '$eq' })
109
85
  else
110
- request.object.$filter.query.push({ key: 'default', value: true, operator: '$eq' })
86
+ request.$filter.query.push({ key: 'default', value: true, operator: '$eq' })
111
87
 
112
88
 
113
89
  let authorization = await crud.send(request)
@@ -125,20 +101,19 @@
125
101
  role_ids.push({ _id })
126
102
  })
127
103
 
128
- delete request.object.$filter
129
- delete request.request
104
+ delete request.$filter
105
+ delete request.isFilter
106
+
130
107
  request.object = role_ids
131
108
 
132
109
  let roles = await crud.send(request)
133
110
  roles = roles.object
134
111
 
135
- authorization = createAuthorization(authorization, roles)
112
+ authorization = await createAuthorization(authorization, roles)
136
113
  }
137
-
138
- }
139
-
140
- return authorization;
141
-
114
+ return authorization;
115
+ } else
116
+ return {}
142
117
  } catch (error) {
143
118
  console.log("authorization Error", error)
144
119
  return { error };
@@ -199,171 +174,111 @@
199
174
  }
200
175
 
201
176
  async function checkAuthorization({ key, data }) {
202
- // let method = data.method
203
- let { method, organization_id, endPoint } = data
204
- if (!organization_id)
205
- return { error: '' };
177
+ if (!data.organization_id)
178
+ return { error: 'organization_id is required' };
179
+ if (!data.method)
180
+ return { error: 'method is required' };
206
181
 
207
- let authorized = await getAuthorization(key, organization_id)
182
+ let authorized = await getAuthorization(key, data.organization_id)
208
183
  if (!authorized || authorized.error)
209
184
  return authorized
210
- if (authorized.organization_id !== organization_id)
185
+ if (authorized.organization_id !== data.organization_id)
211
186
  return false;
212
187
  if (authorized.host && authorized.host.length) {
213
188
  if (!authorized.host || (!authorized.host.includes(data.host) && !authorized.host.includes("*")))
214
189
  return false;
215
-
216
190
  }
217
- if (authorized.admin == 'true' || authorized.admin === true)
191
+ if (authorized.admin === 'true' || authorized.admin === true)
218
192
  return true;
219
193
 
220
- 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)
221
197
 
222
- if (!status)
198
+ if (!status) {
223
199
  return false
200
+ }
224
201
 
225
202
  return { authorized: data };
226
203
  }
227
204
 
228
- async function checkMethod(autorized, method, endPoint, data) {
229
- if (!autorized || !method || !autorized[method] || autorized[method] == 'false') return false;
230
- if (autorized[method] === true || autorized[method] == 'true' || autorized[method] == '*') return true;
231
-
232
- let authorized = autorized[method].authorize
233
- if (authorized) {
234
- let status = await checkAthorized(authorized, method, endPoint, data)
235
- if (!status)
236
- return false
237
- else {
238
- let unauthorized = autorized[method].unauthorize
239
- if (unauthorized) {
240
- let status = await checkAthorized(unauthorized, method, endPoint, data, true)
241
- if (status)
242
- return false
243
- }
244
- 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
245
220
  }
246
221
  } else
247
- return false
222
+ return false;
248
223
  }
249
224
 
250
- async function checkAthorized(authorized, method, endPoint, data, unauthorize) {
251
- if (!Array.isArray(authorized))
252
- authorized = [authorized]
253
-
254
- let status = false
255
- for (let i = 0; i < authorized.length; i++) {
256
- // if authorized[i] is a booleaan
257
- 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')
258
232
  return true
259
-
260
- // if authorized[i] is a string or an array
261
- if (typeof authorized[i] === "string" || Array.isArray(authorized[i])) {
262
- if (authorized[i].includes(true) || authorized[i].includes('true') || authorized[i].includes('*'))
263
- return true
264
- else if (endPoint)
265
- return authorized.includes(endPoint)
266
- else
267
- return false
268
- }
269
-
270
- // if authorized[i] is an object
271
- for (const key of Object.keys(authorized[i])) {
272
- 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
+ }
273
257
  }
274
-
258
+ return status
275
259
  }
276
-
277
- return status
278
-
279
260
  }
280
261
 
281
- async function checkAthorizedKey(authorized, method, endPoint, data, key, unauthorize) {
282
- let status = false;
283
- let keyStatus = false;
284
-
285
- // if authorized[key] is a booleaan
286
- if (authorized[key] === true)
287
- keyStatus = true
288
-
289
- // if authorized[key] is a string or number
290
- else if (typeof authorized[key] === "string" || typeof authorized[key] === "number") {
291
- if (authorized[key] === true || authorized[key] === 'true' || authorized[key] === '*')
292
- keyStatus = true
293
- else if (data[key]) {
294
- keyStatus = await checkArray(authorized, data, key, unauthorize)
295
- if (await checkFilter(authorized, data, key, unauthorize))
296
- status = true
297
- }
298
- }
299
-
300
- // if authorized[key] is an array
301
- else if (Array.isArray(authorized[key])) {
302
- if (authorized[key].includes(true) || authorized[key].includes('true') || authorized[key].includes('*'))
303
- keyStatus = true
304
- else if (data[key]) {
305
- keyStatus = await checkArray(authorized, data, key, unauthorize)
306
- if (await checkFilter(authorized, data, key, unauthorize))
307
- status = true
308
- }
309
- }
310
-
311
- // if authorized[key] is an object
312
- else if (typeof authorized[key] === "object") {
313
- console.log('authorized[key] is an object', authorized[key])
314
- } else
315
- delete data[key]
316
-
317
- // if key status is false for unauthorized case
318
- if (!keyStatus || keyStatus && unauthorize) {
319
- if (!data.unauthorized || !data.unauthorized[method])
320
- data.unauthorized = { [method]: { [key]: [data[key]] } }
321
- else if (!data.unauthorized[method][key])
322
- 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]
323
274
  else
324
- data.unauthorized[method][key].push(data[key])
325
- } else
326
- status = true
327
- return status
328
- }
275
+ data.$filter.query.push(query)
329
276
 
330
- async function checkArray(authorized, data, key, unauthorize) {
331
- let keyStatus = false
332
- let authorizedValue = getValueFromObject(authorized, key);
333
- let dataValue = getValueFromObject(data, key);
334
-
335
- if (!authorizedValue && !unauthorize) {
336
- data = deleteKey(data, key)
337
- } else if (typeof dataValue == "string") {
338
- if (unauthorize && authorizedValue.includes(dataValue))
339
- data = deleteKey(data, key)
340
- else {
341
- if (!authorizedValue.includes(dataValue))
342
- data = deleteKey(data, key)
343
- else
344
- keyStatus = true
345
- }
346
- } else if (Array.isArray(dataValue)) {
347
- for (let i = 0; i < dataValue.length; i++) {
348
- keyStatus = await checkArray(authorized, data, `${key}[${i}]`, unauthorize)
349
- }
350
- } else if (typeof dataValue === "object") {
351
- let checkKeys = true
352
- if (dataValue['_id']) {
353
- if (authorized.object.includes(dataValue['_id']))
354
- checkKeys = true
355
- }
356
- if (checkKeys) {
357
- if (authorizedValue['*'] || authorizedValue['*'] == '')
358
- keyStatus = true
359
- else
360
- for (const k of Object.keys(dataValue)) {
361
- keyStatus = await checkArray(authorized, data, `${key}.${k}`, unauthorize)
362
- }
363
- }
277
+ } else {
278
+ // TODO: sanitize data by removing items user does not have access to.
279
+ // console.log('key is a query operator', key)
364
280
  }
365
-
366
- return keyStatus
281
+ return true
367
282
  }
368
283
 
369
284
  async function checkFilter(authorized, data, apikey, unauthorize) {
@@ -388,6 +303,7 @@
388
303
  }
389
304
  }
390
305
 
306
+
391
307
  function deleteKey(data, path) {
392
308
  if (!data || !path) return
393
309
  if (path.includes('._id'))