@budibase/backend-core 2.13.14 → 2.13.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +302 -242
- package/dist/index.js.map +3 -3
- package/dist/index.js.meta.json +1 -1
- package/dist/package.json +4 -4
- package/dist/plugins.js.meta.json +1 -1
- package/dist/src/auth/auth.js.map +1 -1
- package/dist/src/configs/configs.js +3 -4
- package/dist/src/configs/configs.js.map +1 -1
- package/dist/src/constants/db.js.map +1 -1
- package/dist/src/db/utils.js.map +1 -1
- package/dist/src/docIds/conversions.js.map +1 -1
- package/dist/src/events/processors/posthog/index.js.map +1 -1
- package/dist/src/features/index.js.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/installation.js +2 -3
- package/dist/src/installation.js.map +1 -1
- package/dist/src/logging/correlation/correlation.js.map +1 -1
- package/dist/src/logging/correlation/middleware.js.map +1 -1
- package/dist/src/logging/pino/middleware.js.map +1 -1
- package/dist/src/middleware/index.js.map +1 -1
- package/dist/src/middleware/passport/sso/google.js.map +1 -1
- package/dist/src/objectStore/objectStore.js.map +1 -1
- package/dist/src/security/permissions.d.ts +1 -0
- package/dist/src/security/permissions.js +2 -1
- package/dist/src/security/permissions.js.map +1 -1
- package/dist/src/security/roles.js +1 -2
- package/dist/src/security/roles.js.map +1 -1
- package/dist/src/security/sessions.js.map +1 -1
- package/dist/src/users/db.d.ts +6 -1
- package/dist/src/users/db.js +29 -8
- package/dist/src/users/db.js.map +1 -1
- package/dist/src/users/users.d.ts +14 -11
- package/dist/src/users/users.js +200 -144
- package/dist/src/users/users.js.map +1 -1
- package/dist/src/utils/hashing.js.map +1 -1
- package/dist/src/utils/utils.js.map +1 -1
- package/dist/tests/core/utilities/mocks/alerts.js.map +1 -1
- package/dist/tests/core/utilities/mocks/index.js.map +1 -1
- package/dist/tests/core/utilities/structures/generator.js.map +1 -1
- package/dist/tests/jestSetup.js.map +1 -1
- package/package.json +4 -4
- package/src/auth/auth.ts +2 -0
- package/src/configs/configs.ts +3 -4
- package/src/constants/db.ts +1 -0
- package/src/db/utils.ts +1 -0
- package/src/docIds/conversions.ts +1 -0
- package/src/events/processors/posthog/index.ts +1 -0
- package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +2 -0
- package/src/features/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/installation.ts +1 -2
- package/src/logging/correlation/correlation.ts +1 -0
- package/src/logging/correlation/middleware.ts +1 -0
- package/src/logging/pino/middleware.ts +3 -0
- package/src/middleware/index.ts +1 -0
- package/src/middleware/passport/sso/google.ts +1 -0
- package/src/middleware/passport/sso/tests/google.spec.ts +1 -0
- package/src/middleware/passport/sso/tests/sso.spec.ts +1 -0
- package/src/middleware/tests/builder.spec.ts +1 -0
- package/src/objectStore/objectStore.ts +1 -0
- package/src/security/permissions.ts +1 -0
- package/src/security/roles.ts +7 -2
- package/src/security/sessions.ts +1 -0
- package/src/users/db.ts +35 -14
- package/src/users/users.ts +46 -16
- package/src/utils/hashing.ts +1 -0
- package/src/utils/utils.ts +1 -0
- package/tests/core/utilities/mocks/alerts.ts +1 -0
- package/tests/core/utilities/mocks/index.ts +1 -0
- package/tests/core/utilities/structures/generator.ts +1 -0
- package/tests/jestSetup.ts +1 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { testEnv } from "../../../../../tests/extra"
|
|
2
2
|
import PosthogProcessor from "../PosthogProcessor"
|
|
3
3
|
import { Event, IdentityType, Hosting } from "@budibase/types"
|
|
4
|
+
|
|
4
5
|
const tk = require("timekeeper")
|
|
6
|
+
|
|
5
7
|
import * as cache from "../../../../cache/generic"
|
|
6
8
|
import { CacheKey } from "../../../../cache/generic"
|
|
7
9
|
import * as context from "../../../../context"
|
package/src/features/index.ts
CHANGED
package/src/index.ts
CHANGED
package/src/installation.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { newid } from "./utils"
|
|
2
2
|
import * as events from "./events"
|
|
3
|
-
import { StaticDatabases } from "./db"
|
|
4
|
-
import { doWithDB } from "./db"
|
|
3
|
+
import { StaticDatabases, doWithDB } from "./db"
|
|
5
4
|
import { Installation, IdentityType, Database } from "@budibase/types"
|
|
6
5
|
import * as context from "./context"
|
|
7
6
|
import semver from "semver"
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import env from "../../environment"
|
|
2
2
|
import { logger } from "./logger"
|
|
3
3
|
import { IncomingMessage } from "http"
|
|
4
|
+
|
|
4
5
|
const pino = require("koa-pino-logger")
|
|
6
|
+
|
|
5
7
|
import { Options } from "pino-http"
|
|
6
8
|
import { Ctx } from "@budibase/types"
|
|
9
|
+
|
|
7
10
|
const correlator = require("correlation-id")
|
|
8
11
|
|
|
9
12
|
export function pinoSettings(): Options {
|
package/src/middleware/index.ts
CHANGED
|
@@ -160,4 +160,5 @@ export function isPermissionLevelHigherThanRead(level: PermissionLevel) {
|
|
|
160
160
|
|
|
161
161
|
// utility as a lot of things need simply the builder permission
|
|
162
162
|
export const BUILDER = PermissionType.BUILDER
|
|
163
|
+
export const CREATOR = PermissionType.CREATOR
|
|
163
164
|
export const GLOBAL_BUILDER = PermissionType.GLOBAL_BUILDER
|
package/src/security/roles.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { BuiltinPermissionID, PermissionLevel } from "./permissions"
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
prefixRoleID,
|
|
4
|
+
getRoleParams,
|
|
5
|
+
DocumentType,
|
|
6
|
+
SEPARATOR,
|
|
7
|
+
doWithDB,
|
|
8
|
+
} from "../db"
|
|
3
9
|
import { getAppDB } from "../context"
|
|
4
|
-
import { doWithDB } from "../db"
|
|
5
10
|
import { Screen, Role as RoleDoc } from "@budibase/types"
|
|
6
11
|
import cloneDeep from "lodash/fp/cloneDeep"
|
|
7
12
|
|
package/src/security/sessions.ts
CHANGED
package/src/users/db.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import env from "../environment"
|
|
2
2
|
import * as eventHelpers from "./events"
|
|
3
|
-
import * as accounts from "../accounts"
|
|
4
3
|
import * as accountSdk from "../accounts"
|
|
5
4
|
import * as cache from "../cache"
|
|
6
|
-
import { getGlobalDB, getIdentity, getTenantId } from "../context"
|
|
5
|
+
import { doInTenant, getGlobalDB, getIdentity, getTenantId } from "../context"
|
|
7
6
|
import * as dbUtils from "../db"
|
|
8
7
|
import { EmailUnavailableError, HTTPError } from "../errors"
|
|
9
8
|
import * as platform from "../platform"
|
|
@@ -11,12 +10,10 @@ import * as sessions from "../security/sessions"
|
|
|
11
10
|
import * as usersCore from "./users"
|
|
12
11
|
import {
|
|
13
12
|
Account,
|
|
14
|
-
AllDocsResponse,
|
|
15
13
|
BulkUserCreated,
|
|
16
14
|
BulkUserDeleted,
|
|
17
15
|
isSSOAccount,
|
|
18
16
|
isSSOUser,
|
|
19
|
-
RowResponse,
|
|
20
17
|
SaveUserOpts,
|
|
21
18
|
User,
|
|
22
19
|
UserStatus,
|
|
@@ -149,12 +146,12 @@ export class UserDB {
|
|
|
149
146
|
|
|
150
147
|
static async allUsers() {
|
|
151
148
|
const db = getGlobalDB()
|
|
152
|
-
const response = await db.allDocs(
|
|
149
|
+
const response = await db.allDocs<User>(
|
|
153
150
|
dbUtils.getGlobalUserParams(null, {
|
|
154
151
|
include_docs: true,
|
|
155
152
|
})
|
|
156
153
|
)
|
|
157
|
-
return response.rows.map(
|
|
154
|
+
return response.rows.map(row => row.doc!)
|
|
158
155
|
}
|
|
159
156
|
|
|
160
157
|
static async countUsersByApp(appId: string) {
|
|
@@ -212,13 +209,6 @@ export class UserDB {
|
|
|
212
209
|
throw new Error("_id or email is required")
|
|
213
210
|
}
|
|
214
211
|
|
|
215
|
-
if (
|
|
216
|
-
user.builder?.apps?.length &&
|
|
217
|
-
!(await UserDB.features.isAppBuildersEnabled())
|
|
218
|
-
) {
|
|
219
|
-
throw new Error("Unable to update app builders, please check license")
|
|
220
|
-
}
|
|
221
|
-
|
|
222
212
|
let dbUser: User | undefined
|
|
223
213
|
if (_id) {
|
|
224
214
|
// try to get existing user from db
|
|
@@ -467,7 +457,7 @@ export class UserDB {
|
|
|
467
457
|
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
|
|
468
458
|
// root account holder can't be deleted from inside budibase
|
|
469
459
|
const email = dbUser.email
|
|
470
|
-
const account = await
|
|
460
|
+
const account = await accountSdk.getAccount(email)
|
|
471
461
|
if (account) {
|
|
472
462
|
if (dbUser.userId === getIdentity()!._id) {
|
|
473
463
|
throw new HTTPError('Please visit "Account" to delete this user', 400)
|
|
@@ -488,6 +478,37 @@ export class UserDB {
|
|
|
488
478
|
await sessions.invalidateSessions(userId, { reason: "deletion" })
|
|
489
479
|
}
|
|
490
480
|
|
|
481
|
+
static async createAdminUser(
|
|
482
|
+
email: string,
|
|
483
|
+
password: string,
|
|
484
|
+
tenantId: string,
|
|
485
|
+
opts?: { ssoId?: string; hashPassword?: boolean; requirePassword?: boolean }
|
|
486
|
+
) {
|
|
487
|
+
const user: User = {
|
|
488
|
+
email: email,
|
|
489
|
+
password: password,
|
|
490
|
+
createdAt: Date.now(),
|
|
491
|
+
roles: {},
|
|
492
|
+
builder: {
|
|
493
|
+
global: true,
|
|
494
|
+
},
|
|
495
|
+
admin: {
|
|
496
|
+
global: true,
|
|
497
|
+
},
|
|
498
|
+
tenantId,
|
|
499
|
+
}
|
|
500
|
+
if (opts?.ssoId) {
|
|
501
|
+
user.ssoId = opts.ssoId
|
|
502
|
+
}
|
|
503
|
+
// always bust checklist beforehand, if an error occurs but can proceed, don't get
|
|
504
|
+
// stuck in a cycle
|
|
505
|
+
await cache.bustCache(cache.CacheKey.CHECKLIST)
|
|
506
|
+
return await UserDB.save(user, {
|
|
507
|
+
hashPassword: opts?.hashPassword,
|
|
508
|
+
requirePassword: opts?.requirePassword,
|
|
509
|
+
})
|
|
510
|
+
}
|
|
511
|
+
|
|
491
512
|
static async getGroups(groupIds: string[]) {
|
|
492
513
|
return await this.groups.getBulk(groupIds)
|
|
493
514
|
}
|
package/src/users/users.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
import { getGlobalDB } from "../context"
|
|
26
26
|
import * as context from "../context"
|
|
27
27
|
import { isCreator } from "./utils"
|
|
28
|
+
import { UserDB } from "./db"
|
|
28
29
|
|
|
29
30
|
type GetOpts = { cleanup?: boolean }
|
|
30
31
|
|
|
@@ -43,7 +44,7 @@ function removeUserPassword(users: User | User[]) {
|
|
|
43
44
|
return users
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
export
|
|
47
|
+
export function isSupportedUserSearch(query: SearchQuery) {
|
|
47
48
|
const allowed = [
|
|
48
49
|
{ op: SearchQueryOperators.STRING, key: "email" },
|
|
49
50
|
{ op: SearchQueryOperators.EQUAL, key: "_id" },
|
|
@@ -68,10 +69,10 @@ export const isSupportedUserSearch = (query: SearchQuery) => {
|
|
|
68
69
|
return true
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
export
|
|
72
|
+
export async function bulkGetGlobalUsersById(
|
|
72
73
|
userIds: string[],
|
|
73
74
|
opts?: GetOpts
|
|
74
|
-
)
|
|
75
|
+
) {
|
|
75
76
|
const db = getGlobalDB()
|
|
76
77
|
let users = (
|
|
77
78
|
await db.allDocs({
|
|
@@ -85,7 +86,7 @@ export const bulkGetGlobalUsersById = async (
|
|
|
85
86
|
return users
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
export
|
|
89
|
+
export async function getAllUserIds() {
|
|
89
90
|
const db = getGlobalDB()
|
|
90
91
|
const startKey = `${DocumentType.USER}${SEPARATOR}`
|
|
91
92
|
const response = await db.allDocs({
|
|
@@ -95,7 +96,7 @@ export const getAllUserIds = async () => {
|
|
|
95
96
|
return response.rows.map(row => row.id)
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
export
|
|
99
|
+
export async function bulkUpdateGlobalUsers(users: User[]) {
|
|
99
100
|
const db = getGlobalDB()
|
|
100
101
|
return (await db.bulkDocs(users)) as BulkDocsResponse
|
|
101
102
|
}
|
|
@@ -113,10 +114,10 @@ export async function getById(id: string, opts?: GetOpts): Promise<User> {
|
|
|
113
114
|
* Given an email address this will use a view to search through
|
|
114
115
|
* all the users to find one with this email address.
|
|
115
116
|
*/
|
|
116
|
-
export
|
|
117
|
+
export async function getGlobalUserByEmail(
|
|
117
118
|
email: String,
|
|
118
119
|
opts?: GetOpts
|
|
119
|
-
): Promise<User | undefined>
|
|
120
|
+
): Promise<User | undefined> {
|
|
120
121
|
if (email == null) {
|
|
121
122
|
throw "Must supply an email address to view"
|
|
122
123
|
}
|
|
@@ -139,11 +140,23 @@ export const getGlobalUserByEmail = async (
|
|
|
139
140
|
return user
|
|
140
141
|
}
|
|
141
142
|
|
|
142
|
-
export
|
|
143
|
+
export async function doesUserExist(email: string) {
|
|
144
|
+
try {
|
|
145
|
+
const user = await getGlobalUserByEmail(email)
|
|
146
|
+
if (Array.isArray(user) || user != null) {
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
} catch (err) {
|
|
150
|
+
return false
|
|
151
|
+
}
|
|
152
|
+
return false
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function searchGlobalUsersByApp(
|
|
143
156
|
appId: any,
|
|
144
157
|
opts: DatabaseQueryOpts,
|
|
145
158
|
getOpts?: GetOpts
|
|
146
|
-
)
|
|
159
|
+
) {
|
|
147
160
|
if (typeof appId !== "string") {
|
|
148
161
|
throw new Error("Must provide a string based app ID")
|
|
149
162
|
}
|
|
@@ -167,10 +180,10 @@ export const searchGlobalUsersByApp = async (
|
|
|
167
180
|
Return any user who potentially has access to the application
|
|
168
181
|
Admins, developers and app users with the explicitly role.
|
|
169
182
|
*/
|
|
170
|
-
export
|
|
183
|
+
export async function searchGlobalUsersByAppAccess(
|
|
171
184
|
appId: any,
|
|
172
185
|
opts?: { limit?: number }
|
|
173
|
-
)
|
|
186
|
+
) {
|
|
174
187
|
const roleSelector = `roles.${appId}`
|
|
175
188
|
|
|
176
189
|
let orQuery: any[] = [
|
|
@@ -205,7 +218,7 @@ export const searchGlobalUsersByAppAccess = async (
|
|
|
205
218
|
return resp.rows
|
|
206
219
|
}
|
|
207
220
|
|
|
208
|
-
export
|
|
221
|
+
export function getGlobalUserByAppPage(appId: string, user: User) {
|
|
209
222
|
if (!user) {
|
|
210
223
|
return
|
|
211
224
|
}
|
|
@@ -215,11 +228,11 @@ export const getGlobalUserByAppPage = (appId: string, user: User) => {
|
|
|
215
228
|
/**
|
|
216
229
|
* Performs a starts with search on the global email view.
|
|
217
230
|
*/
|
|
218
|
-
export
|
|
231
|
+
export async function searchGlobalUsersByEmail(
|
|
219
232
|
email: string | unknown,
|
|
220
233
|
opts: any,
|
|
221
234
|
getOpts?: GetOpts
|
|
222
|
-
)
|
|
235
|
+
) {
|
|
223
236
|
if (typeof email !== "string") {
|
|
224
237
|
throw new Error("Must provide a string to search by")
|
|
225
238
|
}
|
|
@@ -242,12 +255,12 @@ export const searchGlobalUsersByEmail = async (
|
|
|
242
255
|
}
|
|
243
256
|
|
|
244
257
|
const PAGE_LIMIT = 8
|
|
245
|
-
export
|
|
258
|
+
export async function paginatedUsers({
|
|
246
259
|
bookmark,
|
|
247
260
|
query,
|
|
248
261
|
appId,
|
|
249
262
|
limit,
|
|
250
|
-
}: SearchUsersRequest = {})
|
|
263
|
+
}: SearchUsersRequest = {}) {
|
|
251
264
|
const db = getGlobalDB()
|
|
252
265
|
const pageSize = limit ?? PAGE_LIMIT
|
|
253
266
|
const pageLimit = pageSize + 1
|
|
@@ -324,3 +337,20 @@ export function cleanseUserObject(user: User | ContextUser, base?: User) {
|
|
|
324
337
|
}
|
|
325
338
|
return user
|
|
326
339
|
}
|
|
340
|
+
|
|
341
|
+
export async function addAppBuilder(user: User, appId: string) {
|
|
342
|
+
const prodAppId = getProdAppID(appId)
|
|
343
|
+
user.builder ??= {}
|
|
344
|
+
user.builder.creator = true
|
|
345
|
+
user.builder.apps ??= []
|
|
346
|
+
user.builder.apps.push(prodAppId)
|
|
347
|
+
await UserDB.save(user, { hashPassword: false })
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export async function removeAppBuilder(user: User, appId: string) {
|
|
351
|
+
const prodAppId = getProdAppID(appId)
|
|
352
|
+
if (user.builder && user.builder.apps?.includes(prodAppId)) {
|
|
353
|
+
user.builder.apps = user.builder.apps.filter(id => id !== prodAppId)
|
|
354
|
+
}
|
|
355
|
+
await UserDB.save(user, { hashPassword: false })
|
|
356
|
+
}
|
package/src/utils/hashing.ts
CHANGED
package/src/utils/utils.ts
CHANGED