@budibase/worker 2.1.44 → 2.1.46-alpha.0

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 (209) hide show
  1. package/__mocks__/aws-sdk.ts +15 -0
  2. package/__mocks__/oauth.ts +57 -0
  3. package/coverage/clover.xml +2167 -0
  4. package/coverage/coverage-final.json +78 -0
  5. package/coverage/lcov-report/base.css +224 -0
  6. package/coverage/lcov-report/block-navigation.js +87 -0
  7. package/coverage/lcov-report/favicon.png +0 -0
  8. package/coverage/lcov-report/index.html +431 -0
  9. package/coverage/lcov-report/prettify.css +1 -0
  10. package/coverage/lcov-report/prettify.js +2 -0
  11. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  12. package/coverage/lcov-report/sorter.js +196 -0
  13. package/coverage/lcov-report/src/api/controllers/global/auth.ts.html +925 -0
  14. package/coverage/lcov-report/src/api/controllers/global/configs.ts.html +1405 -0
  15. package/coverage/lcov-report/src/api/controllers/global/email.ts.html +196 -0
  16. package/coverage/lcov-report/src/api/controllers/global/index.html +236 -0
  17. package/coverage/lcov-report/src/api/controllers/global/license.ts.html +187 -0
  18. package/coverage/lcov-report/src/api/controllers/global/roles.ts.html +283 -0
  19. package/coverage/lcov-report/src/api/controllers/global/self.ts.html +577 -0
  20. package/coverage/lcov-report/src/api/controllers/global/templates.ts.html +316 -0
  21. package/coverage/lcov-report/src/api/controllers/global/users.ts.html +799 -0
  22. package/coverage/lcov-report/src/api/controllers/global/workspaces.ts.html +244 -0
  23. package/coverage/lcov-report/src/api/controllers/system/accounts.ts.html +148 -0
  24. package/coverage/lcov-report/src/api/controllers/system/environment.ts.html +124 -0
  25. package/coverage/lcov-report/src/api/controllers/system/index.html +191 -0
  26. package/coverage/lcov-report/src/api/controllers/system/migrations.ts.html +124 -0
  27. package/coverage/lcov-report/src/api/controllers/system/restore.ts.html +124 -0
  28. package/coverage/lcov-report/src/api/controllers/system/status.ts.html +133 -0
  29. package/coverage/lcov-report/src/api/controllers/system/tenants.ts.html +154 -0
  30. package/coverage/lcov-report/src/api/index.html +116 -0
  31. package/coverage/lcov-report/src/api/index.ts.html +583 -0
  32. package/coverage/lcov-report/src/api/routes/global/auth.ts.html +349 -0
  33. package/coverage/lcov-report/src/api/routes/global/configs.ts.html +457 -0
  34. package/coverage/lcov-report/src/api/routes/global/email.ts.html +193 -0
  35. package/coverage/lcov-report/src/api/routes/global/index.html +236 -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 +433 -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 +196 -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 +613 -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 +373 -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 +577 -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 +1942 -0
  78. package/coverage/lcov-report/src/tests/TestConfiguration.ts.html +1051 -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/index.html +296 -0
  86. package/coverage/lcov-report/src/tests/api/index.ts.html +205 -0
  87. package/coverage/lcov-report/src/tests/api/migrations.ts.html +151 -0
  88. package/coverage/lcov-report/src/tests/api/restore.ts.html +127 -0
  89. package/coverage/lcov-report/src/tests/api/self.ts.html +163 -0
  90. package/coverage/lcov-report/src/tests/api/status.ts.html +121 -0
  91. package/coverage/lcov-report/src/tests/api/tenants.ts.html +130 -0
  92. package/coverage/lcov-report/src/tests/api/users.ts.html +511 -0
  93. package/coverage/lcov-report/src/tests/controllers.ts.html +100 -0
  94. package/coverage/lcov-report/src/tests/index.html +146 -0
  95. package/coverage/lcov-report/src/tests/index.ts.html +139 -0
  96. package/coverage/lcov-report/src/tests/mocks/email.js.html +115 -0
  97. package/coverage/lcov-report/src/tests/mocks/index.html +131 -0
  98. package/coverage/lcov-report/src/tests/mocks/index.ts.html +106 -0
  99. package/coverage/lcov-report/src/tests/structures/configs.ts.html +313 -0
  100. package/coverage/lcov-report/src/tests/structures/groups.ts.html +118 -0
  101. package/coverage/lcov-report/src/tests/structures/index.html +161 -0
  102. package/coverage/lcov-report/src/tests/structures/index.ts.html +151 -0
  103. package/coverage/lcov-report/src/tests/structures/users.ts.html +196 -0
  104. package/coverage/lcov-report/src/utilities/appService.ts.html +181 -0
  105. package/coverage/lcov-report/src/utilities/email.ts.html +850 -0
  106. package/coverage/lcov-report/src/utilities/fileSystem.ts.html +100 -0
  107. package/coverage/lcov-report/src/utilities/index.html +206 -0
  108. package/coverage/lcov-report/src/utilities/index.ts.html +112 -0
  109. package/coverage/lcov-report/src/utilities/redis.ts.html +424 -0
  110. package/coverage/lcov-report/src/utilities/templates.ts.html +232 -0
  111. package/coverage/lcov-report/src/utilities/users.ts.html +133 -0
  112. package/coverage/lcov.info +3989 -0
  113. package/jest.config.ts +29 -0
  114. package/package.json +14 -24
  115. package/scripts/localdomain.js +33 -7
  116. package/src/api/controllers/global/auth.ts +51 -43
  117. package/src/api/controllers/global/{configs.js → configs.ts} +119 -114
  118. package/src/api/controllers/global/{email.js → email.ts} +6 -5
  119. package/src/api/controllers/global/roles.ts +66 -0
  120. package/src/api/controllers/global/self.ts +2 -2
  121. package/src/api/controllers/global/users.ts +6 -3
  122. package/src/api/controllers/global/{workspaces.js → workspaces.ts} +15 -18
  123. package/src/api/controllers/system/{environment.js → environment.ts} +3 -2
  124. package/src/api/controllers/system/restore.ts +1 -1
  125. package/src/api/controllers/system/{status.js → status.ts} +4 -3
  126. package/src/api/controllers/system/tenants.ts +8 -51
  127. package/src/api/index.ts +31 -8
  128. package/src/api/routes/global/{auth.js → auth.ts} +31 -48
  129. package/src/api/routes/global/{configs.js → configs.ts} +22 -23
  130. package/src/api/routes/global/{email.js → email.ts} +9 -10
  131. package/src/api/routes/global/license.ts +1 -1
  132. package/src/api/routes/global/roles.ts +16 -0
  133. package/src/api/routes/global/self.ts +2 -2
  134. package/src/api/routes/global/templates.ts +4 -4
  135. package/src/api/routes/global/tests/auth.spec.ts +134 -64
  136. package/src/api/routes/global/tests/configs.spec.ts +34 -35
  137. package/src/api/routes/global/tests/email.spec.ts +4 -3
  138. package/src/api/routes/global/tests/license.spec.ts +31 -0
  139. package/src/api/routes/global/tests/realEmail.spec.ts +2 -3
  140. package/src/api/routes/global/tests/roles.spec.ts +27 -0
  141. package/src/api/routes/global/tests/self.spec.ts +3 -4
  142. package/src/api/routes/global/tests/templates.spec.ts +35 -0
  143. package/src/api/routes/global/tests/users.spec.ts +79 -46
  144. package/src/api/routes/global/tests/workspaces.spec.ts +29 -0
  145. package/src/api/routes/global/{users.js → users.ts} +28 -26
  146. package/src/api/routes/global/{workspaces.js → workspaces.ts} +9 -10
  147. package/src/api/routes/index.ts +2 -1
  148. package/src/api/routes/system/accounts.ts +1 -1
  149. package/src/api/routes/system/environment.ts +8 -0
  150. package/src/api/routes/system/migrations.ts +1 -1
  151. package/src/api/routes/system/restore.ts +1 -1
  152. package/src/api/routes/system/status.ts +8 -0
  153. package/src/api/routes/system/tenants.ts +13 -0
  154. package/src/api/routes/system/tests/accounts.spec.ts +5 -6
  155. package/src/api/routes/system/tests/environment.spec.ts +29 -0
  156. package/src/api/routes/system/tests/migrations.spec.ts +63 -0
  157. package/src/api/routes/system/tests/restore.spec.ts +36 -0
  158. package/src/api/routes/system/tests/status.spec.ts +48 -0
  159. package/src/api/routes/system/tests/tenants.spec.ts +61 -0
  160. package/src/api/routes/validation/users.ts +3 -3
  161. package/src/constants/{index.js → index.ts} +57 -64
  162. package/src/constants/templates/{index.js → index.ts} +23 -19
  163. package/src/db/index.ts +10 -0
  164. package/src/environment.ts +9 -7
  165. package/src/index.ts +15 -16
  166. package/src/middleware/{cloudRestricted.js → cloudRestricted.ts} +5 -4
  167. package/src/middleware/tests/tenancy.spec.ts +73 -0
  168. package/src/sdk/users/users.ts +28 -15
  169. package/src/tests/TestConfiguration.ts +99 -50
  170. package/src/tests/api/accounts.ts +5 -8
  171. package/src/tests/api/auth.ts +3 -6
  172. package/src/tests/api/base.ts +16 -0
  173. package/src/tests/api/configs.ts +15 -8
  174. package/src/tests/api/email.ts +3 -6
  175. package/src/tests/api/environment.ts +15 -0
  176. package/src/tests/api/index.ts +15 -0
  177. package/src/tests/api/migrations.ts +22 -0
  178. package/src/tests/api/restore.ts +14 -0
  179. package/src/tests/api/self.ts +11 -6
  180. package/src/tests/api/status.ts +12 -0
  181. package/src/tests/api/tenants.ts +15 -0
  182. package/src/tests/api/users.ts +38 -6
  183. package/src/tests/controllers.ts +5 -0
  184. package/src/tests/index.ts +5 -1
  185. package/{scripts/jestSetup.js → src/tests/jestSetup.ts} +12 -3
  186. package/src/tests/structures/{configs.js → configs.ts} +11 -11
  187. package/src/tests/structures/index.ts +5 -3
  188. package/src/tests/structures/users.ts +1 -0
  189. package/src/utilities/appService.ts +32 -0
  190. package/src/utilities/{email.js → email.ts} +78 -45
  191. package/src/utilities/fileSystem.ts +5 -0
  192. package/src/utilities/{index.js → index.ts} +1 -1
  193. package/src/utilities/{redis.js → redis.ts} +29 -24
  194. package/src/utilities/templates.ts +49 -0
  195. package/src/utilities/users.ts +16 -0
  196. package/tsconfig.build.json +2 -3
  197. package/tsconfig.json +3 -1
  198. package/src/api/controllers/global/roles.js +0 -68
  199. package/src/api/routes/global/roles.js +0 -12
  200. package/src/api/routes/system/environment.js +0 -8
  201. package/src/api/routes/system/status.js +0 -8
  202. package/src/api/routes/system/tenants.js +0 -12
  203. package/src/db/index.js +0 -11
  204. package/src/tests/controllers.js +0 -7
  205. package/src/tests/structures/accounts.ts +0 -24
  206. package/src/utilities/appService.js +0 -33
  207. package/src/utilities/fileSystem.js +0 -5
  208. package/src/utilities/templates.js +0 -49
  209. package/src/utilities/users.js +0 -17
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // need to load environment first
2
- const env = require("./environment")
2
+ import env from "./environment"
3
3
 
4
4
  // enable APM if configured
5
5
  if (process.env.ELASTIC_APM_ENABLED) {
@@ -13,20 +13,18 @@ import { Scope } from "@sentry/node"
13
13
  import { Event } from "@sentry/types/dist/event"
14
14
  import Application from "koa"
15
15
  import { bootstrap } from "global-agent"
16
- import db from "./db"
16
+ import * as db from "./db"
17
+ import { auth, logging, events, pinoSettings } from "@budibase/backend-core"
17
18
  db.init()
18
- const Koa = require("koa")
19
- const destroyable = require("server-destroy")
20
- const koaBody = require("koa-body")
19
+ import Koa from "koa"
20
+ import koaBody from "koa-body"
21
+ import http from "http"
22
+ import api from "./api"
23
+ import * as redis from "./utilities/redis"
24
+ const Sentry = require("@sentry/node")
21
25
  const koaSession = require("koa-session")
22
- const { passport } = require("@budibase/backend-core/auth")
23
- const { logAlert } = require("@budibase/backend-core/logging")
24
26
  const logger = require("koa-pino-logger")
25
- const http = require("http")
26
- const api = require("./api")
27
- const redis = require("./utilities/redis")
28
- const Sentry = require("@sentry/node")
29
- import { events, pinoSettings } from "@budibase/backend-core"
27
+ const destroyable = require("server-destroy")
30
28
 
31
29
  // this will setup http and https proxies form env variables
32
30
  bootstrap()
@@ -41,8 +39,8 @@ app.use(koaSession(app))
41
39
  app.use(logger(pinoSettings()))
42
40
 
43
41
  // authentication
44
- app.use(passport.initialize())
45
- app.use(passport.session())
42
+ app.use(auth.passport.initialize())
43
+ app.use(auth.passport.session())
46
44
 
47
45
  // api routes
48
46
  app.use(api.routes())
@@ -81,17 +79,18 @@ server.on("close", async () => {
81
79
 
82
80
  const shutdown = () => {
83
81
  server.close()
82
+ // @ts-ignore
84
83
  server.destroy()
85
84
  }
86
85
 
87
- export = server.listen(parseInt(env.PORT || 4002), async () => {
86
+ export = server.listen(parseInt(env.PORT || "4002"), async () => {
88
87
  console.log(`Worker running on ${JSON.stringify(server.address())}`)
89
88
  await redis.init()
90
89
  })
91
90
 
92
91
  process.on("uncaughtException", err => {
93
92
  errCode = -1
94
- logAlert("Uncaught exception.", err)
93
+ logging.logAlert("Uncaught exception.", err)
95
94
  shutdown()
96
95
  })
97
96
 
@@ -1,13 +1,14 @@
1
- const env = require("../environment")
2
- const { Headers } = require("@budibase/backend-core/constants")
1
+ import env from "../environment"
2
+ import { constants } from "@budibase/backend-core"
3
+ import { BBContext } from "@budibase/types"
3
4
 
4
5
  /**
5
6
  * This is a restricted endpoint in the cloud.
6
7
  * Ensure that the correct API key has been supplied.
7
8
  */
8
- module.exports = async (ctx, next) => {
9
+ export = async (ctx: BBContext, next: any) => {
9
10
  if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
10
- const apiKey = ctx.request.headers[Headers.API_KEY]
11
+ const apiKey = ctx.request.headers[constants.Header.API_KEY]
11
12
  if (apiKey !== env.INTERNAL_API_KEY) {
12
13
  ctx.throw(403, "Unauthorized")
13
14
  }
@@ -0,0 +1,73 @@
1
+ import { TestConfiguration, structures } from "../../tests"
2
+ import { constants } from "@budibase/backend-core"
3
+
4
+ describe("tenancy middleware", () => {
5
+ const config = new TestConfiguration()
6
+
7
+ beforeAll(async () => {
8
+ await config.beforeAll()
9
+ })
10
+
11
+ afterAll(async () => {
12
+ await config.afterAll()
13
+ })
14
+
15
+ afterEach(() => {
16
+ jest.clearAllMocks()
17
+ })
18
+
19
+ it("should get tenant id from user", async () => {
20
+ const user = await config.createTenant()
21
+ await config.createSession(user)
22
+ const res = await config.api.self.getSelf(user)
23
+ expect(res.headers[constants.Header.TENANT_ID]).toBe(user.tenantId)
24
+ })
25
+
26
+ it("should get tenant id from header", async () => {
27
+ const tenantId = structures.uuid()
28
+ const headers = {
29
+ [constants.Header.TENANT_ID]: tenantId,
30
+ }
31
+ const res = await config.request
32
+ .get(`/api/global/configs/checklist`)
33
+ .set(headers)
34
+ expect(res.headers[constants.Header.TENANT_ID]).toBe(tenantId)
35
+ })
36
+
37
+ it("should get tenant id from query param", async () => {
38
+ const tenantId = structures.uuid()
39
+ const res = await config.request.get(
40
+ `/api/global/configs/checklist?tenantId=${tenantId}`
41
+ )
42
+ expect(res.headers[constants.Header.TENANT_ID]).toBe(tenantId)
43
+ })
44
+
45
+ it("should get tenant id from subdomain", async () => {
46
+ const tenantId = structures.uuid()
47
+ const headers = {
48
+ host: `${tenantId}.localhost:10000`,
49
+ }
50
+ const res = await config.request
51
+ .get(`/api/global/configs/checklist`)
52
+ .set(headers)
53
+ expect(res.headers[constants.Header.TENANT_ID]).toBe(tenantId)
54
+ })
55
+
56
+ it("should get tenant id from path variable", async () => {
57
+ const user = await config.createTenant()
58
+ const res = await config.request
59
+ .post(`/api/global/auth/${user.tenantId}/login`)
60
+ .send({
61
+ username: user.email,
62
+ password: user.password,
63
+ })
64
+ expect(res.headers[constants.Header.TENANT_ID]).toBe(user.tenantId)
65
+ })
66
+
67
+ it("should throw when no tenant id is found", async () => {
68
+ const res = await config.request.get(`/api/global/configs/checklist`)
69
+ expect(res.status).toBe(403)
70
+ expect(res.text).toBe("Tenant id not set")
71
+ expect(res.headers[constants.Header.TENANT_ID]).toBe(undefined)
72
+ })
73
+ })
@@ -29,6 +29,7 @@ import {
29
29
  RowResponse,
30
30
  SearchUsersRequest,
31
31
  User,
32
+ ThirdPartyUser,
32
33
  } from "@budibase/types"
33
34
  import { sendEmail } from "../../utilities/email"
34
35
  import { EmailTemplatePurpose } from "../../constants"
@@ -103,13 +104,14 @@ export const getUser = async (userId: string) => {
103
104
  return user
104
105
  }
105
106
 
106
- interface SaveUserOpts {
107
+ export interface SaveUserOpts {
107
108
  hashPassword?: boolean
108
109
  requirePassword?: boolean
110
+ currentUserId?: string
109
111
  }
110
112
 
111
113
  const buildUser = async (
112
- user: User,
114
+ user: User | ThirdPartyUser,
113
115
  opts: SaveUserOpts = {
114
116
  hashPassword: true,
115
117
  requirePassword: true,
@@ -117,7 +119,8 @@ const buildUser = async (
117
119
  tenantId: string,
118
120
  dbUser?: any
119
121
  ): Promise<User> => {
120
- let { password, _id } = user
122
+ let fullUser = user as User
123
+ let { password, _id } = fullUser
121
124
 
122
125
  let hashedPassword
123
126
  if (password) {
@@ -130,24 +133,24 @@ const buildUser = async (
130
133
 
131
134
  _id = _id || dbUtils.generateGlobalUserID()
132
135
 
133
- user = {
136
+ fullUser = {
134
137
  createdAt: Date.now(),
135
138
  ...dbUser,
136
- ...user,
139
+ ...fullUser,
137
140
  _id,
138
141
  password: hashedPassword,
139
142
  tenantId,
140
143
  }
141
144
  // make sure the roles object is always present
142
- if (!user.roles) {
143
- user.roles = {}
145
+ if (!fullUser.roles) {
146
+ fullUser.roles = {}
144
147
  }
145
148
  // add the active status to a user if its not provided
146
- if (user.status == null) {
147
- user.status = constants.UserStatus.ACTIVE
149
+ if (fullUser.status == null) {
150
+ fullUser.status = constants.UserStatus.ACTIVE
148
151
  }
149
152
 
150
- return user
153
+ return fullUser
151
154
  }
152
155
 
153
156
  const validateUniqueUser = async (email: string, tenantId: string) => {
@@ -169,12 +172,16 @@ const validateUniqueUser = async (email: string, tenantId: string) => {
169
172
  }
170
173
 
171
174
  export const save = async (
172
- user: User,
173
- opts: SaveUserOpts = {
174
- hashPassword: true,
175
- requirePassword: true,
176
- }
175
+ user: User | ThirdPartyUser,
176
+ opts: SaveUserOpts = {}
177
177
  ): Promise<CreateUserResponse> => {
178
+ // default booleans to true
179
+ if (opts.hashPassword == null) {
180
+ opts.hashPassword = true
181
+ }
182
+ if (opts.requirePassword == null) {
183
+ opts.requirePassword = true
184
+ }
178
185
  const tenantId = tenancy.getTenantId()
179
186
  const db = tenancy.getGlobalDB()
180
187
 
@@ -213,6 +220,12 @@ export const save = async (
213
220
  await validateUniqueUser(email, tenantId)
214
221
 
215
222
  let builtUser = await buildUser(user, opts, tenantId, dbUser)
223
+ // don't allow a user to update its own roles/perms
224
+ if (opts.currentUserId && opts.currentUserId === dbUser?._id) {
225
+ builtUser.builder = dbUser.builder
226
+ builtUser.admin = dbUser.admin
227
+ builtUser.roles = dbUser.roles
228
+ }
216
229
 
217
230
  // make sure we set the _id field for a new user
218
231
  // Also if this is a new user, associate groups with them
@@ -1,41 +1,42 @@
1
1
  import "./mocks"
2
- import dbConfig from "../db"
2
+ import * as dbConfig from "../db"
3
3
  dbConfig.init()
4
4
  import env from "../environment"
5
- import controllers from "./controllers"
5
+ import * as controllers from "./controllers"
6
6
  const supertest = require("supertest")
7
- import { Configs } from "../constants"
7
+ import { Config } from "../constants"
8
8
  import {
9
9
  users,
10
10
  tenancy,
11
- Cookies,
12
- Headers,
13
11
  sessions,
14
12
  auth,
13
+ constants,
14
+ env as coreEnv,
15
15
  } from "@budibase/backend-core"
16
- import { TENANT_ID, TENANT_1, CSRF_TOKEN } from "./structures"
17
- import structures from "./structures"
16
+ import structures, { TENANT_ID, TENANT_1, CSRF_TOKEN } from "./structures"
18
17
  import { CreateUserResponse, User, AuthToken } from "@budibase/types"
18
+ import API from "./api"
19
19
 
20
20
  enum Mode {
21
- ACCOUNT = "account",
21
+ CLOUD = "cloud",
22
22
  SELF = "self",
23
23
  }
24
24
 
25
25
  class TestConfiguration {
26
26
  server: any
27
27
  request: any
28
+ api: API
28
29
  defaultUser?: User
29
30
  tenant1User?: User
30
31
 
31
32
  constructor(
32
33
  opts: { openServer: boolean; mode: Mode } = {
33
34
  openServer: true,
34
- mode: Mode.ACCOUNT,
35
+ mode: Mode.CLOUD,
35
36
  }
36
37
  ) {
37
- if (opts.mode === Mode.ACCOUNT) {
38
- this.modeAccount()
38
+ if (opts.mode === Mode.CLOUD) {
39
+ this.modeCloud()
39
40
  } else if (opts.mode === Mode.SELF) {
40
41
  this.modeSelf()
41
42
  }
@@ -46,6 +47,8 @@ class TestConfiguration {
46
47
  // we need the request for logging in, involves cookies, hard to fake
47
48
  this.request = supertest(this.server)
48
49
  }
50
+
51
+ this.api = new API(this)
49
52
  }
50
53
 
51
54
  getRequest() {
@@ -54,20 +57,24 @@ class TestConfiguration {
54
57
 
55
58
  // MODES
56
59
 
57
- modeAccount = () => {
58
- env.SELF_HOSTED = false
59
- // @ts-ignore
60
- env.MULTI_TENANCY = true
61
- // @ts-ignore
62
- env.DISABLE_ACCOUNT_PORTAL = false
60
+ setMultiTenancy = (value: boolean) => {
61
+ env._set("MULTI_TENANCY", value)
62
+ coreEnv._set("MULTI_TENANCY", value)
63
+ }
64
+
65
+ setSelfHosted = (value: boolean) => {
66
+ env._set("SELF_HOSTED", value)
67
+ coreEnv._set("SELF_HOSTED", value)
68
+ }
69
+
70
+ modeCloud = () => {
71
+ this.setSelfHosted(false)
72
+ this.setMultiTenancy(true)
63
73
  }
64
74
 
65
75
  modeSelf = () => {
66
- env.SELF_HOSTED = true
67
- // @ts-ignore
68
- env.MULTI_TENANCY = false
69
- // @ts-ignore
70
- env.DISABLE_ACCOUNT_PORTAL = true
76
+ this.setSelfHosted(true)
77
+ this.setMultiTenancy(false)
71
78
  }
72
79
 
73
80
  // UTILS
@@ -114,6 +121,25 @@ class TestConfiguration {
114
121
 
115
122
  // TENANCY
116
123
 
124
+ createTenant = async (): Promise<User> => {
125
+ // create user / new tenant
126
+ const res = await this.api.users.createAdminUser()
127
+
128
+ // return the created user
129
+ const userRes = await this.api.users.getUser(res.userId, {
130
+ headers: {
131
+ ...this.internalAPIHeaders(),
132
+ [constants.Header.TENANT_ID]: res.tenantId,
133
+ },
134
+ })
135
+
136
+ // create a session for the new user
137
+ const user = userRes.body
138
+ await this.createSession(user)
139
+
140
+ return user
141
+ }
142
+
117
143
  getTenantId() {
118
144
  try {
119
145
  return tenancy.getTenantId()
@@ -122,35 +148,32 @@ class TestConfiguration {
122
148
  }
123
149
  }
124
150
 
125
- // USER / AUTH
126
-
127
- async createDefaultUser() {
128
- const user = structures.users.adminUser({
129
- email: "test@test.com",
130
- password: "test",
131
- })
132
- this.defaultUser = await this.createUser(user)
133
- }
151
+ // AUTH
134
152
 
135
- async createTenant1User() {
136
- const user = structures.users.adminUser({
137
- email: "tenant1@test.com",
138
- password: "test",
153
+ async _createSession({
154
+ userId,
155
+ tenantId,
156
+ }: {
157
+ userId: string
158
+ tenantId: string
159
+ }) {
160
+ await sessions.createASession(userId!, {
161
+ sessionId: "sessionid",
162
+ tenantId: tenantId,
163
+ csrfToken: CSRF_TOKEN,
139
164
  })
140
- this.tenant1User = await this.createUser(user)
141
165
  }
142
166
 
143
167
  async createSession(user: User) {
144
- await sessions.createASession(user._id!, {
145
- sessionId: "sessionid",
146
- tenantId: user.tenantId,
147
- csrfToken: CSRF_TOKEN,
148
- })
168
+ return this._createSession({ userId: user._id!, tenantId: user.tenantId })
149
169
  }
150
170
 
151
171
  cookieHeader(cookies: any) {
172
+ if (!Array.isArray(cookies)) {
173
+ cookies = [cookies]
174
+ }
152
175
  return {
153
- Cookie: [cookies],
176
+ Cookie: cookies,
154
177
  }
155
178
  }
156
179
 
@@ -163,8 +186,8 @@ class TestConfiguration {
163
186
  const authCookie = auth.jwt.sign(authToken, env.JWT_SECRET)
164
187
  return {
165
188
  Accept: "application/json",
166
- ...this.cookieHeader([`${Cookies.Auth}=${authCookie}`]),
167
- [Headers.CSRF_TOKEN]: CSRF_TOKEN,
189
+ ...this.cookieHeader([`${constants.Cookie.Auth}=${authCookie}`]),
190
+ [constants.Header.CSRF_TOKEN]: CSRF_TOKEN,
168
191
  }
169
192
  }
170
193
 
@@ -179,6 +202,32 @@ class TestConfiguration {
179
202
  }
180
203
  }
181
204
 
205
+ internalAPIHeaders() {
206
+ return { [constants.Header.API_KEY]: env.INTERNAL_API_KEY }
207
+ }
208
+
209
+ adminOnlyResponse = () => {
210
+ return { message: "Admin user only endpoint.", status: 403 }
211
+ }
212
+
213
+ // USERS
214
+
215
+ async createDefaultUser() {
216
+ const user = structures.users.adminUser({
217
+ email: "test@test.com",
218
+ password: "test",
219
+ })
220
+ this.defaultUser = await this.createUser(user)
221
+ }
222
+
223
+ async createTenant1User() {
224
+ const user = structures.users.adminUser({
225
+ email: "tenant1@test.com",
226
+ password: "test",
227
+ })
228
+ this.tenant1User = await this.createUser(user)
229
+ }
230
+
182
231
  async getUser(email: string): Promise<User> {
183
232
  return tenancy.doInTenant(this.getTenantId(), () => {
184
233
  return users.getGlobalUserByEmail(email)
@@ -223,7 +272,7 @@ class TestConfiguration {
223
272
  // CONFIGS - SETTINGS
224
273
 
225
274
  async saveSettingsConfig() {
226
- await this.deleteConfig(Configs.SETTINGS)
275
+ await this.deleteConfig(Config.SETTINGS)
227
276
  await this._req(
228
277
  structures.configs.settings(),
229
278
  null,
@@ -234,7 +283,7 @@ class TestConfiguration {
234
283
  // CONFIGS - GOOGLE
235
284
 
236
285
  async saveGoogleConfig() {
237
- await this.deleteConfig(Configs.GOOGLE)
286
+ await this.deleteConfig(Config.GOOGLE)
238
287
  await this._req(structures.configs.google(), null, controllers.config.save)
239
288
  }
240
289
 
@@ -242,11 +291,11 @@ class TestConfiguration {
242
291
 
243
292
  getOIDConfigCookie(configId: string) {
244
293
  const token = auth.jwt.sign(configId, env.JWT_SECRET)
245
- return this.cookieHeader([[`${Cookies.OIDC_CONFIG}=${token}`]])
294
+ return this.cookieHeader([[`${constants.Cookie.OIDC_CONFIG}=${token}`]])
246
295
  }
247
296
 
248
297
  async saveOIDCConfig() {
249
- await this.deleteConfig(Configs.OIDC)
298
+ await this.deleteConfig(Config.OIDC)
250
299
  const config = structures.configs.oidc()
251
300
 
252
301
  await this._req(config, null, controllers.config.save)
@@ -256,12 +305,12 @@ class TestConfiguration {
256
305
  // CONFIGS - SMTP
257
306
 
258
307
  async saveSmtpConfig() {
259
- await this.deleteConfig(Configs.SMTP)
308
+ await this.deleteConfig(Config.SMTP)
260
309
  await this._req(structures.configs.smtp(), null, controllers.config.save)
261
310
  }
262
311
 
263
312
  async saveEtherealSmtpConfig() {
264
- await this.deleteConfig(Configs.SMTP)
313
+ await this.deleteConfig(Config.SMTP)
265
314
  await this._req(
266
315
  structures.configs.smtpEthereal(),
267
316
  null,
@@ -1,20 +1,17 @@
1
1
  import { Account, AccountMetadata } from "@budibase/types"
2
2
  import TestConfiguration from "../TestConfiguration"
3
+ import { TestAPI } from "./base"
3
4
 
4
- export class AccountAPI {
5
- config: TestConfiguration
6
- request: any
7
-
5
+ export class AccountAPI extends TestAPI {
8
6
  constructor(config: TestConfiguration) {
9
- this.config = config
10
- this.request = config.request
7
+ super(config)
11
8
  }
12
9
 
13
10
  saveMetadata = async (account: Account) => {
14
11
  const res = await this.request
15
12
  .put(`/api/system/accounts/${account.accountId}/metadata`)
16
13
  .send(account)
17
- .set(this.config.defaultHeaders())
14
+ .set(this.config.internalAPIHeaders())
18
15
  .expect("Content-Type", /json/)
19
16
  .expect(200)
20
17
  return res.body as AccountMetadata
@@ -23,6 +20,6 @@ export class AccountAPI {
23
20
  destroyMetadata = (accountId: string) => {
24
21
  return this.request
25
22
  .del(`/api/system/accounts/${accountId}/metadata`)
26
- .set(this.config.defaultHeaders())
23
+ .set(this.config.internalAPIHeaders())
27
24
  }
28
25
  }
@@ -1,12 +1,9 @@
1
1
  import TestConfiguration from "../TestConfiguration"
2
+ import { TestAPI } from "./base"
2
3
 
3
- export class AuthAPI {
4
- config: TestConfiguration
5
- request: any
6
-
4
+ export class AuthAPI extends TestAPI {
7
5
  constructor(config: TestConfiguration) {
8
- this.config = config
9
- this.request = config.request
6
+ super(config)
10
7
  }
11
8
 
12
9
  updatePassword = (code: string) => {
@@ -0,0 +1,16 @@
1
+ import TestConfiguration from "../TestConfiguration"
2
+
3
+ export interface TestAPIOpts {
4
+ headers?: any
5
+ status?: number
6
+ }
7
+
8
+ export abstract class TestAPI {
9
+ config: TestConfiguration
10
+ request: any
11
+
12
+ protected constructor(config: TestConfiguration) {
13
+ this.config = config
14
+ this.request = config.request
15
+ }
16
+ }
@@ -1,12 +1,9 @@
1
1
  import TestConfiguration from "../TestConfiguration"
2
+ import { TestAPI } from "./base"
2
3
 
3
- export class ConfigAPI {
4
- config: TestConfiguration
5
- request: any
6
-
4
+ export class ConfigAPI extends TestAPI {
7
5
  constructor(config: TestConfiguration) {
8
- this.config = config
9
- this.request = config.request
6
+ super(config)
10
7
  }
11
8
 
12
9
  getConfigChecklist = () => {
@@ -26,10 +23,20 @@ export class ConfigAPI {
26
23
  .expect(200)
27
24
  }
28
25
 
29
- OIDCCallback = (configId: string) => {
26
+ OIDCCallback = (configId: string, preAuthRes: any) => {
27
+ const cookie = this.config.cookieHeader(preAuthRes.get("set-cookie"))
28
+ const setKoaSession = cookie.Cookie.find((c: string) =>
29
+ c.includes("koa:sess")
30
+ )
31
+ const koaSession = setKoaSession.split("=")[1] + "=="
32
+ const sessionContent = JSON.parse(
33
+ Buffer.from(koaSession, "base64").toString("utf-8")
34
+ )
35
+ const handle = sessionContent["openidconnect:localhost"].state.handle
30
36
  return this.request
31
37
  .get(`/api/global/auth/${this.config.getTenantId()}/oidc/callback`)
32
- .set(this.config.getOIDConfigCookie(configId))
38
+ .query({ code: "test", state: handle })
39
+ .set(cookie)
33
40
  }
34
41
 
35
42
  getOIDCConfig = (configId: string) => {
@@ -1,12 +1,9 @@
1
1
  import TestConfiguration from "../TestConfiguration"
2
+ import { TestAPI } from "./base"
2
3
 
3
- export class EmailAPI {
4
- config: TestConfiguration
5
- request: any
6
-
4
+ export class EmailAPI extends TestAPI {
7
5
  constructor(config: TestConfiguration) {
8
- this.config = config
9
- this.request = config.request
6
+ super(config)
10
7
  }
11
8
 
12
9
  sendEmail = (purpose: string) => {
@@ -0,0 +1,15 @@
1
+ import TestConfiguration from "../TestConfiguration"
2
+ import { TestAPI } from "./base"
3
+
4
+ export class EnvironmentAPI extends TestAPI {
5
+ constructor(config: TestConfiguration) {
6
+ super(config)
7
+ }
8
+
9
+ getEnvironment = () => {
10
+ return this.request
11
+ .get(`/api/system/environment`)
12
+ .expect("Content-Type", /json/)
13
+ .expect(200)
14
+ }
15
+ }