diff --git a/packages/server/src/middleware/currentapp.ts b/packages/server/src/middleware/currentapp.ts index e13982a624..4b11b933af 100644 --- a/packages/server/src/middleware/currentapp.ts +++ b/packages/server/src/middleware/currentapp.ts @@ -15,109 +15,106 @@ import { UserCtx, ContextUser } from "@budibase/types" import tracer from "dd-trace" export default async (ctx: UserCtx, next: any) => { - return tracer.trace("currentapp middleware", {}, async span => { - // try to get the appID from the request - let requestAppId = await utils.getAppIdFromCtx(ctx) - if (!requestAppId) { - return next() - } + // try to get the appID from the request + let requestAppId = await utils.getAppIdFromCtx(ctx) + if (!requestAppId) { + return next() + } - if (requestAppId) { - span?.addTags({ app_id: requestAppId }) - } + if (requestAppId) { + const span = tracer.scope().active() + span?.addTags({ app_id: requestAppId }) + } - // deny access to application preview - if (!env.isTest()) { - if ( - isDevAppID(requestAppId) && - !isWebhookEndpoint(ctx) && - !users.isBuilder(ctx.user, requestAppId) - ) { - return ctx.redirect("/") - } - } - - let appId: string | undefined, - roleId = roles.BUILTIN_ROLE_IDS.PUBLIC - if (!ctx.user?._id) { - // not logged in, try to set a cookie for public apps - appId = requestAppId - } else if (requestAppId != null) { - // Different App ID means cookie needs reset, or if the same public user has logged in - const globalUser = await getCachedSelf(ctx, requestAppId) - appId = requestAppId - // retrieving global user gets the right role - roleId = globalUser.roleId || roleId - - // Allow builders to specify their role via a header - const isBuilder = users.isBuilder(globalUser, appId) - const isDevApp = appId && isDevAppID(appId) - const roleHeader = - ctx.request && - (ctx.request.headers[constants.Header.PREVIEW_ROLE] as string) - if (isBuilder && isDevApp && roleHeader) { - // Ensure the role is valid by ensuring a definition exists - try { - if (roleHeader) { - await roles.getRole(roleHeader) - roleId = roleHeader - - // Delete admin and builder flags so that the specified role is honoured - ctx.user = users.removePortalUserPermissions( - ctx.user - ) as ContextUser - } - } catch (error) { - // Swallow error and do nothing - } - } - } - - // nothing more to do - if (!appId) { - return next() - } - - const userId = ctx.user ? generateUserMetadataID(ctx.user._id!) : undefined - - // if the user is not in the right tenant then make sure to wipe their cookie - // also cleanse any information about them that has been allocated - // this avoids apps making calls to say the worker which are cross tenant, - // we simply remove the authentication + // deny access to application preview + if (!env.isTest()) { if ( - env.MULTI_TENANCY && - userId && - requestAppId && - !tenancy.isUserInAppTenant(requestAppId, ctx.user) + isDevAppID(requestAppId) && + !isWebhookEndpoint(ctx) && + !users.isBuilder(ctx.user, requestAppId) ) { - // clear out the user - ctx.user = users.cleanseUserObject(ctx.user) as ContextUser - ctx.isAuthenticated = false - roleId = roles.BUILTIN_ROLE_IDS.PUBLIC - // remove the cookie, so future calls are public - await auth.platformLogout({ - ctx, + return ctx.redirect("/") + } + } + + let appId: string | undefined, + roleId = roles.BUILTIN_ROLE_IDS.PUBLIC + if (!ctx.user?._id) { + // not logged in, try to set a cookie for public apps + appId = requestAppId + } else if (requestAppId != null) { + // Different App ID means cookie needs reset, or if the same public user has logged in + const globalUser = await getCachedSelf(ctx, requestAppId) + appId = requestAppId + // retrieving global user gets the right role + roleId = globalUser.roleId || roleId + + // Allow builders to specify their role via a header + const isBuilder = users.isBuilder(globalUser, appId) + const isDevApp = appId && isDevAppID(appId) + const roleHeader = + ctx.request && + (ctx.request.headers[constants.Header.PREVIEW_ROLE] as string) + if (isBuilder && isDevApp && roleHeader) { + // Ensure the role is valid by ensuring a definition exists + try { + if (roleHeader) { + await roles.getRole(roleHeader) + roleId = roleHeader + + // Delete admin and builder flags so that the specified role is honoured + ctx.user = users.removePortalUserPermissions(ctx.user) as ContextUser + } + } catch (error) { + // Swallow error and do nothing + } + } + } + + // nothing more to do + if (!appId) { + return next() + } + + const userId = ctx.user ? generateUserMetadataID(ctx.user._id!) : undefined + + // if the user is not in the right tenant then make sure to wipe their cookie + // also cleanse any information about them that has been allocated + // this avoids apps making calls to say the worker which are cross tenant, + // we simply remove the authentication + if ( + env.MULTI_TENANCY && + userId && + requestAppId && + !tenancy.isUserInAppTenant(requestAppId, ctx.user) + ) { + // clear out the user + ctx.user = users.cleanseUserObject(ctx.user) as ContextUser + ctx.isAuthenticated = false + roleId = roles.BUILTIN_ROLE_IDS.PUBLIC + // remove the cookie, so future calls are public + await auth.platformLogout({ + ctx, + userId, + }) + } + + return context.doInAppContext(appId, async () => { + ctx.appId = appId + if (roleId) { + ctx.roleId = roleId + const globalId = ctx.user ? ctx.user._id : undefined + ctx.user = { + ...ctx.user!, + // override userID with metadata one + _id: userId, userId, - }) + globalId, + roleId, + role: await roles.getRole(roleId, { defaultPublic: true }), + } } - return context.doInAppContext(appId, async () => { - ctx.appId = appId - if (roleId) { - ctx.roleId = roleId - const globalId = ctx.user ? ctx.user._id : undefined - ctx.user = { - ...ctx.user!, - // override userID with metadata one - _id: userId, - userId, - globalId, - roleId, - role: await roles.getRole(roleId, { defaultPublic: true }), - } - } - - return next() - }) + return next() }) } diff --git a/packages/server/src/utilities/rowProcessor/utils.ts b/packages/server/src/utilities/rowProcessor/utils.ts index d0072053b8..cafd366cae 100644 --- a/packages/server/src/utilities/rowProcessor/utils.ts +++ b/packages/server/src/utilities/rowProcessor/utils.ts @@ -52,7 +52,8 @@ export function processFormulas( { dynamic, contextRows }: FormulaOpts = { dynamic: true } ): T { return tracer.trace("processFormulas", {}, span => { - span?.addTags({ table_id: table._id }) + const numRows = Array.isArray(inputRows) ? inputRows.length : 1 + span?.addTags({ table_id: table._id, dynamic, numRows }) const rows = Array.isArray(inputRows) ? inputRows : [inputRows] if (rows) { for (let [column, schema] of Object.entries(table.schema)) { @@ -77,7 +78,7 @@ export function processFormulas( rows[i] = { ...row, [column]: tracer.trace("processStringSync", {}, span => { - span?.addTags({ column }) + span?.addTags({ table_id: table._id, column, static: isStatic }) return processStringSync(formula, context) }), }