@live-change/access-control-service 0.2.40 → 0.2.43

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/access.js CHANGED
@@ -1,4 +1,4 @@
1
- const { parents, parentsSourcesMap } = require('./accessControlParents.js')
1
+ const { parents, parentsSources } = require('./accessControlParents.js')
2
2
  const App = require('@live-change/framework')
3
3
  const app = App.app()
4
4
 
@@ -16,6 +16,16 @@ module.exports = (definition) => {
16
16
  canRequest = (roles, client, { objectType, object }) => false
17
17
  } = config
18
18
 
19
+ function testRoles(requiredRoles, clientRoles) {
20
+ for(const requiredRolesOption of requiredRoles) {
21
+ if(
22
+ (Array.isArray(requiredRolesOption) ? requiredRolesOption : [requiredRolesOption])
23
+ .every(role => clientRoles.includes(role))
24
+ ) return true
25
+ }
26
+ return false
27
+ }
28
+
19
29
  async function clientHasAnyAccess(client, { objectType, object, objects }) {
20
30
  return checkRoles(client, { objectType, object, objects }, hasAny)
21
31
  }
@@ -38,7 +48,7 @@ module.exports = (definition) => {
38
48
 
39
49
  function clientHasAccessRoles(client, { objectType, object, objects }, roles) {
40
50
  return checkRoles(client, { objectType, object, objects },
41
- (clientRoles) => roles.every(role => clientRoles.includes(role))
51
+ (clientRoles) => testRoles(requiredRoles, roles)
42
52
  )
43
53
  }
44
54
 
@@ -98,7 +108,10 @@ module.exports = (definition) => {
98
108
 
99
109
  /// QUERIES:
100
110
 
101
- function dbAccessFunctions({ input, publicAccessTable, accessTable, updateRoles, isLoaded }) {
111
+ function dbAccessFunctions({
112
+ input, publicAccessTable, accessTable, updateRoles, isLoaded,
113
+ client, parentsSourcesMap, output
114
+ }) {
102
115
  async function treeNode(objectType, object) {
103
116
  const node = {
104
117
  objectType, object,
@@ -119,7 +132,7 @@ module.exports = (definition) => {
119
132
  })
120
133
 
121
134
  const sessionAccessObject = accessTable.object(
122
- `session_Session:${JSON.stringify(client.session)}:${JSON.stringify(objectType)}:${JSON.stringify(object)}`
135
+ `"session_Session":${JSON.stringify(client.session)}:${JSON.stringify(objectType)}:${JSON.stringify(object)}`
123
136
  )
124
137
  sessionAccessObserver = sessionAccessObject && sessionAccessObject.onChange((accessData, oldAccessData) => {
125
138
  node.sessionRoles = accessData?.roles ?? []
@@ -127,10 +140,10 @@ module.exports = (definition) => {
127
140
  })
128
141
 
129
142
  const userAccessObject = client.user && accessTable.object(
130
- `user_User:${JSON.stringify(client.user)}:${JSON.stringify(objectType)}:${JSON.stringify(object)}`
143
+ `"user_User":${JSON.stringify(client.user)}:${JSON.stringify(objectType)}:${JSON.stringify(object)}`
131
144
  )
132
145
  userAccessObserver = userAccessObject && userAccessObject.onChange((accessData, oldAccessData) => {
133
- node.sessionRoles = accessData?.roles ?? []
146
+ node.userRoles = accessData?.roles ?? []
134
147
  if(isLoaded()) updateRoles()
135
148
  })
136
149
 
@@ -187,9 +200,12 @@ module.exports = (definition) => {
187
200
  let loaded = false
188
201
 
189
202
  const { treeNode, computeNodeRoles } =
190
- eval(dbAccessFunctions)({ input, publicAccessTable, accessTable, updateRoles, isLoaded: () => loaded })
203
+ eval(dbAccessFunctions)({
204
+ input, publicAccessTable, accessTable, updateRoles, isLoaded: () => loaded,
205
+ client, parentsSourcesMap, output
206
+ })
191
207
 
192
- let rolesTreesRoots = objects.map(({ object, objectType }) => treeNode(objectType, object))
208
+ let rolesTreesRoots = objects.map(({ object, objectType }) => treeNode(objectType, object, client))
193
209
 
194
210
  const outputObjectId = `${JSON.stringify(client.session)}:${JSON.stringify(client.user)}:` +
195
211
  objects.map( obj => `${JSON.stringify(objectType)}:${JSON.stringify(object)}`)
@@ -216,7 +232,7 @@ module.exports = (definition) => {
216
232
  await updateRoles()
217
233
  }
218
234
  })`, {
219
- objectType, object, parentsSourcesMap, client,
235
+ objectType, object, parentsSourcesMap: parentsSources, client,
220
236
  accessTableName: Access.tableName, publicAccessTableName: PublicAccess.tableName,
221
237
  dbAccessFunctions: `(${dbAccessFunctions})`
222
238
  }]
@@ -233,9 +249,12 @@ module.exports = (definition) => {
233
249
  let loaded = false
234
250
 
235
251
  const { treeNode, computeNodeRoles } =
236
- eval(dbAccessFunctions)({ input, publicAccessTable, accessTable, updateRoles, isLoaded: () => loaded })
252
+ eval(dbAccessFunctions)({
253
+ input, publicAccessTable, accessTable, updateRoles, isLoaded: () => loaded,
254
+ client, parentsSourcesMap, output,
255
+ })
237
256
 
238
- let rolesTreesRoots = objects.map(({ object, objectType }) => treeNode(objectType, object))
257
+ let rolesTreesRoots = objects.map(({ object, objectType }) => treeNode(objectType, object, client))
239
258
  const accesses = []
240
259
  async function updateRoles() {
241
260
  const roots = await Promise.all(rolesTreesRoots)
@@ -264,8 +283,9 @@ module.exports = (definition) => {
264
283
  await updateRoles()
265
284
  }
266
285
  })`, {
267
- objects, parentsSourcesMap, client,
286
+ objects, parentsSourcesMap: parentsSources, client,
268
287
  accessTableName: Access.tableName, publicAccessTableName: PublicAccess.tableName,
288
+ dbAccessFunctions: `(${dbAccessFunctions})`
269
289
  }]
270
290
  }
271
291
 
@@ -282,6 +302,7 @@ module.exports = (definition) => {
282
302
  }
283
303
 
284
304
  return {
305
+ testRoles,
285
306
  clientHasAnyAccess, clientHasAdminAccess,
286
307
  clientCanInvite,
287
308
  clientCanRequest,
@@ -0,0 +1,110 @@
1
+ const definition = require('./definition.js')
2
+ const App = require("@live-change/framework")
3
+ const { ObservableValue, ObservableList, ObservableProxy } = require("@live-change/dao")
4
+ const app = App.app()
5
+ const access = require('./access.js')(definition)
6
+
7
+ definition.processor({
8
+ priority: -1,
9
+ process(service, app) {
10
+
11
+ for(const actionName in service.actions) {
12
+ const action = service.actions[actionName]
13
+ if(!action.accessControl) continue
14
+ const config = action.accessControl
15
+
16
+ console.log("ACCESS CONTROL", service.name, "ACTION", action.name)
17
+
18
+ const oldExec = action.execute
19
+ action.execute = async (...args) => {
20
+ const [ properties, context, emit ] = args
21
+ const { client } = context
22
+
23
+ const objects = [].concat(
24
+ config.objects ? config.objects(properties) : [],
25
+ (objectType && object) ? [{ objectType, object }] : []
26
+ )
27
+ if(objects.length == 0) {
28
+ throw new Error('no objects for access control to work')
29
+ }
30
+ const accessible = access.clientHasAccessRoles(client, { objects }, config.roles)
31
+ if(!accessible) throw 'notAuthorized'
32
+
33
+ return oldExec.apply(action, args)
34
+ }
35
+ }
36
+
37
+ for(const viewName in service.views) {
38
+ const view = service.views[viewName]
39
+ if(!view.accessControl) continue
40
+ const config = view.accessControl
41
+
42
+ console.log("ACCESS CONTROL", service.name, "VIEW", view.name)
43
+
44
+ const oldGet = view.get
45
+ const oldObservable = view.observable
46
+ view.get = async (...args) => {
47
+ const [ properties, context ] = args
48
+ const { client } = context
49
+ const { objectType, object } = properties
50
+ const objects = [].concat(
51
+ config.objects ? config.objects(properties) : [],
52
+ (objectType && object) ? [{ objectType, object }] : []
53
+ )
54
+ if(objects.length == 0) {
55
+ throw new Error('no objects for access control to work')
56
+ }
57
+ const accessible = access.clientHasAccessRoles(client, { objects }, config.roles)
58
+ if(!accessible) throw 'notAuthorized'
59
+ return oldGet.apply(view, args)
60
+ }
61
+ view.observable = (...args) => {
62
+ const [ properties, context ] = args
63
+ const { client } = context
64
+ const { objectType, object } = properties
65
+ const objects = [].concat(
66
+ config.objects ? config.objects(properties) : [],
67
+ (objectType && object) ? [{ objectType, object }] : []
68
+ )
69
+ if(objects.length == 0) {
70
+ throw new Error('no objects for access control to work')
71
+ }
72
+
73
+ const rolesPath = access.accessPath(client, objects)
74
+
75
+ const errorObservable = new ObservableValue()
76
+ errorObservable.handleError('notAuthorized')
77
+
78
+ const observableProxy = new ObservableProxy(null)
79
+
80
+ let valueObservable
81
+
82
+ let accessible
83
+ const rolesObservable = app.dao.observable(rolesPath)
84
+ const rolesObserver = (signal, value) => {
85
+ const accessObject = rolesObservable.getValue()
86
+ const newAccessible = access.testRoles(config.roles, accessObject.roles)
87
+ if(newAccessible !== accessible) {
88
+ if(newAccessible === true /*&& !valueObservable*/) {
89
+ valueObservable = oldObservable.apply(view, args)
90
+ }
91
+ observableProxy.setTarget(accessible ? valueObservable : errorObservable)
92
+ }
93
+ }
94
+ rolesObservable.observe(rolesObserver)
95
+
96
+ const oldDispose = observableProxy.dispose
97
+ const oldRespawn = observableProxy.respawn
98
+ observableProxy.dispose = () => {
99
+ rolesObservable.unobserve(rolesObserver)
100
+ oldDispose.apply(observableProxy)
101
+ }
102
+ observableProxy.respawn = () => {
103
+ rolesObservable.observe(rolesObserver)
104
+ oldRespawn.apply(observableProxy)
105
+ }
106
+ }
107
+ }
108
+
109
+ }
110
+ })
package/index.js CHANGED
@@ -6,5 +6,6 @@ require('./model.js')
6
6
  require('./invite.js')
7
7
  require('./request.js')
8
8
  require('./view.js')
9
+ require('./accessControl.js')
9
10
 
10
11
  module.exports = definition
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/access-control-service",
3
- "version": "0.2.40",
3
+ "version": "0.2.43",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,7 +21,7 @@
21
21
  "url": "https://www.viamage.com/"
22
22
  },
23
23
  "dependencies": {
24
- "@live-change/framework": "0.6.6"
24
+ "@live-change/framework": "0.6.10"
25
25
  },
26
- "gitHead": "4a920b328b0a7f3f25c67cdba3e574687971ee22"
26
+ "gitHead": "8db9a604d14d85f750056ce9c3b7bb859aface27"
27
27
  }
package/limitedAccess.js DELETED
@@ -1,107 +0,0 @@
1
- const definition = require('./definition.js')
2
- const App = require("@live-change/framework")
3
- const { ObservableValue, ObservableList, ObservableProxy } = require("@live-change/dao")
4
- const app = App.app()
5
- const access = require('./access.js')(definition)
6
-
7
- definition.processor(function(service, app) {
8
-
9
- for(const actionName in service.actions) {
10
- const action = service.actions[actionName]
11
- if(!action.limitedAccess) continue
12
- const config = action.limitedAccess
13
-
14
- console.log("LIMITED ACCESS", service.name, "ACTION", action.name)
15
-
16
- const oldExec = action.execute
17
- action.execute = async (...args) => {
18
- const [ properties, context, emit ] = args
19
- const { client } = context
20
-
21
- const objects = [].concat(
22
- config.objects ? config.objects(properties) : [],
23
- (objectType && object) ? [{ objectType, object }] : []
24
- )
25
- if(objects.length == 0) {
26
- throw new Error('no objects for access control to work')
27
- }
28
- const accessible = access.clientHasAccessRoles(client, { objects }, config.roles)
29
- if(!accessible) throw 'notAuthorized'
30
-
31
- return oldExec.apply(action, args)
32
- }
33
- }
34
-
35
- for(const viewName in service.views) {
36
- const view = service.view[viewName]
37
- if(!view.limitedAccess) continue
38
- const config = view.limitedAccess
39
-
40
- console.log("LIMITED ACCESS", service.name, "VIEW", view.name)
41
-
42
- const oldGet = view.get
43
- const oldObservable = view.observable
44
- view.get = async (...args) => {
45
- const [ properties, context ] = args
46
- const { client } = context
47
- const { objectType, object } = properties
48
- const objects = [].concat(
49
- config.objects ? config.objects(properties) : [],
50
- (objectType && object) ? [{ objectType, object }] : []
51
- )
52
- if(objects.length == 0) {
53
- throw new Error('no objects for access control to work')
54
- }
55
- const accessible = access.clientHasAccessRoles(client, { objects }, config.roles)
56
- if(!accessible) throw 'notAuthorized'
57
- return oldGet.apply(view, args)
58
- }
59
- view.observable = (...args) => {
60
- const [ properties, context ] = args
61
- const { client } = context
62
- const { objectType, object } = properties
63
- const objects = [].concat(
64
- config.objects ? config.objects(properties) : [],
65
- (objectType && object) ? [{ objectType, object }] : []
66
- )
67
- if(objects.length == 0) {
68
- throw new Error('no objects for access control to work')
69
- }
70
-
71
- const rolesPath = access.accessPath(client, objects)
72
-
73
- const errorObservable = new ObservableValue()
74
- errorObservable.handleError('notAuthorized')
75
-
76
- const observableProxy = new ObservableProxy(null)
77
-
78
- let valueObservable
79
-
80
- let accessible
81
- const rolesObservable = app.dao.observable(rolesPath)
82
- const rolesObserver = (signal, value) => {
83
- const accessObject = rolesObservable.getValue()
84
- const newAccessible = config.roles.every(role => accessObject.roles.includes(role))
85
- if(newAccessible !== accessible) {
86
- if(newAccessible === true /*&& !valueObservable*/) {
87
- valueObservable = oldObservable.apply(view, args)
88
- }
89
- observableProxy.setTarget(accessible ? valueObservable : errorObservable)
90
- }
91
- }
92
- rolesObservable.observe(rolesObserver)
93
-
94
- const oldDispose = observableProxy.dispose
95
- const oldRespawn = observableProxy.respawn
96
- observableProxy.dispose = () => {
97
- rolesObservable.unobserve(rolesObserver)
98
- oldDispose.apply(observableProxy)
99
- }
100
- observableProxy.respawn = () => {
101
- rolesObservable.observe(rolesObserver)
102
- oldRespawn.apply(observableProxy)
103
- }
104
- }
105
- }
106
-
107
- })