2021-04-12 19:31:58 +02:00
|
|
|
const { getUserPermissions } = require("../utilities/security/roles")
|
2020-11-12 18:06:55 +01:00
|
|
|
const {
|
|
|
|
PermissionTypes,
|
2021-02-08 18:52:22 +01:00
|
|
|
doesHaveResourcePermission,
|
|
|
|
doesHaveBasePermission,
|
2020-11-12 18:06:55 +01:00
|
|
|
} = require("../utilities/security/permissions")
|
2021-05-12 18:37:09 +02:00
|
|
|
const { APP_DEV_PREFIX, getGlobalIDFromUserMetadataID } = require("../db/utils")
|
|
|
|
const { doesUserHaveLock, updateLock } = require("../utilities/redis")
|
2020-11-11 18:34:15 +01:00
|
|
|
|
2021-02-08 18:52:22 +01:00
|
|
|
function hasResource(ctx) {
|
|
|
|
return ctx.resourceId != null
|
|
|
|
}
|
|
|
|
|
2021-04-12 19:31:58 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
// not a development app, don't need to do anything
|
|
|
|
if (!appId.startsWith(APP_DEV_PREFIX)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// get the user which is currently using the dev app
|
|
|
|
const userId = getGlobalIDFromUserMetadataID(ctx.user._id)
|
|
|
|
if (!await doesUserHaveLock(appId, userId)) {
|
|
|
|
ctx.throw(403, "User does not hold app lock.")
|
|
|
|
}
|
|
|
|
|
|
|
|
// they do have lock, update it
|
|
|
|
await updateLock(appId, userId)
|
|
|
|
}
|
|
|
|
|
2021-04-12 19:31:58 +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
|
2021-03-22 17:39:11 +01:00
|
|
|
|
2021-05-12 18:37:09 +02:00
|
|
|
// this makes sure that builder calls abide by dev locks
|
|
|
|
if (builderCall) {
|
|
|
|
await checkDevAppLocks(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
const isAuthed = ctx.isAuthenticated
|
2021-02-08 18:52:22 +01:00
|
|
|
const { basePermissions, permissions } = await getUserPermissions(
|
|
|
|
ctx.appId,
|
2021-04-12 19:31:58 +02:00
|
|
|
ctx.roleId
|
2021-02-08 18:52:22 +01:00
|
|
|
)
|
2020-05-27 18:23:01 +02:00
|
|
|
|
2021-04-14 17:00:58 +02:00
|
|
|
// builders for now have permission to do anything
|
|
|
|
// TODO: in future should consider separating permissions with an require("@budibase/auth").isClient check
|
2021-04-13 19:12:35 +02:00
|
|
|
let isBuilder = ctx.user && ctx.user.builder && ctx.user.builder.global
|
2021-04-14 17:00:58 +02:00
|
|
|
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
|
|
|
|
2021-02-09 17:01:02 +01:00
|
|
|
if (
|
|
|
|
hasResource(ctx) &&
|
|
|
|
doesHaveResourcePermission(permissions, permLevel, ctx)
|
|
|
|
) {
|
|
|
|
return next()
|
|
|
|
}
|
2021-02-08 18:52:22 +01:00
|
|
|
|
2021-02-09 18:24:36 +01:00
|
|
|
if (!isAuthed) {
|
|
|
|
ctx.throw(403, "Session not authenticated")
|
|
|
|
}
|
|
|
|
|
2021-02-08 18:52:22 +01:00
|
|
|
if (!doesHaveBasePermission(permType, permLevel, basePermissions)) {
|
2020-11-12 18:06:55 +01:00
|
|
|
ctx.throw(403, "User does not have permission")
|
|
|
|
}
|
2020-05-27 18:23:01 +02:00
|
|
|
|
2020-11-12 18:06:55 +01:00
|
|
|
return next()
|
2020-05-27 18:23:01 +02:00
|
|
|
}
|