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
|
|
|
}
|