@budibase/backend-core 3.2.5 → 3.2.7

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 (276) hide show
  1. package/dist/index.js +7 -1
  2. package/dist/index.js.map +2 -2
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +11 -4
  5. package/dist/plugins.js.meta.json +1 -1
  6. package/dist/src/environment.d.ts +1 -0
  7. package/dist/src/environment.js +6 -1
  8. package/dist/src/environment.js.map +1 -1
  9. package/package.json +11 -4
  10. package/src/accounts/accounts.ts +0 -82
  11. package/src/accounts/api.ts +0 -59
  12. package/src/accounts/index.ts +0 -1
  13. package/src/auth/auth.ts +0 -210
  14. package/src/auth/index.ts +0 -1
  15. package/src/auth/tests/auth.spec.ts +0 -14
  16. package/src/blacklist/blacklist.ts +0 -54
  17. package/src/blacklist/index.ts +0 -1
  18. package/src/blacklist/tests/blacklist.spec.ts +0 -46
  19. package/src/cache/appMetadata.ts +0 -88
  20. package/src/cache/base/index.ts +0 -150
  21. package/src/cache/docWritethrough.ts +0 -105
  22. package/src/cache/generic.ts +0 -33
  23. package/src/cache/index.ts +0 -8
  24. package/src/cache/invite.ts +0 -86
  25. package/src/cache/passwordReset.ts +0 -49
  26. package/src/cache/tests/docWritethrough.spec.ts +0 -296
  27. package/src/cache/tests/user.spec.ts +0 -145
  28. package/src/cache/tests/writethrough.spec.ts +0 -139
  29. package/src/cache/user.ts +0 -154
  30. package/src/cache/writethrough.ts +0 -133
  31. package/src/configs/configs.ts +0 -263
  32. package/src/configs/index.ts +0 -1
  33. package/src/configs/tests/configs.spec.ts +0 -184
  34. package/src/constants/db.ts +0 -75
  35. package/src/constants/index.ts +0 -2
  36. package/src/constants/misc.ts +0 -36
  37. package/src/context/Context.ts +0 -14
  38. package/src/context/identity.ts +0 -58
  39. package/src/context/index.ts +0 -3
  40. package/src/context/mainContext.ts +0 -422
  41. package/src/context/tests/index.spec.ts +0 -255
  42. package/src/context/types.ts +0 -26
  43. package/src/db/Replication.ts +0 -94
  44. package/src/db/couch/DatabaseImpl.ts +0 -511
  45. package/src/db/couch/connections.ts +0 -89
  46. package/src/db/couch/index.ts +0 -4
  47. package/src/db/couch/pouchDB.ts +0 -97
  48. package/src/db/couch/pouchDump.ts +0 -0
  49. package/src/db/couch/tests/DatabaseImpl.spec.ts +0 -118
  50. package/src/db/couch/utils.ts +0 -55
  51. package/src/db/db.ts +0 -34
  52. package/src/db/errors.ts +0 -14
  53. package/src/db/index.ts +0 -12
  54. package/src/db/instrumentation.ts +0 -199
  55. package/src/db/lucene.ts +0 -721
  56. package/src/db/searchIndexes/index.ts +0 -1
  57. package/src/db/searchIndexes/searchIndexes.ts +0 -62
  58. package/src/db/tests/DatabaseImpl.spec.ts +0 -55
  59. package/src/db/tests/connections.spec.ts +0 -22
  60. package/src/db/tests/index.spec.ts +0 -32
  61. package/src/db/tests/lucene.spec.ts +0 -400
  62. package/src/db/tests/pouch.spec.js +0 -62
  63. package/src/db/tests/utils.spec.ts +0 -63
  64. package/src/db/utils.ts +0 -208
  65. package/src/db/views.ts +0 -245
  66. package/src/docIds/conversions.ts +0 -60
  67. package/src/docIds/ids.ts +0 -126
  68. package/src/docIds/index.ts +0 -2
  69. package/src/docIds/newid.ts +0 -5
  70. package/src/docIds/params.ts +0 -189
  71. package/src/docUpdates/index.ts +0 -24
  72. package/src/environment.ts +0 -293
  73. package/src/errors/errors.ts +0 -119
  74. package/src/errors/index.ts +0 -1
  75. package/src/events/analytics.ts +0 -6
  76. package/src/events/asyncEvents/index.ts +0 -2
  77. package/src/events/asyncEvents/publisher.ts +0 -12
  78. package/src/events/asyncEvents/queue.ts +0 -22
  79. package/src/events/backfill.ts +0 -183
  80. package/src/events/documentId.ts +0 -56
  81. package/src/events/events.ts +0 -47
  82. package/src/events/identification.ts +0 -311
  83. package/src/events/index.ts +0 -15
  84. package/src/events/processors/AnalyticsProcessor.ts +0 -64
  85. package/src/events/processors/AuditLogsProcessor.ts +0 -92
  86. package/src/events/processors/LoggingProcessor.ts +0 -36
  87. package/src/events/processors/Processors.ts +0 -52
  88. package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -38
  89. package/src/events/processors/index.ts +0 -19
  90. package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
  91. package/src/events/processors/posthog/index.ts +0 -3
  92. package/src/events/processors/posthog/rateLimiting.ts +0 -106
  93. package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -164
  94. package/src/events/processors/types.ts +0 -1
  95. package/src/events/publishers/account.ts +0 -41
  96. package/src/events/publishers/ai.ts +0 -21
  97. package/src/events/publishers/app.ts +0 -168
  98. package/src/events/publishers/auditLog.ts +0 -26
  99. package/src/events/publishers/auth.ts +0 -73
  100. package/src/events/publishers/automation.ts +0 -110
  101. package/src/events/publishers/backfill.ts +0 -74
  102. package/src/events/publishers/backup.ts +0 -42
  103. package/src/events/publishers/datasource.ts +0 -48
  104. package/src/events/publishers/email.ts +0 -17
  105. package/src/events/publishers/environmentVariable.ts +0 -38
  106. package/src/events/publishers/group.ts +0 -99
  107. package/src/events/publishers/index.ts +0 -25
  108. package/src/events/publishers/installation.ts +0 -38
  109. package/src/events/publishers/layout.ts +0 -26
  110. package/src/events/publishers/license.ts +0 -84
  111. package/src/events/publishers/org.ts +0 -37
  112. package/src/events/publishers/plugin.ts +0 -47
  113. package/src/events/publishers/query.ts +0 -89
  114. package/src/events/publishers/role.ts +0 -62
  115. package/src/events/publishers/rows.ts +0 -29
  116. package/src/events/publishers/screen.ts +0 -36
  117. package/src/events/publishers/serve.ts +0 -43
  118. package/src/events/publishers/table.ts +0 -70
  119. package/src/events/publishers/user.ts +0 -202
  120. package/src/events/publishers/view.ts +0 -107
  121. package/src/features/features.ts +0 -277
  122. package/src/features/index.ts +0 -2
  123. package/src/features/tests/features.spec.ts +0 -267
  124. package/src/features/tests/utils.ts +0 -64
  125. package/src/helpers.ts +0 -9
  126. package/src/index.ts +0 -59
  127. package/src/installation.ts +0 -115
  128. package/src/logging/alerts.ts +0 -26
  129. package/src/logging/correlation/correlation.ts +0 -15
  130. package/src/logging/correlation/index.ts +0 -1
  131. package/src/logging/correlation/middleware.ts +0 -18
  132. package/src/logging/index.ts +0 -4
  133. package/src/logging/pino/logger.ts +0 -239
  134. package/src/logging/pino/middleware.ts +0 -48
  135. package/src/logging/system.ts +0 -81
  136. package/src/logging/tests/system.spec.ts +0 -61
  137. package/src/middleware/adminOnly.ts +0 -9
  138. package/src/middleware/auditLog.ts +0 -6
  139. package/src/middleware/authenticated.ts +0 -247
  140. package/src/middleware/builderOnly.ts +0 -21
  141. package/src/middleware/builderOrAdmin.ts +0 -21
  142. package/src/middleware/contentSecurityPolicy.ts +0 -113
  143. package/src/middleware/csrf.ts +0 -81
  144. package/src/middleware/errorHandling.ts +0 -43
  145. package/src/middleware/index.ts +0 -24
  146. package/src/middleware/internalApi.ts +0 -23
  147. package/src/middleware/ip.ts +0 -12
  148. package/src/middleware/joi-validator.ts +0 -58
  149. package/src/middleware/matchers.ts +0 -39
  150. package/src/middleware/passport/datasource/google.ts +0 -102
  151. package/src/middleware/passport/local.ts +0 -54
  152. package/src/middleware/passport/sso/google.ts +0 -77
  153. package/src/middleware/passport/sso/oidc.ts +0 -152
  154. package/src/middleware/passport/sso/sso.ts +0 -138
  155. package/src/middleware/passport/sso/tests/google.spec.ts +0 -68
  156. package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -144
  157. package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
  158. package/src/middleware/passport/utils.ts +0 -38
  159. package/src/middleware/querystringToBody.ts +0 -28
  160. package/src/middleware/tenancy.ts +0 -36
  161. package/src/middleware/tests/builder.spec.ts +0 -181
  162. package/src/middleware/tests/contentSecurityPolicy.spec.ts +0 -75
  163. package/src/middleware/tests/matchers.spec.ts +0 -100
  164. package/src/migrations/definitions.ts +0 -40
  165. package/src/migrations/index.ts +0 -2
  166. package/src/migrations/migrations.ts +0 -186
  167. package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
  168. package/src/migrations/tests/migrations.spec.ts +0 -64
  169. package/src/objectStore/buckets/app.ts +0 -53
  170. package/src/objectStore/buckets/global.ts +0 -29
  171. package/src/objectStore/buckets/index.ts +0 -3
  172. package/src/objectStore/buckets/plugins.ts +0 -71
  173. package/src/objectStore/buckets/tests/app.spec.ts +0 -161
  174. package/src/objectStore/buckets/tests/global.spec.ts +0 -74
  175. package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
  176. package/src/objectStore/cloudfront.ts +0 -41
  177. package/src/objectStore/index.ts +0 -3
  178. package/src/objectStore/objectStore.ts +0 -585
  179. package/src/objectStore/utils.ts +0 -113
  180. package/src/platform/index.ts +0 -3
  181. package/src/platform/platformDb.ts +0 -6
  182. package/src/platform/tenants.ts +0 -101
  183. package/src/platform/tests/tenants.spec.ts +0 -26
  184. package/src/platform/users.ts +0 -129
  185. package/src/plugin/index.ts +0 -1
  186. package/src/plugin/tests/validation.spec.ts +0 -209
  187. package/src/plugin/utils.ts +0 -175
  188. package/src/queue/constants.ts +0 -8
  189. package/src/queue/inMemoryQueue.ts +0 -189
  190. package/src/queue/index.ts +0 -2
  191. package/src/queue/listeners.ts +0 -199
  192. package/src/queue/queue.ts +0 -84
  193. package/src/redis/index.ts +0 -6
  194. package/src/redis/init.ts +0 -118
  195. package/src/redis/redis.ts +0 -358
  196. package/src/redis/redlockImpl.ts +0 -155
  197. package/src/redis/tests/redis.spec.ts +0 -207
  198. package/src/redis/tests/redlockImpl.spec.ts +0 -105
  199. package/src/redis/utils.ts +0 -128
  200. package/src/security/auth.ts +0 -24
  201. package/src/security/encryption.ts +0 -185
  202. package/src/security/index.ts +0 -1
  203. package/src/security/permissions.ts +0 -166
  204. package/src/security/roles.ts +0 -655
  205. package/src/security/secrets.ts +0 -20
  206. package/src/security/sessions.ts +0 -123
  207. package/src/security/tests/auth.spec.ts +0 -45
  208. package/src/security/tests/encryption.spec.ts +0 -31
  209. package/src/security/tests/permissions.spec.ts +0 -146
  210. package/src/security/tests/secrets.spec.ts +0 -35
  211. package/src/security/tests/sessions.spec.ts +0 -12
  212. package/src/sql/designDoc.ts +0 -17
  213. package/src/sql/index.ts +0 -5
  214. package/src/sql/sql.ts +0 -1854
  215. package/src/sql/sqlTable.ts +0 -319
  216. package/src/sql/utils.ts +0 -193
  217. package/src/tenancy/db.ts +0 -6
  218. package/src/tenancy/index.ts +0 -2
  219. package/src/tenancy/tenancy.ts +0 -148
  220. package/src/tenancy/tests/tenancy.spec.ts +0 -184
  221. package/src/timers/index.ts +0 -1
  222. package/src/timers/timers.ts +0 -22
  223. package/src/users/db.ts +0 -582
  224. package/src/users/events.ts +0 -176
  225. package/src/users/index.ts +0 -4
  226. package/src/users/lookup.ts +0 -99
  227. package/src/users/test/db.spec.ts +0 -188
  228. package/src/users/test/utils.spec.ts +0 -67
  229. package/src/users/users.ts +0 -353
  230. package/src/users/utils.ts +0 -81
  231. package/src/utils/Duration.ts +0 -56
  232. package/src/utils/hashing.ts +0 -15
  233. package/src/utils/index.ts +0 -4
  234. package/src/utils/stringUtils.ts +0 -8
  235. package/src/utils/tests/Duration.spec.ts +0 -19
  236. package/src/utils/tests/utils.spec.ts +0 -204
  237. package/src/utils/utils.ts +0 -249
  238. package/tests/core/logging.ts +0 -34
  239. package/tests/core/users/users.spec.js +0 -53
  240. package/tests/core/utilities/index.ts +0 -7
  241. package/tests/core/utilities/jestUtils.ts +0 -33
  242. package/tests/core/utilities/mocks/alerts.ts +0 -4
  243. package/tests/core/utilities/mocks/date.ts +0 -3
  244. package/tests/core/utilities/mocks/events.ts +0 -132
  245. package/tests/core/utilities/mocks/index.ts +0 -9
  246. package/tests/core/utilities/mocks/licenses.ts +0 -119
  247. package/tests/core/utilities/queue.ts +0 -9
  248. package/tests/core/utilities/structures/Chance.ts +0 -20
  249. package/tests/core/utilities/structures/accounts.ts +0 -80
  250. package/tests/core/utilities/structures/apps.ts +0 -21
  251. package/tests/core/utilities/structures/common.ts +0 -7
  252. package/tests/core/utilities/structures/db.ts +0 -12
  253. package/tests/core/utilities/structures/documents/index.ts +0 -1
  254. package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
  255. package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
  256. package/tests/core/utilities/structures/generator.ts +0 -3
  257. package/tests/core/utilities/structures/index.ts +0 -15
  258. package/tests/core/utilities/structures/koa.ts +0 -16
  259. package/tests/core/utilities/structures/licenses.ts +0 -190
  260. package/tests/core/utilities/structures/plugins.ts +0 -19
  261. package/tests/core/utilities/structures/quotas.ts +0 -72
  262. package/tests/core/utilities/structures/scim.ts +0 -80
  263. package/tests/core/utilities/structures/sso.ts +0 -118
  264. package/tests/core/utilities/structures/tenants.ts +0 -5
  265. package/tests/core/utilities/structures/userGroups.ts +0 -10
  266. package/tests/core/utilities/structures/users.ts +0 -89
  267. package/tests/core/utilities/testContainerUtils.ts +0 -165
  268. package/tests/core/utilities/utils/index.ts +0 -2
  269. package/tests/core/utilities/utils/queue.ts +0 -27
  270. package/tests/core/utilities/utils/time.ts +0 -3
  271. package/tests/extra/DBTestConfiguration.ts +0 -36
  272. package/tests/extra/index.ts +0 -2
  273. package/tests/extra/testEnv.ts +0 -95
  274. package/tests/index.ts +0 -2
  275. package/tests/jestEnv.ts +0 -10
  276. package/tests/jestSetup.ts +0 -36
package/src/users/db.ts DELETED
@@ -1,582 +0,0 @@
1
- import env from "../environment"
2
- import * as eventHelpers from "./events"
3
- import * as accountSdk from "../accounts"
4
- import * as cache from "../cache"
5
- import { getGlobalDB, getIdentity, getTenantId } from "../context"
6
- import * as dbUtils from "../db"
7
- import { EmailUnavailableError, HTTPError } from "../errors"
8
- import * as platform from "../platform"
9
- import * as sessions from "../security/sessions"
10
- import * as usersCore from "./users"
11
- import {
12
- Account,
13
- BulkUserCreated,
14
- BulkUserDeleted,
15
- isSSOAccount,
16
- isSSOUser,
17
- SaveUserOpts,
18
- User,
19
- UserGroup,
20
- UserIdentifier,
21
- UserStatus,
22
- PlatformUserBySsoId,
23
- PlatformUserById,
24
- AnyDocument,
25
- } from "@budibase/types"
26
- import {
27
- getAccountHolderFromUsers,
28
- isAdmin,
29
- isCreator,
30
- validateUniqueUser,
31
- } from "./utils"
32
- import {
33
- getFirstPlatformUser,
34
- getPlatformUsers,
35
- searchExistingEmails,
36
- } from "./lookup"
37
- import { hash } from "../utils"
38
- import { validatePassword } from "../security"
39
-
40
- type QuotaUpdateFn = (
41
- change: number,
42
- creatorsChange: number,
43
- cb?: () => Promise<any>
44
- ) => Promise<any>
45
- type GroupUpdateFn = (groupId: string, userIds: string[]) => Promise<any>
46
- type FeatureFn = () => Promise<Boolean>
47
- type GroupGetFn = (ids: string[]) => Promise<UserGroup[]>
48
- type GroupBuildersFn = (user: User) => Promise<string[]>
49
- type QuotaFns = { addUsers: QuotaUpdateFn; removeUsers: QuotaUpdateFn }
50
- type GroupFns = {
51
- addUsers: GroupUpdateFn
52
- getBulk: GroupGetFn
53
- getGroupBuilderAppIds: GroupBuildersFn
54
- }
55
- type CreateAdminUserOpts = {
56
- password?: string
57
- ssoId?: string
58
- hashPassword?: boolean
59
- requirePassword?: boolean
60
- skipPasswordValidation?: boolean
61
- firstName?: string
62
- lastName?: string
63
- }
64
- type FeatureFns = { isSSOEnforced: FeatureFn; isAppBuildersEnabled: FeatureFn }
65
-
66
- const bulkDeleteProcessing = async (dbUser: User) => {
67
- const userId = dbUser._id as string
68
- await platform.users.removeUser(dbUser)
69
- await eventHelpers.handleDeleteEvents(dbUser)
70
- await cache.user.invalidateUser(userId)
71
- await sessions.invalidateSessions(userId, { reason: "bulk-deletion" })
72
- }
73
-
74
- export class UserDB {
75
- static quotas: QuotaFns
76
- static groups: GroupFns
77
- static features: FeatureFns
78
-
79
- static init(quotaFns: QuotaFns, groupFns: GroupFns, featureFns: FeatureFns) {
80
- UserDB.quotas = quotaFns
81
- UserDB.groups = groupFns
82
- UserDB.features = featureFns
83
- }
84
-
85
- static async isPreventPasswordActions(user: User, account?: Account) {
86
- // when in maintenance mode we allow sso users with the admin role
87
- // to perform any password action - this prevents lockout
88
- if (env.ENABLE_SSO_MAINTENANCE_MODE && isAdmin(user)) {
89
- return false
90
- }
91
-
92
- // SSO is enforced for all users
93
- if (await UserDB.features.isSSOEnforced()) {
94
- return true
95
- }
96
-
97
- // Check local sso
98
- if (isSSOUser(user)) {
99
- return true
100
- }
101
-
102
- // Check account sso
103
- if (!account) {
104
- account = await accountSdk.getAccountByTenantId(getTenantId())
105
- }
106
- return !!(account && account.email === user.email && isSSOAccount(account))
107
- }
108
-
109
- static async buildUser(
110
- user: User,
111
- opts: SaveUserOpts = {
112
- hashPassword: true,
113
- requirePassword: true,
114
- },
115
- tenantId: string,
116
- dbUser?: any,
117
- account?: Account
118
- ): Promise<User> {
119
- let { password, _id } = user
120
-
121
- // don't require a password if the db user doesn't already have one
122
- if (dbUser && !dbUser.password) {
123
- opts.requirePassword = false
124
- }
125
-
126
- let hashedPassword
127
- if (password) {
128
- if (await UserDB.isPreventPasswordActions(user, account)) {
129
- throw new HTTPError("Password change is disabled for this user", 400)
130
- }
131
-
132
- if (!opts.skipPasswordValidation) {
133
- const passwordValidation = validatePassword(password)
134
- if (!passwordValidation.valid) {
135
- throw new HTTPError(passwordValidation.error, 400)
136
- }
137
- }
138
-
139
- hashedPassword = opts.hashPassword ? await hash(password) : password
140
- } else if (dbUser) {
141
- hashedPassword = dbUser.password
142
- }
143
-
144
- // passwords are never required if sso is enforced
145
- const requirePasswords =
146
- opts.requirePassword && !(await UserDB.features.isSSOEnforced())
147
- if (!hashedPassword && requirePasswords) {
148
- throw "Password must be specified."
149
- }
150
-
151
- _id = _id || dbUtils.generateGlobalUserID()
152
-
153
- const fullUser = {
154
- createdAt: Date.now(),
155
- ...dbUser,
156
- ...user,
157
- _id,
158
- password: hashedPassword,
159
- tenantId,
160
- }
161
- // make sure the roles object is always present
162
- if (!fullUser.roles) {
163
- fullUser.roles = {}
164
- }
165
- // add the active status to a user if it's not provided
166
- if (fullUser.status == null) {
167
- fullUser.status = UserStatus.ACTIVE
168
- }
169
-
170
- return fullUser
171
- }
172
-
173
- static async allUsers() {
174
- const db = getGlobalDB()
175
- const response = await db.allDocs<User>(
176
- dbUtils.getGlobalUserParams(null, {
177
- include_docs: true,
178
- })
179
- )
180
- return response.rows.map(row => row.doc!)
181
- }
182
-
183
- static async countUsersByApp(appId: string) {
184
- let response: any = await usersCore.searchGlobalUsersByApp(appId, {})
185
- return {
186
- userCount: response.length,
187
- }
188
- }
189
-
190
- static async getUsersByAppAccess(opts: { appId?: string; limit?: number }) {
191
- let response: User[] = await usersCore.searchGlobalUsersByAppAccess(
192
- opts.appId,
193
- { limit: opts.limit || 50 }
194
- )
195
- return response
196
- }
197
-
198
- static async getUserByEmail(email: string) {
199
- return usersCore.getGlobalUserByEmail(email)
200
- }
201
-
202
- /**
203
- * Gets a user by ID from the global database, based on the current tenancy.
204
- */
205
- static async getUser(userId: string) {
206
- const user = await usersCore.getById(userId)
207
- if (user) {
208
- delete user.password
209
- }
210
- return user
211
- }
212
-
213
- static async bulkGet(userIds: string[]) {
214
- return await usersCore.bulkGetGlobalUsersById(userIds)
215
- }
216
-
217
- static async bulkUpdate(users: User[]) {
218
- return await usersCore.bulkUpdateGlobalUsers(users)
219
- }
220
-
221
- static async save(user: User, opts: SaveUserOpts = {}): Promise<User> {
222
- // default booleans to true
223
- if (opts.hashPassword == null) {
224
- opts.hashPassword = true
225
- }
226
- if (opts.requirePassword == null) {
227
- opts.requirePassword = true
228
- }
229
- const tenantId = getTenantId()
230
- const db = getGlobalDB()
231
-
232
- const { email, _id, userGroups = [], roles } = user
233
-
234
- if (!email && !_id) {
235
- throw new Error("_id or email is required")
236
- }
237
-
238
- let dbUser: User | undefined
239
- if (_id) {
240
- // try to get existing user from db
241
- try {
242
- dbUser = await usersCore.getById(_id)
243
- if (email && dbUser.email !== email && !opts.allowChangingEmail) {
244
- throw new Error("Email address cannot be changed")
245
- }
246
- } catch (e: any) {
247
- if (e.status === 404) {
248
- // do nothing, save this new user with the id specified - required for SSO auth
249
- } else {
250
- throw e
251
- }
252
- }
253
- }
254
-
255
- if (!dbUser && email) {
256
- // no id was specified - load from email instead
257
- dbUser = await usersCore.getGlobalUserByEmail(email)
258
- if (dbUser && dbUser._id !== _id) {
259
- throw new EmailUnavailableError(email)
260
- }
261
- }
262
-
263
- const change = dbUser ? 0 : 1 // no change if there is existing user
264
- const creatorsChange =
265
- (await isCreator(dbUser)) !== (await isCreator(user)) ? 1 : 0
266
- return UserDB.quotas.addUsers(change, creatorsChange, async () => {
267
- await validateUniqueUser(email, tenantId)
268
-
269
- let builtUser = await UserDB.buildUser(user, opts, tenantId, dbUser)
270
- // don't allow a user to update its own roles/perms
271
- if (opts.currentUserId && opts.currentUserId === dbUser?._id) {
272
- builtUser = usersCore.cleanseUserObject(builtUser, dbUser) as User
273
- }
274
-
275
- if (!dbUser && roles?.length) {
276
- builtUser.roles = { ...roles }
277
- }
278
-
279
- // make sure we set the _id field for a new user
280
- // Also if this is a new user, associate groups with them
281
- const groupPromises = []
282
- if (!_id) {
283
- if (userGroups.length > 0) {
284
- for (let groupId of userGroups) {
285
- groupPromises.push(
286
- UserDB.groups.addUsers(groupId, [builtUser._id!])
287
- )
288
- }
289
- }
290
- }
291
-
292
- try {
293
- // save the user to db
294
- let response = await db.put(builtUser)
295
- builtUser._rev = response.rev
296
-
297
- await eventHelpers.handleSaveEvents(builtUser, dbUser)
298
- if (dbUser && builtUser.email !== dbUser.email) {
299
- // Remove the plaform email reference if the email changed
300
- await platform.users.removeUser({ email: dbUser.email } as User)
301
- }
302
-
303
- await platform.users.addUser(
304
- tenantId,
305
- builtUser._id!,
306
- builtUser.email,
307
- builtUser.ssoId
308
- )
309
- await cache.user.invalidateUser(response.id)
310
-
311
- await Promise.all(groupPromises)
312
-
313
- // finally returned the saved user from the db
314
- return db.get(builtUser._id!)
315
- } catch (err: any) {
316
- if (err.status === 409) {
317
- throw "User exists already"
318
- } else {
319
- throw err
320
- }
321
- }
322
- })
323
- }
324
-
325
- static async bulkCreate(
326
- newUsersRequested: User[],
327
- groups?: string[]
328
- ): Promise<BulkUserCreated> {
329
- const tenantId = getTenantId()
330
-
331
- let usersToSave: any[] = []
332
- let newUsers: any[] = []
333
- let newCreators: any[] = []
334
-
335
- const emails = newUsersRequested.map((user: User) => user.email)
336
- const existingEmails = await searchExistingEmails(emails)
337
- const unsuccessful: { email: string; reason: string }[] = []
338
-
339
- for (const newUser of newUsersRequested) {
340
- if (
341
- newUsers.find(
342
- (x: User) => x.email.toLowerCase() === newUser.email.toLowerCase()
343
- ) ||
344
- existingEmails.includes(newUser.email.toLowerCase())
345
- ) {
346
- unsuccessful.push({
347
- email: newUser.email,
348
- reason: `Unavailable`,
349
- })
350
- continue
351
- }
352
- newUser.userGroups = groups || []
353
- newUsers.push(newUser)
354
- if (await isCreator(newUser)) {
355
- newCreators.push(newUser)
356
- }
357
- }
358
-
359
- const account = await accountSdk.getAccountByTenantId(tenantId)
360
- return UserDB.quotas.addUsers(
361
- newUsers.length,
362
- newCreators.length,
363
- async () => {
364
- // create the promises array that will be called by bulkDocs
365
- newUsers.forEach((user: any) => {
366
- usersToSave.push(
367
- UserDB.buildUser(
368
- user,
369
- {
370
- hashPassword: true,
371
- requirePassword: user.requirePassword,
372
- },
373
- tenantId,
374
- undefined, // no dbUser
375
- account
376
- )
377
- )
378
- })
379
-
380
- const usersToBulkSave = await Promise.all(usersToSave)
381
- await usersCore.bulkUpdateGlobalUsers(usersToBulkSave)
382
-
383
- // Post-processing of bulk added users, e.g. events and cache operations
384
- for (const user of usersToBulkSave) {
385
- // TODO: Refactor to bulk insert users into the info db
386
- // instead of relying on looping tenant creation
387
- await platform.users.addUser(tenantId, user._id, user.email)
388
- await eventHelpers.handleSaveEvents(user, undefined)
389
- }
390
-
391
- const saved = usersToBulkSave.map(user => {
392
- return {
393
- _id: user._id,
394
- email: user.email,
395
- }
396
- })
397
-
398
- // now update the groups
399
- if (Array.isArray(saved) && groups) {
400
- const groupPromises = []
401
- const createdUserIds = saved.map(user => user._id)
402
- for (let groupId of groups) {
403
- groupPromises.push(UserDB.groups.addUsers(groupId, createdUserIds))
404
- }
405
- await Promise.all(groupPromises)
406
- }
407
-
408
- return {
409
- successful: saved,
410
- unsuccessful,
411
- }
412
- }
413
- )
414
- }
415
-
416
- static async bulkDelete(
417
- users: Array<UserIdentifier>
418
- ): Promise<BulkUserDeleted> {
419
- const db = getGlobalDB()
420
-
421
- const response: BulkUserDeleted = {
422
- successful: [],
423
- unsuccessful: [],
424
- }
425
-
426
- // remove the account holder from the delete request if present
427
- const accountHolder = await getAccountHolderFromUsers(users)
428
- if (accountHolder) {
429
- users = users.filter(u => u.userId !== accountHolder.userId)
430
- // mark user as unsuccessful
431
- response.unsuccessful.push({
432
- _id: accountHolder.userId,
433
- email: accountHolder.email,
434
- reason: "Account holder cannot be deleted",
435
- })
436
- }
437
-
438
- // Get users and delete
439
- const allDocsResponse = await db.allDocs<User>({
440
- include_docs: true,
441
- keys: users.map(u => u.userId),
442
- })
443
- const usersToDelete = allDocsResponse.rows.map(user => {
444
- return user.doc!
445
- })
446
-
447
- // Delete from DB
448
- const toDelete = usersToDelete.map(user => ({
449
- ...user,
450
- _deleted: true,
451
- }))
452
- const dbResponse = await usersCore.bulkUpdateGlobalUsers(toDelete)
453
-
454
- const creatorsEval = await Promise.all(usersToDelete.map(isCreator))
455
- const creatorsToDeleteCount = creatorsEval.filter(
456
- creator => !!creator
457
- ).length
458
-
459
- const ssoUsersToDelete: AnyDocument[] = []
460
- for (let user of usersToDelete) {
461
- const platformUser = (await getFirstPlatformUser(
462
- user._id!
463
- )) as PlatformUserById
464
- const ssoId = platformUser.ssoId
465
- if (ssoId) {
466
- // Need to get the _rev of the SSO user doc to delete it. The view also returns docs that have the ssoId property, so we need to ignore those.
467
- const ssoUsers = (await getPlatformUsers(
468
- ssoId
469
- )) as PlatformUserBySsoId[]
470
- ssoUsers
471
- .filter(user => user.ssoId == null)
472
- .forEach(user => {
473
- ssoUsersToDelete.push({
474
- ...user,
475
- _deleted: true,
476
- })
477
- })
478
- }
479
- await bulkDeleteProcessing(user)
480
- }
481
-
482
- // Delete any associated SSO user docs
483
- await platform.getPlatformDB().bulkDocs(ssoUsersToDelete)
484
-
485
- await UserDB.quotas.removeUsers(toDelete.length, creatorsToDeleteCount)
486
-
487
- // Build Response
488
- // index users by id
489
- const userIndex: { [key: string]: User } = {}
490
- usersToDelete.reduce((prev, current) => {
491
- prev[current._id!] = current
492
- return prev
493
- }, userIndex)
494
-
495
- // add the successful and unsuccessful users to response
496
- dbResponse.forEach(item => {
497
- const email = userIndex[item.id].email
498
- if (item.ok) {
499
- response.successful.push({ _id: item.id, email })
500
- } else {
501
- response.unsuccessful.push({
502
- _id: item.id,
503
- email,
504
- reason: "Database error",
505
- })
506
- }
507
- })
508
-
509
- return response
510
- }
511
-
512
- static async destroy(id: string) {
513
- const db = getGlobalDB()
514
- const dbUser = (await db.get(id)) as User
515
- const userId = dbUser._id as string
516
-
517
- if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
518
- // root account holder can't be deleted from inside budibase
519
- const email = dbUser.email
520
- const account = await accountSdk.getAccount(email)
521
- if (account) {
522
- if (dbUser.userId === getIdentity()!._id) {
523
- throw new HTTPError('Please visit "Account" to delete this user', 400)
524
- } else {
525
- throw new HTTPError("Account holder cannot be deleted", 400)
526
- }
527
- }
528
- }
529
-
530
- await platform.users.removeUser(dbUser)
531
-
532
- await db.remove(userId, dbUser._rev!)
533
-
534
- const creatorsToDelete = (await isCreator(dbUser)) ? 1 : 0
535
- await UserDB.quotas.removeUsers(1, creatorsToDelete)
536
- await eventHelpers.handleDeleteEvents(dbUser)
537
- await cache.user.invalidateUser(userId)
538
- await sessions.invalidateSessions(userId, { reason: "deletion" })
539
- }
540
-
541
- static async createAdminUser(
542
- email: string,
543
- tenantId: string,
544
- opts?: CreateAdminUserOpts
545
- ) {
546
- const password = opts?.password
547
- const user: User = {
548
- email: email,
549
- password,
550
- createdAt: Date.now(),
551
- roles: {},
552
- builder: {
553
- global: true,
554
- },
555
- admin: {
556
- global: true,
557
- },
558
- tenantId,
559
- firstName: opts?.firstName,
560
- lastName: opts?.lastName,
561
- }
562
- if (opts?.ssoId) {
563
- user.ssoId = opts.ssoId
564
- }
565
- // always bust checklist beforehand, if an error occurs but can proceed, don't get
566
- // stuck in a cycle
567
- await cache.bustCache(cache.CacheKey.CHECKLIST)
568
- return await UserDB.save(user, {
569
- hashPassword: opts?.hashPassword,
570
- requirePassword: opts?.requirePassword,
571
- skipPasswordValidation: opts?.skipPasswordValidation,
572
- })
573
- }
574
-
575
- static async getGroups(groupIds: string[]) {
576
- return await this.groups.getBulk(groupIds)
577
- }
578
-
579
- static async getGroupBuilderAppIds(user: User) {
580
- return await this.groups.getGroupBuilderAppIds(user)
581
- }
582
- }