budibase/packages/server/src/sdk/app/permissions/index.ts

116 lines
2.8 KiB
TypeScript
Raw Normal View History

2023-08-31 10:36:17 +02:00
import { context, roles } from "@budibase/backend-core"
import { features } from "@budibase/pro"
2023-08-21 16:56:40 +02:00
import {
DocumentType,
PermissionLevel,
2023-08-31 13:01:17 +02:00
Role,
2023-08-21 16:56:40 +02:00
VirtualDocumentType,
} from "@budibase/types"
2023-08-31 13:01:17 +02:00
import {
extractViewInfoFromID,
getRoleParams,
isViewID,
} from "../../../db/utils"
2023-08-31 10:36:17 +02:00
import {
CURRENTLY_SUPPORTED_LEVELS,
getBasePermissions,
} from "../../../utilities/security"
2023-08-21 16:56:40 +02:00
type ResourceActionAllowedResult =
| { allowed: true }
| {
allowed: false
level: PermissionLevel
resourceType: DocumentType | VirtualDocumentType
}
export async function resourceActionAllowed({
resourceId,
level,
}: {
resourceId: string
level: PermissionLevel
}): Promise<ResourceActionAllowedResult> {
if (!isViewID(resourceId)) {
return { allowed: true }
}
2023-08-22 10:27:06 +02:00
if (await features.isViewPermissionEnabled()) {
return { allowed: true }
}
2023-08-21 16:56:40 +02:00
return {
allowed: false,
level,
resourceType: VirtualDocumentType.VIEW,
}
}
2023-08-31 10:36:17 +02:00
2023-09-01 09:50:55 +02:00
enum PermissionSource {
EXPLICIT = "EXPLICIT",
INHERITED = "INHERITED",
BASE = "BASE",
2023-09-01 09:40:29 +02:00
}
2023-08-31 13:01:17 +02:00
type ResourcePermissions = Record<
string,
2023-09-01 09:50:55 +02:00
{ role: string; type: PermissionSource }
2023-08-31 13:01:17 +02:00
>
2023-09-01 09:50:55 +02:00
export async function getInheritablePermissions(
resourceId: string
): Promise<ResourcePermissions | undefined> {
if (isViewID(resourceId) && (await features.isViewPermissionEnabled())) {
return await getResourcePerms(extractViewInfoFromID(resourceId).tableId)
}
}
2023-08-31 13:01:17 +02:00
export async function getResourcePerms(
resourceId: string
): Promise<ResourcePermissions> {
2023-08-31 10:36:17 +02:00
const db = context.getAppDB()
const body = await db.allDocs(
getRoleParams(null, {
include_docs: true,
})
)
2023-08-31 13:01:17 +02:00
const rolesList = body.rows.map<Role>(row => row.doc)
2023-09-01 09:40:29 +02:00
let permissions: ResourcePermissions = {}
2023-08-31 13:01:17 +02:00
2023-09-01 09:50:55 +02:00
const permsToInherit = await getInheritablePermissions(resourceId)
2023-08-31 13:01:17 +02:00
2023-08-31 10:36:17 +02:00
for (let level of CURRENTLY_SUPPORTED_LEVELS) {
// update the various roleIds in the resource permissions
for (let role of rolesList) {
const rolePerms = roles.checkForRoleResourceArray(
role.permissions,
resourceId
)
2023-08-31 13:01:17 +02:00
if (rolePerms[resourceId]?.indexOf(level) > -1) {
permissions[level] = {
role: roles.getExternalRoleID(role._id!, role.version),
2023-09-01 09:50:55 +02:00
type: PermissionSource.EXPLICIT,
2023-08-31 13:01:17 +02:00
}
2023-09-01 10:52:06 +02:00
} else if (
!permissions[level] &&
permsToInherit &&
permsToInherit[level]
) {
2023-08-31 13:01:17 +02:00
permissions[level] = {
2023-09-01 09:40:29 +02:00
role: permsToInherit[level].role,
2023-09-01 09:50:55 +02:00
type: PermissionSource.INHERITED,
2023-08-31 13:01:17 +02:00
}
2023-08-31 10:36:17 +02:00
}
}
}
2023-08-31 13:01:17 +02:00
const basePermissions = Object.entries(
getBasePermissions(resourceId)
).reduce<ResourcePermissions>((p, [level, role]) => {
2023-09-01 09:50:55 +02:00
p[level] = { role, type: PermissionSource.BASE }
2023-08-31 13:01:17 +02:00
return p
}, {})
const result = Object.assign(basePermissions, permissions)
return result
2023-08-31 10:36:17 +02:00
}