Merge pull request #14565 from Budibase/fix/role-permission-update

Fixing role API validator (for saving)
This commit is contained in:
Michael Drury 2024-09-12 14:25:57 +01:00 committed by GitHub
commit d756c54ea4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 30 additions and 18 deletions

View File

@ -44,7 +44,7 @@ export class Role implements RoleDoc {
permissionId: string permissionId: string
inherits?: string inherits?: string
version?: string version?: string
permissions = {} permissions: Record<string, PermissionLevel[]> = {}
constructor(id: string, name: string, permissionId: string) { constructor(id: string, name: string, permissionId: string) {
this._id = id this._id = id
@ -244,9 +244,9 @@ export async function getUserRoleHierarchy(
// some templates/older apps will use a simple string instead of array for roles // some templates/older apps will use a simple string instead of array for roles
// convert the string to an array using the theory that write is higher than read // convert the string to an array using the theory that write is higher than read
export function checkForRoleResourceArray( export function checkForRoleResourceArray(
rolePerms: { [key: string]: string[] }, rolePerms: Record<string, PermissionLevel[]>,
resourceId: string resourceId: string
) { ): Record<string, PermissionLevel[]> {
if (rolePerms && !Array.isArray(rolePerms[resourceId])) { if (rolePerms && !Array.isArray(rolePerms[resourceId])) {
const permLevel = rolePerms[resourceId] as any const permLevel = rolePerms[resourceId] as any
rolePerms[resourceId] = [permLevel] rolePerms[resourceId] = [permLevel]

View File

@ -75,7 +75,9 @@ async function updatePermissionOnRole(
// resource from another role and then adding to the new role // resource from another role and then adding to the new role
for (let role of dbRoles) { for (let role of dbRoles) {
let updated = false let updated = false
const rolePermissions = role.permissions ? role.permissions : {} const rolePermissions: Record<string, PermissionLevel[]> = role.permissions
? role.permissions
: {}
// make sure its an array, also handle migrating // make sure its an array, also handle migrating
if ( if (
!rolePermissions[resourceId] || !rolePermissions[resourceId] ||
@ -83,7 +85,7 @@ async function updatePermissionOnRole(
) { ) {
rolePermissions[resourceId] = rolePermissions[resourceId] =
typeof rolePermissions[resourceId] === "string" typeof rolePermissions[resourceId] === "string"
? [rolePermissions[resourceId] as unknown as string] ? [rolePermissions[resourceId] as unknown as PermissionLevel]
: [] : []
} }
// handle the removal/updating the role which has this permission first // handle the removal/updating the role which has this permission first

View File

@ -17,7 +17,7 @@ import {
SaveRoleResponse, SaveRoleResponse,
UserCtx, UserCtx,
UserMetadata, UserMetadata,
UserRoles, DocumentType,
} from "@budibase/types" } from "@budibase/types"
import { sdk as sharedSdk } from "@budibase/shared-core" import { sdk as sharedSdk } from "@budibase/shared-core"
import sdk from "../../sdk" import sdk from "../../sdk"
@ -80,17 +80,21 @@ export async function save(ctx: UserCtx<SaveRoleRequest, SaveRoleResponse>) {
_id = dbCore.prefixRoleID(_id) _id = dbCore.prefixRoleID(_id)
} }
let dbRole let dbRole: Role | undefined
if (!isCreate) { if (!isCreate && _id?.startsWith(DocumentType.ROLE)) {
dbRole = await db.get<UserRoles>(_id) dbRole = await db.get<Role>(_id)
} }
if (dbRole && dbRole.name !== name && isNewVersion) { if (dbRole && dbRole.name !== name && isNewVersion) {
ctx.throw(400, "Cannot change custom role name") ctx.throw(400, "Cannot change custom role name")
} }
const role = new roles.Role(_id, name, permissionId).addInheritance(inherits) const role = new roles.Role(_id, name, permissionId).addInheritance(inherits)
if (ctx.request.body._rev) { if (dbRole?.permissions && !role.permissions) {
role._rev = ctx.request.body._rev role.permissions = dbRole.permissions
}
const foundRev = ctx.request.body._rev || dbRole?._rev
if (foundRev) {
role._rev = foundRev
} }
const result = await db.put(role) const result = await db.put(role)
if (isCreate) { if (isCreate) {

View File

@ -200,7 +200,7 @@ export function webhookValidator() {
export function roleValidator() { export function roleValidator() {
const permLevelArray = Object.values(permissions.PermissionLevel) const permLevelArray = Object.values(permissions.PermissionLevel)
const permissionString = Joi.string().valid(...permLevelArray)
return auth.joiValidator.body( return auth.joiValidator.body(
Joi.object({ Joi.object({
_id: OPTIONAL_STRING, _id: OPTIONAL_STRING,
@ -213,7 +213,13 @@ export function roleValidator() {
.valid(...Object.values(permissions.BuiltinPermissionID)) .valid(...Object.values(permissions.BuiltinPermissionID))
.required(), .required(),
permissions: Joi.object() permissions: Joi.object()
.pattern(/.*/, [Joi.string().valid(...permLevelArray)]) .pattern(
/.*/,
Joi.alternatives().try(
Joi.array().items(permissionString),
permissionString
)
)
.optional(), .optional(),
inherits: OPTIONAL_STRING, inherits: OPTIONAL_STRING,
}).unknown(true) }).unknown(true)

View File

@ -90,7 +90,7 @@ export async function getResourcePerms(
const rolePerms = allowsExplicitPerm const rolePerms = allowsExplicitPerm
? roles.checkForRoleResourceArray(role.permissions || {}, resourceId) ? roles.checkForRoleResourceArray(role.permissions || {}, resourceId)
: {} : {}
if (rolePerms[resourceId]?.indexOf(level) > -1) { if (rolePerms[resourceId]?.indexOf(level as PermissionLevel) > -1) {
permissions[level] = { permissions[level] = {
role: roles.getExternalRoleID(role._id!, role.version), role: roles.getExternalRoleID(role._id!, role.version),
type: PermissionSource.EXPLICIT, type: PermissionSource.EXPLICIT,

View File

@ -1,9 +1,10 @@
import { Document } from "../document" import { Document } from "../document"
import { PermissionLevel } from "../../sdk"
export interface Role extends Document { export interface Role extends Document {
permissionId: string permissionId: string
inherits?: string inherits?: string
permissions: { [key: string]: string[] } permissions: Record<string, PermissionLevel[]>
version?: string version?: string
name: string name: string
} }

View File

@ -74,9 +74,8 @@ export enum UserStatus {
INACTIVE = "inactive", INACTIVE = "inactive",
} }
export interface UserRoles { // specifies a map of app ID to role ID
[key: string]: string export type UserRoles = Record<string, string>
}
// UTILITY TYPES // UTILITY TYPES