Moving user admin/builder functions to shared-core for frontend to use.
This commit is contained in:
parent
91847504c8
commit
85dea47a31
|
@ -22,6 +22,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/nano": "10.1.2",
|
"@budibase/nano": "10.1.2",
|
||||||
"@budibase/pouchdb-replication-stream": "1.2.10",
|
"@budibase/pouchdb-replication-stream": "1.2.10",
|
||||||
|
"@budibase/shared-core": "0.0.0",
|
||||||
"@budibase/types": "0.0.0",
|
"@budibase/types": "0.0.0",
|
||||||
"@shopify/jest-koa-mocks": "5.0.1",
|
"@shopify/jest-koa-mocks": "5.0.1",
|
||||||
"@techpass/passport-openidconnect": "0.3.2",
|
"@techpass/passport-openidconnect": "0.3.2",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export const SEPARATOR = "_"
|
import { prefixed, DocumentType } from "@budibase/types"
|
||||||
export const UNICODE_MAX = "\ufff0"
|
export { SEPARATOR, UNICODE_MAX, DocumentType } from "@budibase/types"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can be used to create a few different forms of querying a view.
|
* Can be used to create a few different forms of querying a view.
|
||||||
|
@ -34,42 +34,6 @@ export enum InternalTable {
|
||||||
USER_METADATA = "ta_users",
|
USER_METADATA = "ta_users",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DocumentType {
|
|
||||||
USER = "us",
|
|
||||||
GROUP = "gr",
|
|
||||||
WORKSPACE = "workspace",
|
|
||||||
CONFIG = "config",
|
|
||||||
TEMPLATE = "template",
|
|
||||||
APP = "app",
|
|
||||||
DEV = "dev",
|
|
||||||
APP_DEV = "app_dev",
|
|
||||||
APP_METADATA = "app_metadata",
|
|
||||||
ROLE = "role",
|
|
||||||
MIGRATIONS = "migrations",
|
|
||||||
DEV_INFO = "devinfo",
|
|
||||||
AUTOMATION_LOG = "log_au",
|
|
||||||
ACCOUNT_METADATA = "acc_metadata",
|
|
||||||
PLUGIN = "plg",
|
|
||||||
DATASOURCE = "datasource",
|
|
||||||
DATASOURCE_PLUS = "datasource_plus",
|
|
||||||
APP_BACKUP = "backup",
|
|
||||||
TABLE = "ta",
|
|
||||||
ROW = "ro",
|
|
||||||
AUTOMATION = "au",
|
|
||||||
LINK = "li",
|
|
||||||
WEBHOOK = "wh",
|
|
||||||
INSTANCE = "inst",
|
|
||||||
LAYOUT = "layout",
|
|
||||||
SCREEN = "screen",
|
|
||||||
QUERY = "query",
|
|
||||||
DEPLOYMENTS = "deployments",
|
|
||||||
METADATA = "metadata",
|
|
||||||
MEM_VIEW = "view",
|
|
||||||
USER_FLAG = "flag",
|
|
||||||
AUTOMATION_METADATA = "meta_au",
|
|
||||||
AUDIT_LOG = "al",
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StaticDatabases = {
|
export const StaticDatabases = {
|
||||||
GLOBAL: {
|
GLOBAL: {
|
||||||
name: "global-db",
|
name: "global-db",
|
||||||
|
@ -93,7 +57,7 @@ export const StaticDatabases = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const APP_PREFIX = DocumentType.APP + SEPARATOR
|
export const APP_PREFIX = prefixed(DocumentType.APP)
|
||||||
export const APP_DEV = DocumentType.APP_DEV + SEPARATOR
|
export const APP_DEV = prefixed(DocumentType.APP_DEV)
|
||||||
export const APP_DEV_PREFIX = APP_DEV
|
export const APP_DEV_PREFIX = APP_DEV
|
||||||
export const BUDIBASE_DATASOURCE_TYPE = "budibase"
|
export const BUDIBASE_DATASOURCE_TYPE = "budibase"
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {
|
||||||
User,
|
User,
|
||||||
ContextUser,
|
ContextUser,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
import { sdk } from "@budibase/shared-core"
|
||||||
import { getGlobalDB } from "./context"
|
import { getGlobalDB } from "./context"
|
||||||
import * as context from "./context"
|
import * as context from "./context"
|
||||||
|
|
||||||
|
@ -38,6 +39,12 @@ function removeUserPassword(users: User | User[]) {
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extract from shared-core to make easily accessible from backend-core
|
||||||
|
export const isBuilder = sdk.users.isBuilder
|
||||||
|
export const isAdmin = sdk.users.isAdmin
|
||||||
|
export const hasAdminPermissions = sdk.users.hasAdminPermissions
|
||||||
|
export const hasBuilderPermissions = sdk.users.hasBuilderPermissions
|
||||||
|
|
||||||
export const bulkGetGlobalUsersById = async (
|
export const bulkGetGlobalUsersById = async (
|
||||||
userIds: string[],
|
userIds: string[],
|
||||||
opts?: GetOpts
|
opts?: GetOpts
|
||||||
|
@ -254,39 +261,6 @@ export async function getUserCount() {
|
||||||
return response.total_rows
|
return response.total_rows
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks if a user is specifically a builder, given an app ID
|
|
||||||
export function isBuilder(user: User | ContextUser, appId?: string) {
|
|
||||||
if (user.builder?.global) {
|
|
||||||
return true
|
|
||||||
} else if (appId && user.builder?.apps?.includes(getProdAppID(appId))) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// alias for hasAdminPermission, currently do the same thing
|
|
||||||
// in future whether someone has admin permissions and whether they are
|
|
||||||
// an admin for a specific resource could be separated
|
|
||||||
export function isAdmin(user: User | ContextUser) {
|
|
||||||
return hasAdminPermissions(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks if a user is capable of building any app
|
|
||||||
export function hasBuilderPermissions(user?: User | ContextUser) {
|
|
||||||
if (!user) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return user.builder?.global || user.builder?.apps?.length !== 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks if a user is capable of being an admin
|
|
||||||
export function hasAdminPermissions(user?: User | ContextUser) {
|
|
||||||
if (!user) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return user.admin?.global
|
|
||||||
}
|
|
||||||
|
|
||||||
// used to remove the builder/admin permissions, for processing the
|
// used to remove the builder/admin permissions, for processing the
|
||||||
// user as an app user (they may have some specific role/group
|
// user as an app user (they may have some specific role/group
|
||||||
export function removePortalUserPermissions(user: User | ContextUser) {
|
export function removePortalUserPermissions(user: User | ContextUser) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ export default async (ctx: UserCtx, next: any) => {
|
||||||
if (
|
if (
|
||||||
isDevAppID(requestAppId) &&
|
isDevAppID(requestAppId) &&
|
||||||
!isWebhookEndpoint(ctx) &&
|
!isWebhookEndpoint(ctx) &&
|
||||||
(!ctx.user || !ctx.user.builder || !ctx.user.builder.global)
|
!users.isBuilder(ctx.user, requestAppId)
|
||||||
) {
|
) {
|
||||||
return ctx.redirect("/")
|
return ctx.redirect("/")
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,6 @@ export default async (ctx: UserCtx, next: any) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.doInAppContext(appId, async () => {
|
return context.doInAppContext(appId, async () => {
|
||||||
let skipCookie = false
|
|
||||||
// if the user not in the right tenant then make sure they have no permissions
|
// if the user not in the right tenant then make sure they have no permissions
|
||||||
// need to judge this only based on the request app ID,
|
// need to judge this only based on the request app ID,
|
||||||
if (
|
if (
|
||||||
|
@ -83,7 +82,6 @@ export default async (ctx: UserCtx, next: any) => {
|
||||||
ctx.user = users.cleanseUserObject(ctx.user) as ContextUser
|
ctx.user = users.cleanseUserObject(ctx.user) as ContextUser
|
||||||
ctx.isAuthenticated = false
|
ctx.isAuthenticated = false
|
||||||
roleId = roles.BUILTIN_ROLE_IDS.PUBLIC
|
roleId = roles.BUILTIN_ROLE_IDS.PUBLIC
|
||||||
skipCookie = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.appId = appId
|
ctx.appId = appId
|
||||||
|
|
|
@ -2,3 +2,4 @@ export * from "./constants"
|
||||||
export * as dataFilters from "./filters"
|
export * as dataFilters from "./filters"
|
||||||
export * as helpers from "./helpers"
|
export * as helpers from "./helpers"
|
||||||
export * as utils from "./utils"
|
export * as utils from "./utils"
|
||||||
|
export * as sdk from "./sdk"
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { DocumentType, prefixed } from "@budibase/types"
|
||||||
|
|
||||||
|
const APP_PREFIX = prefixed(DocumentType.APP)
|
||||||
|
const APP_DEV_PREFIX = prefixed(DocumentType.APP_DEV)
|
||||||
|
|
||||||
|
export function getDevAppID(appId: string) {
|
||||||
|
if (!appId || appId.startsWith(APP_DEV_PREFIX)) {
|
||||||
|
return appId
|
||||||
|
}
|
||||||
|
// split to take off the app_ element, then join it together incase any other app_ exist
|
||||||
|
const split = appId.split(APP_PREFIX)
|
||||||
|
split.shift()
|
||||||
|
const rest = split.join(APP_PREFIX)
|
||||||
|
return `${APP_DEV_PREFIX}${rest}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a development app ID to a deployed app ID.
|
||||||
|
*/
|
||||||
|
export function getProdAppID(appId: string) {
|
||||||
|
if (!appId || !appId.startsWith(APP_DEV_PREFIX)) {
|
||||||
|
return appId
|
||||||
|
}
|
||||||
|
// split to take off the app_dev element, then join it together incase any other app_ exist
|
||||||
|
const split = appId.split(APP_DEV_PREFIX)
|
||||||
|
split.shift()
|
||||||
|
const rest = split.join(APP_DEV_PREFIX)
|
||||||
|
return `${APP_PREFIX}${rest}`
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * as applications from "./applications"
|
||||||
|
export * as users from "./users"
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { ContextUser, User } from "@budibase/types"
|
||||||
|
import { getProdAppID } from "./applications"
|
||||||
|
|
||||||
|
// checks if a user is specifically a builder, given an app ID
|
||||||
|
export function isBuilder(user: User | ContextUser, appId?: string) {
|
||||||
|
if (user.builder?.global) {
|
||||||
|
return true
|
||||||
|
} else if (appId && user.builder?.apps?.includes(getProdAppID(appId))) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// alias for hasAdminPermission, currently do the same thing
|
||||||
|
// in future whether someone has admin permissions and whether they are
|
||||||
|
// an admin for a specific resource could be separated
|
||||||
|
export function isAdmin(user: User | ContextUser) {
|
||||||
|
return hasAdminPermissions(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks if a user is capable of building any app
|
||||||
|
export function hasBuilderPermissions(user?: User | ContextUser) {
|
||||||
|
if (!user) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return user.builder?.global || user.builder?.apps?.length !== 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks if a user is capable of being an admin
|
||||||
|
export function hasAdminPermissions(user?: User | ContextUser) {
|
||||||
|
if (!user) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return user.admin?.global
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./documents"
|
|
@ -1,3 +1,44 @@
|
||||||
|
export const SEPARATOR = "_"
|
||||||
|
export const UNICODE_MAX = "\ufff0"
|
||||||
|
|
||||||
|
export const prefixed = (type: DocumentType) => `${type}${SEPARATOR}`
|
||||||
|
|
||||||
|
export enum DocumentType {
|
||||||
|
USER = "us",
|
||||||
|
GROUP = "gr",
|
||||||
|
WORKSPACE = "workspace",
|
||||||
|
CONFIG = "config",
|
||||||
|
TEMPLATE = "template",
|
||||||
|
APP = "app",
|
||||||
|
DEV = "dev",
|
||||||
|
APP_DEV = "app_dev",
|
||||||
|
APP_METADATA = "app_metadata",
|
||||||
|
ROLE = "role",
|
||||||
|
MIGRATIONS = "migrations",
|
||||||
|
DEV_INFO = "devinfo",
|
||||||
|
AUTOMATION_LOG = "log_au",
|
||||||
|
ACCOUNT_METADATA = "acc_metadata",
|
||||||
|
PLUGIN = "plg",
|
||||||
|
DATASOURCE = "datasource",
|
||||||
|
DATASOURCE_PLUS = "datasource_plus",
|
||||||
|
APP_BACKUP = "backup",
|
||||||
|
TABLE = "ta",
|
||||||
|
ROW = "ro",
|
||||||
|
AUTOMATION = "au",
|
||||||
|
LINK = "li",
|
||||||
|
WEBHOOK = "wh",
|
||||||
|
INSTANCE = "inst",
|
||||||
|
LAYOUT = "layout",
|
||||||
|
SCREEN = "screen",
|
||||||
|
QUERY = "query",
|
||||||
|
DEPLOYMENTS = "deployments",
|
||||||
|
METADATA = "metadata",
|
||||||
|
MEM_VIEW = "view",
|
||||||
|
USER_FLAG = "flag",
|
||||||
|
AUTOMATION_METADATA = "meta_au",
|
||||||
|
AUDIT_LOG = "al",
|
||||||
|
}
|
||||||
|
|
||||||
export interface Document {
|
export interface Document {
|
||||||
_id?: string
|
_id?: string
|
||||||
_rev?: string
|
_rev?: string
|
||||||
|
|
|
@ -176,7 +176,7 @@ const validateUniqueUser = async (email: string, tenantId: string) => {
|
||||||
export async function isPreventPasswordActions(user: User, account?: Account) {
|
export async function isPreventPasswordActions(user: User, account?: Account) {
|
||||||
// when in maintenance mode we allow sso users with the admin role
|
// when in maintenance mode we allow sso users with the admin role
|
||||||
// to perform any password action - this prevents lockout
|
// to perform any password action - this prevents lockout
|
||||||
if (coreEnv.ENABLE_SSO_MAINTENANCE_MODE && user.admin?.global) {
|
if (coreEnv.ENABLE_SSO_MAINTENANCE_MODE && usersCore.isAdmin(user)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue