Skip to content

Commit

Permalink
Merge pull request #14813 from Budibase/budi-8755-hide-power-role-for…
Browse files Browse the repository at this point in the history
…-v3-apps

Hide power role for v3 apps
  • Loading branch information
adrinr authored Oct 17, 2024
2 parents 42086f3 + 4c688b9 commit d6d95c7
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 49 deletions.
50 changes: 33 additions & 17 deletions packages/backend-core/src/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,30 +54,46 @@ function getPackageJsonFields(): {
VERSION: string
SERVICE_NAME: string
} {
function findFileInAncestors(
fileName: string,
currentDir: string
): string | null {
const filePath = `${currentDir}/${fileName}`
if (existsSync(filePath)) {
return filePath
}
function getParentFile(file: string) {
function findFileInAncestors(
fileName: string,
currentDir: string
): string | null {
const filePath = `${currentDir}/${fileName}`
if (existsSync(filePath)) {
return filePath
}

const parentDir = `${currentDir}/..`
if (parentDir === currentDir) {
// reached root directory
return null
}

const parentDir = `${currentDir}/..`
if (parentDir === currentDir) {
// reached root directory
return null
return findFileInAncestors(fileName, parentDir)
}

return findFileInAncestors(fileName, parentDir)
const packageJsonFile = findFileInAncestors(file, process.cwd())
const content = readFileSync(packageJsonFile!, "utf-8")
const parsedContent = JSON.parse(content)
return parsedContent
}

let localVersion: string | undefined
if (isDev() && !isTest()) {
try {
const lerna = getParentFile("lerna.json")
localVersion = lerna.version
} catch {
//
}
}

try {
const packageJsonFile = findFileInAncestors("package.json", process.cwd())
const content = readFileSync(packageJsonFile!, "utf-8")
const parsedContent = JSON.parse(content)
const parsedContent = getParentFile("package.json")
return {
VERSION: process.env.BUDIBASE_VERSION || parsedContent.version,
VERSION:
localVersion || process.env.BUDIBASE_VERSION || parsedContent.version,
SERVICE_NAME: parsedContent.name,
}
} catch {
Expand Down
51 changes: 40 additions & 11 deletions packages/backend-core/src/security/roles.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import semver from "semver"
import { BuiltinPermissionID, PermissionLevel } from "./permissions"
import {
prefixRoleID,
Expand All @@ -7,7 +8,13 @@ import {
doWithDB,
} from "../db"
import { getAppDB } from "../context"
import { Screen, Role as RoleDoc, RoleUIMetadata } from "@budibase/types"
import {
Screen,
Role as RoleDoc,
RoleUIMetadata,
Database,
App,
} from "@budibase/types"
import cloneDeep from "lodash/fp/cloneDeep"
import { RoleColor } from "@budibase/shared-core"

Expand All @@ -23,14 +30,6 @@ const BUILTIN_IDS = {
BUILDER: "BUILDER",
}

// exclude internal roles like builder
const EXTERNAL_BUILTIN_ROLE_IDS = [
BUILTIN_IDS.ADMIN,
BUILTIN_IDS.POWER,
BUILTIN_IDS.BASIC,
BUILTIN_IDS.PUBLIC,
]

export const RoleIDVersion = {
// original version, with a UUID based ID
UUID: undefined,
Expand Down Expand Up @@ -319,7 +318,7 @@ export async function getAllRoles(appId?: string): Promise<RoleDoc[]> {
}
return internal(appDB)
}
async function internal(db: any) {
async function internal(db: Database | undefined) {
let roles: RoleDoc[] = []
if (db) {
const body = await db.allDocs(
Expand All @@ -334,8 +333,26 @@ export async function getAllRoles(appId?: string): Promise<RoleDoc[]> {
}
const builtinRoles = getBuiltinRoles()

// exclude internal roles like builder
let externalBuiltinRoles = []

if (!db || (await shouldIncludePowerRole(db))) {
externalBuiltinRoles = [
BUILTIN_IDS.ADMIN,
BUILTIN_IDS.POWER,
BUILTIN_IDS.BASIC,
BUILTIN_IDS.PUBLIC,
]
} else {
externalBuiltinRoles = [
BUILTIN_IDS.ADMIN,
BUILTIN_IDS.BASIC,
BUILTIN_IDS.PUBLIC,
]
}

// need to combine builtin with any DB record of them (for sake of permissions)
for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) {
for (let builtinRoleId of externalBuiltinRoles) {
const builtinRole = builtinRoles[builtinRoleId]
const dbBuiltin = roles.filter(
dbRole =>
Expand Down Expand Up @@ -366,6 +383,18 @@ export async function getAllRoles(appId?: string): Promise<RoleDoc[]> {
}
}

async function shouldIncludePowerRole(db: Database) {
const app = await db.tryGet<App>(DocumentType.APP_METADATA)
const creationVersion = app?.creationVersion
if (!creationVersion || !semver.valid(creationVersion)) {
// Old apps don't have creationVersion, so we should include it for backward compatibility
return true
}

const isGreaterThan3x = semver.gte(creationVersion, "3.0.0")
return !isGreaterThan3x
}

export class AccessController {
userHierarchies: { [key: string]: string[] }
constructor() {
Expand Down
41 changes: 21 additions & 20 deletions packages/server/src/api/controllers/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,8 @@ export async function fetchAppDefinition(
export async function fetchAppPackage(
ctx: UserCtx<void, FetchAppPackageResponse>
) {
const db = context.getAppDB()
const appId = context.getAppId()
let application = await db.get<App>(DocumentType.APP_METADATA)
const application = await sdk.applications.metadata.get()
const layouts = await getLayouts()
let screens = await getScreens()
const license = await licensing.cache.getCachedLicense()
Expand Down Expand Up @@ -272,14 +271,15 @@ async function performAppCreate(ctx: UserCtx<CreateAppRequest, App>) {
path: ctx.request.body.file?.path,
}
}

const tenantId = tenancy.isMultiTenant() ? tenancy.getTenantId() : null
const appId = generateDevAppID(generateAppID(tenantId))

return await context.doInAppContext(appId, async () => {
const instance = await createInstance(appId, instanceConfig)
const db = context.getAppDB()

let newApplication: App = {
const newApplication: App = {
_id: DocumentType.APP_METADATA,
_rev: undefined,
appId,
Expand Down Expand Up @@ -310,19 +310,26 @@ async function performAppCreate(ctx: UserCtx<CreateAppRequest, App>) {
disableUserMetadata: true,
skeletonLoader: true,
},
creationVersion: undefined,
}

const isImport = !!instanceConfig.file
if (!isImport) {
newApplication.creationVersion = envCore.VERSION
}

const existing = await sdk.applications.metadata.tryGet()
// If we used a template or imported an app there will be an existing doc.
// Fetch and migrate some metadata from the existing app.
try {
const existing: App = await db.get(DocumentType.APP_METADATA)
if (existing) {
const keys: (keyof App)[] = [
"_rev",
"navigation",
"theme",
"customTheme",
"icon",
"snippets",
"creationVersion",
]
keys.forEach(key => {
if (existing[key]) {
Expand All @@ -340,14 +347,10 @@ async function performAppCreate(ctx: UserCtx<CreateAppRequest, App>) {
}

// Migrate navigation settings and screens if required
if (existing) {
const navigation = await migrateAppNavigation()
if (navigation) {
newApplication.navigation = navigation
}
const navigation = await migrateAppNavigation()
if (navigation) {
newApplication.navigation = navigation
}
} catch (err) {
// Nothing to do
}

const response = await db.put(newApplication, { force: true })
Expand Down Expand Up @@ -489,8 +492,7 @@ export async function update(

export async function updateClient(ctx: UserCtx) {
// Get current app version
const db = context.getAppDB()
const application = await db.get<App>(DocumentType.APP_METADATA)
const application = await sdk.applications.metadata.get()
const currentVersion = application.version

let manifest
Expand Down Expand Up @@ -518,8 +520,7 @@ export async function updateClient(ctx: UserCtx) {

export async function revertClient(ctx: UserCtx) {
// Check app can be reverted
const db = context.getAppDB()
const application = await db.get<App>(DocumentType.APP_METADATA)
const application = await sdk.applications.metadata.get()
if (!application.revertableVersion) {
ctx.throw(400, "There is no version to revert to")
}
Expand Down Expand Up @@ -577,7 +578,7 @@ async function destroyApp(ctx: UserCtx) {

const db = dbCore.getDB(devAppId)
// standard app deletion flow
const app = await db.get<App>(DocumentType.APP_METADATA)
const app = await sdk.applications.metadata.get()
const result = await db.destroy()
await quotas.removeApp()
await events.app.deleted(app)
Expand Down Expand Up @@ -728,7 +729,7 @@ export async function updateAppPackage(
) {
return context.doInAppContext(appId, async () => {
const db = context.getAppDB()
const application = await db.get<App>(DocumentType.APP_METADATA)
const application = await sdk.applications.metadata.get()

const newAppPackage: App = { ...application, ...appPackage }
if (appPackage._rev !== application._rev) {
Expand All @@ -754,7 +755,7 @@ export async function setRevertableVersion(
return
}
const db = context.getAppDB()
const app = await db.get<App>(DocumentType.APP_METADATA)
const app = await sdk.applications.metadata.get()
app.revertableVersion = ctx.request.body.revertableVersion
await db.put(app)

Expand All @@ -763,7 +764,7 @@ export async function setRevertableVersion(

async function migrateAppNavigation() {
const db = context.getAppDB()
const existing: App = await db.get(DocumentType.APP_METADATA)
const existing = await sdk.applications.metadata.get()
const layouts: Layout[] = await getLayouts()
const screens: Screen[] = await getScreens()

Expand Down
2 changes: 2 additions & 0 deletions packages/server/src/sdk/app/applications/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import * as sync from "./sync"
import * as utils from "./utils"
import * as applications from "./applications"
import * as imports from "./import"
import * as metadata from "./metadata"

export default {
...sync,
...utils,
...applications,
...imports,
metadata,
}
18 changes: 18 additions & 0 deletions packages/server/src/sdk/app/applications/metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { context, DocumentType } from "@budibase/backend-core"
import { App } from "@budibase/types"

/**
* @deprecated the plan is to get everything using `tryGet` instead, then rename
* `tryGet` to `get`.
*/
export async function get() {
const db = context.getAppDB()
const application = await db.get<App>(DocumentType.APP_METADATA)
return application
}

export async function tryGet() {
const db = context.getAppDB()
const application = await db.tryGet<App>(DocumentType.APP_METADATA)
return application
}
1 change: 1 addition & 0 deletions packages/types/src/documents/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface App extends Document {
usedPlugins?: Plugin[]
upgradableVersion?: string
snippets?: Snippet[]
creationVersion?: string
}

export interface AppInstance {
Expand Down
Loading

0 comments on commit d6d95c7

Please sign in to comment.