New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@live-change/access-control-service

Package Overview
Dependencies
Maintainers
1
Versions
267
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@live-change/access-control-service - npm Package Compare versions

Comparing version 0.2.39 to 0.2.40

accessControlParents.js

293

access.js

@@ -0,31 +1,284 @@

const { parents, parentsSourcesMap } = require('./accessControlParents.js')
const App = require('@live-change/framework')
const app = App.app()
module.exports = (definition) => {
const Access = definition.foreignModel('access-control', 'Access')
const PublicAccess = definition.foreignModel('access-control', 'PublicAccess')
const Access = definition.foreignModel('accessControl', 'Access')
const PublicAccess = definition.foreignModel('accessControl', 'PublicAccess')
function clientHasAnyAccess(client, { objectType, object }) {
/// TODO: access control
return true
const config = definition?.config?.access ?? {}
const {
hasAny = (roles, client, { objectType, object }) => roles.length > 0,
isAdmin = (roles, client, { objectType, object }) => roles.includes('administrator'),
canInvite = (roles, client, { objectType, object }) => roles.length > 0,
canRequest = (roles, client, { objectType, object }) => false
} = config
async function clientHasAnyAccess(client, { objectType, object, objects }) {
return checkRoles(client, { objectType, object, objects }, hasAny)
}
function clientHasAdminAccess(client, { objectType, object }) {
/// TODO: access control
return true
function clientHasAdminAccess(client, { objectType, object, objects }) {
return checkRoles(client, { objectType, object, objects }, isAdmin)
}
function clientCanInvite(client, { roles, objectType, object }) {
/// TODO: access control
return true
function clientCanInvite(client, { objectType, object, objects }) {
return checkRoles(client, { objectType, object, objects }, canInvite, true)
}
function clientCanRequest(client, { roles, objectType, object }) {
/// TODO: access control
return true
function clientCanRequest(client, { objectType, object, objects }) {
return checkRoles(client, { objectType, object, objects }, canRequest)
}
function clientHasAccessRole(client, { objectType, object }, role) {
return true
function clientHasAccessRole(client, { objectType, object, objects }, role) {
return checkRoles(client, { objectType, object, objects }, (roles) => roles.includes(role) )
}
function clientHasAccessRoles(client, { objectType, object, objects }, roles) {
return checkRoles(client, { objectType, object, objects },
(clientRoles) => roles.every(role => clientRoles.includes(role))
)
}
async function getUnitClientRoles(client, { objectType, object }, ignorePublic) {
const [ sessionOrUserType, sessionOrUser ] = client.user ? ['user_User', client.user] : ['session_Session']
const [
publicAccessData,
sessionAccess,
userAccess,
] = await Promise.all([
ignorePublic ? null : PublicAccess.get(App.encodeIdentifier([ objectType, object ])),
Access.get(App.encodeIdentifier([ 'session_Session', client.session, objectType, object ])),
client.user
? Access.get(App.encodeIdentifier([ 'user_User', client.user, objectType, object ]))
: Promise.resolve(null)
])
let roles = []
if(publicAccessData) {
roles.push(...publicAccessData.sessionRoles)
if(client.user) roles.push(...publicAccessData.userRoles)
}
if(sessionAccess) roles.push(...sessionAccess.roles)
if(userAccess) roles.push(...userAccess.roles)
return Array.from(new Set(roles))
}
async function getClientObjectRoles(client, { objectType, object }, ignorePublic) {
const unitRolesPromise = getUnitClientRoles(client, { objectType, object}, ignorePublic)
const accessParentsPromise = parents[objectType]
? parents[objectType]({ objectType, object })
: Promise.resolve([])
const parentRolesPromise = accessParentsPromise.then(accessParents => Promise.all(
accessParents.map(
({ objectType, object }) =>
getClientObjectRoles(client, { objectType, object }, ignorePublic)
)
).then(rolesArrays => rolesArrays.flat()))
const [ unitRoles, parentRoles ] = await Promise.all([ unitRolesPromise, parentRolesPromise ])
return Array.from(new Set([ ...client.roles, ...unitRoles, ...parentRoles]))
}
async function getClientObjectsRoles(client, objects, ignorePublic) {
const objectsRoles = await Promise.all(objects.map(obj => getClientObjectRoles(client, obj, ignorePublic)))
const firstObjectRoles = objectsRoles.shift()
let roles = firstObjectRoles
for(const objectRoles of objectsRoles) {
roles = roles.filter(role => objectRoles.includes(role))
}
return roles
}
async function checkRoles(client, { objectType, object, objects }, callback, ignorePublic) {
const allObjects = ((objectType && object) ? [{ objectType, object }] : []).concat(objects || [])
const roles = await getClientObjectsRoles(client, allObjects, ignorePublic)
return await callback(roles, client, { objectType, object })
}
/// QUERIES:
function dbAccessFunctions({ input, publicAccessTable, accessTable, updateRoles, isLoaded }) {
async function treeNode(objectType, object) {
const node = {
objectType, object,
data: null,
parents: [],
publicSessionRoles: [],
publicUserRoles: [],
sessionRoles: [],
userRoles: []
}
let objectObserver, publicAccessObserver, sessionAccessObserver, userAccessObserver
const publicAccessObject = publicAccessTable.object(`${JSON.stringify(objectType)}:${JSON.stringify(object)}`)
publicAccessObserver = publicAccessObject.onChange((accessData, oldAccessData) => {
node.publicSessionRoles = accessData?.sessionRoles ?? []
node.publicUserRoles = (client.user && accessData?.userRoles) ?? []
if(isLoaded()) updateRoles()
})
const sessionAccessObject = accessTable.object(
`session_Session:${JSON.stringify(client.session)}:${JSON.stringify(objectType)}:${JSON.stringify(object)}`
)
sessionAccessObserver = sessionAccessObject && sessionAccessObject.onChange((accessData, oldAccessData) => {
node.sessionRoles = accessData?.roles ?? []
if(isLoaded()) updateRoles()
})
const userAccessObject = client.user && accessTable.object(
`user_User:${JSON.stringify(client.user)}:${JSON.stringify(objectType)}:${JSON.stringify(object)}`
)
userAccessObserver = userAccessObject && userAccessObject.onChange((accessData, oldAccessData) => {
node.sessionRoles = accessData?.roles ?? []
if(isLoaded()) updateRoles()
})
async function disposeParents() {
const oldParents = node.parents
return Promise.all(oldParents.map(parent => parent.dispose()))
}
const parentsSources = parentsSourcesMap[objectType]
if(parentsSources) {
const objectTable = input.table(objectType)
const objectTableObject = objectTable.object(object)
objectObserver = objectTableObject.onChange(async (objectData, oldObjectData) => {
await disposeParents()
node.parents = objectData ? await Promise.all(parentsSources.map(parentSource => {
const parentType = parentSource.type || objectData[parentSource.property + 'Type']
const parent = objectData[parentSource.property]
return treeNode(parentType, parent)
})) : []
})
}
node.dispose = async function() {
const disposePromises = []
if(objectObserver) disposePromises.push(objectObserver.then(obs => obs.dispose()))
if(publicAccessObserver) disposePromises.push(publicAccessObserver.then(obs => obs.dispose()))
if(sessionAccessObserver) disposePromises.push(sessionAccessObserver.then(obs => obs.dispose()))
if(userAccessObserver) disposePromises.push(userAccessObserver.then(obs => obs.dispose()))
disposePromises.push(disposeParents())
return Promise.all(disposePromises)
}
await Promise.all([ objectObserver, publicAccessObserver, sessionAccessObserver, userAccessObserver ])
return node
}
function computeNodeRoles(node) {
const parentsRoles = node.parents.map(parent => computeNodeRoles(parent)).flat()
return Array.from(new Set([
...parentsRoles,
...node.publicUserRoles,
...node.publicSessionRoles,
...node.userRoles,
...node.sessionRoles
]))
}
return { treeNode, computeNodeRoles }
}
function accessPath(client, objects) {
return ['database', 'queryObject', app.databaseName, `(${
async (input, output, {
objects, parentsSourcesMap, client,
accessTableName, publicAccessTableName, dbAccessFunctions
}) => {
const accessTable = input.table(accessTableName)
const publicAccessTable = input.table(publicAccessTableName)
let loaded = false
const { treeNode, computeNodeRoles } =
eval(dbAccessFunctions)({ input, publicAccessTable, accessTable, updateRoles, isLoaded: () => loaded })
let rolesTreesRoots = objects.map(({ object, objectType }) => treeNode(objectType, object))
const outputObjectId = `${JSON.stringify(client.session)}:${JSON.stringify(client.user)}:` +
objects.map( obj => `${JSON.stringify(objectType)}:${JSON.stringify(object)}`)
.join(':')
let oldOutputObject = null
async function updateRoles() {
const roots = await Promise.all(rolesTreesRoots)
const accesses = roots.map(root => computeNodeRoles(root))
const firstAccess = accesses.shift()
let roles = firstAccess.roles
for(const access of accesses) {
roles = roles.filter(role => access.roles.includes(role))
}
const accessControlRoles = computeNodeRoles()
const outputObject = {
id: outputObjectId,
roles: Array.from(new Set([...accessControlRoles, ...client.roles]))
}
output.change(outputObject, oldOutputObject)
oldOutputObject = outputObject
}
await Promise.all(rolesTreesRoots)
loaded = true
await updateRoles()
}
})`, {
objectType, object, parentsSourcesMap, client,
accessTableName: Access.tableName, publicAccessTableName: PublicAccess.tableName,
dbAccessFunctions: `(${dbAccessFunctions})`
}]
}
function accessesPath(client, objects) {
return ['database', 'query', app.databaseName, `(${
async (input, output, {
objects, parentsSourcesMap, client,
accessTableName, publicAccessTableName, dbAccessFunctions
}) => {
const accessTable = input.table(accessTableName)
const publicAccessTable = input.table(publicAccessTableName)
let loaded = false
const { treeNode, computeNodeRoles } =
eval(dbAccessFunctions)({ input, publicAccessTable, accessTable, updateRoles, isLoaded: () => loaded })
let rolesTreesRoots = objects.map(({ object, objectType }) => treeNode(objectType, object))
const accesses = []
async function updateRoles() {
const roots = await Promise.all(rolesTreesRoots)
for(let root of roots) {
const outputObjectId = `${JSON.stringify(client.session)}:${JSON.stringify(client.user)}` +
`:${JSON.stringify(root.objectType)}:${JSON.stringify(root.object)}`
const nodeRoles = computeNodeRoles(root)
const outputObject = {
id: outputObjectId,
roles: Array.from(new Set([...nodeRoles, ...client.roles]))
}
const existingAccessIndex = accesses.findIndex(acc => acc.id == outputObjectId)
if(existingAccessIndex != -1) {
if(JSON.stringify(outputObject) != JSON.stringify(accesses[existingAccessIndex])) {
output.change(outputObject, accesses[existingAccessIndex])
accesses[existingAccessIndex] = outputObject
} /// else ignore
} else {
output.change(outputObject, null)
accesses.push(outputObject)
}
}
}
await Promise.all(rolesTreesRoots)
loaded = true
await updateRoles()
}
})`, {
objects, parentsSourcesMap, client,
accessTableName: Access.tableName, publicAccessTableName: PublicAccess.tableName,
}]
}
function accessLimitedGet(client, objects, requiredRoles, path) {
const roles = getClientObjectsRoles(client, objects)
for(const requiredRole of requiredRoles) {
}
}
function accessLimitedObservable(client, objects, path) {
if(path[0] != 'database') throw new Error("non database path "+ JSON.stringify(path))
const isObject = path[1] == 'queryObject' || path[1] == ''
}
return {

@@ -35,5 +288,11 @@ clientHasAnyAccess, clientHasAdminAccess,

clientCanRequest,
clientHasAccessRole
clientHasAccessRole,
clientHasAccessRoles,
getClientObjectRoles,
getClientObjectsRoles,
checkRoles,
accessPath,
accessesPath
}
}

@@ -8,3 +8,4 @@ const app = require("@live-change/framework").app()

require('./request.js')
require('./view.js')
module.exports = definition

@@ -224,2 +224,10 @@ const App = require("@live-change/framework")

async execute(params, { client, service }, emit) {
const { roles } = params
const myRoles = await access.getClientObjectRoles(client, { objectType, object }, true)
if(!myRoles.includes('administrator')) {
for(const requestedRole of roles) {
if(!myRoles.includes(requestedRole)) throw 'notAuthorized'
}
}
const [ fromType, from ] = client.user ? ['user_User', client.user] : ['session_Session', client.session]

@@ -226,0 +234,0 @@ const { [contactTypeName]: contact } = params

2

model.js

@@ -42,3 +42,3 @@ const App = require("@live-change/framework")

visibilityTest || access.clientHasAnyAccess(client, params),
writeAccess: (params, { client, context, visibilityTest }) =>
writeAccess: async (params, { client, context, visibilityTest }) =>
visibilityTest || access.clientHasAdminAccess(client, params)

@@ -45,0 +45,0 @@ },

{
"name": "@live-change/access-control-service",
"version": "0.2.39",
"version": "0.2.40",
"description": "",

@@ -24,5 +24,5 @@ "main": "index.js",

"dependencies": {
"@live-change/framework": "0.6.5"
"@live-change/framework": "0.6.6"
},
"gitHead": "09bd3c0c5e1991360c8f13c30b29ccca8f3158ea"
"gitHead": "4a920b328b0a7f3f25c67cdba3e574687971ee22"
}

@@ -46,2 +46,8 @@ const App = require("@live-change/framework")

async execute({ objectType, object, sessionOrUserType, sessionOrUser, roles }, { client, service }, emit) {
const myRoles = await access.getClientObjectRoles(client, { objectType, object }, true)
if(!myRoles.includes('administrator')) {
for(const requestedRole of roles) {
if(!myRoles.includes(requestedRole)) throw 'notAuthorized'
}
}
const request = App.encodeIdentifier([ sessionOrUserType, sessionOrUser, objectType, object ])

@@ -48,0 +54,0 @@ const requestData = await AccessRequest.get(request)

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc