From a2667c6d72fdd6b2a6774d6cafc77926ea394a68 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 4 Aug 2023 15:43:02 +0100 Subject: [PATCH] Removing the ability to set roles, builder and admin structure through basic public API. --- .../api/controllers/public/applications.ts | 18 ++++---- .../src/api/controllers/public/queries.ts | 6 ++- .../server/src/api/controllers/public/rows.ts | 13 +++--- .../src/api/controllers/public/tables.ts | 13 +++--- .../src/api/controllers/public/users.ts | 44 ++++++++++++------- packages/server/src/utilities/users.ts | 17 ++----- 6 files changed, 60 insertions(+), 51 deletions(-) diff --git a/packages/server/src/api/controllers/public/applications.ts b/packages/server/src/api/controllers/public/applications.ts index c4041bedcf..fd72db95d3 100644 --- a/packages/server/src/api/controllers/public/applications.ts +++ b/packages/server/src/api/controllers/public/applications.ts @@ -3,6 +3,8 @@ import { search as stringSearch, addRev } from "./utils" import * as controller from "../application" import * as deployController from "../deploy" import { Application } from "../../../definitions/common" +import { UserCtx } from "@budibase/types" +import { Next } from "koa" function fixAppID(app: Application, params: any) { if (!params) { @@ -14,7 +16,7 @@ function fixAppID(app: Application, params: any) { return app } -async function setResponseApp(ctx: any) { +async function setResponseApp(ctx: UserCtx) { const appId = ctx.body?.appId if (appId && (!ctx.params || !ctx.params.appId)) { ctx.params = { appId } @@ -28,14 +30,14 @@ async function setResponseApp(ctx: any) { } } -export async function search(ctx: any, next: any) { +export async function search(ctx: UserCtx, next: Next) { const { name } = ctx.request.body const apps = await dbCore.getAllApps({ all: true }) ctx.body = stringSearch(apps, name) await next() } -export async function create(ctx: any, next: any) { +export async function create(ctx: UserCtx, next: Next) { if (!ctx.request.body || !ctx.request.body.useTemplate) { ctx.request.body = { useTemplate: false, @@ -47,14 +49,14 @@ export async function create(ctx: any, next: any) { await next() } -export async function read(ctx: any, next: any) { +export async function read(ctx: UserCtx, next: Next) { await context.doInAppContext(ctx.params.appId, async () => { await setResponseApp(ctx) await next() }) } -export async function update(ctx: any, next: any) { +export async function update(ctx: UserCtx, next: Next) { ctx.request.body = await addRev(fixAppID(ctx.request.body, ctx.params)) await context.doInAppContext(ctx.params.appId, async () => { await controller.update(ctx) @@ -63,7 +65,7 @@ export async function update(ctx: any, next: any) { }) } -export async function destroy(ctx: any, next: any) { +export async function destroy(ctx: UserCtx, next: Next) { await context.doInAppContext(ctx.params.appId, async () => { // get the app before deleting it await setResponseApp(ctx) @@ -75,14 +77,14 @@ export async function destroy(ctx: any, next: any) { }) } -export async function unpublish(ctx: any, next: any) { +export async function unpublish(ctx: UserCtx, next: Next) { await context.doInAppContext(ctx.params.appId, async () => { await controller.unpublish(ctx) await next() }) } -export async function publish(ctx: any, next: any) { +export async function publish(ctx: UserCtx, next: Next) { await context.doInAppContext(ctx.params.appId, async () => { await deployController.publishApp(ctx) await next() diff --git a/packages/server/src/api/controllers/public/queries.ts b/packages/server/src/api/controllers/public/queries.ts index 57ec608379..3cb1ab3812 100644 --- a/packages/server/src/api/controllers/public/queries.ts +++ b/packages/server/src/api/controllers/public/queries.ts @@ -1,14 +1,16 @@ import { search as stringSearch } from "./utils" import * as queryController from "../query" +import { UserCtx } from "@budibase/types" +import { Next } from "koa" -export async function search(ctx: any, next: any) { +export async function search(ctx: UserCtx, next: Next) { await queryController.fetch(ctx) const { name } = ctx.request.body ctx.body = stringSearch(ctx.body, name) await next() } -export async function execute(ctx: any, next: any) { +export async function execute(ctx: UserCtx, next: Next) { // don't wrap this, already returns "data" await queryController.executeV2(ctx) await next() diff --git a/packages/server/src/api/controllers/public/rows.ts b/packages/server/src/api/controllers/public/rows.ts index 39cf85a2a3..16403b06c9 100644 --- a/packages/server/src/api/controllers/public/rows.ts +++ b/packages/server/src/api/controllers/public/rows.ts @@ -1,7 +1,8 @@ import * as rowController from "../row" import { addRev } from "./utils" -import { Row } from "@budibase/types" +import { Row, UserCtx } from "@budibase/types" import { convertBookmark } from "../../../utilities" +import { Next } from "koa" // makes sure that the user doesn't need to pass in the type, tableId or _id params for // the call to be correct @@ -21,7 +22,7 @@ export function fixRow(row: Row, params: any) { return row } -export async function search(ctx: any, next: any) { +export async function search(ctx: UserCtx, next: Next) { let { sort, paginate, bookmark, limit, query } = ctx.request.body // update the body to the correct format of the internal search if (!sort) { @@ -40,25 +41,25 @@ export async function search(ctx: any, next: any) { await next() } -export async function create(ctx: any, next: any) { +export async function create(ctx: UserCtx, next: Next) { ctx.request.body = fixRow(ctx.request.body, ctx.params) await rowController.save(ctx) await next() } -export async function read(ctx: any, next: any) { +export async function read(ctx: UserCtx, next: Next) { await rowController.fetchEnrichedRow(ctx) await next() } -export async function update(ctx: any, next: any) { +export async function update(ctx: UserCtx, next: Next) { const { tableId } = ctx.params ctx.request.body = await addRev(fixRow(ctx.request.body, ctx.params), tableId) await rowController.save(ctx) await next() } -export async function destroy(ctx: any, next: any) { +export async function destroy(ctx: UserCtx, next: Next) { const { tableId } = ctx.params // set the body as expected, with the _id and _rev fields ctx.request.body = await addRev( diff --git a/packages/server/src/api/controllers/public/tables.ts b/packages/server/src/api/controllers/public/tables.ts index a346a750da..7486172fa3 100644 --- a/packages/server/src/api/controllers/public/tables.ts +++ b/packages/server/src/api/controllers/public/tables.ts @@ -1,6 +1,7 @@ import { search as stringSearch, addRev } from "./utils" import * as controller from "../table" -import { Table } from "@budibase/types" +import { Table, UserCtx } from "@budibase/types" +import { Next } from "koa" function fixTable(table: Table, params: any) { if (!params || !table) { @@ -15,24 +16,24 @@ function fixTable(table: Table, params: any) { return table } -export async function search(ctx: any, next: any) { +export async function search(ctx: UserCtx, next: Next) { const { name } = ctx.request.body await controller.fetch(ctx) ctx.body = stringSearch(ctx.body, name) await next() } -export async function create(ctx: any, next: any) { +export async function create(ctx: UserCtx, next: Next) { await controller.save(ctx) await next() } -export async function read(ctx: any, next: any) { +export async function read(ctx: UserCtx, next: Next) { await controller.find(ctx) await next() } -export async function update(ctx: any, next: any) { +export async function update(ctx: UserCtx, next: Next) { ctx.request.body = await addRev( fixTable(ctx.request.body, ctx.params), ctx.params.tableId @@ -41,7 +42,7 @@ export async function update(ctx: any, next: any) { await next() } -export async function destroy(ctx: any, next: any) { +export async function destroy(ctx: UserCtx, next: Next) { await controller.destroy(ctx) ctx.body = ctx.table await next() diff --git a/packages/server/src/api/controllers/public/users.ts b/packages/server/src/api/controllers/public/users.ts index 7192077d04..7aaf520dc4 100644 --- a/packages/server/src/api/controllers/public/users.ts +++ b/packages/server/src/api/controllers/public/users.ts @@ -7,16 +7,32 @@ import { import { publicApiUserFix } from "../../../utilities/users" import { db as dbCore } from "@budibase/backend-core" import { search as stringSearch } from "./utils" -import { BBContext, User } from "@budibase/types" +import { UserCtx, User } from "@budibase/types" +import { Next } from "koa" -function isLoggedInUser(ctx: BBContext, user: User) { +function removeRoles(ctx: UserCtx, oldUser?: User) { + const user = ctx.request.body + if (user.builder) { + user.builder = oldUser?.builder || undefined + } + if (user.admin) { + user.admin = oldUser?.admin || undefined + } + if (user.roles) { + user.roles = oldUser?.roles || {} + } + ctx.request.body = user + return ctx +} + +function isLoggedInUser(ctx: UserCtx, user: User) { const loggedInId = ctx.user?._id const globalUserId = dbCore.getGlobalIDFromUserMetadataID(loggedInId!) // check both just incase return globalUserId === user._id || loggedInId === user._id } -function getUser(ctx: BBContext, userId?: string) { +function getUser(ctx: UserCtx, userId?: string) { if (userId) { ctx.params = { userId } } else if (!ctx.params?.userId) { @@ -25,42 +41,38 @@ function getUser(ctx: BBContext, userId?: string) { return readGlobalUser(ctx) } -export async function search(ctx: BBContext, next: any) { +export async function search(ctx: UserCtx, next: Next) { const { name } = ctx.request.body const users = await allGlobalUsers(ctx) ctx.body = stringSearch(users, name, "email") await next() } -export async function create(ctx: BBContext, next: any) { - const response = await saveGlobalUser(publicApiUserFix(ctx)) +export async function create(ctx: UserCtx, next: Next) { + ctx = publicApiUserFix(removeRoles(ctx)) + const response = await saveGlobalUser(ctx) ctx.body = await getUser(ctx, response._id) await next() } -export async function read(ctx: BBContext, next: any) { +export async function read(ctx: UserCtx, next: Next) { ctx.body = await readGlobalUser(ctx) await next() } -export async function update(ctx: BBContext, next: any) { +export async function update(ctx: UserCtx, next: Next) { const user = await readGlobalUser(ctx) ctx.request.body = { ...ctx.request.body, _rev: user._rev, } - // disallow updating your own role - always overwrite with DB roles - if (isLoggedInUser(ctx, user)) { - ctx.request.body.builder = user.builder - ctx.request.body.admin = user.admin - ctx.request.body.roles = user.roles - } - const response = await saveGlobalUser(publicApiUserFix(ctx)) + ctx = publicApiUserFix(removeRoles(ctx, user)) + const response = await saveGlobalUser(ctx) ctx.body = await getUser(ctx, response._id) await next() } -export async function destroy(ctx: BBContext, next: any) { +export async function destroy(ctx: UserCtx, next: Next) { const user = await getUser(ctx) // disallow deleting yourself if (isLoggedInUser(ctx, user)) { diff --git a/packages/server/src/utilities/users.ts b/packages/server/src/utilities/users.ts index 1498a79719..f841ec3646 100644 --- a/packages/server/src/utilities/users.ts +++ b/packages/server/src/utilities/users.ts @@ -1,9 +1,9 @@ import { InternalTables } from "../db/utils" import { getGlobalUser } from "./global" -import { context, db as dbCore, roles } from "@budibase/backend-core" -import { BBContext } from "@budibase/types" +import { context, roles } from "@budibase/backend-core" +import { UserCtx } from "@budibase/types" -export async function getFullUser(ctx: BBContext, userId: string) { +export async function getFullUser(ctx: UserCtx, userId: string) { const global = await getGlobalUser(userId) let metadata: any = {} @@ -29,21 +29,12 @@ export async function getFullUser(ctx: BBContext, userId: string) { } } -export function publicApiUserFix(ctx: BBContext) { +export function publicApiUserFix(ctx: UserCtx) { if (!ctx.request.body) { return ctx } if (!ctx.request.body._id && ctx.params.userId) { ctx.request.body._id = ctx.params.userId } - if (!ctx.request.body.roles) { - ctx.request.body.roles = {} - } else { - const newRoles: { [key: string]: any } = {} - for (let [appId, role] of Object.entries(ctx.request.body.roles)) { - newRoles[dbCore.getProdAppID(appId)] = role - } - ctx.request.body.roles = newRoles - } return ctx }