@budibase/worker 2.3.18-alpha.8 → 2.3.18
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/coverage/clover.xml +2199 -0
- package/coverage/coverage-final.json +84 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +431 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov-report/src/api/controllers/global/auth.ts.html +934 -0
- package/coverage/lcov-report/src/api/controllers/global/configs.ts.html +1348 -0
- package/coverage/lcov-report/src/api/controllers/global/email.ts.html +196 -0
- package/coverage/lcov-report/src/api/controllers/global/events.ts.html +136 -0
- package/coverage/lcov-report/src/api/controllers/global/index.html +251 -0
- package/coverage/lcov-report/src/api/controllers/global/license.ts.html +187 -0
- package/coverage/lcov-report/src/api/controllers/global/roles.ts.html +283 -0
- package/coverage/lcov-report/src/api/controllers/global/self.ts.html +577 -0
- package/coverage/lcov-report/src/api/controllers/global/templates.ts.html +316 -0
- package/coverage/lcov-report/src/api/controllers/global/users.ts.html +838 -0
- package/coverage/lcov-report/src/api/controllers/global/workspaces.ts.html +244 -0
- package/coverage/lcov-report/src/api/controllers/system/accounts.ts.html +148 -0
- package/coverage/lcov-report/src/api/controllers/system/environment.ts.html +124 -0
- package/coverage/lcov-report/src/api/controllers/system/index.html +191 -0
- package/coverage/lcov-report/src/api/controllers/system/migrations.ts.html +124 -0
- package/coverage/lcov-report/src/api/controllers/system/restore.ts.html +124 -0
- package/coverage/lcov-report/src/api/controllers/system/status.ts.html +133 -0
- package/coverage/lcov-report/src/api/controllers/system/tenants.ts.html +154 -0
- package/coverage/lcov-report/src/api/index.html +116 -0
- package/coverage/lcov-report/src/api/index.ts.html +595 -0
- package/coverage/lcov-report/src/api/routes/global/auth.ts.html +349 -0
- package/coverage/lcov-report/src/api/routes/global/configs.ts.html +457 -0
- package/coverage/lcov-report/src/api/routes/global/email.ts.html +193 -0
- package/coverage/lcov-report/src/api/routes/global/events.ts.html +109 -0
- package/coverage/lcov-report/src/api/routes/global/index.html +251 -0
- package/coverage/lcov-report/src/api/routes/global/license.ts.html +124 -0
- package/coverage/lcov-report/src/api/routes/global/roles.ts.html +133 -0
- package/coverage/lcov-report/src/api/routes/global/self.ts.html +139 -0
- package/coverage/lcov-report/src/api/routes/global/templates.ts.html +196 -0
- package/coverage/lcov-report/src/api/routes/global/users.ts.html +475 -0
- package/coverage/lcov-report/src/api/routes/global/workspaces.ts.html +196 -0
- package/coverage/lcov-report/src/api/routes/index.html +116 -0
- package/coverage/lcov-report/src/api/routes/index.ts.html +202 -0
- package/coverage/lcov-report/src/api/routes/system/accounts.ts.html +142 -0
- package/coverage/lcov-report/src/api/routes/system/environment.ts.html +109 -0
- package/coverage/lcov-report/src/api/routes/system/index.html +191 -0
- package/coverage/lcov-report/src/api/routes/system/migrations.ts.html +142 -0
- package/coverage/lcov-report/src/api/routes/system/restore.ts.html +109 -0
- package/coverage/lcov-report/src/api/routes/system/status.ts.html +109 -0
- package/coverage/lcov-report/src/api/routes/system/tenants.ts.html +124 -0
- package/coverage/lcov-report/src/api/routes/validation/index.html +131 -0
- package/coverage/lcov-report/src/api/routes/validation/index.ts.html +88 -0
- package/coverage/lcov-report/src/api/routes/validation/users.ts.html +235 -0
- package/coverage/lcov-report/src/constants/index.html +116 -0
- package/coverage/lcov-report/src/constants/index.ts.html +637 -0
- package/coverage/lcov-report/src/constants/templates/index.html +116 -0
- package/coverage/lcov-report/src/constants/templates/index.ts.html +316 -0
- package/coverage/lcov-report/src/db/index.html +116 -0
- package/coverage/lcov-report/src/db/index.ts.html +115 -0
- package/coverage/lcov-report/src/environment.ts.html +388 -0
- package/coverage/lcov-report/src/index.html +131 -0
- package/coverage/lcov-report/src/index.ts.html +394 -0
- package/coverage/lcov-report/src/middleware/cloudRestricted.ts.html +139 -0
- package/coverage/lcov-report/src/middleware/index.html +116 -0
- package/coverage/lcov-report/src/migrations/functions/globalInfoSyncUsers.ts.html +145 -0
- package/coverage/lcov-report/src/migrations/functions/index.html +116 -0
- package/coverage/lcov-report/src/migrations/index.html +116 -0
- package/coverage/lcov-report/src/migrations/index.ts.html +271 -0
- package/coverage/lcov-report/src/sdk/accounts/accounts.ts.html +262 -0
- package/coverage/lcov-report/src/sdk/accounts/index.html +131 -0
- package/coverage/lcov-report/src/sdk/accounts/index.ts.html +88 -0
- package/coverage/lcov-report/src/sdk/index.html +116 -0
- package/coverage/lcov-report/src/sdk/index.ts.html +106 -0
- package/coverage/lcov-report/src/sdk/users/events.ts.html +601 -0
- package/coverage/lcov-report/src/sdk/users/index.html +146 -0
- package/coverage/lcov-report/src/sdk/users/index.ts.html +88 -0
- package/coverage/lcov-report/src/sdk/users/users.ts.html +1999 -0
- package/coverage/lcov-report/src/tests/TestConfiguration.ts.html +1075 -0
- package/coverage/lcov-report/src/tests/api/accounts.ts.html +160 -0
- package/coverage/lcov-report/src/tests/api/auth.ts.html +220 -0
- package/coverage/lcov-report/src/tests/api/base.ts.html +133 -0
- package/coverage/lcov-report/src/tests/api/configs.ts.html +226 -0
- package/coverage/lcov-report/src/tests/api/email.ts.html +148 -0
- package/coverage/lcov-report/src/tests/api/environment.ts.html +130 -0
- package/coverage/lcov-report/src/tests/api/groups.ts.html +163 -0
- package/coverage/lcov-report/src/tests/api/index.html +356 -0
- package/coverage/lcov-report/src/tests/api/index.ts.html +238 -0
- package/coverage/lcov-report/src/tests/api/license.ts.html +136 -0
- package/coverage/lcov-report/src/tests/api/migrations.ts.html +151 -0
- package/coverage/lcov-report/src/tests/api/restore.ts.html +127 -0
- package/coverage/lcov-report/src/tests/api/roles.ts.html +181 -0
- package/coverage/lcov-report/src/tests/api/self.ts.html +163 -0
- package/coverage/lcov-report/src/tests/api/status.ts.html +121 -0
- package/coverage/lcov-report/src/tests/api/templates.ts.html +175 -0
- package/coverage/lcov-report/src/tests/api/tenants.ts.html +130 -0
- package/coverage/lcov-report/src/tests/api/users.ts.html +514 -0
- package/coverage/lcov-report/src/tests/controllers.ts.html +100 -0
- package/coverage/lcov-report/src/tests/index.html +146 -0
- package/coverage/lcov-report/src/tests/index.ts.html +103 -0
- package/coverage/lcov-report/src/tests/mocks/email.ts.html +115 -0
- package/coverage/lcov-report/src/tests/mocks/index.html +131 -0
- package/coverage/lcov-report/src/tests/mocks/index.ts.html +106 -0
- package/coverage/lcov-report/src/tests/structures/configs.ts.html +313 -0
- package/coverage/lcov-report/src/tests/structures/groups.ts.html +118 -0
- package/coverage/lcov-report/src/tests/structures/index.html +161 -0
- package/coverage/lcov-report/src/tests/structures/index.ts.html +151 -0
- package/coverage/lcov-report/src/tests/structures/users.ts.html +196 -0
- package/coverage/lcov-report/src/utilities/appService.ts.html +208 -0
- package/coverage/lcov-report/src/utilities/email.ts.html +850 -0
- package/coverage/lcov-report/src/utilities/fileSystem.ts.html +100 -0
- package/coverage/lcov-report/src/utilities/index.html +206 -0
- package/coverage/lcov-report/src/utilities/index.ts.html +112 -0
- package/coverage/lcov-report/src/utilities/redis.ts.html +424 -0
- package/coverage/lcov-report/src/utilities/templates.ts.html +232 -0
- package/coverage/lcov-report/src/utilities/users.ts.html +133 -0
- package/coverage/lcov.info +4187 -0
- package/jest.config.ts +17 -13
- package/package.json +8 -11
- package/scripts/dev/manage.js +0 -1
- package/src/api/controllers/global/auth.ts +70 -77
- package/src/api/controllers/global/self.ts +44 -28
- package/src/api/controllers/global/users.ts +25 -65
- package/src/api/controllers/system/accounts.ts +5 -7
- package/src/api/controllers/system/tenants.ts +8 -4
- package/src/api/index.ts +20 -4
- package/src/api/routes/global/auth.ts +7 -10
- package/src/api/routes/global/tests/auth.spec.ts +17 -226
- package/src/api/routes/global/tests/configs.spec.ts +5 -5
- package/src/api/routes/global/tests/roles.spec.ts +14 -20
- package/src/api/routes/global/tests/self.spec.ts +4 -3
- package/src/api/routes/global/tests/users.spec.ts +27 -24
- package/src/api/routes/system/tenants.ts +1 -1
- package/src/api/routes/system/tests/accounts.spec.ts +4 -4
- package/src/api/routes/system/tests/migrations.spec.ts +2 -2
- package/src/api/routes/system/tests/restore.spec.ts +2 -2
- package/src/api/routes/system/tests/status.spec.ts +5 -5
- package/src/environment.ts +1 -15
- package/src/index.ts +7 -12
- package/src/middleware/tests/tenancy.spec.ts +4 -4
- package/src/migrations/functions/globalInfoSyncUsers.ts +3 -4
- package/src/sdk/accounts/{metadata.ts → accounts.ts} +1 -0
- package/src/sdk/accounts/index.ts +1 -2
- package/src/sdk/users/events.ts +0 -4
- package/src/sdk/users/index.ts +0 -1
- package/src/sdk/users/users.ts +46 -53
- package/src/tests/TestConfiguration.ts +62 -41
- package/src/tests/api/auth.ts +14 -42
- package/src/tests/api/base.ts +1 -2
- package/src/tests/api/configs.ts +2 -2
- package/src/tests/api/restore.ts +0 -1
- package/src/tests/api/users.ts +2 -2
- package/src/tests/jestEnv.ts +1 -2
- package/src/tests/jestSetup.ts +6 -10
- package/src/tests/structures/index.ts +4 -0
- package/src/tests/structures/users.ts +37 -0
- package/src/utilities/email.ts +3 -3
- package/src/utilities/redis.ts +0 -2
- package/__mocks__/node-fetch.ts +0 -23
- package/jest-testcontainers-config.js +0 -8
- package/scripts/test.sh +0 -12
- package/src/ddApm.ts +0 -7
- package/src/elasticApm.ts +0 -10
- package/src/sdk/auth/auth.ts +0 -86
- package/src/sdk/auth/index.ts +0 -1
- package/src/sdk/tenants/index.ts +0 -1
- package/src/sdk/tenants/tenants.ts +0 -76
- package/src/sdk/users/tests/users.spec.ts +0 -52
- package/src/tests/logging.ts +0 -34
package/src/sdk/users/users.ts
CHANGED
|
@@ -6,11 +6,12 @@ import {
|
|
|
6
6
|
cache,
|
|
7
7
|
constants,
|
|
8
8
|
db as dbUtils,
|
|
9
|
+
deprovisioning,
|
|
9
10
|
events,
|
|
10
11
|
HTTPError,
|
|
12
|
+
migrations,
|
|
11
13
|
sessions,
|
|
12
14
|
tenancy,
|
|
13
|
-
platform,
|
|
14
15
|
users as usersCore,
|
|
15
16
|
utils,
|
|
16
17
|
ViewName,
|
|
@@ -20,22 +21,21 @@ import {
|
|
|
20
21
|
AllDocsResponse,
|
|
21
22
|
BulkUserResponse,
|
|
22
23
|
CloudAccount,
|
|
24
|
+
CreateUserResponse,
|
|
23
25
|
InviteUsersRequest,
|
|
24
26
|
InviteUsersResponse,
|
|
25
|
-
|
|
26
|
-
isSSOUser,
|
|
27
|
+
MigrationType,
|
|
27
28
|
PlatformUser,
|
|
28
29
|
PlatformUserByEmail,
|
|
29
30
|
RowResponse,
|
|
30
31
|
SearchUsersRequest,
|
|
31
|
-
UpdateSelf,
|
|
32
32
|
User,
|
|
33
|
-
|
|
33
|
+
ThirdPartyUser,
|
|
34
|
+
isUser,
|
|
34
35
|
} from "@budibase/types"
|
|
35
36
|
import { sendEmail } from "../../utilities/email"
|
|
36
37
|
import { EmailTemplatePurpose } from "../../constants"
|
|
37
38
|
import { groups as groupsSdk } from "@budibase/pro"
|
|
38
|
-
import * as accountSdk from "../accounts"
|
|
39
39
|
|
|
40
40
|
const PAGE_LIMIT = 8
|
|
41
41
|
|
|
@@ -94,23 +94,26 @@ export const paginatedUsers = async ({
|
|
|
94
94
|
})
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
export async function getUserByEmail(email: string) {
|
|
98
|
-
return usersCore.getGlobalUserByEmail(email)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
97
|
/**
|
|
102
98
|
* Gets a user by ID from the global database, based on the current tenancy.
|
|
103
99
|
*/
|
|
104
100
|
export const getUser = async (userId: string) => {
|
|
105
|
-
const
|
|
101
|
+
const db = tenancy.getGlobalDB()
|
|
102
|
+
let user = await db.get(userId)
|
|
106
103
|
if (user) {
|
|
107
104
|
delete user.password
|
|
108
105
|
}
|
|
109
106
|
return user
|
|
110
107
|
}
|
|
111
108
|
|
|
109
|
+
export interface SaveUserOpts {
|
|
110
|
+
hashPassword?: boolean
|
|
111
|
+
requirePassword?: boolean
|
|
112
|
+
currentUserId?: string
|
|
113
|
+
}
|
|
114
|
+
|
|
112
115
|
const buildUser = async (
|
|
113
|
-
user: User,
|
|
116
|
+
user: User | ThirdPartyUser,
|
|
114
117
|
opts: SaveUserOpts = {
|
|
115
118
|
hashPassword: true,
|
|
116
119
|
requirePassword: true,
|
|
@@ -118,13 +121,11 @@ const buildUser = async (
|
|
|
118
121
|
tenantId: string,
|
|
119
122
|
dbUser?: any
|
|
120
123
|
): Promise<User> => {
|
|
121
|
-
let
|
|
124
|
+
let fullUser = user as User
|
|
125
|
+
let { password, _id } = fullUser
|
|
122
126
|
|
|
123
127
|
let hashedPassword
|
|
124
128
|
if (password) {
|
|
125
|
-
if (await isPreventSSOPasswords(user)) {
|
|
126
|
-
throw new HTTPError("SSO user cannot set password", 400)
|
|
127
|
-
}
|
|
128
129
|
hashedPassword = opts.hashPassword ? await utils.hash(password) : password
|
|
129
130
|
} else if (dbUser) {
|
|
130
131
|
hashedPassword = dbUser.password
|
|
@@ -134,10 +135,10 @@ const buildUser = async (
|
|
|
134
135
|
|
|
135
136
|
_id = _id || dbUtils.generateGlobalUserID()
|
|
136
137
|
|
|
137
|
-
|
|
138
|
+
fullUser = {
|
|
138
139
|
createdAt: Date.now(),
|
|
139
140
|
...dbUser,
|
|
140
|
-
...
|
|
141
|
+
...fullUser,
|
|
141
142
|
_id,
|
|
142
143
|
password: hashedPassword,
|
|
143
144
|
tenantId,
|
|
@@ -188,36 +189,10 @@ const validateUniqueUser = async (email: string, tenantId: string) => {
|
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
191
|
|
|
191
|
-
export async function isPreventSSOPasswords(user: User) {
|
|
192
|
-
// when in maintenance mode we allow sso users with the admin role
|
|
193
|
-
// to perform any password action - this prevents lockout
|
|
194
|
-
if (env.ENABLE_SSO_MAINTENANCE_MODE && user.admin?.global) {
|
|
195
|
-
return false
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Check local sso
|
|
199
|
-
if (isSSOUser(user)) {
|
|
200
|
-
return true
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Check account sso
|
|
204
|
-
const account = await accountSdk.api.getAccount(user.email)
|
|
205
|
-
return !!(account && isSSOAccount(account))
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export async function updateSelf(id: string, data: UpdateSelf) {
|
|
209
|
-
let user = await getUser(id)
|
|
210
|
-
user = {
|
|
211
|
-
...user,
|
|
212
|
-
...data,
|
|
213
|
-
}
|
|
214
|
-
return save(user)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
192
|
export const save = async (
|
|
218
|
-
user: User,
|
|
193
|
+
user: User | ThirdPartyUser,
|
|
219
194
|
opts: SaveUserOpts = {}
|
|
220
|
-
): Promise<
|
|
195
|
+
): Promise<CreateUserResponse> => {
|
|
221
196
|
// default booleans to true
|
|
222
197
|
if (opts.hashPassword == null) {
|
|
223
198
|
opts.hashPassword = true
|
|
@@ -289,7 +264,7 @@ export const save = async (
|
|
|
289
264
|
builtUser._rev = response.rev
|
|
290
265
|
|
|
291
266
|
await eventHelpers.handleSaveEvents(builtUser, dbUser)
|
|
292
|
-
await
|
|
267
|
+
await addTenant(tenantId, _id, email)
|
|
293
268
|
await cache.user.invalidateUser(response.id)
|
|
294
269
|
|
|
295
270
|
// let server know to sync user
|
|
@@ -297,8 +272,11 @@ export const save = async (
|
|
|
297
272
|
|
|
298
273
|
await Promise.all(groupPromises)
|
|
299
274
|
|
|
300
|
-
|
|
301
|
-
|
|
275
|
+
return {
|
|
276
|
+
_id: response.id,
|
|
277
|
+
_rev: response.rev,
|
|
278
|
+
email,
|
|
279
|
+
}
|
|
302
280
|
} catch (err: any) {
|
|
303
281
|
if (err.status === 409) {
|
|
304
282
|
throw "User exists already"
|
|
@@ -308,6 +286,21 @@ export const save = async (
|
|
|
308
286
|
}
|
|
309
287
|
}
|
|
310
288
|
|
|
289
|
+
export const addTenant = async (
|
|
290
|
+
tenantId: string,
|
|
291
|
+
_id: string,
|
|
292
|
+
email: string
|
|
293
|
+
) => {
|
|
294
|
+
if (env.MULTI_TENANCY) {
|
|
295
|
+
const afterCreateTenant = () =>
|
|
296
|
+
migrations.backPopulateMigrations({
|
|
297
|
+
type: MigrationType.GLOBAL,
|
|
298
|
+
tenantId,
|
|
299
|
+
})
|
|
300
|
+
await tenancy.tryAddTenant(tenantId, _id, email, afterCreateTenant)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
311
304
|
const getExistingTenantUsers = async (emails: string[]): Promise<User[]> => {
|
|
312
305
|
const lcEmails = emails.map(email => email.toLowerCase())
|
|
313
306
|
const params = {
|
|
@@ -439,7 +432,7 @@ export const bulkCreate = async (
|
|
|
439
432
|
for (const user of usersToBulkSave) {
|
|
440
433
|
// TODO: Refactor to bulk insert users into the info db
|
|
441
434
|
// instead of relying on looping tenant creation
|
|
442
|
-
await
|
|
435
|
+
await addTenant(tenantId, user._id, user.email)
|
|
443
436
|
await eventHelpers.handleSaveEvents(user, undefined)
|
|
444
437
|
await apps.syncUserInApps(user._id)
|
|
445
438
|
}
|
|
@@ -557,7 +550,7 @@ export const bulkDelete = async (
|
|
|
557
550
|
|
|
558
551
|
export const destroy = async (id: string, currentUser: any) => {
|
|
559
552
|
const db = tenancy.getGlobalDB()
|
|
560
|
-
const dbUser =
|
|
553
|
+
const dbUser = await db.get(id)
|
|
561
554
|
const userId = dbUser._id as string
|
|
562
555
|
|
|
563
556
|
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
|
|
@@ -573,7 +566,7 @@ export const destroy = async (id: string, currentUser: any) => {
|
|
|
573
566
|
}
|
|
574
567
|
}
|
|
575
568
|
|
|
576
|
-
await
|
|
569
|
+
await deprovisioning.removeUserFromInfoDB(dbUser)
|
|
577
570
|
|
|
578
571
|
await db.remove(userId, dbUser._rev)
|
|
579
572
|
|
|
@@ -586,7 +579,7 @@ export const destroy = async (id: string, currentUser: any) => {
|
|
|
586
579
|
|
|
587
580
|
const bulkDeleteProcessing = async (dbUser: User) => {
|
|
588
581
|
const userId = dbUser._id as string
|
|
589
|
-
await
|
|
582
|
+
await deprovisioning.removeUserFromInfoDB(dbUser)
|
|
590
583
|
await eventHelpers.handleDeleteEvents(dbUser)
|
|
591
584
|
await cache.user.invalidateUser(userId)
|
|
592
585
|
await sessions.invalidateSessions(userId, { reason: "bulk-deletion" })
|
|
@@ -15,29 +15,39 @@ const supertest = require("supertest")
|
|
|
15
15
|
import { Config } from "../constants"
|
|
16
16
|
import {
|
|
17
17
|
users,
|
|
18
|
-
|
|
18
|
+
tenancy,
|
|
19
19
|
sessions,
|
|
20
20
|
auth,
|
|
21
21
|
constants,
|
|
22
22
|
env as coreEnv,
|
|
23
23
|
} from "@budibase/backend-core"
|
|
24
|
-
import structures, { CSRF_TOKEN } from "./structures"
|
|
25
|
-
import {
|
|
24
|
+
import structures, { TENANT_ID, TENANT_1, CSRF_TOKEN } from "./structures"
|
|
25
|
+
import { CreateUserResponse, User, AuthToken } from "@budibase/types"
|
|
26
26
|
import API from "./api"
|
|
27
27
|
|
|
28
|
+
enum Mode {
|
|
29
|
+
CLOUD = "cloud",
|
|
30
|
+
SELF = "self",
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
class TestConfiguration {
|
|
29
34
|
server: any
|
|
30
35
|
request: any
|
|
31
36
|
api: API
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
userPassword = "test"
|
|
35
|
-
|
|
36
|
-
constructor(opts: { openServer: boolean } = { openServer: true }) {
|
|
37
|
-
// default to cloud hosting
|
|
38
|
-
this.cloudHosted()
|
|
37
|
+
defaultUser?: User
|
|
38
|
+
tenant1User?: User
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
constructor(
|
|
41
|
+
opts: { openServer: boolean; mode: Mode } = {
|
|
42
|
+
openServer: true,
|
|
43
|
+
mode: Mode.CLOUD,
|
|
44
|
+
}
|
|
45
|
+
) {
|
|
46
|
+
if (opts.mode === Mode.CLOUD) {
|
|
47
|
+
this.modeCloud()
|
|
48
|
+
} else if (opts.mode === Mode.SELF) {
|
|
49
|
+
this.modeSelf()
|
|
50
|
+
}
|
|
41
51
|
|
|
42
52
|
if (opts.openServer) {
|
|
43
53
|
env.PORT = "0" // random port
|
|
@@ -53,19 +63,26 @@ class TestConfiguration {
|
|
|
53
63
|
return this.request
|
|
54
64
|
}
|
|
55
65
|
|
|
56
|
-
//
|
|
66
|
+
// MODES
|
|
67
|
+
|
|
68
|
+
setMultiTenancy = (value: boolean) => {
|
|
69
|
+
env._set("MULTI_TENANCY", value)
|
|
70
|
+
coreEnv._set("MULTI_TENANCY", value)
|
|
71
|
+
}
|
|
57
72
|
|
|
58
73
|
setSelfHosted = (value: boolean) => {
|
|
59
74
|
env._set("SELF_HOSTED", value)
|
|
60
75
|
coreEnv._set("SELF_HOSTED", value)
|
|
61
76
|
}
|
|
62
77
|
|
|
63
|
-
|
|
78
|
+
modeCloud = () => {
|
|
64
79
|
this.setSelfHosted(false)
|
|
80
|
+
this.setMultiTenancy(true)
|
|
65
81
|
}
|
|
66
82
|
|
|
67
|
-
|
|
83
|
+
modeSelf = () => {
|
|
68
84
|
this.setSelfHosted(true)
|
|
85
|
+
this.setMultiTenancy(false)
|
|
69
86
|
}
|
|
70
87
|
|
|
71
88
|
// UTILS
|
|
@@ -86,7 +103,7 @@ class TestConfiguration {
|
|
|
86
103
|
if (params) {
|
|
87
104
|
request.params = params
|
|
88
105
|
}
|
|
89
|
-
await
|
|
106
|
+
await tenancy.doInTenant(this.getTenantId(), () => {
|
|
90
107
|
return controlFunc(request)
|
|
91
108
|
})
|
|
92
109
|
return request.body
|
|
@@ -95,13 +112,13 @@ class TestConfiguration {
|
|
|
95
112
|
// SETUP / TEARDOWN
|
|
96
113
|
|
|
97
114
|
async beforeAll() {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
115
|
+
await this.createDefaultUser()
|
|
116
|
+
await this.createSession(this.defaultUser!)
|
|
117
|
+
|
|
118
|
+
await tenancy.doInTenant(TENANT_1, async () => {
|
|
119
|
+
await this.createTenant1User()
|
|
120
|
+
await this.createSession(this.tenant1User!)
|
|
121
|
+
})
|
|
105
122
|
}
|
|
106
123
|
|
|
107
124
|
async afterAll() {
|
|
@@ -112,12 +129,6 @@ class TestConfiguration {
|
|
|
112
129
|
|
|
113
130
|
// TENANCY
|
|
114
131
|
|
|
115
|
-
doInTenant(task: any) {
|
|
116
|
-
return context.doInTenant(this.tenantId, () => {
|
|
117
|
-
return task()
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
|
|
121
132
|
createTenant = async (): Promise<User> => {
|
|
122
133
|
// create user / new tenant
|
|
123
134
|
const res = await this.api.users.createAdminUser()
|
|
@@ -139,9 +150,9 @@ class TestConfiguration {
|
|
|
139
150
|
|
|
140
151
|
getTenantId() {
|
|
141
152
|
try {
|
|
142
|
-
return
|
|
143
|
-
} catch (e) {
|
|
144
|
-
return
|
|
153
|
+
return tenancy.getTenantId()
|
|
154
|
+
} catch (e: any) {
|
|
155
|
+
return TENANT_ID
|
|
145
156
|
}
|
|
146
157
|
}
|
|
147
158
|
|
|
@@ -189,11 +200,14 @@ class TestConfiguration {
|
|
|
189
200
|
}
|
|
190
201
|
|
|
191
202
|
defaultHeaders() {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
203
|
+
const tenantId = this.getTenantId()
|
|
204
|
+
if (tenantId === TENANT_ID) {
|
|
205
|
+
return this.authHeaders(this.defaultUser!)
|
|
206
|
+
} else if (tenantId === TENANT_1) {
|
|
207
|
+
return this.authHeaders(this.tenant1User!)
|
|
208
|
+
} else {
|
|
209
|
+
throw new Error("could not determine auth headers to use")
|
|
210
|
+
}
|
|
197
211
|
}
|
|
198
212
|
|
|
199
213
|
internalAPIHeaders() {
|
|
@@ -208,15 +222,22 @@ class TestConfiguration {
|
|
|
208
222
|
|
|
209
223
|
async createDefaultUser() {
|
|
210
224
|
const user = structures.users.adminUser({
|
|
211
|
-
|
|
225
|
+
email: "test@test.com",
|
|
226
|
+
password: "test",
|
|
212
227
|
})
|
|
213
|
-
await
|
|
214
|
-
|
|
228
|
+
this.defaultUser = await this.createUser(user)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async createTenant1User() {
|
|
232
|
+
const user = structures.users.adminUser({
|
|
233
|
+
email: "tenant1@test.com",
|
|
234
|
+
password: "test",
|
|
215
235
|
})
|
|
236
|
+
this.tenant1User = await this.createUser(user)
|
|
216
237
|
}
|
|
217
238
|
|
|
218
239
|
async getUser(email: string): Promise<User> {
|
|
219
|
-
return
|
|
240
|
+
return tenancy.doInTenant(this.getTenantId(), () => {
|
|
220
241
|
return users.getGlobalUserByEmail(email)
|
|
221
242
|
})
|
|
222
243
|
}
|
|
@@ -226,7 +247,7 @@ class TestConfiguration {
|
|
|
226
247
|
user = structures.users.user()
|
|
227
248
|
}
|
|
228
249
|
const response = await this._req(user, null, controllers.users.save)
|
|
229
|
-
const body = response as
|
|
250
|
+
const body = response as CreateUserResponse
|
|
230
251
|
return this.getUser(body.email)
|
|
231
252
|
}
|
|
232
253
|
|
package/src/tests/api/auth.ts
CHANGED
|
@@ -1,39 +1,20 @@
|
|
|
1
1
|
import TestConfiguration from "../TestConfiguration"
|
|
2
|
-
import { TestAPI
|
|
2
|
+
import { TestAPI } from "./base"
|
|
3
3
|
|
|
4
4
|
export class AuthAPI extends TestAPI {
|
|
5
5
|
constructor(config: TestConfiguration) {
|
|
6
6
|
super(config)
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
updatePassword = (
|
|
10
|
-
resetCode: string,
|
|
11
|
-
password: string,
|
|
12
|
-
opts?: TestAPIOpts
|
|
13
|
-
) => {
|
|
9
|
+
updatePassword = (code: string) => {
|
|
14
10
|
return this.request
|
|
15
11
|
.post(`/api/global/auth/${this.config.getTenantId()}/reset/update`)
|
|
16
12
|
.send({
|
|
17
|
-
password,
|
|
18
|
-
resetCode,
|
|
13
|
+
password: "newpassword",
|
|
14
|
+
resetCode: code,
|
|
19
15
|
})
|
|
20
16
|
.expect("Content-Type", /json/)
|
|
21
|
-
.expect(
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
login = (
|
|
25
|
-
tenantId: string,
|
|
26
|
-
email: string,
|
|
27
|
-
password: string,
|
|
28
|
-
opts?: TestAPIOpts
|
|
29
|
-
) => {
|
|
30
|
-
return this.request
|
|
31
|
-
.post(`/api/global/auth/${tenantId}/login`)
|
|
32
|
-
.send({
|
|
33
|
-
username: email,
|
|
34
|
-
password: password,
|
|
35
|
-
})
|
|
36
|
-
.expect(opts?.status ? opts.status : 200)
|
|
17
|
+
.expect(200)
|
|
37
18
|
}
|
|
38
19
|
|
|
39
20
|
logout = () => {
|
|
@@ -43,31 +24,22 @@ export class AuthAPI extends TestAPI {
|
|
|
43
24
|
.expect(200)
|
|
44
25
|
}
|
|
45
26
|
|
|
46
|
-
requestPasswordReset = async (
|
|
47
|
-
sendMailMock: any,
|
|
48
|
-
email: string,
|
|
49
|
-
opts?: TestAPIOpts
|
|
50
|
-
) => {
|
|
27
|
+
requestPasswordReset = async (sendMailMock: any) => {
|
|
51
28
|
await this.config.saveSmtpConfig()
|
|
52
29
|
await this.config.saveSettingsConfig()
|
|
53
|
-
|
|
30
|
+
await this.config.createUser()
|
|
54
31
|
const res = await this.request
|
|
55
32
|
.post(`/api/global/auth/${this.config.getTenantId()}/reset`)
|
|
56
33
|
.send({
|
|
57
|
-
email:
|
|
34
|
+
email: "test@test.com",
|
|
58
35
|
})
|
|
59
36
|
.expect("Content-Type", /json/)
|
|
60
|
-
.expect(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
`http://localhost:10000/builder/auth/reset?code=`
|
|
67
|
-
)
|
|
68
|
-
code = parts[1].split('"')[0].split("&")[0]
|
|
69
|
-
}
|
|
70
|
-
|
|
37
|
+
.expect(200)
|
|
38
|
+
const emailCall = sendMailMock.mock.calls[0][0]
|
|
39
|
+
const parts = emailCall.html.split(
|
|
40
|
+
`http://localhost:10000/builder/auth/reset?code=`
|
|
41
|
+
)
|
|
42
|
+
const code = parts[1].split('"')[0].split("&")[0]
|
|
71
43
|
return { code, res }
|
|
72
44
|
}
|
|
73
45
|
}
|
package/src/tests/api/base.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import TestConfiguration from "../TestConfiguration"
|
|
2
|
-
import { SuperTest, Test } from "supertest"
|
|
3
2
|
|
|
4
3
|
export interface TestAPIOpts {
|
|
5
4
|
headers?: any
|
|
@@ -8,7 +7,7 @@ export interface TestAPIOpts {
|
|
|
8
7
|
|
|
9
8
|
export abstract class TestAPI {
|
|
10
9
|
config: TestConfiguration
|
|
11
|
-
request:
|
|
10
|
+
request: any
|
|
12
11
|
|
|
13
12
|
protected constructor(config: TestConfiguration) {
|
|
14
13
|
this.config = config
|
package/src/tests/api/configs.ts
CHANGED
|
@@ -10,8 +10,8 @@ export class ConfigAPI extends TestAPI {
|
|
|
10
10
|
return this.request
|
|
11
11
|
.get(`/api/global/configs/checklist`)
|
|
12
12
|
.set(this.config.defaultHeaders())
|
|
13
|
-
.expect(200)
|
|
14
13
|
.expect("Content-Type", /json/)
|
|
14
|
+
.expect(200)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
saveConfig = (data: any) => {
|
|
@@ -19,8 +19,8 @@ export class ConfigAPI extends TestAPI {
|
|
|
19
19
|
.post(`/api/global/configs`)
|
|
20
20
|
.send(data)
|
|
21
21
|
.set(this.config.defaultHeaders())
|
|
22
|
-
.expect(200)
|
|
23
22
|
.expect("Content-Type", /json/)
|
|
23
|
+
.expect(200)
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
OIDCCallback = (configId: string, preAuthRes: any) => {
|
package/src/tests/api/restore.ts
CHANGED
package/src/tests/api/users.ts
CHANGED
|
@@ -26,8 +26,8 @@ export class UserAPI extends TestAPI {
|
|
|
26
26
|
email,
|
|
27
27
|
})
|
|
28
28
|
.set(this.config.defaultHeaders())
|
|
29
|
-
.expect(status)
|
|
30
29
|
.expect("Content-Type", /json/)
|
|
30
|
+
.expect(status)
|
|
31
31
|
|
|
32
32
|
if (status !== 200) {
|
|
33
33
|
return { code: undefined, res }
|
|
@@ -100,7 +100,7 @@ export class UserAPI extends TestAPI {
|
|
|
100
100
|
request = {
|
|
101
101
|
email: structures.email(),
|
|
102
102
|
password: generator.string(),
|
|
103
|
-
tenantId: structures.
|
|
103
|
+
tenantId: structures.uuid(),
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
const res = await this.request
|
package/src/tests/jestEnv.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
process.env.SELF_HOSTED = "0"
|
|
2
2
|
process.env.NODE_ENV = "jest"
|
|
3
3
|
process.env.JWT_SECRET = "test-jwtsecret"
|
|
4
|
-
process.env.LOG_LEVEL =
|
|
5
|
-
process.env.ENABLE_4XX_HTTP_LOGGING = "0"
|
|
4
|
+
process.env.LOG_LEVEL = "silent"
|
|
6
5
|
process.env.MULTI_TENANCY = "1"
|
|
7
6
|
process.env.MINIO_URL = "http://localhost"
|
|
8
7
|
process.env.MINIO_ACCESS_KEY = "test"
|
package/src/tests/jestSetup.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import "
|
|
2
|
-
|
|
3
|
-
import { mocks, testContainerUtils } from "@budibase/backend-core/tests"
|
|
4
|
-
import env from "../environment"
|
|
5
|
-
import { env as coreEnv } from "@budibase/backend-core"
|
|
1
|
+
import { mocks } from "@budibase/backend-core/tests"
|
|
6
2
|
|
|
7
3
|
// must explicitly enable fetch mock
|
|
8
4
|
mocks.fetch.enable()
|
|
@@ -12,12 +8,12 @@ mocks.fetch.enable()
|
|
|
12
8
|
const tk = require("timekeeper")
|
|
13
9
|
tk.freeze(mocks.date.MOCK_DATE)
|
|
14
10
|
|
|
11
|
+
if (!process.env.DEBUG) {
|
|
12
|
+
global.console.log = jest.fn() // console.log are ignored in tests
|
|
13
|
+
}
|
|
14
|
+
|
|
15
15
|
if (!process.env.CI) {
|
|
16
16
|
// set a longer timeout in dev for debugging
|
|
17
17
|
// 100 seconds
|
|
18
|
-
jest.setTimeout(
|
|
19
|
-
} else {
|
|
20
|
-
jest.setTimeout(10 * 1000)
|
|
18
|
+
jest.setTimeout(100000)
|
|
21
19
|
}
|
|
22
|
-
|
|
23
|
-
testContainerUtils.setupEnv(env, coreEnv)
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { structures } from "@budibase/backend-core/tests"
|
|
2
2
|
import * as configs from "./configs"
|
|
3
|
+
import * as users from "./users"
|
|
3
4
|
import * as groups from "./groups"
|
|
4
5
|
import { v4 as uuid } from "uuid"
|
|
5
6
|
|
|
6
7
|
export const TENANT_ID = "default"
|
|
8
|
+
export const TENANT_1 = "tenant1"
|
|
7
9
|
export const CSRF_TOKEN = "e3727778-7af0-4226-b5eb-f43cbe60a306"
|
|
8
10
|
|
|
9
11
|
const pkg = {
|
|
10
12
|
...structures,
|
|
11
13
|
uuid,
|
|
12
14
|
configs,
|
|
15
|
+
users,
|
|
13
16
|
TENANT_ID,
|
|
17
|
+
TENANT_1,
|
|
14
18
|
CSRF_TOKEN,
|
|
15
19
|
groups,
|
|
16
20
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const email = "test@test.com"
|
|
2
|
+
import { AdminUser, BuilderUser, User } from "@budibase/types"
|
|
3
|
+
import { v4 as uuid } from "uuid"
|
|
4
|
+
|
|
5
|
+
export const newEmail = () => {
|
|
6
|
+
return `${uuid()}@test.com`
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const user = (userProps?: any): User => {
|
|
10
|
+
return {
|
|
11
|
+
email: newEmail(),
|
|
12
|
+
password: "test",
|
|
13
|
+
roles: { app_test: "admin" },
|
|
14
|
+
...userProps,
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const adminUser = (userProps?: any): AdminUser => {
|
|
19
|
+
return {
|
|
20
|
+
...user(userProps),
|
|
21
|
+
admin: {
|
|
22
|
+
global: true,
|
|
23
|
+
},
|
|
24
|
+
builder: {
|
|
25
|
+
global: true,
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const builderUser = (userProps?: any): BuilderUser => {
|
|
31
|
+
return {
|
|
32
|
+
...user(userProps),
|
|
33
|
+
builder: {
|
|
34
|
+
global: true,
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/utilities/email.ts
CHANGED
|
@@ -26,7 +26,7 @@ type SendEmailOpts = {
|
|
|
26
26
|
automation?: boolean
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const TEST_MODE =
|
|
29
|
+
const TEST_MODE = false
|
|
30
30
|
const TYPE = TemplateType.EMAIL
|
|
31
31
|
|
|
32
32
|
const FULL_EMAIL_PURPOSES = [
|
|
@@ -62,8 +62,8 @@ function createSMTPTransport(config: any) {
|
|
|
62
62
|
host: "smtp.ethereal.email",
|
|
63
63
|
secure: false,
|
|
64
64
|
auth: {
|
|
65
|
-
user: "
|
|
66
|
-
pass: "
|
|
65
|
+
user: "don.bahringer@ethereal.email",
|
|
66
|
+
pass: "yCKSH8rWyUPbnhGYk9",
|
|
67
67
|
},
|
|
68
68
|
}
|
|
69
69
|
}
|
package/src/utilities/redis.ts
CHANGED
|
@@ -54,8 +54,6 @@ export async function init() {
|
|
|
54
54
|
export async function shutdown() {
|
|
55
55
|
if (pwResetClient) await pwResetClient.finish()
|
|
56
56
|
if (invitationClient) await invitationClient.finish()
|
|
57
|
-
// shutdown core clients
|
|
58
|
-
await redis.clients.shutdown()
|
|
59
57
|
console.log("Redis shutdown")
|
|
60
58
|
}
|
|
61
59
|
|