budibase/packages/server/src/middleware/authorized.js

88 lines
2.3 KiB
JavaScript
Raw Normal View History

const { getUserPermissions } = require("@budibase/auth/roles")
const {
PermissionTypes,
doesHaveResourcePermission,
doesHaveBasePermission,
} = require("@budibase/auth/permissions")
const { APP_DEV_PREFIX } = require("../db/utils")
2021-05-12 18:37:09 +02:00
const { doesUserHaveLock, updateLock } = require("../utilities/redis")
function hasResource(ctx) {
return ctx.resourceId != null
}
const WEBHOOK_ENDPOINTS = new RegExp(
["webhooks/trigger", "webhooks/schema"].join("|")
)
2020-10-12 12:57:37 +02:00
2021-05-12 18:37:09 +02:00
async function checkDevAppLocks(ctx) {
const appId = ctx.appId
2021-05-20 21:48:24 +02:00
// if any public usage, don't proceed
if (!ctx.user._id && !ctx.user.userId) {
return
}
2021-05-12 18:37:09 +02:00
// not a development app, don't need to do anything
if (!appId || !appId.startsWith(APP_DEV_PREFIX)) {
2021-05-12 18:37:09 +02:00
return
}
if (!(await doesUserHaveLock(appId, ctx.user))) {
2021-05-12 18:37:09 +02:00
ctx.throw(403, "User does not hold app lock.")
}
// they do have lock, update it
await updateLock(appId, ctx.user)
2021-05-12 18:37:09 +02:00
}
module.exports = (permType, permLevel = null) => async (ctx, next) => {
// webhooks don't need authentication, each webhook unique
if (WEBHOOK_ENDPOINTS.test(ctx.request.url)) {
return next()
2020-10-12 12:57:37 +02:00
}
2020-06-18 17:59:31 +02:00
if (!ctx.user) {
2021-03-09 12:27:12 +01:00
return ctx.throw(403, "No user info found")
2020-06-18 17:59:31 +02:00
}
2021-05-12 18:37:09 +02:00
const builderCall = permType === PermissionTypes.BUILDER
const referer = ctx.headers["referer"]
const editingApp = referer ? referer.includes(ctx.appId) : false
2021-05-12 18:37:09 +02:00
// this makes sure that builder calls abide by dev locks
if (builderCall && editingApp) {
2021-05-12 18:37:09 +02:00
await checkDevAppLocks(ctx)
}
const isAuthed = ctx.isAuthenticated
const { basePermissions, permissions } = await getUserPermissions(
ctx.appId,
ctx.roleId
)
2020-05-27 18:23:01 +02:00
// builders for now have permission to do anything
// TODO: in future should consider separating permissions with an require("@budibase/auth").isClient check
let isBuilder = ctx.user && ctx.user.builder && ctx.user.builder.global
if (isBuilder) {
2021-04-12 12:20:01 +02:00
return next()
2021-05-12 18:37:09 +02:00
} else if (builderCall && !isBuilder) {
2021-04-12 12:20:01 +02:00
return ctx.throw(403, "Not Authorized")
}
2020-05-27 18:23:01 +02:00
if (
hasResource(ctx) &&
doesHaveResourcePermission(permissions, permLevel, ctx)
) {
return next()
}
if (!isAuthed) {
ctx.throw(403, "Session not authenticated")
}
if (!doesHaveBasePermission(permType, permLevel, basePermissions)) {
ctx.throw(403, "User does not have permission")
}
2020-05-27 18:23:01 +02:00
return next()
2020-05-27 18:23:01 +02:00
}