From cea82f9335636033793eeb40a73216be5b6f19e1 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 14 May 2021 15:43:41 +0100 Subject: [PATCH 1/4] A general re-work of some parts of the auth lib, as well as moving roles/permissions around to make it possible to build an admin API which has role knowledge. --- packages/auth/README.md | 13 ++++++- packages/auth/db.js | 1 + packages/auth/package.json | 1 + packages/auth/permissions.js | 1 + packages/auth/redis.js | 4 ++ packages/auth/roles.js | 1 + packages/auth/src/db/utils.js | 39 +++++++++++++++++++ packages/auth/src/objectStore/index.js | 8 +++- .../src}/security/permissions.js | 0 .../utilities => auth/src}/security/roles.js | 8 ++-- .../src/components/start/AppCard.svelte | 4 +- packages/builder/src/constants/index.js | 2 +- .../pages/builder/portal/apps/index.svelte | 2 +- .../server/src/api/controllers/application.js | 4 +- .../src/api/controllers/deploy/index.js | 2 +- .../server/src/api/controllers/hosting.js | 2 +- .../server/src/api/controllers/permission.js | 6 +-- packages/server/src/api/controllers/role.js | 2 +- .../server/src/api/controllers/routing.js | 2 +- packages/server/src/api/controllers/screen.js | 2 +- packages/server/src/api/controllers/user.js | 2 +- packages/server/src/api/routes/analytics.js | 2 +- packages/server/src/api/routes/apikeys.js | 2 +- packages/server/src/api/routes/application.js | 2 +- packages/server/src/api/routes/automation.js | 2 +- packages/server/src/api/routes/backup.js | 2 +- packages/server/src/api/routes/component.js | 2 +- packages/server/src/api/routes/datasource.js | 2 +- packages/server/src/api/routes/deploy.js | 2 +- packages/server/src/api/routes/dev.js | 8 +--- packages/server/src/api/routes/hosting.js | 2 +- packages/server/src/api/routes/integration.js | 2 +- packages/server/src/api/routes/layout.js | 2 +- packages/server/src/api/routes/permission.js | 2 +- packages/server/src/api/routes/query.js | 4 +- packages/server/src/api/routes/role.js | 8 ++-- packages/server/src/api/routes/routing.js | 2 +- packages/server/src/api/routes/row.js | 2 +- packages/server/src/api/routes/screen.js | 2 +- packages/server/src/api/routes/script.js | 2 +- packages/server/src/api/routes/search.js | 2 +- packages/server/src/api/routes/static.js | 2 +- packages/server/src/api/routes/table.js | 2 +- packages/server/src/api/routes/templates.js | 2 +- .../src/api/routes/tests/application.spec.js | 10 ++++- .../src/api/routes/tests/permissions.spec.js | 2 +- .../server/src/api/routes/tests/role.spec.js | 4 +- .../src/api/routes/tests/routing.spec.js | 2 +- .../server/src/api/routes/tests/user.spec.js | 2 +- .../routes/tests/utilities/TestFunctions.js | 2 +- packages/server/src/api/routes/user.js | 2 +- packages/server/src/api/routes/view.js | 2 +- packages/server/src/api/routes/webhook.js | 2 +- .../src/automations/steps/createUser.js | 2 +- .../src/automations/tests/createUser.spec.js | 2 +- packages/server/src/automations/triggers.js | 2 +- packages/server/src/constants/index.js | 2 +- packages/server/src/constants/screens.js | 2 +- packages/server/src/db/utils.js | 24 ++++-------- packages/server/src/middleware/authorized.js | 4 +- packages/server/src/middleware/currentapp.js | 4 +- .../src/middleware/tests/authorized.spec.js | 2 +- .../src/middleware/tests/currentapp.spec.js | 3 +- .../src/middleware/tests/selfhost.spec.js | 3 +- .../src/tests/utilities/TestConfiguration.js | 4 +- .../server/src/tests/utilities/structures.js | 4 +- packages/server/src/utilities/redis.js | 2 +- .../{security/utilities.js => security.js} | 6 +-- .../server/src/utilities/workerRequests.js | 2 +- packages/worker/src/utilities/redis.js | 2 +- 70 files changed, 160 insertions(+), 104 deletions(-) create mode 100644 packages/auth/db.js create mode 100644 packages/auth/permissions.js create mode 100644 packages/auth/redis.js create mode 100644 packages/auth/roles.js rename packages/{server/src/utilities => auth/src}/security/permissions.js (100%) rename packages/{server/src/utilities => auth/src}/security/roles.js (98%) rename packages/server/src/utilities/{security/utilities.js => security.js} (92%) diff --git a/packages/auth/README.md b/packages/auth/README.md index bbe704026a..4c6a474b5b 100644 --- a/packages/auth/README.md +++ b/packages/auth/README.md @@ -1 +1,12 @@ -# Budibase Authentication Library \ No newline at end of file +# Budibase Core backend library + +This library contains core functionality, like auth and security features +which are shared between backend services. + +#### Note about top level JS files +For the purposes of being able to do say `require("@budibase/auth/permissions")` we need to +specify the exports at the top-level of the module. + +For these files they should be limited to a single `require` of the file that should +be exported and then a single `module.exports = ...` to export the file in +commonJS. \ No newline at end of file diff --git a/packages/auth/db.js b/packages/auth/db.js new file mode 100644 index 0000000000..4b03ec36cc --- /dev/null +++ b/packages/auth/db.js @@ -0,0 +1 @@ +module.exports = require("./src/db/utils") diff --git a/packages/auth/package.json b/packages/auth/package.json index 56b904c966..42bc76f3f4 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -11,6 +11,7 @@ "ioredis": "^4.27.1", "jsonwebtoken": "^8.5.1", "koa-passport": "^4.1.4", + "lodash": "^4.17.21", "node-fetch": "^2.6.1", "passport-google-auth": "^1.0.2", "passport-google-oauth": "^2.0.0", diff --git a/packages/auth/permissions.js b/packages/auth/permissions.js new file mode 100644 index 0000000000..42f37c9c7e --- /dev/null +++ b/packages/auth/permissions.js @@ -0,0 +1 @@ +module.exports = require("./src/security/permissions") diff --git a/packages/auth/redis.js b/packages/auth/redis.js new file mode 100644 index 0000000000..0a9dc91881 --- /dev/null +++ b/packages/auth/redis.js @@ -0,0 +1,4 @@ +module.exports = { + Client: require("./src/redis"), + utils: require("./src/redis/utils"), +} diff --git a/packages/auth/roles.js b/packages/auth/roles.js new file mode 100644 index 0000000000..158bcdb6b8 --- /dev/null +++ b/packages/auth/roles.js @@ -0,0 +1 @@ +module.exports = require("./src/security/roles") diff --git a/packages/auth/src/db/utils.js b/packages/auth/src/db/utils.js index 44fe1da2db..87ff10bd46 100644 --- a/packages/auth/src/db/utils.js +++ b/packages/auth/src/db/utils.js @@ -21,6 +21,7 @@ const DocumentTypes = { TEMPLATE: "template", APP: "app", APP_DEV: "app_dev", + ROLE: "role", } exports.DocumentTypes = DocumentTypes @@ -28,6 +29,29 @@ exports.APP_PREFIX = DocumentTypes.APP + SEPARATOR exports.APP_DEV_PREFIX = DocumentTypes.APP_DEV + SEPARATOR exports.SEPARATOR = SEPARATOR +/** + * If creating DB allDocs/query params with only a single top level ID this can be used, this + * is usually the case as most of our docs are top level e.g. tables, automations, users and so on. + * More complex cases such as link docs and rows which have multiple levels of IDs that their + * ID consists of need their own functions to build the allDocs parameters. + * @param {string} docType The type of document which input params are being built for, e.g. user, + * link, app, table and so on. + * @param {string|null} docId The ID of the document minus its type - this is only needed if looking + * for a singular document. + * @param {object} otherProps Add any other properties onto the request, e.g. include_docs. + * @returns {object} Parameters which can then be used with an allDocs request. + */ +function getDocParams(docType, docId = null, otherProps = {}) { + if (docId == null) { + docId = "" + } + return { + ...otherProps, + startkey: `${docType}${SEPARATOR}${docId}`, + endkey: `${docType}${SEPARATOR}${docId}${UNICODE_MAX}`, + } +} + /** * Generates a new group ID. * @returns {string} The new group ID which the group doc can be stored under. @@ -97,6 +121,21 @@ exports.getTemplateParams = (ownerId, templateId, otherProps = {}) => { } } +/** + * Generates a new role ID. + * @returns {string} The new role ID which the role doc can be stored under. + */ +exports.generateRoleID = id => { + return `${DocumentTypes.ROLE}${SEPARATOR}${id || newid()}` +} + +/** + * Gets parameters for retrieving a role, this is a utility function for the getDocParams function. + */ +exports.getRoleParams = (roleId = null, otherProps = {}) => { + return getDocParams(DocumentTypes.ROLE, roleId, otherProps) +} + /** * Generates a new configuration ID. * @returns {string} The new configuration ID which the config doc can be stored under. diff --git a/packages/auth/src/objectStore/index.js b/packages/auth/src/objectStore/index.js index ecd3bd3af6..c6d1c3e2ce 100644 --- a/packages/auth/src/objectStore/index.js +++ b/packages/auth/src/objectStore/index.js @@ -126,7 +126,13 @@ exports.makeSureBucketExists = async (client, bucketName) => { * Uploads the contents of a file given the required parameters, useful when * temp files in use (for example file uploaded as an attachment). */ -exports.upload = async ({ bucket: bucketName, filename, path, type, metadata }) => { +exports.upload = async ({ + bucket: bucketName, + filename, + path, + type, + metadata, +}) => { const extension = [...filename.split(".")].pop() const fileBytes = fs.readFileSync(path) diff --git a/packages/server/src/utilities/security/permissions.js b/packages/auth/src/security/permissions.js similarity index 100% rename from packages/server/src/utilities/security/permissions.js rename to packages/auth/src/security/permissions.js diff --git a/packages/server/src/utilities/security/roles.js b/packages/auth/src/security/roles.js similarity index 98% rename from packages/server/src/utilities/security/roles.js rename to packages/auth/src/security/roles.js index abfaa5c241..93e1769cf1 100644 --- a/packages/server/src/utilities/security/roles.js +++ b/packages/auth/src/security/roles.js @@ -1,7 +1,7 @@ -const CouchDB = require("../../db") +const { getDB } = require("../db") const { cloneDeep } = require("lodash/fp") const { BUILTIN_PERMISSION_IDS, higherPermission } = require("./permissions") -const { generateRoleID, DocumentTypes, SEPARATOR } = require("../../db/utils") +const { generateRoleID, DocumentTypes, SEPARATOR } = require("../db/utils") const BUILTIN_IDS = { ADMIN: "ADMIN", @@ -116,7 +116,7 @@ exports.getRole = async (appId, roleId) => { ) } try { - const db = new CouchDB(appId) + const db = getDB(appId) const dbRole = await db.get(exports.getDBRoleID(roleId)) role = Object.assign(role, dbRole) // finalise the ID @@ -145,7 +145,7 @@ async function getAllUserRoles(appId, userRoleId) { currentRole && currentRole.inherits && roleIds.indexOf(currentRole.inherits) === -1 - ) { + ) { roleIds.push(currentRole.inherits) currentRole = await exports.getRole(appId, currentRole.inherits) roles.push(currentRole) diff --git a/packages/builder/src/components/start/AppCard.svelte b/packages/builder/src/components/start/AppCard.svelte index 174ac585d4..a4edb756f4 100644 --- a/packages/builder/src/components/start/AppCard.svelte +++ b/packages/builder/src/components/start/AppCard.svelte @@ -37,8 +37,8 @@ {#if deletable} deleteApp(app)} icon="Delete"> - Delete - + Delete + {/if} {#if app.lockedBy && app.lockedBy?.email === $auth.user?.email} releaseLock(app._id)} icon="LockOpen"> diff --git a/packages/builder/src/constants/index.js b/packages/builder/src/constants/index.js index 808c4468a1..4d2f700ee7 100644 --- a/packages/builder/src/constants/index.js +++ b/packages/builder/src/constants/index.js @@ -11,7 +11,7 @@ export const FrontendTypes = { export const AppStatus = { DEV: "dev", - PUBLISHED: "published" + PUBLISHED: "published", } // fields on the user table that cannot be edited diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index 79fee91c96..01f360b6fd 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -64,7 +64,7 @@ if (appStatus === AppStatus.DEV) { $goto(`../../app/${app._id}`) } else { - window.open(`/${app._id}`, '_blank'); + window.open(`/${app._id}`, "_blank") } } diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 306535c087..e9b047ce82 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -23,7 +23,7 @@ const { const { BUILTIN_ROLE_IDS, AccessController, -} = require("../../utilities/security/roles") +} = require("@budibase/auth/roles") const { BASE_LAYOUTS } = require("../../constants/layouts") const { createHomeScreen, @@ -123,7 +123,7 @@ async function createInstance(template) { exports.fetch = async function (ctx) { let apps = await getAllApps() - const isDev = ctx.query.status === AppStatus.DEV + const isDev = ctx.query && ctx.query.status === AppStatus.DEV apps = apps.filter(app => { if (isDev) { return app._id.startsWith(DocumentTypes.APP_DEV) diff --git a/packages/server/src/api/controllers/deploy/index.js b/packages/server/src/api/controllers/deploy/index.js index 381ab95444..6aab3bc3dd 100644 --- a/packages/server/src/api/controllers/deploy/index.js +++ b/packages/server/src/api/controllers/deploy/index.js @@ -1,6 +1,6 @@ const PouchDB = require("../../../db") const Deployment = require("./Deployment") -const { Replication } = require("@budibase/auth").db +const { Replication } = require("@budibase/auth/db") // the max time we can wait for an invalidation to complete before considering it failed const MAX_PENDING_TIME_MS = 30 * 60000 const DeploymentStatus = { diff --git a/packages/server/src/api/controllers/hosting.js b/packages/server/src/api/controllers/hosting.js index 03b0e8c755..aa8664cd92 100644 --- a/packages/server/src/api/controllers/hosting.js +++ b/packages/server/src/api/controllers/hosting.js @@ -1,6 +1,6 @@ const CouchDB = require("../../db") const { getDeployedApps } = require("../../utilities/workerRequests") -const { getScopedConfig } = require("@budibase/auth").db +const { getScopedConfig } = require("@budibase/auth/db") const { Configs } = require("@budibase/auth").constants const { checkSlashesInUrl } = require("../../utilities") diff --git a/packages/server/src/api/controllers/permission.js b/packages/server/src/api/controllers/permission.js index 74987d5214..e269f8c41d 100644 --- a/packages/server/src/api/controllers/permission.js +++ b/packages/server/src/api/controllers/permission.js @@ -3,19 +3,19 @@ const { PermissionLevels, isPermissionLevelHigherThanRead, higherPermission, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const { isBuiltin, getDBRoleID, getExternalRoleID, getBuiltinRoles, -} = require("../../utilities/security/roles") +} = require("@budibase/auth/roles") const { getRoleParams } = require("../../db/utils") const CouchDB = require("../../db") const { CURRENTLY_SUPPORTED_LEVELS, getBasePermissions, -} = require("../../utilities/security/utilities") +} = require("../../utilities/security") const PermissionUpdateType = { REMOVE: "remove", diff --git a/packages/server/src/api/controllers/role.js b/packages/server/src/api/controllers/role.js index e1d469d977..a72c6ae55d 100644 --- a/packages/server/src/api/controllers/role.js +++ b/packages/server/src/api/controllers/role.js @@ -6,7 +6,7 @@ const { getRole, isBuiltin, getExternalRoleID, -} = require("../../utilities/security/roles") +} = require("@budibase/auth/roles") const { generateRoleID, getRoleParams, diff --git a/packages/server/src/api/controllers/routing.js b/packages/server/src/api/controllers/routing.js index fc3237c6d5..1bbb521eab 100644 --- a/packages/server/src/api/controllers/routing.js +++ b/packages/server/src/api/controllers/routing.js @@ -2,7 +2,7 @@ const { getRoutingInfo } = require("../../utilities/routing") const { getUserRoleHierarchy, BUILTIN_ROLE_IDS, -} = require("../../utilities/security/roles") +} = require("@budibase/auth/roles") const URL_SEPARATOR = "/" diff --git a/packages/server/src/api/controllers/screen.js b/packages/server/src/api/controllers/screen.js index 6095d00c95..7898476227 100644 --- a/packages/server/src/api/controllers/screen.js +++ b/packages/server/src/api/controllers/screen.js @@ -1,6 +1,6 @@ const CouchDB = require("../../db") const { getScreenParams, generateScreenID } = require("../../db/utils") -const { AccessController } = require("../../utilities/security/roles") +const { AccessController } = require("@budibase/auth/roles") exports.fetch = async ctx => { const appId = ctx.appId diff --git a/packages/server/src/api/controllers/user.js b/packages/server/src/api/controllers/user.js index ace77a1ea5..39901990c2 100644 --- a/packages/server/src/api/controllers/user.js +++ b/packages/server/src/api/controllers/user.js @@ -5,7 +5,7 @@ const { getGlobalIDFromUserMetadataID, } = require("../../db/utils") const { InternalTables } = require("../../db/utils") -const { getRole, BUILTIN_ROLE_IDS } = require("../../utilities/security/roles") +const { getRole, BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { getGlobalUsers, saveGlobalUser, diff --git a/packages/server/src/api/routes/analytics.js b/packages/server/src/api/routes/analytics.js index 0d5e38c34d..fc05ecfecd 100644 --- a/packages/server/src/api/routes/analytics.js +++ b/packages/server/src/api/routes/analytics.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const authorized = require("../../middleware/authorized") const controller = require("../controllers/analytics") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/apikeys.js b/packages/server/src/api/routes/apikeys.js index d6d0edeac0..d1174eb475 100644 --- a/packages/server/src/api/routes/apikeys.js +++ b/packages/server/src/api/routes/apikeys.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../controllers/apikeys") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/application.js b/packages/server/src/api/routes/application.js index 34d44cfaef..edb6957144 100644 --- a/packages/server/src/api/routes/application.js +++ b/packages/server/src/api/routes/application.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../controllers/application") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/automation.js b/packages/server/src/api/routes/automation.js index 3088bc521f..c7b674b4e4 100644 --- a/packages/server/src/api/routes/automation.js +++ b/packages/server/src/api/routes/automation.js @@ -6,7 +6,7 @@ const { BUILDER, PermissionLevels, PermissionTypes, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const Joi = require("joi") const { bodyResource, paramResource } = require("../../middleware/resourceId") diff --git a/packages/server/src/api/routes/backup.js b/packages/server/src/api/routes/backup.js index 7f24a452e5..51c53e37b6 100644 --- a/packages/server/src/api/routes/backup.js +++ b/packages/server/src/api/routes/backup.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../controllers/backup") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/component.js b/packages/server/src/api/routes/component.js index a7aac53ea9..7b14b2b440 100644 --- a/packages/server/src/api/routes/component.js +++ b/packages/server/src/api/routes/component.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../controllers/component") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/datasource.js b/packages/server/src/api/routes/datasource.js index ee2210704f..3c022e8e26 100644 --- a/packages/server/src/api/routes/datasource.js +++ b/packages/server/src/api/routes/datasource.js @@ -5,7 +5,7 @@ const { BUILDER, PermissionLevels, PermissionTypes, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/deploy.js b/packages/server/src/api/routes/deploy.js index d8667c6fc1..261a440c2e 100644 --- a/packages/server/src/api/routes/deploy.js +++ b/packages/server/src/api/routes/deploy.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../controllers/deploy") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/dev.js b/packages/server/src/api/routes/dev.js index 50a97cb345..8bc7483fc6 100644 --- a/packages/server/src/api/routes/dev.js +++ b/packages/server/src/api/routes/dev.js @@ -2,7 +2,7 @@ const Router = require("@koa/router") const controller = require("../controllers/dev") const env = require("../../environment") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() @@ -13,10 +13,6 @@ if (env.isDev() || env.isTest()) { .delete("/api/admin/:devPath(.*)", controller.redirectDelete) } -router.delete( - "/api/dev/:appId/lock", - authorized(BUILDER), - controller.clearLock -) +router.delete("/api/dev/:appId/lock", authorized(BUILDER), controller.clearLock) module.exports = router diff --git a/packages/server/src/api/routes/hosting.js b/packages/server/src/api/routes/hosting.js index 2243e5303c..0ebb4bb0e4 100644 --- a/packages/server/src/api/routes/hosting.js +++ b/packages/server/src/api/routes/hosting.js @@ -2,7 +2,7 @@ const Router = require("@koa/router") const controller = require("../controllers/hosting") const authorized = require("../../middleware/authorized") const selfhost = require("../../middleware/selfhost") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/integration.js b/packages/server/src/api/routes/integration.js index 6bb0cd8573..6b523867c3 100644 --- a/packages/server/src/api/routes/integration.js +++ b/packages/server/src/api/routes/integration.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../controllers/integration") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/layout.js b/packages/server/src/api/routes/layout.js index a903aab959..ad3ac0aa9e 100644 --- a/packages/server/src/api/routes/layout.js +++ b/packages/server/src/api/routes/layout.js @@ -1,6 +1,6 @@ const Router = require("@koa/router") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const controller = require("../controllers/layout") const router = Router() diff --git a/packages/server/src/api/routes/permission.js b/packages/server/src/api/routes/permission.js index 9cf5ae287e..898e8fa1d7 100644 --- a/packages/server/src/api/routes/permission.js +++ b/packages/server/src/api/routes/permission.js @@ -4,7 +4,7 @@ const authorized = require("../../middleware/authorized") const { BUILDER, PermissionLevels, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const Joi = require("joi") const joiValidator = require("../../middleware/joi-validator") diff --git a/packages/server/src/api/routes/query.js b/packages/server/src/api/routes/query.js index 55223e4e9e..dd307c9444 100644 --- a/packages/server/src/api/routes/query.js +++ b/packages/server/src/api/routes/query.js @@ -1,12 +1,12 @@ const Router = require("@koa/router") const queryController = require("../controllers/query") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") const Joi = require("joi") const { PermissionLevels, PermissionTypes, -} = require("../../utilities/security/permissions") + BUILDER, +} = require("@budibase/auth/permissions") const joiValidator = require("../../middleware/joi-validator") const { bodyResource, diff --git a/packages/server/src/api/routes/role.js b/packages/server/src/api/routes/role.js index 760acaa7e7..8736bb93c6 100644 --- a/packages/server/src/api/routes/role.js +++ b/packages/server/src/api/routes/role.js @@ -1,15 +1,13 @@ const Router = require("@koa/router") const controller = require("../controllers/role") const authorized = require("../../middleware/authorized") -const { - BUILDER, - PermissionLevels, -} = require("../../utilities/security/permissions") const Joi = require("joi") const joiValidator = require("../../middleware/joi-validator") const { BUILTIN_PERMISSION_IDS, -} = require("../../utilities/security/permissions") + BUILDER, + PermissionLevels, +} = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/routing.js b/packages/server/src/api/routes/routing.js index 99903db790..4d75705f14 100644 --- a/packages/server/src/api/routes/routing.js +++ b/packages/server/src/api/routes/routing.js @@ -1,6 +1,6 @@ const Router = require("@koa/router") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const controller = require("../controllers/routing") const router = Router() diff --git a/packages/server/src/api/routes/row.js b/packages/server/src/api/routes/row.js index be14910f3e..e0e3c5ab81 100644 --- a/packages/server/src/api/routes/row.js +++ b/packages/server/src/api/routes/row.js @@ -9,7 +9,7 @@ const { const { PermissionLevels, PermissionTypes, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/screen.js b/packages/server/src/api/routes/screen.js index 2810f22e08..3a9baa25fc 100644 --- a/packages/server/src/api/routes/screen.js +++ b/packages/server/src/api/routes/screen.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../controllers/screen") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const joiValidator = require("../../middleware/joi-validator") const Joi = require("joi") diff --git a/packages/server/src/api/routes/script.js b/packages/server/src/api/routes/script.js index 5f8c5156b8..cda8fa8df9 100644 --- a/packages/server/src/api/routes/script.js +++ b/packages/server/src/api/routes/script.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../controllers/script") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/search.js b/packages/server/src/api/routes/search.js index 63493078b7..bd513fd348 100644 --- a/packages/server/src/api/routes/search.js +++ b/packages/server/src/api/routes/search.js @@ -3,7 +3,7 @@ const controller = require("../controllers/search") const { PermissionTypes, PermissionLevels, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const authorized = require("../../middleware/authorized") const { paramResource } = require("../../middleware/resourceId") diff --git a/packages/server/src/api/routes/static.js b/packages/server/src/api/routes/static.js index 21c14f87a1..1ec0ba8e12 100644 --- a/packages/server/src/api/routes/static.js +++ b/packages/server/src/api/routes/static.js @@ -6,7 +6,7 @@ const { BUILDER, PermissionTypes, PermissionLevels, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const usage = require("../../middleware/usageQuota") const env = require("../../environment") diff --git a/packages/server/src/api/routes/table.js b/packages/server/src/api/routes/table.js index 7c7f45afeb..381e0ecc2a 100644 --- a/packages/server/src/api/routes/table.js +++ b/packages/server/src/api/routes/table.js @@ -6,7 +6,7 @@ const { BUILDER, PermissionLevels, PermissionTypes, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const joiValidator = require("../../middleware/joi-validator") const Joi = require("joi") diff --git a/packages/server/src/api/routes/templates.js b/packages/server/src/api/routes/templates.js index 6a427e8383..ee29730406 100644 --- a/packages/server/src/api/routes/templates.js +++ b/packages/server/src/api/routes/templates.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../controllers/templates") const authorized = require("../../middleware/authorized") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const router = Router() diff --git a/packages/server/src/api/routes/tests/application.spec.js b/packages/server/src/api/routes/tests/application.spec.js index 12fcf6f8ea..2ca0601d38 100644 --- a/packages/server/src/api/routes/tests/application.spec.js +++ b/packages/server/src/api/routes/tests/application.spec.js @@ -1,6 +1,14 @@ const { clearAllApps, checkBuilderEndpoint } = require("./utilities/TestFunctions") const setup = require("./utilities") +jest.mock("../../../utilities/redis", () => ({ + init: jest.fn(), + getAllLocks: () => { + return [] + }, + updateLock: jest.fn(), +})) + describe("/applications", () => { let request = setup.getRequest() let config = setup.getConfig() @@ -40,7 +48,7 @@ describe("/applications", () => { await config.createApp(request, "app2") const res = await request - .get("/api/applications") + .get("/api/applications?status=dev") .set(config.defaultHeaders()) .expect('Content-Type', /json/) .expect(200) diff --git a/packages/server/src/api/routes/tests/permissions.spec.js b/packages/server/src/api/routes/tests/permissions.spec.js index aab5567881..ce9f24a572 100644 --- a/packages/server/src/api/routes/tests/permissions.spec.js +++ b/packages/server/src/api/routes/tests/permissions.spec.js @@ -1,4 +1,4 @@ -const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const setup = require("./utilities") const { basicRow } = setup.structures diff --git a/packages/server/src/api/routes/tests/role.spec.js b/packages/server/src/api/routes/tests/role.spec.js index 062450cf63..ad42ef180a 100644 --- a/packages/server/src/api/routes/tests/role.spec.js +++ b/packages/server/src/api/routes/tests/role.spec.js @@ -1,7 +1,7 @@ -const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { BUILTIN_PERMISSION_IDS, -} = require("../../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const setup = require("./utilities") const { basicRole } = setup.structures diff --git a/packages/server/src/api/routes/tests/routing.spec.js b/packages/server/src/api/routes/tests/routing.spec.js index d40b35ba8d..622552c77f 100644 --- a/packages/server/src/api/routes/tests/routing.spec.js +++ b/packages/server/src/api/routes/tests/routing.spec.js @@ -1,7 +1,7 @@ const setup = require("./utilities") const { basicScreen } = setup.structures const { checkBuilderEndpoint } = require("./utilities/TestFunctions") -const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const workerRequests = require("../../../utilities/workerRequests") const route = "/test" diff --git a/packages/server/src/api/routes/tests/user.spec.js b/packages/server/src/api/routes/tests/user.spec.js index b474e360a8..4581cdf798 100644 --- a/packages/server/src/api/routes/tests/user.spec.js +++ b/packages/server/src/api/routes/tests/user.spec.js @@ -1,4 +1,4 @@ -const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { checkPermissionsEndpoint } = require("./utilities/TestFunctions") const setup = require("./utilities") const { basicUser } = setup.structures diff --git a/packages/server/src/api/routes/tests/utilities/TestFunctions.js b/packages/server/src/api/routes/tests/utilities/TestFunctions.js index 0e11dd2056..d2139e2780 100644 --- a/packages/server/src/api/routes/tests/utilities/TestFunctions.js +++ b/packages/server/src/api/routes/tests/utilities/TestFunctions.js @@ -14,7 +14,7 @@ exports.getAllTableRows = async config => { } exports.clearAllApps = async () => { - const req = {} + const req = { query: { status: "dev"} } await appController.fetch(req) const apps = req.body if (!apps || apps.length <= 0) { diff --git a/packages/server/src/api/routes/user.js b/packages/server/src/api/routes/user.js index a9e4aac5a2..01af18b933 100644 --- a/packages/server/src/api/routes/user.js +++ b/packages/server/src/api/routes/user.js @@ -4,7 +4,7 @@ const authorized = require("../../middleware/authorized") const { PermissionLevels, PermissionTypes, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const usage = require("../../middleware/usageQuota") const router = Router() diff --git a/packages/server/src/api/routes/view.js b/packages/server/src/api/routes/view.js index f6d1a55803..7d390805c6 100644 --- a/packages/server/src/api/routes/view.js +++ b/packages/server/src/api/routes/view.js @@ -7,7 +7,7 @@ const { BUILDER, PermissionTypes, PermissionLevels, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const usage = require("../../middleware/usageQuota") const router = Router() diff --git a/packages/server/src/api/routes/webhook.js b/packages/server/src/api/routes/webhook.js index 7a5577c564..73790acd64 100644 --- a/packages/server/src/api/routes/webhook.js +++ b/packages/server/src/api/routes/webhook.js @@ -2,7 +2,7 @@ const Router = require("@koa/router") const controller = require("../controllers/webhook") const authorized = require("../../middleware/authorized") const joiValidator = require("../../middleware/joi-validator") -const { BUILDER } = require("../../utilities/security/permissions") +const { BUILDER } = require("@budibase/auth/permissions") const Joi = require("joi") const router = Router() diff --git a/packages/server/src/automations/steps/createUser.js b/packages/server/src/automations/steps/createUser.js index 6bdc784441..02250901fc 100644 --- a/packages/server/src/automations/steps/createUser.js +++ b/packages/server/src/automations/steps/createUser.js @@ -1,4 +1,4 @@ -const roles = require("../../utilities/security/roles") +const roles = require("@budibase/auth/roles") const userController = require("../../api/controllers/user") const env = require("../../environment") const usage = require("../../utilities/usageQuota") diff --git a/packages/server/src/automations/tests/createUser.spec.js b/packages/server/src/automations/tests/createUser.spec.js index 7291b75505..3adfa637dd 100644 --- a/packages/server/src/automations/tests/createUser.spec.js +++ b/packages/server/src/automations/tests/createUser.spec.js @@ -1,6 +1,6 @@ const usageQuota = require("../../utilities/usageQuota") const setup = require("./utilities") -const { BUILTIN_ROLE_IDS } = require("../../utilities/security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { InternalTables } = require("../../db/utils") jest.mock("../../utilities/usageQuota") diff --git a/packages/server/src/automations/triggers.js b/packages/server/src/automations/triggers.js index 273a95aa57..801207ca80 100644 --- a/packages/server/src/automations/triggers.js +++ b/packages/server/src/automations/triggers.js @@ -6,7 +6,7 @@ const Queue = env.isTest() : require("bull") const { getAutomationParams } = require("../db/utils") const { coerce } = require("../utilities/rowProcessor") -const { utils } = require("@budibase/auth").redis +const { utils } = require("@budibase/auth/redis") const { opts } = utils.getRedisOptions() let automationQueue = new Queue("automationQueue", { redis: opts }) diff --git a/packages/server/src/constants/index.js b/packages/server/src/constants/index.js index c57db67a0e..e4a65a94f6 100644 --- a/packages/server/src/constants/index.js +++ b/packages/server/src/constants/index.js @@ -1,4 +1,4 @@ -const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { UserStatus } = require("@budibase/auth").constants const { ObjectStoreBuckets } = require("@budibase/auth").objectStore diff --git a/packages/server/src/constants/screens.js b/packages/server/src/constants/screens.js index ac6112a63f..55f493c362 100644 --- a/packages/server/src/constants/screens.js +++ b/packages/server/src/constants/screens.js @@ -1,4 +1,4 @@ -const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { BASE_LAYOUT_PROP_IDS } = require("./layouts") const { LOGO_URL } = require("../constants") diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js index 2c434691e8..c5d10c1444 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -1,10 +1,12 @@ const newid = require("./newid") const { DocumentTypes: CoreDocTypes, + getRoleParams, + generateRoleID, APP_DEV_PREFIX, APP_PREFIX, SEPARATOR, -} = require("@budibase/auth").db +} = require("@budibase/auth/db") const UNICODE_MAX = "\ufff0" @@ -23,12 +25,12 @@ const AppStatus = { const DocumentTypes = { APP: CoreDocTypes.APP, APP_DEV: CoreDocTypes.APP_DEV, + ROLE: CoreDocTypes.ROLE, TABLE: "ta", ROW: "ro", USER: "us", AUTOMATION: "au", LINK: "li", - ROLE: "role", WEBHOOK: "wh", INSTANCE: "inst", LAYOUT: "layout", @@ -61,6 +63,9 @@ exports.UNICODE_MAX = UNICODE_MAX exports.SearchIndexes = SearchIndexes exports.AppStatus = AppStatus +exports.generateRoleID = generateRoleID +exports.getRoleParams = getRoleParams + exports.getQueryIndex = viewName => { return `database/${viewName}` } @@ -224,21 +229,6 @@ exports.generateDevAppID = appId => { return `${DocumentTypes.APP_DEV}${SEPARATOR}${uuid}` } -/** - * Generates a new role ID. - * @returns {string} The new role ID which the role doc can be stored under. - */ -exports.generateRoleID = id => { - return `${DocumentTypes.ROLE}${SEPARATOR}${id || newid()}` -} - -/** - * Gets parameters for retrieving a role, this is a utility function for the getDocParams function. - */ -exports.getRoleParams = (roleId = null, otherProps = {}) => { - return getDocParams(DocumentTypes.ROLE, roleId, otherProps) -} - /** * Generates a new layout ID. * @returns {string} The new layout ID which the layout doc can be stored under. diff --git a/packages/server/src/middleware/authorized.js b/packages/server/src/middleware/authorized.js index 339b1160da..513572ddff 100644 --- a/packages/server/src/middleware/authorized.js +++ b/packages/server/src/middleware/authorized.js @@ -1,9 +1,9 @@ -const { getUserPermissions } = require("../utilities/security/roles") +const { getUserPermissions } = require("@budibase/auth/roles") const { PermissionTypes, doesHaveResourcePermission, doesHaveBasePermission, -} = require("../utilities/security/permissions") +} = require("@budibase/auth/permissions") const { APP_DEV_PREFIX } = require("../db/utils") const { doesUserHaveLock, updateLock } = require("../utilities/redis") diff --git a/packages/server/src/middleware/currentapp.js b/packages/server/src/middleware/currentapp.js index adf976e611..f808403bac 100644 --- a/packages/server/src/middleware/currentapp.js +++ b/packages/server/src/middleware/currentapp.js @@ -1,8 +1,8 @@ const { getAppId, setCookie, getCookie } = require("@budibase/auth").utils const { Cookies } = require("@budibase/auth").constants -const { getRole } = require("../utilities/security/roles") +const { getRole } = require("@budibase/auth/roles") const { getGlobalUsers } = require("../utilities/workerRequests") -const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { generateUserMetadataID } = require("../db/utils") module.exports = async (ctx, next) => { diff --git a/packages/server/src/middleware/tests/authorized.spec.js b/packages/server/src/middleware/tests/authorized.spec.js index a3dd9bdfd2..1f36b6b512 100644 --- a/packages/server/src/middleware/tests/authorized.spec.js +++ b/packages/server/src/middleware/tests/authorized.spec.js @@ -1,6 +1,6 @@ const authorizedMiddleware = require("../authorized") const env = require("../../environment") -const { PermissionTypes, PermissionLevels } = require("../../utilities/security/permissions") +const { PermissionTypes, PermissionLevels } = require("@budibase/auth/permissions") jest.mock("../../environment", () => ({ prod: false, isTest: () => true, diff --git a/packages/server/src/middleware/tests/currentapp.spec.js b/packages/server/src/middleware/tests/currentapp.spec.js index e83b364cb5..fd5a6623af 100644 --- a/packages/server/src/middleware/tests/currentapp.spec.js +++ b/packages/server/src/middleware/tests/currentapp.spec.js @@ -8,7 +8,8 @@ function mockWorker() { _id: "us_uuid1", roles: { "app_test": "BASIC", - } + }, + roleId: "BASIC", } } })) diff --git a/packages/server/src/middleware/tests/selfhost.spec.js b/packages/server/src/middleware/tests/selfhost.spec.js index 6ce61c60ef..48f4e2f152 100644 --- a/packages/server/src/middleware/tests/selfhost.spec.js +++ b/packages/server/src/middleware/tests/selfhost.spec.js @@ -1,7 +1,6 @@ const selfHostMiddleware = require("../selfhost") const env = require("../../environment") -jest.mock("../../environment") -jest.mock("../../utilities/builder/hosting") +jest.mock("../../environment") class TestConfiguration { constructor() { diff --git a/packages/server/src/tests/utilities/TestConfiguration.js b/packages/server/src/tests/utilities/TestConfiguration.js index c031cf082d..b3f5d5ce04 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.js +++ b/packages/server/src/tests/utilities/TestConfiguration.js @@ -1,4 +1,4 @@ -const { BUILTIN_ROLE_IDS } = require("../../utilities/security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const env = require("../../environment") const { basicTable, @@ -16,7 +16,7 @@ const supertest = require("supertest") const { cleanup } = require("../../utilities/fileSystem") const { Cookies } = require("@budibase/auth").constants const { jwt } = require("@budibase/auth").auth -const { StaticDatabases } = require("@budibase/auth").db +const { StaticDatabases } = require("@budibase/auth/db") const CouchDB = require("../../db") const GLOBAL_USER_ID = "us_uuid1" diff --git a/packages/server/src/tests/utilities/structures.js b/packages/server/src/tests/utilities/structures.js index 5e27ff4a3b..08647f4a08 100644 --- a/packages/server/src/tests/utilities/structures.js +++ b/packages/server/src/tests/utilities/structures.js @@ -1,7 +1,7 @@ -const { BUILTIN_ROLE_IDS } = require("../../utilities/security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { BUILTIN_PERMISSION_IDS, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const { createHomeScreen } = require("../../constants/screens") const { EMPTY_LAYOUT } = require("../../constants/layouts") const { cloneDeep } = require("lodash/fp") diff --git a/packages/server/src/utilities/redis.js b/packages/server/src/utilities/redis.js index 0234d6d218..d1fd3de469 100644 --- a/packages/server/src/utilities/redis.js +++ b/packages/server/src/utilities/redis.js @@ -1,4 +1,4 @@ -const { Client, utils } = require("@budibase/auth").redis +const { Client, utils } = require("@budibase/auth/redis") const { getGlobalIDFromUserMetadataID } = require("../db/utils") const APP_DEV_LOCK_SECONDS = 600 diff --git a/packages/server/src/utilities/security/utilities.js b/packages/server/src/utilities/security.js similarity index 92% rename from packages/server/src/utilities/security/utilities.js rename to packages/server/src/utilities/security.js index f22b11dbd3..dca6a60a98 100644 --- a/packages/server/src/utilities/security/utilities.js +++ b/packages/server/src/utilities/security.js @@ -3,12 +3,12 @@ const { PermissionTypes, getBuiltinPermissionByID, isPermissionLevelHigherThanRead, -} = require("../../utilities/security/permissions") +} = require("@budibase/auth/permissions") const { lowerBuiltinRoleID, getBuiltinRoles, -} = require("../../utilities/security/roles") -const { DocumentTypes } = require("../../db/utils") +} = require("@budibase/auth/roles") +const { DocumentTypes } = require("../db/utils") const CURRENTLY_SUPPORTED_LEVELS = [ PermissionLevels.WRITE, diff --git a/packages/server/src/utilities/workerRequests.js b/packages/server/src/utilities/workerRequests.js index 1aee6fa8f9..aecc79eaa6 100644 --- a/packages/server/src/utilities/workerRequests.js +++ b/packages/server/src/utilities/workerRequests.js @@ -1,7 +1,7 @@ const fetch = require("node-fetch") const env = require("../environment") const { checkSlashesInUrl } = require("./index") -const { BUILTIN_ROLE_IDS } = require("./security/roles") +const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") function getAppRole(appId, user) { if (!user.roles) { diff --git a/packages/worker/src/utilities/redis.js b/packages/worker/src/utilities/redis.js index 73ef8a0d43..004fd73d02 100644 --- a/packages/worker/src/utilities/redis.js +++ b/packages/worker/src/utilities/redis.js @@ -1,4 +1,4 @@ -const { Client, utils } = require("@budibase/auth").redis +const { Client, utils } = require("@budibase/auth/redis") const { newid } = require("@budibase/auth").utils function getExpirySecondsForDB(db) { From c947199558299b76bee6e6f2923d535c7a7aad89 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 14 May 2021 16:31:07 +0100 Subject: [PATCH 2/4] Adding administration roles API. --- packages/auth/src/db/index.js | 4 ++ packages/auth/src/db/utils.js | 29 +++++++++++++ packages/auth/src/security/roles.js | 43 ++++++++++++++++++- .../server/src/api/controllers/application.js | 9 +--- packages/server/src/api/controllers/role.js | 36 +--------------- packages/server/src/utilities/index.js | 23 +--------- .../worker/src/api/controllers/admin/roles.js | 24 +++++++++++ packages/worker/src/api/routes/admin/roles.js | 11 +++++ packages/worker/src/api/routes/admin/users.js | 1 + 9 files changed, 116 insertions(+), 64 deletions(-) create mode 100644 packages/worker/src/api/controllers/admin/roles.js create mode 100644 packages/worker/src/api/routes/admin/roles.js diff --git a/packages/auth/src/db/index.js b/packages/auth/src/db/index.js index f94fe4afea..163364dbf3 100644 --- a/packages/auth/src/db/index.js +++ b/packages/auth/src/db/index.js @@ -7,3 +7,7 @@ module.exports.setDB = pouch => { module.exports.getDB = dbName => { return new Pouch(dbName) } + +module.exports.getCouch = () => { + return Pouch +} diff --git a/packages/auth/src/db/utils.js b/packages/auth/src/db/utils.js index 87ff10bd46..ecb11824bd 100644 --- a/packages/auth/src/db/utils.js +++ b/packages/auth/src/db/utils.js @@ -1,5 +1,6 @@ const { newid } = require("../hashing") const Replication = require("./Replication") +const { getCouch } = require("./index") const UNICODE_MAX = "\ufff0" const SEPARATOR = "_" @@ -136,6 +137,34 @@ exports.getRoleParams = (roleId = null, otherProps = {}) => { return getDocParams(DocumentTypes.ROLE, roleId, otherProps) } +/** + * Lots of different points in the system need to find the full list of apps, this will + * enumerate the entire CouchDB cluster and get the list of databases (every app). + * NOTE: this operation is fine in self hosting, but cannot be used when hosting many + * different users/companies apps as there is no security around it - all apps are returned. + * @return {Promise} returns the app information document stored in each app database. + */ +exports.getAllApps = async (devApps = false) => { + const CouchDB = getCouch() + let allDbs = await CouchDB.allDbs() + const appDbNames = allDbs.filter(dbName => dbName.startsWith(exports.APP_PREFIX)) + const appPromises = appDbNames.map(db => new CouchDB(db).get(db)) + if (appPromises.length === 0) { + return [] + } else { + const response = await Promise.allSettled(appPromises) + const apps = response + .filter(result => result.status === "fulfilled") + .map(({ value }) => value) + return apps.filter(app => { + if (devApps) { + return app._id.startsWith(exports.APP_DEV_PREFIX) + } + return !app._id.startsWith(exports.APP_DEV_PREFIX) + }) + } +} + /** * Generates a new configuration ID. * @returns {string} The new configuration ID which the config doc can be stored under. diff --git a/packages/auth/src/security/roles.js b/packages/auth/src/security/roles.js index 93e1769cf1..d88be96b2c 100644 --- a/packages/auth/src/security/roles.js +++ b/packages/auth/src/security/roles.js @@ -1,7 +1,7 @@ const { getDB } = require("../db") const { cloneDeep } = require("lodash/fp") const { BUILTIN_PERMISSION_IDS, higherPermission } = require("./permissions") -const { generateRoleID, DocumentTypes, SEPARATOR } = require("../db/utils") +const { generateRoleID, getRoleParams, DocumentTypes, SEPARATOR } = require("../db/utils") const BUILTIN_IDS = { ADMIN: "ADMIN", @@ -11,6 +11,14 @@ 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, +] + function Role(id, name) { this._id = id this.name = name @@ -192,6 +200,39 @@ exports.getUserPermissions = async (appId, userRoleId) => { } } +/** + * Given an app ID this will retrieve all of the roles that are currently within that app. + * @param {string} appId The ID of the app to retrieve the roles from. + * @return {Promise} An array of the role objects that were found. + */ +exports.getAllRoles = async appId => { + const db = getDB(appId) + const body = await db.allDocs( + getRoleParams(null, { + include_docs: true, + }) + ) + let roles = body.rows.map(row => row.doc) + const builtinRoles = exports.getBuiltinRoles() + + // need to combine builtin with any DB record of them (for sake of permissions) + for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) { + const builtinRole = builtinRoles[builtinRoleId] + const dbBuiltin = roles.filter( + dbRole => exports.getExternalRoleID(dbRole._id) === builtinRoleId + )[0] + if (dbBuiltin == null) { + roles.push(builtinRole) + } else { + // remove role and all back after combining with the builtin + roles = roles.filter(role => role._id !== dbBuiltin._id) + dbBuiltin._id = exports.getExternalRoleID(dbBuiltin._id) + roles.push(Object.assign(builtinRole, dbBuiltin)) + } + } + return roles +} + class AccessController { constructor(appId) { this.appId = appId diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index e9b047ce82..cdc3c59a52 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -121,15 +121,8 @@ async function createInstance(template) { } exports.fetch = async function (ctx) { - let apps = await getAllApps() - const isDev = ctx.query && ctx.query.status === AppStatus.DEV - apps = apps.filter(app => { - if (isDev) { - return app._id.startsWith(DocumentTypes.APP_DEV) - } - return !app._id.startsWith(DocumentTypes.APP_DEV) - }) + const apps = await getAllApps(isDev) // get the locks for all the dev apps if (isDev) { diff --git a/packages/server/src/api/controllers/role.js b/packages/server/src/api/controllers/role.js index a72c6ae55d..1ab368e5c5 100644 --- a/packages/server/src/api/controllers/role.js +++ b/packages/server/src/api/controllers/role.js @@ -1,11 +1,11 @@ const CouchDB = require("../../db") const { getBuiltinRoles, - BUILTIN_ROLE_IDS, Role, getRole, isBuiltin, getExternalRoleID, + getAllRoles, } = require("@budibase/auth/roles") const { generateRoleID, @@ -19,14 +19,6 @@ const UpdateRolesOptions = { REMOVED: "removed", } -// exclude internal roles like builder -const EXTERNAL_BUILTIN_ROLE_IDS = [ - BUILTIN_ROLE_IDS.ADMIN, - BUILTIN_ROLE_IDS.POWER, - BUILTIN_ROLE_IDS.BASIC, - BUILTIN_ROLE_IDS.PUBLIC, -] - async function updateRolesOnUserTable(db, roleId, updateOption) { const table = await db.get(InternalTables.USER_METADATA) const schema = table.schema @@ -51,31 +43,7 @@ async function updateRolesOnUserTable(db, roleId, updateOption) { } exports.fetch = async function (ctx) { - const db = new CouchDB(ctx.appId) - const body = await db.allDocs( - getRoleParams(null, { - include_docs: true, - }) - ) - let roles = body.rows.map(row => row.doc) - const builtinRoles = getBuiltinRoles() - - // need to combine builtin with any DB record of them (for sake of permissions) - for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) { - const builtinRole = builtinRoles[builtinRoleId] - const dbBuiltin = roles.filter( - dbRole => getExternalRoleID(dbRole._id) === builtinRoleId - )[0] - if (dbBuiltin == null) { - roles.push(builtinRole) - } else { - // remove role and all back after combining with the builtin - roles = roles.filter(role => role._id !== dbBuiltin._id) - dbBuiltin._id = getExternalRoleID(dbBuiltin._id) - roles.push(Object.assign(builtinRole, dbBuiltin)) - } - } - ctx.body = roles + ctx.body = await getAllRoles(ctx.appId) } exports.find = async function (ctx) { diff --git a/packages/server/src/utilities/index.js b/packages/server/src/utilities/index.js index ac3b668ad5..80852f8c04 100644 --- a/packages/server/src/utilities/index.js +++ b/packages/server/src/utilities/index.js @@ -2,33 +2,14 @@ const env = require("../environment") const { APP_PREFIX } = require("../db/utils") const CouchDB = require("../db") const { OBJ_STORE_DIRECTORY, ObjectStoreBuckets } = require("../constants") +const { getAllApps } = require("@budibase/auth/db") const BB_CDN = "https://cdn.app.budi.live/assets" exports.wait = ms => new Promise(resolve => setTimeout(resolve, ms)) exports.isDev = env.isDev - -/** - * Lots of different points in the app need to find the full list of apps, this will - * enumerate the entire CouchDB cluster and get the list of databases (every app). - * NOTE: this operation is fine in self hosting, but cannot be used when hosting many - * different users/companies apps as there is no security around it - all apps are returned. - * @return {Promise} returns the app information document stored in each app database. - */ -exports.getAllApps = async () => { - let allDbs = await CouchDB.allDbs() - const appDbNames = allDbs.filter(dbName => dbName.startsWith(APP_PREFIX)) - const appPromises = appDbNames.map(db => new CouchDB(db).get(db)) - if (appPromises.length === 0) { - return [] - } else { - const response = await Promise.allSettled(appPromises) - return response - .filter(result => result.status === "fulfilled") - .map(({ value }) => value) - } -} +exports.getAllApps = getAllApps /** * Makes sure that a URL has the correct number of slashes, while maintaining the diff --git a/packages/worker/src/api/controllers/admin/roles.js b/packages/worker/src/api/controllers/admin/roles.js new file mode 100644 index 0000000000..30c44a9b18 --- /dev/null +++ b/packages/worker/src/api/controllers/admin/roles.js @@ -0,0 +1,24 @@ +const { getAllRoles } = require("@budibase/auth/roles") +const { getAllApps } = require("@budibase/auth/db") + +exports.fetch = async ctx => { + // always use the dev apps as they'll be most up to date (true) + const apps = await getAllApps(true) + const promises = [] + for (let app of apps) { + promises.push(getAllRoles(app._id)) + } + const roles = await Promise.all(promises) + const response = {} + for (let app of apps) { + response[app._id] = roles.shift() + } + ctx.body = response +} + +exports.find = async ctx => { + const appId = ctx.params.appId + ctx.body = { + roles: await getAllRoles(appId) + } +} diff --git a/packages/worker/src/api/routes/admin/roles.js b/packages/worker/src/api/routes/admin/roles.js new file mode 100644 index 0000000000..8595662ac3 --- /dev/null +++ b/packages/worker/src/api/routes/admin/roles.js @@ -0,0 +1,11 @@ +const Router = require("@koa/router") +const controller = require("../../controllers/admin/roles") + +const router = Router() + + +router + .get("/api/admin/roles", controller.fetch) + .get("/api/admin/roles/:appId", controller.find) + +module.exports = router diff --git a/packages/worker/src/api/routes/admin/users.js b/packages/worker/src/api/routes/admin/users.js index b498fbe291..cac1d5af9c 100644 --- a/packages/worker/src/api/routes/admin/users.js +++ b/packages/worker/src/api/routes/admin/users.js @@ -45,6 +45,7 @@ router .post("/api/admin/users/init", controller.adminUser) .delete("/api/admin/users/:id", controller.destroy) .get("/api/admin/users/:id", controller.find) + .get("/api/admin/roles/:appId") .post("/api/admin/users/invite", buildInviteValidation(), controller.invite) .post( "/api/admin/users/invite/accept", From a61edd81243aa66a870657a3370b000676d5d1a2 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 14 May 2021 16:32:51 +0100 Subject: [PATCH 3/4] Formatting. --- packages/auth/src/db/utils.js | 4 +++- packages/auth/src/security/roles.js | 9 +++++++-- packages/server/src/api/controllers/application.js | 5 +---- packages/server/src/api/routes/permission.js | 5 +---- .../src/api/routes/tests/utilities/TestFunctions.js | 2 +- packages/server/src/tests/utilities/structures.js | 4 +--- packages/server/src/utilities/security.js | 5 +---- packages/worker/src/api/controllers/admin/roles.js | 2 +- packages/worker/src/api/routes/admin/roles.js | 1 - 9 files changed, 16 insertions(+), 21 deletions(-) diff --git a/packages/auth/src/db/utils.js b/packages/auth/src/db/utils.js index ecb11824bd..f065f9f89a 100644 --- a/packages/auth/src/db/utils.js +++ b/packages/auth/src/db/utils.js @@ -147,7 +147,9 @@ exports.getRoleParams = (roleId = null, otherProps = {}) => { exports.getAllApps = async (devApps = false) => { const CouchDB = getCouch() let allDbs = await CouchDB.allDbs() - const appDbNames = allDbs.filter(dbName => dbName.startsWith(exports.APP_PREFIX)) + const appDbNames = allDbs.filter(dbName => + dbName.startsWith(exports.APP_PREFIX) + ) const appPromises = appDbNames.map(db => new CouchDB(db).get(db)) if (appPromises.length === 0) { return [] diff --git a/packages/auth/src/security/roles.js b/packages/auth/src/security/roles.js index d88be96b2c..d652c25b00 100644 --- a/packages/auth/src/security/roles.js +++ b/packages/auth/src/security/roles.js @@ -1,7 +1,12 @@ const { getDB } = require("../db") const { cloneDeep } = require("lodash/fp") const { BUILTIN_PERMISSION_IDS, higherPermission } = require("./permissions") -const { generateRoleID, getRoleParams, DocumentTypes, SEPARATOR } = require("../db/utils") +const { + generateRoleID, + getRoleParams, + DocumentTypes, + SEPARATOR, +} = require("../db/utils") const BUILTIN_IDS = { ADMIN: "ADMIN", @@ -153,7 +158,7 @@ async function getAllUserRoles(appId, userRoleId) { currentRole && currentRole.inherits && roleIds.indexOf(currentRole.inherits) === -1 - ) { + ) { roleIds.push(currentRole.inherits) currentRole = await exports.getRole(appId, currentRole.inherits) roles.push(currentRole) diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index cdc3c59a52..b9485a3ac4 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -20,10 +20,7 @@ const { DocumentTypes, AppStatus, } = require("../../db/utils") -const { - BUILTIN_ROLE_IDS, - AccessController, -} = require("@budibase/auth/roles") +const { BUILTIN_ROLE_IDS, AccessController } = require("@budibase/auth/roles") const { BASE_LAYOUTS } = require("../../constants/layouts") const { createHomeScreen, diff --git a/packages/server/src/api/routes/permission.js b/packages/server/src/api/routes/permission.js index 898e8fa1d7..f395b13577 100644 --- a/packages/server/src/api/routes/permission.js +++ b/packages/server/src/api/routes/permission.js @@ -1,10 +1,7 @@ const Router = require("@koa/router") const controller = require("../controllers/permission") const authorized = require("../../middleware/authorized") -const { - BUILDER, - PermissionLevels, -} = require("@budibase/auth/permissions") +const { BUILDER, PermissionLevels } = require("@budibase/auth/permissions") const Joi = require("joi") const joiValidator = require("../../middleware/joi-validator") diff --git a/packages/server/src/api/routes/tests/utilities/TestFunctions.js b/packages/server/src/api/routes/tests/utilities/TestFunctions.js index d2139e2780..cbb7d59ce2 100644 --- a/packages/server/src/api/routes/tests/utilities/TestFunctions.js +++ b/packages/server/src/api/routes/tests/utilities/TestFunctions.js @@ -14,7 +14,7 @@ exports.getAllTableRows = async config => { } exports.clearAllApps = async () => { - const req = { query: { status: "dev"} } + const req = { query: { status: "dev" } } await appController.fetch(req) const apps = req.body if (!apps || apps.length <= 0) { diff --git a/packages/server/src/tests/utilities/structures.js b/packages/server/src/tests/utilities/structures.js index 08647f4a08..e925c272ac 100644 --- a/packages/server/src/tests/utilities/structures.js +++ b/packages/server/src/tests/utilities/structures.js @@ -1,7 +1,5 @@ const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") -const { - BUILTIN_PERMISSION_IDS, -} = require("@budibase/auth/permissions") +const { BUILTIN_PERMISSION_IDS } = require("@budibase/auth/permissions") const { createHomeScreen } = require("../../constants/screens") const { EMPTY_LAYOUT } = require("../../constants/layouts") const { cloneDeep } = require("lodash/fp") diff --git a/packages/server/src/utilities/security.js b/packages/server/src/utilities/security.js index dca6a60a98..78b2f5b713 100644 --- a/packages/server/src/utilities/security.js +++ b/packages/server/src/utilities/security.js @@ -4,10 +4,7 @@ const { getBuiltinPermissionByID, isPermissionLevelHigherThanRead, } = require("@budibase/auth/permissions") -const { - lowerBuiltinRoleID, - getBuiltinRoles, -} = require("@budibase/auth/roles") +const { lowerBuiltinRoleID, getBuiltinRoles } = require("@budibase/auth/roles") const { DocumentTypes } = require("../db/utils") const CURRENTLY_SUPPORTED_LEVELS = [ diff --git a/packages/worker/src/api/controllers/admin/roles.js b/packages/worker/src/api/controllers/admin/roles.js index 30c44a9b18..3bb5647ca7 100644 --- a/packages/worker/src/api/controllers/admin/roles.js +++ b/packages/worker/src/api/controllers/admin/roles.js @@ -19,6 +19,6 @@ exports.fetch = async ctx => { exports.find = async ctx => { const appId = ctx.params.appId ctx.body = { - roles: await getAllRoles(appId) + roles: await getAllRoles(appId), } } diff --git a/packages/worker/src/api/routes/admin/roles.js b/packages/worker/src/api/routes/admin/roles.js index 8595662ac3..3e14eb0601 100644 --- a/packages/worker/src/api/routes/admin/roles.js +++ b/packages/worker/src/api/routes/admin/roles.js @@ -3,7 +3,6 @@ const controller = require("../../controllers/admin/roles") const router = Router() - router .get("/api/admin/roles", controller.fetch) .get("/api/admin/roles/:appId", controller.find) From b41620729281bcab8efdafd0f7a313cd1c0daf64 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 14 May 2021 16:47:47 +0100 Subject: [PATCH 4/4] Making sure routes are included. --- packages/worker/src/api/routes/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/worker/src/api/routes/index.js b/packages/worker/src/api/routes/index.js index 90fafffa2a..8b232f7b7c 100644 --- a/packages/worker/src/api/routes/index.js +++ b/packages/worker/src/api/routes/index.js @@ -4,6 +4,7 @@ const groupRoutes = require("./admin/groups") const templateRoutes = require("./admin/templates") const emailRoutes = require("./admin/email") const authRoutes = require("./admin/auth") +const roleRoutes = require("./admin/roles") const appRoutes = require("./app") exports.routes = [ @@ -14,4 +15,5 @@ exports.routes = [ appRoutes, templateRoutes, emailRoutes, + roleRoutes, ]