@budibase/worker 2.3.18-alpha.9 → 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.
Files changed (168) hide show
  1. package/coverage/clover.xml +2199 -0
  2. package/coverage/coverage-final.json +84 -0
  3. package/coverage/lcov-report/base.css +224 -0
  4. package/coverage/lcov-report/block-navigation.js +87 -0
  5. package/coverage/lcov-report/favicon.png +0 -0
  6. package/coverage/lcov-report/index.html +431 -0
  7. package/coverage/lcov-report/prettify.css +1 -0
  8. package/coverage/lcov-report/prettify.js +2 -0
  9. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  10. package/coverage/lcov-report/sorter.js +196 -0
  11. package/coverage/lcov-report/src/api/controllers/global/auth.ts.html +934 -0
  12. package/coverage/lcov-report/src/api/controllers/global/configs.ts.html +1348 -0
  13. package/coverage/lcov-report/src/api/controllers/global/email.ts.html +196 -0
  14. package/coverage/lcov-report/src/api/controllers/global/events.ts.html +136 -0
  15. package/coverage/lcov-report/src/api/controllers/global/index.html +251 -0
  16. package/coverage/lcov-report/src/api/controllers/global/license.ts.html +187 -0
  17. package/coverage/lcov-report/src/api/controllers/global/roles.ts.html +283 -0
  18. package/coverage/lcov-report/src/api/controllers/global/self.ts.html +577 -0
  19. package/coverage/lcov-report/src/api/controllers/global/templates.ts.html +316 -0
  20. package/coverage/lcov-report/src/api/controllers/global/users.ts.html +838 -0
  21. package/coverage/lcov-report/src/api/controllers/global/workspaces.ts.html +244 -0
  22. package/coverage/lcov-report/src/api/controllers/system/accounts.ts.html +148 -0
  23. package/coverage/lcov-report/src/api/controllers/system/environment.ts.html +124 -0
  24. package/coverage/lcov-report/src/api/controllers/system/index.html +191 -0
  25. package/coverage/lcov-report/src/api/controllers/system/migrations.ts.html +124 -0
  26. package/coverage/lcov-report/src/api/controllers/system/restore.ts.html +124 -0
  27. package/coverage/lcov-report/src/api/controllers/system/status.ts.html +133 -0
  28. package/coverage/lcov-report/src/api/controllers/system/tenants.ts.html +154 -0
  29. package/coverage/lcov-report/src/api/index.html +116 -0
  30. package/coverage/lcov-report/src/api/index.ts.html +595 -0
  31. package/coverage/lcov-report/src/api/routes/global/auth.ts.html +349 -0
  32. package/coverage/lcov-report/src/api/routes/global/configs.ts.html +457 -0
  33. package/coverage/lcov-report/src/api/routes/global/email.ts.html +193 -0
  34. package/coverage/lcov-report/src/api/routes/global/events.ts.html +109 -0
  35. package/coverage/lcov-report/src/api/routes/global/index.html +251 -0
  36. package/coverage/lcov-report/src/api/routes/global/license.ts.html +124 -0
  37. package/coverage/lcov-report/src/api/routes/global/roles.ts.html +133 -0
  38. package/coverage/lcov-report/src/api/routes/global/self.ts.html +139 -0
  39. package/coverage/lcov-report/src/api/routes/global/templates.ts.html +196 -0
  40. package/coverage/lcov-report/src/api/routes/global/users.ts.html +475 -0
  41. package/coverage/lcov-report/src/api/routes/global/workspaces.ts.html +196 -0
  42. package/coverage/lcov-report/src/api/routes/index.html +116 -0
  43. package/coverage/lcov-report/src/api/routes/index.ts.html +202 -0
  44. package/coverage/lcov-report/src/api/routes/system/accounts.ts.html +142 -0
  45. package/coverage/lcov-report/src/api/routes/system/environment.ts.html +109 -0
  46. package/coverage/lcov-report/src/api/routes/system/index.html +191 -0
  47. package/coverage/lcov-report/src/api/routes/system/migrations.ts.html +142 -0
  48. package/coverage/lcov-report/src/api/routes/system/restore.ts.html +109 -0
  49. package/coverage/lcov-report/src/api/routes/system/status.ts.html +109 -0
  50. package/coverage/lcov-report/src/api/routes/system/tenants.ts.html +124 -0
  51. package/coverage/lcov-report/src/api/routes/validation/index.html +131 -0
  52. package/coverage/lcov-report/src/api/routes/validation/index.ts.html +88 -0
  53. package/coverage/lcov-report/src/api/routes/validation/users.ts.html +235 -0
  54. package/coverage/lcov-report/src/constants/index.html +116 -0
  55. package/coverage/lcov-report/src/constants/index.ts.html +637 -0
  56. package/coverage/lcov-report/src/constants/templates/index.html +116 -0
  57. package/coverage/lcov-report/src/constants/templates/index.ts.html +316 -0
  58. package/coverage/lcov-report/src/db/index.html +116 -0
  59. package/coverage/lcov-report/src/db/index.ts.html +115 -0
  60. package/coverage/lcov-report/src/environment.ts.html +388 -0
  61. package/coverage/lcov-report/src/index.html +131 -0
  62. package/coverage/lcov-report/src/index.ts.html +394 -0
  63. package/coverage/lcov-report/src/middleware/cloudRestricted.ts.html +139 -0
  64. package/coverage/lcov-report/src/middleware/index.html +116 -0
  65. package/coverage/lcov-report/src/migrations/functions/globalInfoSyncUsers.ts.html +145 -0
  66. package/coverage/lcov-report/src/migrations/functions/index.html +116 -0
  67. package/coverage/lcov-report/src/migrations/index.html +116 -0
  68. package/coverage/lcov-report/src/migrations/index.ts.html +271 -0
  69. package/coverage/lcov-report/src/sdk/accounts/accounts.ts.html +262 -0
  70. package/coverage/lcov-report/src/sdk/accounts/index.html +131 -0
  71. package/coverage/lcov-report/src/sdk/accounts/index.ts.html +88 -0
  72. package/coverage/lcov-report/src/sdk/index.html +116 -0
  73. package/coverage/lcov-report/src/sdk/index.ts.html +106 -0
  74. package/coverage/lcov-report/src/sdk/users/events.ts.html +601 -0
  75. package/coverage/lcov-report/src/sdk/users/index.html +146 -0
  76. package/coverage/lcov-report/src/sdk/users/index.ts.html +88 -0
  77. package/coverage/lcov-report/src/sdk/users/users.ts.html +1999 -0
  78. package/coverage/lcov-report/src/tests/TestConfiguration.ts.html +1075 -0
  79. package/coverage/lcov-report/src/tests/api/accounts.ts.html +160 -0
  80. package/coverage/lcov-report/src/tests/api/auth.ts.html +220 -0
  81. package/coverage/lcov-report/src/tests/api/base.ts.html +133 -0
  82. package/coverage/lcov-report/src/tests/api/configs.ts.html +226 -0
  83. package/coverage/lcov-report/src/tests/api/email.ts.html +148 -0
  84. package/coverage/lcov-report/src/tests/api/environment.ts.html +130 -0
  85. package/coverage/lcov-report/src/tests/api/groups.ts.html +163 -0
  86. package/coverage/lcov-report/src/tests/api/index.html +356 -0
  87. package/coverage/lcov-report/src/tests/api/index.ts.html +238 -0
  88. package/coverage/lcov-report/src/tests/api/license.ts.html +136 -0
  89. package/coverage/lcov-report/src/tests/api/migrations.ts.html +151 -0
  90. package/coverage/lcov-report/src/tests/api/restore.ts.html +127 -0
  91. package/coverage/lcov-report/src/tests/api/roles.ts.html +181 -0
  92. package/coverage/lcov-report/src/tests/api/self.ts.html +163 -0
  93. package/coverage/lcov-report/src/tests/api/status.ts.html +121 -0
  94. package/coverage/lcov-report/src/tests/api/templates.ts.html +175 -0
  95. package/coverage/lcov-report/src/tests/api/tenants.ts.html +130 -0
  96. package/coverage/lcov-report/src/tests/api/users.ts.html +514 -0
  97. package/coverage/lcov-report/src/tests/controllers.ts.html +100 -0
  98. package/coverage/lcov-report/src/tests/index.html +146 -0
  99. package/coverage/lcov-report/src/tests/index.ts.html +103 -0
  100. package/coverage/lcov-report/src/tests/mocks/email.ts.html +115 -0
  101. package/coverage/lcov-report/src/tests/mocks/index.html +131 -0
  102. package/coverage/lcov-report/src/tests/mocks/index.ts.html +106 -0
  103. package/coverage/lcov-report/src/tests/structures/configs.ts.html +313 -0
  104. package/coverage/lcov-report/src/tests/structures/groups.ts.html +118 -0
  105. package/coverage/lcov-report/src/tests/structures/index.html +161 -0
  106. package/coverage/lcov-report/src/tests/structures/index.ts.html +151 -0
  107. package/coverage/lcov-report/src/tests/structures/users.ts.html +196 -0
  108. package/coverage/lcov-report/src/utilities/appService.ts.html +208 -0
  109. package/coverage/lcov-report/src/utilities/email.ts.html +850 -0
  110. package/coverage/lcov-report/src/utilities/fileSystem.ts.html +100 -0
  111. package/coverage/lcov-report/src/utilities/index.html +206 -0
  112. package/coverage/lcov-report/src/utilities/index.ts.html +112 -0
  113. package/coverage/lcov-report/src/utilities/redis.ts.html +424 -0
  114. package/coverage/lcov-report/src/utilities/templates.ts.html +232 -0
  115. package/coverage/lcov-report/src/utilities/users.ts.html +133 -0
  116. package/coverage/lcov.info +4187 -0
  117. package/jest.config.ts +17 -13
  118. package/package.json +8 -11
  119. package/scripts/dev/manage.js +0 -1
  120. package/src/api/controllers/global/auth.ts +70 -77
  121. package/src/api/controllers/global/self.ts +44 -28
  122. package/src/api/controllers/global/users.ts +25 -65
  123. package/src/api/controllers/system/accounts.ts +5 -7
  124. package/src/api/controllers/system/tenants.ts +8 -4
  125. package/src/api/index.ts +20 -4
  126. package/src/api/routes/global/auth.ts +7 -10
  127. package/src/api/routes/global/tests/auth.spec.ts +17 -226
  128. package/src/api/routes/global/tests/configs.spec.ts +5 -5
  129. package/src/api/routes/global/tests/roles.spec.ts +14 -20
  130. package/src/api/routes/global/tests/self.spec.ts +4 -3
  131. package/src/api/routes/global/tests/users.spec.ts +27 -24
  132. package/src/api/routes/system/tenants.ts +1 -1
  133. package/src/api/routes/system/tests/accounts.spec.ts +4 -4
  134. package/src/api/routes/system/tests/migrations.spec.ts +2 -2
  135. package/src/api/routes/system/tests/restore.spec.ts +2 -2
  136. package/src/api/routes/system/tests/status.spec.ts +5 -5
  137. package/src/environment.ts +1 -15
  138. package/src/index.ts +7 -12
  139. package/src/middleware/tests/tenancy.spec.ts +4 -4
  140. package/src/migrations/functions/globalInfoSyncUsers.ts +3 -4
  141. package/src/sdk/accounts/{metadata.ts → accounts.ts} +1 -0
  142. package/src/sdk/accounts/index.ts +1 -2
  143. package/src/sdk/users/events.ts +0 -4
  144. package/src/sdk/users/index.ts +0 -1
  145. package/src/sdk/users/users.ts +46 -53
  146. package/src/tests/TestConfiguration.ts +62 -41
  147. package/src/tests/api/auth.ts +14 -42
  148. package/src/tests/api/base.ts +1 -2
  149. package/src/tests/api/configs.ts +2 -2
  150. package/src/tests/api/restore.ts +0 -1
  151. package/src/tests/api/users.ts +2 -2
  152. package/src/tests/jestEnv.ts +1 -2
  153. package/src/tests/jestSetup.ts +6 -10
  154. package/src/tests/structures/index.ts +4 -0
  155. package/src/tests/structures/users.ts +37 -0
  156. package/src/utilities/email.ts +3 -3
  157. package/src/utilities/redis.ts +0 -2
  158. package/__mocks__/node-fetch.ts +0 -23
  159. package/jest-testcontainers-config.js +0 -8
  160. package/scripts/test.sh +0 -12
  161. package/src/ddApm.ts +0 -7
  162. package/src/elasticApm.ts +0 -10
  163. package/src/sdk/auth/auth.ts +0 -86
  164. package/src/sdk/auth/index.ts +0 -1
  165. package/src/sdk/tenants/index.ts +0 -1
  166. package/src/sdk/tenants/tenants.ts +0 -76
  167. package/src/sdk/users/tests/users.spec.ts +0 -52
  168. package/src/tests/logging.ts +0 -34
@@ -1,48 +1,31 @@
1
1
  import { checkInviteCode } from "../../../utilities/redis"
2
- import * as userSdk from "../../../sdk/users"
2
+ import sdk from "../../../sdk"
3
3
  import env from "../../../environment"
4
4
  import {
5
- AcceptUserInviteRequest,
6
- AcceptUserInviteResponse,
7
5
  BulkUserRequest,
8
6
  BulkUserResponse,
9
7
  CloudAccount,
10
8
  CreateAdminUserRequest,
11
- CreateAdminUserResponse,
12
- Ctx,
13
9
  InviteUserRequest,
14
10
  InviteUsersRequest,
15
- MigrationType,
16
- SaveUserResponse,
17
11
  SearchUsersRequest,
18
12
  User,
19
- UserCtx,
20
13
  } from "@budibase/types"
21
14
  import {
22
15
  accounts,
23
16
  cache,
24
17
  errors,
25
18
  events,
26
- migrations,
27
19
  tenancy,
28
- platform,
29
20
  } from "@budibase/backend-core"
30
21
  import { checkAnyUserExists } from "../../../utilities/users"
31
22
 
32
23
  const MAX_USERS_UPLOAD_LIMIT = 1000
33
24
 
34
- export const save = async (ctx: UserCtx<User, SaveUserResponse>) => {
25
+ export const save = async (ctx: any) => {
35
26
  try {
36
27
  const currentUserId = ctx.user._id
37
- const requestUser = ctx.request.body
38
-
39
- const user = await userSdk.save(requestUser, { currentUserId })
40
-
41
- ctx.body = {
42
- _id: user._id!,
43
- _rev: user._rev!,
44
- email: user.email,
45
- }
28
+ ctx.body = await sdk.users.save(ctx.request.body, { currentUserId })
46
29
  } catch (err: any) {
47
30
  ctx.throw(err.status || 400, err)
48
31
  }
@@ -52,7 +35,7 @@ const bulkDelete = async (userIds: string[], currentUserId: string) => {
52
35
  if (userIds?.indexOf(currentUserId) !== -1) {
53
36
  throw new Error("Unable to delete self.")
54
37
  }
55
- return await userSdk.bulkDelete(userIds)
38
+ return await sdk.users.bulkDelete(userIds)
56
39
  }
57
40
 
58
41
  const bulkCreate = async (users: User[], groupIds: string[]) => {
@@ -61,7 +44,7 @@ const bulkCreate = async (users: User[], groupIds: string[]) => {
61
44
  "Max limit for upload is 1000 users. Please reduce file size and try again."
62
45
  )
63
46
  }
64
- return await userSdk.bulkCreate(users, groupIds)
47
+ return await sdk.users.bulkCreate(users, groupIds)
65
48
  }
66
49
 
67
50
  export const bulkUpdate = async (ctx: any) => {
@@ -85,30 +68,19 @@ const parseBooleanParam = (param: any) => {
85
68
  return !(param && param === "false")
86
69
  }
87
70
 
88
- export const adminUser = async (
89
- ctx: Ctx<CreateAdminUserRequest, CreateAdminUserResponse>
90
- ) => {
91
- const { email, password, tenantId } = ctx.request.body
92
-
93
- if (await platform.tenants.exists(tenantId)) {
94
- ctx.throw(403, "Organisation already exists.")
95
- }
96
-
97
- if (env.MULTI_TENANCY) {
98
- // store the new tenant record in the platform db
99
- await platform.tenants.addTenant(tenantId)
100
- await migrations.backPopulateMigrations({
101
- type: MigrationType.GLOBAL,
102
- tenantId,
103
- })
104
- }
105
-
71
+ export const adminUser = async (ctx: any) => {
72
+ const { email, password, tenantId } = ctx.request
73
+ .body as CreateAdminUserRequest
106
74
  await tenancy.doInTenant(tenantId, async () => {
107
75
  // account portal sends a pre-hashed password - honour param to prevent double hashing
108
76
  const hashPassword = parseBooleanParam(ctx.request.query.hashPassword)
109
77
  // account portal sends no password for SSO users
110
78
  const requirePassword = parseBooleanParam(ctx.request.query.requirePassword)
111
79
 
80
+ if (await tenancy.doesTenantExist(tenantId)) {
81
+ ctx.throw(403, "Organisation already exists.")
82
+ }
83
+
112
84
  const userExists = await checkAnyUserExists()
113
85
  if (userExists) {
114
86
  ctx.throw(
@@ -134,7 +106,7 @@ export const adminUser = async (
134
106
  // always bust checklist beforehand, if an error occurs but can proceed, don't get
135
107
  // stuck in a cycle
136
108
  await cache.bustCache(cache.CacheKey.CHECKLIST)
137
- const finalUser = await userSdk.save(user, {
109
+ const finalUser = await sdk.users.save(user, {
138
110
  hashPassword,
139
111
  requirePassword,
140
112
  })
@@ -146,11 +118,7 @@ export const adminUser = async (
146
118
  }
147
119
  await events.identification.identifyTenantGroup(tenantId, account)
148
120
 
149
- ctx.body = {
150
- _id: finalUser._id!,
151
- _rev: finalUser._rev!,
152
- email: finalUser.email,
153
- }
121
+ ctx.body = finalUser
154
122
  } catch (err: any) {
155
123
  ctx.throw(err.status || 400, err)
156
124
  }
@@ -160,7 +128,7 @@ export const adminUser = async (
160
128
  export const countByApp = async (ctx: any) => {
161
129
  const appId = ctx.params.appId
162
130
  try {
163
- ctx.body = await userSdk.countUsersByApp(appId)
131
+ ctx.body = await sdk.users.countUsersByApp(appId)
164
132
  } catch (err: any) {
165
133
  ctx.throw(err.status || 400, err)
166
134
  }
@@ -172,7 +140,7 @@ export const destroy = async (ctx: any) => {
172
140
  ctx.throw(400, "Unable to delete self.")
173
141
  }
174
142
 
175
- await userSdk.destroy(id, ctx.user)
143
+ await sdk.users.destroy(id, ctx.user)
176
144
 
177
145
  ctx.body = {
178
146
  message: `User ${id} deleted.`,
@@ -181,7 +149,7 @@ export const destroy = async (ctx: any) => {
181
149
 
182
150
  export const search = async (ctx: any) => {
183
151
  const body = ctx.request.body as SearchUsersRequest
184
- const paginated = await userSdk.paginatedUsers(body)
152
+ const paginated = await sdk.users.paginatedUsers(body)
185
153
  // user hashed password shouldn't ever be returned
186
154
  for (let user of paginated.data) {
187
155
  if (user) {
@@ -193,7 +161,7 @@ export const search = async (ctx: any) => {
193
161
 
194
162
  // called internally by app server user fetch
195
163
  export const fetch = async (ctx: any) => {
196
- const all = await userSdk.allUsers()
164
+ const all = await sdk.users.allUsers()
197
165
  // user hashed password shouldn't ever be returned
198
166
  for (let user of all) {
199
167
  if (user) {
@@ -205,12 +173,12 @@ export const fetch = async (ctx: any) => {
205
173
 
206
174
  // called internally by app server user find
207
175
  export const find = async (ctx: any) => {
208
- ctx.body = await userSdk.getUser(ctx.params.id)
176
+ ctx.body = await sdk.users.getUser(ctx.params.id)
209
177
  }
210
178
 
211
179
  export const tenantUserLookup = async (ctx: any) => {
212
180
  const id = ctx.params.id
213
- const user = await userSdk.getPlatformUser(id)
181
+ const user = await sdk.users.getPlatformUser(id)
214
182
  if (user) {
215
183
  ctx.body = user
216
184
  } else {
@@ -220,7 +188,7 @@ export const tenantUserLookup = async (ctx: any) => {
220
188
 
221
189
  export const invite = async (ctx: any) => {
222
190
  const request = ctx.request.body as InviteUserRequest
223
- const response = await userSdk.invite([request])
191
+ const response = await sdk.users.invite([request])
224
192
 
225
193
  // explicitly throw for single user invite
226
194
  if (response.unsuccessful.length) {
@@ -239,7 +207,7 @@ export const invite = async (ctx: any) => {
239
207
 
240
208
  export const inviteMultiple = async (ctx: any) => {
241
209
  const request = ctx.request.body as InviteUsersRequest
242
- ctx.body = await userSdk.invite(request)
210
+ ctx.body = await sdk.users.invite(request)
243
211
  }
244
212
 
245
213
  export const checkInvite = async (ctx: any) => {
@@ -255,15 +223,13 @@ export const checkInvite = async (ctx: any) => {
255
223
  }
256
224
  }
257
225
 
258
- export const inviteAccept = async (
259
- ctx: Ctx<AcceptUserInviteRequest, AcceptUserInviteResponse>
260
- ) => {
226
+ export const inviteAccept = async (ctx: any) => {
261
227
  const { inviteCode, password, firstName, lastName } = ctx.request.body
262
228
  try {
263
229
  // info is an extension of the user object that was stored by global
264
230
  const { email, info }: any = await checkInviteCode(inviteCode)
265
- const user = await tenancy.doInTenant(info.tenantId, async () => {
266
- const saved = await userSdk.save({
231
+ ctx.body = await tenancy.doInTenant(info.tenantId, async () => {
232
+ const saved = await sdk.users.save({
267
233
  firstName,
268
234
  lastName,
269
235
  password,
@@ -275,12 +241,6 @@ export const inviteAccept = async (
275
241
  await events.user.inviteAccepted(user)
276
242
  return saved
277
243
  })
278
-
279
- ctx.body = {
280
- _id: user._id,
281
- _rev: user._rev,
282
- email: user.email,
283
- }
284
244
  } catch (err: any) {
285
245
  if (err.code === errors.codes.USAGE_LIMIT_EXCEEDED) {
286
246
  // explicitly re-throw limit exceeded errors
@@ -1,23 +1,21 @@
1
1
  import { Account, AccountMetadata } from "@budibase/types"
2
- import * as accounts from "../../../sdk/accounts"
2
+ import sdk from "../../../sdk"
3
3
 
4
4
  export const save = async (ctx: any) => {
5
5
  const account = ctx.request.body as Account
6
6
  let metadata: AccountMetadata = {
7
- _id: accounts.metadata.formatAccountMetadataId(account.accountId),
7
+ _id: sdk.accounts.formatAccountMetadataId(account.accountId),
8
8
  email: account.email,
9
9
  }
10
10
 
11
- metadata = await accounts.metadata.saveMetadata(metadata)
11
+ metadata = await sdk.accounts.saveMetadata(metadata)
12
12
 
13
13
  ctx.body = metadata
14
14
  ctx.status = 200
15
15
  }
16
16
 
17
17
  export const destroy = async (ctx: any) => {
18
- const accountId = accounts.metadata.formatAccountMetadataId(
19
- ctx.params.accountId
20
- )
21
- await accounts.metadata.destroyMetadata(accountId)
18
+ const accountId = sdk.accounts.formatAccountMetadataId(ctx.params.accountId)
19
+ await sdk.accounts.destroyMetadata(accountId)
22
20
  ctx.status = 204
23
21
  }
@@ -1,7 +1,8 @@
1
- import { UserCtx } from "@budibase/types"
2
- import * as tenantSdk from "../../../sdk/tenants"
1
+ import { BBContext } from "@budibase/types"
2
+ import { deprovisioning } from "@budibase/backend-core"
3
+ import { quotas } from "@budibase/pro"
3
4
 
4
- export async function destroy(ctx: UserCtx) {
5
+ const _delete = async (ctx: BBContext) => {
5
6
  const user = ctx.user!
6
7
  const tenantId = ctx.params.tenantId
7
8
 
@@ -10,10 +11,13 @@ export async function destroy(ctx: UserCtx) {
10
11
  }
11
12
 
12
13
  try {
13
- await tenantSdk.deleteTenant(tenantId)
14
+ await quotas.bustCache()
15
+ await deprovisioning.deleteTenant(tenantId)
14
16
  ctx.status = 204
15
17
  } catch (err) {
16
18
  ctx.log.error(err)
17
19
  throw err
18
20
  }
19
21
  }
22
+
23
+ export { _delete as delete }
package/src/api/index.ts CHANGED
@@ -3,7 +3,8 @@ const compress = require("koa-compress")
3
3
  const zlib = require("zlib")
4
4
  import { routes } from "./routes"
5
5
  import { middleware as pro } from "@budibase/pro"
6
- import { auth, middleware } from "@budibase/backend-core"
6
+ import { errors, auth, middleware } from "@budibase/backend-core"
7
+ import { APIError } from "@budibase/types"
7
8
 
8
9
  const PUBLIC_ENDPOINTS = [
9
10
  // deprecated single tenant sso callback
@@ -108,9 +109,7 @@ const NO_TENANCY_ENDPOINTS = [
108
109
  const NO_CSRF_ENDPOINTS = [...PUBLIC_ENDPOINTS]
109
110
 
110
111
  const router: Router = new Router()
111
-
112
112
  router
113
- .use(middleware.errorHandling)
114
113
  .use(
115
114
  compress({
116
115
  threshold: 2048,
@@ -137,12 +136,29 @@ router
137
136
  (!ctx.isAuthenticated || (ctx.user && !ctx.user.budibaseAccess)) &&
138
137
  !ctx.internal
139
138
  ) {
140
- ctx.throw(403, "Unauthorized")
139
+ ctx.throw(403, "Unauthorized - no public worker access")
141
140
  }
142
141
  return next()
143
142
  })
144
143
  .use(middleware.auditLog)
145
144
 
145
+ // error handling middleware - TODO: This could be moved to backend-core
146
+ router.use(async (ctx, next) => {
147
+ try {
148
+ await next()
149
+ } catch (err: any) {
150
+ ctx.log.error(err)
151
+ ctx.status = err.status || err.statusCode || 500
152
+ const error = errors.getPublicError(err)
153
+ const body: APIError = {
154
+ message: err.message,
155
+ status: ctx.status,
156
+ error,
157
+ }
158
+ ctx.body = body
159
+ }
160
+ })
161
+
146
162
  router.get("/health", ctx => (ctx.status = 200))
147
163
 
148
164
  // authenticated routes
@@ -33,7 +33,7 @@ router
33
33
  .post(
34
34
  "/api/global/auth/:tenantId/login",
35
35
  buildAuthValidation(),
36
- authController.login
36
+ authController.authenticate
37
37
  )
38
38
  .post("/api/global/auth/logout", authController.logout)
39
39
  .post(
@@ -68,24 +68,21 @@ router
68
68
 
69
69
  // GOOGLE - MULTI TENANT
70
70
  .get("/api/global/auth/:tenantId/google", authController.googlePreAuth)
71
- .get(
72
- "/api/global/auth/:tenantId/google/callback",
73
- authController.googleCallback
74
- )
71
+ .get("/api/global/auth/:tenantId/google/callback", authController.googleAuth)
75
72
 
76
73
  // GOOGLE - SINGLE TENANT - DEPRECATED
77
- .get("/api/global/auth/google/callback", authController.googleCallback)
78
- .get("/api/admin/auth/google/callback", authController.googleCallback)
74
+ .get("/api/global/auth/google/callback", authController.googleAuth)
75
+ .get("/api/admin/auth/google/callback", authController.googleAuth)
79
76
 
80
77
  // OIDC - MULTI TENANT
81
78
  .get(
82
79
  "/api/global/auth/:tenantId/oidc/configs/:configId",
83
80
  authController.oidcPreAuth
84
81
  )
85
- .get("/api/global/auth/:tenantId/oidc/callback", authController.oidcCallback)
82
+ .get("/api/global/auth/:tenantId/oidc/callback", authController.oidcAuth)
86
83
 
87
84
  // OIDC - SINGLE TENANT - DEPRECATED
88
- .get("/api/global/auth/oidc/callback", authController.oidcCallback)
89
- .get("/api/admin/auth/oidc/callback", authController.oidcCallback)
85
+ .get("/api/global/auth/oidc/callback", authController.oidcAuth)
86
+ .get("/api/admin/auth/oidc/callback", authController.oidcAuth)
90
87
 
91
88
  export default router
@@ -1,27 +1,12 @@
1
- import { CloudAccount, SSOUser, User } from "@budibase/types"
2
-
3
1
  jest.mock("nodemailer")
4
- import {
5
- TestConfiguration,
6
- mocks,
7
- structures,
8
- generator,
9
- } from "../../../../tests"
2
+ import { TestConfiguration, mocks } from "../../../../tests"
10
3
  const sendMailMock = mocks.email.mock()
11
- import { events, constants } from "@budibase/backend-core"
12
- import { Response } from "superagent"
13
-
14
- import * as userSdk from "../../../../sdk/users"
15
-
16
- function getAuthCookie(response: Response) {
17
- return response.headers["set-cookie"]
18
- .find((s: string) => s.startsWith(`${constants.Cookie.Auth}=`))
19
- .split("=")[1]
20
- .split(";")[0]
21
- }
4
+ import { events } from "@budibase/backend-core"
22
5
 
23
- const expectSetAuthCookie = (response: Response) => {
24
- expect(getAuthCookie(response).length > 1).toBe(true)
6
+ const expectSetAuthCookie = (res: any) => {
7
+ expect(
8
+ res.get("Set-Cookie").find((c: string) => c.startsWith("budibase:auth"))
9
+ ).toBeDefined()
25
10
  }
26
11
 
27
12
  describe("/api/global/auth", () => {
@@ -39,247 +24,53 @@ describe("/api/global/auth", () => {
39
24
  jest.clearAllMocks()
40
25
  })
41
26
 
42
- async function createSSOUser() {
43
- return config.doInTenant(async () => {
44
- return userSdk.save(structures.users.ssoUser(), {
45
- requirePassword: false,
46
- })
47
- })
48
- }
49
-
50
27
  describe("password", () => {
51
28
  describe("POST /api/global/auth/:tenantId/login", () => {
52
- it("logs in with correct credentials", async () => {
53
- const tenantId = config.tenantId!
54
- const email = config.user?.email!
55
- const password = config.userPassword
56
-
57
- const response = await config.api.auth.login(tenantId, email, password)
58
-
59
- expectSetAuthCookie(response)
60
- expect(events.auth.login).toBeCalledTimes(1)
61
- })
62
-
63
- it("should return 403 with incorrect credentials", async () => {
64
- const tenantId = config.tenantId!
65
- const email = config.user?.email!
66
- const password = "incorrect"
67
-
68
- const response = await config.api.auth.login(
69
- tenantId,
70
- email,
71
- password,
72
- { status: 403 }
73
- )
74
- expect(response.body).toEqual({
75
- message: "Invalid credentials",
76
- status: 403,
77
- })
78
- })
79
-
80
- it("should return 403 when user doesn't exist", async () => {
81
- const tenantId = config.tenantId!
82
- const email = "invaliduser@test.com"
83
- const password = "password"
84
-
85
- const response = await config.api.auth.login(
86
- tenantId,
87
- email,
88
- password,
89
- { status: 403 }
90
- )
91
- expect(response.body).toEqual({
92
- message: "Invalid credentials",
93
- status: 403,
94
- })
95
- })
96
-
97
- describe("sso user", () => {
98
- let user: User
99
-
100
- async function testSSOUser() {
101
- const tenantId = user.tenantId!
102
- const email = user.email
103
- const password = "test"
104
-
105
- const response = await config.api.auth.login(
106
- tenantId,
107
- email,
108
- password,
109
- { status: 400 }
110
- )
111
-
112
- expect(response.body).toEqual({
113
- message: "SSO user cannot login using password",
114
- status: 400,
115
- })
116
- }
117
-
118
- describe("budibase sso user", () => {
119
- it("should prevent user from logging in", async () => {
120
- user = await createSSOUser()
121
- await testSSOUser()
122
- })
123
- })
124
-
125
- describe("root account sso user", () => {
126
- it("should prevent user from logging in", async () => {
127
- user = await config.createUser()
128
- const account = structures.accounts.ssoAccount() as CloudAccount
129
- mocks.accounts.getAccount.mockReturnValueOnce(
130
- Promise.resolve(account)
131
- )
132
-
133
- await testSSOUser()
134
- })
135
- })
136
- })
29
+ it("should login", () => {})
137
30
  })
138
31
 
139
32
  describe("POST /api/global/auth/logout", () => {
140
33
  it("should logout", async () => {
141
- const response = await config.api.auth.logout()
34
+ await config.api.auth.logout()
142
35
  expect(events.auth.logout).toBeCalledTimes(1)
143
36
 
144
- const authCookie = getAuthCookie(response)
145
- expect(authCookie).toBe("")
37
+ // TODO: Verify sessions deleted
146
38
  })
147
39
  })
148
40
 
149
41
  describe("POST /api/global/auth/:tenantId/reset", () => {
150
42
  it("should generate password reset email", async () => {
151
- const user = await config.createUser()
152
-
153
43
  const { res, code } = await config.api.auth.requestPasswordReset(
154
- sendMailMock,
155
- user.email
44
+ sendMailMock
156
45
  )
46
+ const user = await config.getUser("test@test.com")
157
47
 
158
48
  expect(res.body).toEqual({
159
49
  message: "Please check your email for a reset link.",
160
50
  })
161
51
  expect(sendMailMock).toHaveBeenCalled()
52
+
162
53
  expect(code).toBeDefined()
163
54
  expect(events.user.passwordResetRequested).toBeCalledTimes(1)
164
55
  expect(events.user.passwordResetRequested).toBeCalledWith(user)
165
56
  })
166
-
167
- describe("sso user", () => {
168
- let user: User
169
-
170
- async function testSSOUser() {
171
- const { res } = await config.api.auth.requestPasswordReset(
172
- sendMailMock,
173
- user.email,
174
- { status: 400 }
175
- )
176
-
177
- expect(res.body).toEqual({
178
- message: "SSO user cannot reset password",
179
- status: 400,
180
- error: {
181
- code: "http",
182
- type: "generic",
183
- },
184
- })
185
- expect(sendMailMock).not.toHaveBeenCalled()
186
- }
187
-
188
- describe("budibase sso user", () => {
189
- it("should prevent user from generating password reset email", async () => {
190
- user = await createSSOUser()
191
- await testSSOUser()
192
- })
193
- })
194
-
195
- describe("root account sso user", () => {
196
- it("should prevent user from generating password reset email", async () => {
197
- user = await config.createUser(structures.users.user())
198
- const account = structures.accounts.ssoAccount() as CloudAccount
199
- mocks.accounts.getAccount.mockReturnValueOnce(
200
- Promise.resolve(account)
201
- )
202
-
203
- await testSSOUser()
204
- })
205
- })
206
- })
207
57
  })
208
58
 
209
59
  describe("POST /api/global/auth/:tenantId/reset/update", () => {
210
60
  it("should reset password", async () => {
211
- let user = await config.createUser()
212
61
  const { code } = await config.api.auth.requestPasswordReset(
213
- sendMailMock,
214
- user.email
62
+ sendMailMock
215
63
  )
64
+ const user = await config.getUser("test@test.com")
216
65
  delete user.password
217
66
 
218
- const newPassword = "newpassword"
219
- const res = await config.api.auth.updatePassword(code!, newPassword)
220
-
221
- user = await config.getUser(user.email)
222
- delete user.password
67
+ const res = await config.api.auth.updatePassword(code)
223
68
 
224
69
  expect(res.body).toEqual({ message: "password reset successfully." })
225
70
  expect(events.user.passwordReset).toBeCalledTimes(1)
226
71
  expect(events.user.passwordReset).toBeCalledWith(user)
227
72
 
228
- // login using new password
229
- await config.api.auth.login(user.tenantId, user.email, newPassword)
230
- })
231
-
232
- describe("sso user", () => {
233
- let user: User | SSOUser
234
-
235
- async function testSSOUser(code: string) {
236
- const res = await config.api.auth.updatePassword(
237
- code!,
238
- generator.string(),
239
- { status: 400 }
240
- )
241
-
242
- expect(res.body).toEqual({
243
- message: "Cannot reset password.",
244
- status: 400,
245
- })
246
- }
247
-
248
- describe("budibase sso user", () => {
249
- it("should prevent user from generating password reset email", async () => {
250
- user = await config.createUser()
251
- const { code } = await config.api.auth.requestPasswordReset(
252
- sendMailMock,
253
- user.email
254
- )
255
-
256
- // convert to sso now that password reset has been requested
257
- const ssoUser = user as SSOUser
258
- ssoUser.providerType = structures.sso.providerType()
259
- delete ssoUser.password
260
- await config.doInTenant(() => userSdk.save(ssoUser))
261
-
262
- await testSSOUser(code!)
263
- })
264
- })
265
-
266
- describe("root account sso user", () => {
267
- it("should prevent user from generating password reset email", async () => {
268
- user = await config.createUser()
269
- const { code } = await config.api.auth.requestPasswordReset(
270
- sendMailMock,
271
- user.email
272
- )
273
-
274
- // convert to account owner now that password has been requested
275
- const account = structures.accounts.ssoAccount() as CloudAccount
276
- mocks.accounts.getAccount.mockReturnValueOnce(
277
- Promise.resolve(account)
278
- )
279
-
280
- await testSSOUser(code!)
281
- })
282
- })
73
+ // TODO: Login using new password
283
74
  })
284
75
  })
285
76
  })
@@ -354,7 +145,7 @@ describe("/api/global/auth", () => {
354
145
  const location: string = res.get("location")
355
146
  expect(
356
147
  location.startsWith(
357
- `http://localhost/auth?response_type=code&client_id=clientId&redirect_uri=http%3A%2F%2Flocalhost%3A10000%2Fapi%2Fglobal%2Fauth%2F${config.tenantId}%2Foidc%2Fcallback&scope=openid%20profile%20email%20offline_access`
148
+ "http://localhost/auth?response_type=code&client_id=clientId&redirect_uri=http%3A%2F%2Flocalhost%3A10000%2Fapi%2Fglobal%2Fauth%2Fdefault%2Foidc%2Fcallback&scope=openid%20profile%20email%20offline_access"
358
149
  )
359
150
  ).toBe(true)
360
151
  })