@budibase/backend-core 2.13.13 → 2.13.15

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.
Files changed (66) hide show
  1. package/dist/index.js +355 -24
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +4 -4
  5. package/dist/src/auth/auth.js.map +1 -1
  6. package/dist/src/configs/configs.js +3 -4
  7. package/dist/src/configs/configs.js.map +1 -1
  8. package/dist/src/constants/db.js.map +1 -1
  9. package/dist/src/db/utils.js.map +1 -1
  10. package/dist/src/docIds/conversions.js.map +1 -1
  11. package/dist/src/events/processors/posthog/index.js.map +1 -1
  12. package/dist/src/features/index.js.map +1 -1
  13. package/dist/src/index.js.map +1 -1
  14. package/dist/src/installation.js +2 -3
  15. package/dist/src/installation.js.map +1 -1
  16. package/dist/src/logging/correlation/correlation.js.map +1 -1
  17. package/dist/src/logging/correlation/middleware.js.map +1 -1
  18. package/dist/src/logging/pino/middleware.js.map +1 -1
  19. package/dist/src/middleware/index.js.map +1 -1
  20. package/dist/src/middleware/passport/sso/google.js.map +1 -1
  21. package/dist/src/objectStore/objectStore.js.map +1 -1
  22. package/dist/src/security/roles.js +1 -2
  23. package/dist/src/security/roles.js.map +1 -1
  24. package/dist/src/security/sessions.js.map +1 -1
  25. package/dist/src/users/db.d.ts +5 -0
  26. package/dist/src/users/db.js +28 -2
  27. package/dist/src/users/db.js.map +1 -1
  28. package/dist/src/users/users.d.ts +12 -11
  29. package/dist/src/users/users.js +175 -144
  30. package/dist/src/users/users.js.map +1 -1
  31. package/dist/src/utils/hashing.js.map +1 -1
  32. package/dist/src/utils/utils.js.map +1 -1
  33. package/dist/tests/core/utilities/mocks/alerts.js.map +1 -1
  34. package/dist/tests/core/utilities/mocks/index.js.map +1 -1
  35. package/dist/tests/core/utilities/structures/generator.js.map +1 -1
  36. package/dist/tests/jestSetup.js.map +1 -1
  37. package/package.json +4 -4
  38. package/src/auth/auth.ts +2 -0
  39. package/src/configs/configs.ts +3 -4
  40. package/src/constants/db.ts +1 -0
  41. package/src/db/utils.ts +1 -0
  42. package/src/docIds/conversions.ts +1 -0
  43. package/src/events/processors/posthog/index.ts +1 -0
  44. package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +2 -0
  45. package/src/features/index.ts +1 -0
  46. package/src/index.ts +1 -0
  47. package/src/installation.ts +1 -2
  48. package/src/logging/correlation/correlation.ts +1 -0
  49. package/src/logging/correlation/middleware.ts +1 -0
  50. package/src/logging/pino/middleware.ts +3 -0
  51. package/src/middleware/index.ts +1 -0
  52. package/src/middleware/passport/sso/google.ts +1 -0
  53. package/src/middleware/passport/sso/tests/google.spec.ts +1 -0
  54. package/src/middleware/passport/sso/tests/sso.spec.ts +1 -0
  55. package/src/middleware/tests/builder.spec.ts +1 -0
  56. package/src/objectStore/objectStore.ts +1 -0
  57. package/src/security/roles.ts +7 -2
  58. package/src/security/sessions.ts +1 -0
  59. package/src/users/db.ts +33 -5
  60. package/src/users/users.ts +28 -16
  61. package/src/utils/hashing.ts +1 -0
  62. package/src/utils/utils.ts +1 -0
  63. package/tests/core/utilities/mocks/alerts.ts +1 -0
  64. package/tests/core/utilities/mocks/index.ts +1 -0
  65. package/tests/core/utilities/structures/generator.ts +1 -0
  66. package/tests/jestSetup.ts +1 -0
@@ -1,4 +1,5 @@
1
1
  import { Header } from "../../constants"
2
+
2
3
  const correlator = require("correlation-id")
3
4
 
4
5
  export const setHeader = (headers: any) => {
@@ -1,5 +1,6 @@
1
1
  import { Header } from "../../constants"
2
2
  import { v4 as uuid } from "uuid"
3
+
3
4
  const correlator = require("correlation-id")
4
5
 
5
6
  const correlation = (ctx: any, next: any) => {
@@ -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 {
@@ -2,6 +2,7 @@ export * as local from "./passport/local"
2
2
  export * as google from "./passport/sso/google"
3
3
  export * as oidc from "./passport/sso/oidc"
4
4
  import * as datasourceGoogle from "./passport/datasource/google"
5
+
5
6
  export const datasource = {
6
7
  google: datasourceGoogle,
7
8
  }
@@ -8,6 +8,7 @@ import {
8
8
  SaveSSOUserFunction,
9
9
  GoogleInnerConfig,
10
10
  } from "@budibase/types"
11
+
11
12
  const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy
12
13
 
13
14
  export function buildVerifyFn(saveUserFn: SaveSSOUserFunction) {
@@ -6,6 +6,7 @@ const mockStrategy = require("passport-google-oauth").OAuth2Strategy
6
6
 
7
7
  jest.mock("../sso")
8
8
  import * as _sso from "../sso"
9
+
9
10
  const sso = jest.mocked(_sso)
10
11
 
11
12
  const mockSaveUserFn = jest.fn()
@@ -11,6 +11,7 @@ const mockSaveUser = jest.fn()
11
11
 
12
12
  jest.mock("../../../../users")
13
13
  import * as _users from "../../../../users"
14
+
14
15
  const users = jest.mocked(_users)
15
16
 
16
17
  const getErrorMessage = () => {
@@ -5,6 +5,7 @@ import { structures } from "../../../tests"
5
5
  import { ContextUser, ServiceType } from "@budibase/types"
6
6
  import { doInAppContext } from "../../context"
7
7
  import env from "../../environment"
8
+
8
9
  env._set("SERVICE_TYPE", ServiceType.APPS)
9
10
 
10
11
  const appId = "app_aaa"
@@ -1,4 +1,5 @@
1
1
  const sanitize = require("sanitize-s3-objectkey")
2
+
2
3
  import AWS from "aws-sdk"
3
4
  import stream, { Readable } from "stream"
4
5
  import fetch from "node-fetch"
@@ -1,7 +1,12 @@
1
1
  import { BuiltinPermissionID, PermissionLevel } from "./permissions"
2
- import { prefixRoleID, getRoleParams, DocumentType, SEPARATOR } from "../db"
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
 
@@ -1,6 +1,7 @@
1
1
  const redis = require("../redis/init")
2
2
  const { v4: uuidv4 } = require("uuid")
3
3
  const { logWarn } = require("../logging")
4
+
4
5
  import env from "../environment"
5
6
  import {
6
7
  Session,
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,
@@ -467,7 +464,7 @@ export class UserDB {
467
464
  if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
468
465
  // root account holder can't be deleted from inside budibase
469
466
  const email = dbUser.email
470
- const account = await accounts.getAccount(email)
467
+ const account = await accountSdk.getAccount(email)
471
468
  if (account) {
472
469
  if (dbUser.userId === getIdentity()!._id) {
473
470
  throw new HTTPError('Please visit "Account" to delete this user', 400)
@@ -488,6 +485,37 @@ export class UserDB {
488
485
  await sessions.invalidateSessions(userId, { reason: "deletion" })
489
486
  }
490
487
 
488
+ static async createAdminUser(
489
+ email: string,
490
+ password: string,
491
+ tenantId: string,
492
+ opts?: { ssoId?: string; hashPassword?: boolean; requirePassword?: boolean }
493
+ ) {
494
+ const user: User = {
495
+ email: email,
496
+ password: password,
497
+ createdAt: Date.now(),
498
+ roles: {},
499
+ builder: {
500
+ global: true,
501
+ },
502
+ admin: {
503
+ global: true,
504
+ },
505
+ tenantId,
506
+ }
507
+ if (opts?.ssoId) {
508
+ user.ssoId = opts.ssoId
509
+ }
510
+ // always bust checklist beforehand, if an error occurs but can proceed, don't get
511
+ // stuck in a cycle
512
+ await cache.bustCache(cache.CacheKey.CHECKLIST)
513
+ return await UserDB.save(user, {
514
+ hashPassword: opts?.hashPassword,
515
+ requirePassword: opts?.requirePassword,
516
+ })
517
+ }
518
+
491
519
  static async getGroups(groupIds: string[]) {
492
520
  return await this.groups.getBulk(groupIds)
493
521
  }
@@ -43,7 +43,7 @@ function removeUserPassword(users: User | User[]) {
43
43
  return users
44
44
  }
45
45
 
46
- export const isSupportedUserSearch = (query: SearchQuery) => {
46
+ export function isSupportedUserSearch(query: SearchQuery) {
47
47
  const allowed = [
48
48
  { op: SearchQueryOperators.STRING, key: "email" },
49
49
  { op: SearchQueryOperators.EQUAL, key: "_id" },
@@ -68,10 +68,10 @@ export const isSupportedUserSearch = (query: SearchQuery) => {
68
68
  return true
69
69
  }
70
70
 
71
- export const bulkGetGlobalUsersById = async (
71
+ export async function bulkGetGlobalUsersById(
72
72
  userIds: string[],
73
73
  opts?: GetOpts
74
- ) => {
74
+ ) {
75
75
  const db = getGlobalDB()
76
76
  let users = (
77
77
  await db.allDocs({
@@ -85,7 +85,7 @@ export const bulkGetGlobalUsersById = async (
85
85
  return users
86
86
  }
87
87
 
88
- export const getAllUserIds = async () => {
88
+ export async function getAllUserIds() {
89
89
  const db = getGlobalDB()
90
90
  const startKey = `${DocumentType.USER}${SEPARATOR}`
91
91
  const response = await db.allDocs({
@@ -95,7 +95,7 @@ export const getAllUserIds = async () => {
95
95
  return response.rows.map(row => row.id)
96
96
  }
97
97
 
98
- export const bulkUpdateGlobalUsers = async (users: User[]) => {
98
+ export async function bulkUpdateGlobalUsers(users: User[]) {
99
99
  const db = getGlobalDB()
100
100
  return (await db.bulkDocs(users)) as BulkDocsResponse
101
101
  }
@@ -113,10 +113,10 @@ export async function getById(id: string, opts?: GetOpts): Promise<User> {
113
113
  * Given an email address this will use a view to search through
114
114
  * all the users to find one with this email address.
115
115
  */
116
- export const getGlobalUserByEmail = async (
116
+ export async function getGlobalUserByEmail(
117
117
  email: String,
118
118
  opts?: GetOpts
119
- ): Promise<User | undefined> => {
119
+ ): Promise<User | undefined> {
120
120
  if (email == null) {
121
121
  throw "Must supply an email address to view"
122
122
  }
@@ -139,11 +139,23 @@ export const getGlobalUserByEmail = async (
139
139
  return user
140
140
  }
141
141
 
142
- export const searchGlobalUsersByApp = async (
142
+ export async function doesUserExist(email: string) {
143
+ try {
144
+ const user = await getGlobalUserByEmail(email)
145
+ if (Array.isArray(user) || user != null) {
146
+ return true
147
+ }
148
+ } catch (err) {
149
+ return false
150
+ }
151
+ return false
152
+ }
153
+
154
+ export async function searchGlobalUsersByApp(
143
155
  appId: any,
144
156
  opts: DatabaseQueryOpts,
145
157
  getOpts?: GetOpts
146
- ) => {
158
+ ) {
147
159
  if (typeof appId !== "string") {
148
160
  throw new Error("Must provide a string based app ID")
149
161
  }
@@ -167,10 +179,10 @@ export const searchGlobalUsersByApp = async (
167
179
  Return any user who potentially has access to the application
168
180
  Admins, developers and app users with the explicitly role.
169
181
  */
170
- export const searchGlobalUsersByAppAccess = async (
182
+ export async function searchGlobalUsersByAppAccess(
171
183
  appId: any,
172
184
  opts?: { limit?: number }
173
- ) => {
185
+ ) {
174
186
  const roleSelector = `roles.${appId}`
175
187
 
176
188
  let orQuery: any[] = [
@@ -205,7 +217,7 @@ export const searchGlobalUsersByAppAccess = async (
205
217
  return resp.rows
206
218
  }
207
219
 
208
- export const getGlobalUserByAppPage = (appId: string, user: User) => {
220
+ export function getGlobalUserByAppPage(appId: string, user: User) {
209
221
  if (!user) {
210
222
  return
211
223
  }
@@ -215,11 +227,11 @@ export const getGlobalUserByAppPage = (appId: string, user: User) => {
215
227
  /**
216
228
  * Performs a starts with search on the global email view.
217
229
  */
218
- export const searchGlobalUsersByEmail = async (
230
+ export async function searchGlobalUsersByEmail(
219
231
  email: string | unknown,
220
232
  opts: any,
221
233
  getOpts?: GetOpts
222
- ) => {
234
+ ) {
223
235
  if (typeof email !== "string") {
224
236
  throw new Error("Must provide a string to search by")
225
237
  }
@@ -242,12 +254,12 @@ export const searchGlobalUsersByEmail = async (
242
254
  }
243
255
 
244
256
  const PAGE_LIMIT = 8
245
- export const paginatedUsers = async ({
257
+ export async function paginatedUsers({
246
258
  bookmark,
247
259
  query,
248
260
  appId,
249
261
  limit,
250
- }: SearchUsersRequest = {}) => {
262
+ }: SearchUsersRequest = {}) {
251
263
  const db = getGlobalDB()
252
264
  const pageSize = limit ?? PAGE_LIMIT
253
265
  const pageLimit = pageSize + 1
@@ -1,4 +1,5 @@
1
1
  import env from "../environment"
2
+
2
3
  export * from "../docIds/newid"
3
4
  const bcrypt = env.JS_BCRYPT ? require("bcryptjs") : require("bcrypt")
4
5
 
@@ -11,6 +11,7 @@ import {
11
11
  TenantResolutionStrategy,
12
12
  } from "@budibase/types"
13
13
  import type { SetOption } from "cookies"
14
+
14
15
  const jwt = require("jsonwebtoken")
15
16
 
16
17
  const APP_PREFIX = DocumentType.APP + SEPARATOR
@@ -1,3 +1,4 @@
1
1
  jest.mock("../../../../src/logging/alerts")
2
2
  import * as _alerts from "../../../../src/logging/alerts"
3
+
3
4
  export const alerts = jest.mocked(_alerts)
@@ -1,5 +1,6 @@
1
1
  jest.mock("../../../../src/accounts")
2
2
  import * as _accounts from "../../../../src/accounts"
3
+
3
4
  export const accounts = jest.mocked(_accounts)
4
5
 
5
6
  export * as date from "./date"
@@ -1,2 +1,3 @@
1
1
  import Chance from "./Chance"
2
+
2
3
  export const generator = new Chance()
@@ -9,6 +9,7 @@ mocks.fetch.enable()
9
9
  // mock all dates to 2020-01-01T00:00:00.000Z
10
10
  // use tk.reset() to use real dates in individual tests
11
11
  import tk from "timekeeper"
12
+
12
13
  tk.freeze(mocks.date.MOCK_DATE)
13
14
 
14
15
  if (!process.env.DEBUG) {