From 7a74ce98f103c031464a499ea082a102c7e14f61 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 31 Jul 2023 18:46:21 +0100 Subject: [PATCH] Moving user functions in UserDB to fully static as none of the class properties ever change - simplifying currying. --- packages/backend-core/src/users/db.ts | 65 ++++++++++++-------------- packages/pro | 2 +- packages/worker/src/sdk/auth/auth.ts | 11 ++--- packages/worker/src/sdk/users/index.ts | 3 +- 4 files changed, 38 insertions(+), 43 deletions(-) diff --git a/packages/backend-core/src/users/db.ts b/packages/backend-core/src/users/db.ts index dba17e8975..55cc97bb1c 100644 --- a/packages/backend-core/src/users/db.ts +++ b/packages/backend-core/src/users/db.ts @@ -45,18 +45,17 @@ const bulkDeleteProcessing = async (dbUser: User) => { } export class UserDB { - quotas: QuotaFns - groups: GroupFns - features: FeatureFns + static quotas: QuotaFns + static groups: GroupFns + static features: FeatureFns - constructor(quotaFns: QuotaFns, groupFns: GroupFns, featureFns: FeatureFns) { - this.quotas = quotaFns - this.groups = groupFns - this.features = featureFns + static init(quotaFns: QuotaFns, groupFns: GroupFns, featureFns: FeatureFns) { + UserDB.quotas = quotaFns + UserDB.groups = groupFns + UserDB.features = featureFns } - async isPreventPasswordActions(user: User, account?: Account) { - const userDb = this + static async isPreventPasswordActions(user: User, account?: Account) { // when in maintenance mode we allow sso users with the admin role // to perform any password action - this prevents lockout if (env.ENABLE_SSO_MAINTENANCE_MODE && isAdmin(user)) { @@ -64,7 +63,7 @@ export class UserDB { } // SSO is enforced for all users - if (await userDb.features.isSSOEnforced()) { + if (await UserDB.features.isSSOEnforced()) { return true } @@ -80,7 +79,7 @@ export class UserDB { return !!(account && account.email === user.email && isSSOAccount(account)) } - async buildUser( + static async buildUser( user: User, opts: SaveUserOpts = { hashPassword: true, @@ -99,7 +98,7 @@ export class UserDB { let hashedPassword if (password) { - if (await this.isPreventPasswordActions(user, account)) { + if (await UserDB.isPreventPasswordActions(user, account)) { throw new HTTPError("Password change is disabled for this user", 400) } hashedPassword = opts.hashPassword ? await hash(password) : password @@ -109,7 +108,7 @@ export class UserDB { // passwords are never required if sso is enforced const requirePasswords = - opts.requirePassword && !(await this.features.isSSOEnforced()) + opts.requirePassword && !(await UserDB.features.isSSOEnforced()) if (!hashedPassword && requirePasswords) { throw "Password must be specified." } @@ -136,7 +135,7 @@ export class UserDB { return fullUser } - async allUsers() { + static async allUsers() { const db = getGlobalDB() const response = await db.allDocs( dbUtils.getGlobalUserParams(null, { @@ -146,14 +145,14 @@ export class UserDB { return response.rows.map((row: any) => row.doc) } - async countUsersByApp(appId: string) { + static async countUsersByApp(appId: string) { let response: any = await usersCore.searchGlobalUsersByApp(appId, {}) return { userCount: response.length, } } - async getUsersByAppAccess(appId?: string) { + static async getUsersByAppAccess(appId?: string) { const opts: any = { include_docs: true, limit: 50, @@ -165,14 +164,14 @@ export class UserDB { return response } - async getUserByEmail(email: string) { + static async getUserByEmail(email: string) { return usersCore.getGlobalUserByEmail(email) } /** * Gets a user by ID from the global database, based on the current tenancy. */ - async getUser(userId: string) { + static async getUser(userId: string) { const user = await usersCore.getById(userId) if (user) { delete user.password @@ -180,8 +179,7 @@ export class UserDB { return user } - async save(user: User, opts: SaveUserOpts = {}): Promise { - const userDb = this + static async save(user: User, opts: SaveUserOpts = {}): Promise { // default booleans to true if (opts.hashPassword == null) { opts.hashPassword = true @@ -200,7 +198,7 @@ export class UserDB { if ( user.builder?.apps?.length && - !(await userDb.features.isAppBuildersEnabled()) + !(await UserDB.features.isAppBuildersEnabled()) ) { throw new Error("Unable to update app builders, please check license") } @@ -232,10 +230,10 @@ export class UserDB { } const change = dbUser ? 0 : 1 // no change if there is existing user - return userDb.quotas.addUsers(change, async () => { + return UserDB.quotas.addUsers(change, async () => { await validateUniqueUser(email, tenantId) - let builtUser = await userDb.buildUser(user, opts, tenantId, dbUser) + let builtUser = await UserDB.buildUser(user, opts, tenantId, dbUser) // don't allow a user to update its own roles/perms if (opts.currentUserId && opts.currentUserId === dbUser?._id) { builtUser = usersCore.cleanseUserObject(builtUser, dbUser) as User @@ -253,7 +251,7 @@ export class UserDB { if (userGroups.length > 0) { for (let groupId of userGroups) { - groupPromises.push(userDb.groups.addUsers(groupId, [_id!])) + groupPromises.push(UserDB.groups.addUsers(groupId, [_id!])) } } } @@ -281,11 +279,10 @@ export class UserDB { }) } - async bulkCreate( + static async bulkCreate( newUsersRequested: User[], groups: string[] ): Promise { - const userDb = this const tenantId = getTenantId() let usersToSave: any[] = [] @@ -313,11 +310,11 @@ export class UserDB { } const account = await accountSdk.getAccountByTenantId(tenantId) - return userDb.quotas.addUsers(newUsers.length, async () => { + return UserDB.quotas.addUsers(newUsers.length, async () => { // create the promises array that will be called by bulkDocs newUsers.forEach((user: any) => { usersToSave.push( - userDb.buildUser( + UserDB.buildUser( user, { hashPassword: true, @@ -353,7 +350,7 @@ export class UserDB { const groupPromises = [] const createdUserIds = saved.map(user => user._id) for (let groupId of groups) { - groupPromises.push(userDb.groups.addUsers(groupId, createdUserIds)) + groupPromises.push(UserDB.groups.addUsers(groupId, createdUserIds)) } await Promise.all(groupPromises) } @@ -365,8 +362,7 @@ export class UserDB { }) } - async bulkDelete(userIds: string[]): Promise { - const userDb = this + static async bulkDelete(userIds: string[]): Promise { const db = getGlobalDB() const response: BulkUserDeleted = { @@ -404,7 +400,7 @@ export class UserDB { })) const dbResponse = await usersCore.bulkUpdateGlobalUsers(toDelete) - await userDb.quotas.removeUsers(toDelete.length) + await UserDB.quotas.removeUsers(toDelete.length) for (let user of usersToDelete) { await bulkDeleteProcessing(user) } @@ -434,8 +430,7 @@ export class UserDB { return response } - async destroy(id: string) { - const userDb = this + static async destroy(id: string) { const db = getGlobalDB() const dbUser = (await db.get(id)) as User const userId = dbUser._id as string @@ -457,7 +452,7 @@ export class UserDB { await db.remove(userId, dbUser._rev) - await userDb.quotas.removeUsers(1) + await UserDB.quotas.removeUsers(1) await eventHelpers.handleDeleteEvents(dbUser) await cache.user.invalidateUser(userId) await sessions.invalidateSessions(userId, { reason: "deletion" }) diff --git a/packages/pro b/packages/pro index 23b31acfed..1002b40b03 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 23b31acfedf962ccdc646ee791e5290f6147bf16 +Subproject commit 1002b40b038351419c05daf416f3b94623d3886b diff --git a/packages/worker/src/sdk/auth/auth.ts b/packages/worker/src/sdk/auth/auth.ts index d3abbf7092..d989113c3d 100644 --- a/packages/worker/src/sdk/auth/auth.ts +++ b/packages/worker/src/sdk/auth/auth.ts @@ -1,11 +1,11 @@ import { auth as authCore, - tenancy, - utils as coreUtils, - sessions, + env as coreEnv, events, HTTPError, - env as coreEnv, + sessions, + tenancy, + utils as coreUtils, } from "@budibase/backend-core" import { PlatformLogoutOpts, User } from "@budibase/types" import jwt from "jsonwebtoken" @@ -20,7 +20,7 @@ export async function loginUser(user: User) { const sessionId = coreUtils.newid() const tenantId = tenancy.getTenantId() await sessions.createASession(user._id!, { sessionId, tenantId }) - const token = jwt.sign( + return jwt.sign( { userId: user._id, sessionId, @@ -28,7 +28,6 @@ export async function loginUser(user: User) { }, coreEnv.JWT_SECRET! ) - return token } export async function logout(opts: PlatformLogoutOpts) { diff --git a/packages/worker/src/sdk/users/index.ts b/packages/worker/src/sdk/users/index.ts index d016769c0f..c15ae8cba1 100644 --- a/packages/worker/src/sdk/users/index.ts +++ b/packages/worker/src/sdk/users/index.ts @@ -2,5 +2,6 @@ export * from "./users" import { users } from "@budibase/backend-core" import * as pro from "@budibase/pro" // pass in the components which are specific to the worker/the parts of pro which backend-core cannot access -export const db = new users.UserDB(pro.quotas, pro.groups, pro.features) +users.UserDB.init(pro.quotas, pro.groups, pro.features) +export const db = users.UserDB export { users as core } from "@budibase/backend-core"