@ -1,9 +1,4 @@
const {
const { getBuiltinPermissions } = require ( "@budibase/auth/permissions" )
getBuiltinPermissions ,
PermissionLevels ,
isPermissionLevelHigherThanRead ,
higherPermission ,
} = require ( "@budibase/auth/permissions" )
const {
const {
isBuiltin ,
isBuiltin ,
getDBRoleID ,
getDBRoleID ,
@ -16,6 +11,7 @@ const {
CURRENTLY_SUPPORTED_LEVELS ,
CURRENTLY_SUPPORTED_LEVELS ,
getBasePermissions ,
getBasePermissions ,
} = require ( "../../utilities/security" )
} = require ( "../../utilities/security" )
const { removeFromArray } = require ( "../../utilities" )
const PermissionUpdateType = {
const PermissionUpdateType = {
REMOVE : "remove" ,
REMOVE : "remove" ,
@ -24,22 +20,6 @@ const PermissionUpdateType = {
const SUPPORTED_LEVELS = CURRENTLY_SUPPORTED_LEVELS
const SUPPORTED_LEVELS = CURRENTLY_SUPPORTED_LEVELS
// quick function to perform a bit of weird logic, make sure fetch calls
// always say a write role also has read permission
function fetchLevelPerms ( permissions , level , roleId ) {
if ( ! permissions ) {
permissions = { }
}
permissions [ level ] = roleId
if (
isPermissionLevelHigherThanRead ( level ) &&
! permissions [ PermissionLevels . READ ]
) {
permissions [ PermissionLevels . READ ] = roleId
}
return permissions
}
// utility function to stop this repetition - permissions always stored under roles
// utility function to stop this repetition - permissions always stored under roles
async function getAllDBRoles ( db ) {
async function getAllDBRoles ( db ) {
const body = await db . allDocs (
const body = await db . allDocs (
@ -74,23 +54,31 @@ async function updatePermissionOnRole(
for ( let role of dbRoles ) {
for ( let role of dbRoles ) {
let updated = false
let updated = false
const rolePermissions = role . permissions ? role . permissions : { }
const rolePermissions = role . permissions ? role . permissions : { }
// make sure its an array, also handle migrating
if (
! rolePermissions [ resourceId ] ||
! Array . isArray ( rolePermissions [ resourceId ] )
) {
rolePermissions [ resourceId ] =
typeof rolePermissions [ resourceId ] === "string"
? [ rolePermissions [ resourceId ] ]
: [ ]
}
// handle the removal/updating the role which has this permission first
// handle the removal/updating the role which has this permission first
// the updating (role._id !== dbRoleId) is required because a resource/level can
// the updating (role._id !== dbRoleId) is required because a resource/level can
// only be permitted in a single role (this reduces hierarchy confusion and simplifies
// only be permitted in a single role (this reduces hierarchy confusion and simplifies
// the general UI for this, rather than needing to show everywhere it is used)
// the general UI for this, rather than needing to show everywhere it is used)
if (
if (
( role . _ id !== dbRoleId || remove ) &&
( role . _ id !== dbRoleId || remove ) &&
rolePermissions [ resourceId ] === level
rolePermissions [ resourceId ] . indexOf ( level ) !== - 1
) {
) {
delete rolePermissions [ resourceId ]
removeFromArray ( rolePermissions [ resourceId ] , level )
updated = true
updated = true
}
}
// handle the adding, we're on the correct role, at it to this
// handle the adding, we're on the correct role, at it to this
if ( ! remove && role . _ id === dbRoleId ) {
if ( ! remove && role . _ id === dbRoleId ) {
rolePermissions [ resourceId ] = higherPermission (
const set = new Set ( rolePermissions [ resourceId ] )
rolePermissions [ resourceId ] ,
rolePermissions [ resourceId ] = [ ... set . add ( level ) ]
level
)
updated = true
updated = true
}
}
// handle the update, add it to bulk docs to perform at end
// handle the update, add it to bulk docs to perform at end
@ -127,12 +115,11 @@ exports.fetch = async function (ctx) {
continue
continue
}
}
const roleId = getExternalRoleID ( role . _ id )
const roleId = getExternalRoleID ( role . _ id )
for ( let [ resource , level ] of Object . entries ( role . permissions ) ) {
for ( let [ resource , levelArr ] of Object . entries ( role . permissions ) ) {
permissions [ resource ] = fetchLevelPerms (
const levels = Array . isArray ( levelArr ) ? [ levelArr ] : levelArr
permissions [ resource ] ,
const perms = { }
level ,
levels . forEach ( level => ( perms [ level ] = roleId ) )
roleId
permissions [ resource ] = perms
)
}
}
}
}
// apply the base permissions
// apply the base permissions
@ -157,12 +144,13 @@ exports.getResourcePerms = async function (ctx) {
for ( let level of SUPPORTED_LEVELS ) {
for ( let level of SUPPORTED_LEVELS ) {
// update the various roleIds in the resource permissions
// update the various roleIds in the resource permissions
for ( let role of roles ) {
for ( let role of roles ) {
if ( role . permissions && role . permissions [ resourceId ] === level ) {
const rolePerms = role . permissions
permissions = fetchLevelPerms (
if (
permissions ,
rolePerms &&
level ,
( rolePerms [ resourceId ] === level ||
getExternalRoleID ( role . _ id )
rolePerms [ resourceId ] . indexOf ( level ) !== - 1 )
)
) {
permissions [ level ] = getExternalRoleID ( role . _ id )
}
}
}
}
}
}