@budibase/worker 2.3.17 → 2.3.18-alpha.1

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 (167) hide show
  1. package/__mocks__/node-fetch.ts +23 -0
  2. package/jest-testcontainers-config.js +8 -0
  3. package/jest.config.ts +13 -17
  4. package/package.json +11 -8
  5. package/scripts/dev/manage.js +1 -0
  6. package/src/api/controllers/global/auth.ts +77 -70
  7. package/src/api/controllers/global/self.ts +28 -44
  8. package/src/api/controllers/global/users.ts +65 -25
  9. package/src/api/controllers/system/accounts.ts +7 -5
  10. package/src/api/controllers/system/tenants.ts +4 -8
  11. package/src/api/index.ts +4 -20
  12. package/src/api/routes/global/auth.ts +10 -7
  13. package/src/api/routes/global/tests/auth.spec.ts +226 -17
  14. package/src/api/routes/global/tests/configs.spec.ts +5 -5
  15. package/src/api/routes/global/tests/roles.spec.ts +20 -14
  16. package/src/api/routes/global/tests/self.spec.ts +3 -4
  17. package/src/api/routes/global/tests/users.spec.ts +24 -27
  18. package/src/api/routes/system/tenants.ts +1 -1
  19. package/src/api/routes/system/tests/accounts.spec.ts +4 -4
  20. package/src/api/routes/system/tests/migrations.spec.ts +2 -2
  21. package/src/api/routes/system/tests/restore.spec.ts +2 -2
  22. package/src/api/routes/system/tests/status.spec.ts +5 -5
  23. package/src/ddApm.ts +7 -0
  24. package/src/elasticApm.ts +10 -0
  25. package/src/environment.ts +15 -1
  26. package/src/index.ts +12 -7
  27. package/src/middleware/tests/tenancy.spec.ts +4 -4
  28. package/src/migrations/functions/globalInfoSyncUsers.ts +4 -3
  29. package/src/sdk/accounts/index.ts +2 -1
  30. package/src/sdk/accounts/{accounts.ts → metadata.ts} +0 -1
  31. package/src/sdk/auth/auth.ts +86 -0
  32. package/src/sdk/auth/index.ts +1 -0
  33. package/src/sdk/tenants/index.ts +1 -0
  34. package/src/sdk/tenants/tenants.ts +76 -0
  35. package/src/sdk/users/events.ts +4 -0
  36. package/src/sdk/users/index.ts +1 -0
  37. package/src/sdk/users/tests/users.spec.ts +52 -0
  38. package/src/sdk/users/users.ts +53 -46
  39. package/src/tests/TestConfiguration.ts +41 -62
  40. package/src/tests/api/auth.ts +42 -14
  41. package/src/tests/api/base.ts +2 -1
  42. package/src/tests/api/configs.ts +2 -2
  43. package/src/tests/api/restore.ts +1 -0
  44. package/src/tests/api/users.ts +2 -2
  45. package/src/tests/jestEnv.ts +2 -1
  46. package/src/tests/jestSetup.ts +10 -6
  47. package/src/tests/logging.ts +34 -0
  48. package/src/tests/structures/index.ts +0 -4
  49. package/src/utilities/email.ts +3 -3
  50. package/src/utilities/redis.ts +2 -0
  51. package/coverage/clover.xml +0 -2199
  52. package/coverage/coverage-final.json +0 -84
  53. package/coverage/lcov-report/base.css +0 -224
  54. package/coverage/lcov-report/block-navigation.js +0 -87
  55. package/coverage/lcov-report/favicon.png +0 -0
  56. package/coverage/lcov-report/index.html +0 -431
  57. package/coverage/lcov-report/prettify.css +0 -1
  58. package/coverage/lcov-report/prettify.js +0 -2
  59. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  60. package/coverage/lcov-report/sorter.js +0 -196
  61. package/coverage/lcov-report/src/api/controllers/global/auth.ts.html +0 -934
  62. package/coverage/lcov-report/src/api/controllers/global/configs.ts.html +0 -1348
  63. package/coverage/lcov-report/src/api/controllers/global/email.ts.html +0 -196
  64. package/coverage/lcov-report/src/api/controllers/global/events.ts.html +0 -136
  65. package/coverage/lcov-report/src/api/controllers/global/index.html +0 -251
  66. package/coverage/lcov-report/src/api/controllers/global/license.ts.html +0 -187
  67. package/coverage/lcov-report/src/api/controllers/global/roles.ts.html +0 -283
  68. package/coverage/lcov-report/src/api/controllers/global/self.ts.html +0 -577
  69. package/coverage/lcov-report/src/api/controllers/global/templates.ts.html +0 -316
  70. package/coverage/lcov-report/src/api/controllers/global/users.ts.html +0 -838
  71. package/coverage/lcov-report/src/api/controllers/global/workspaces.ts.html +0 -244
  72. package/coverage/lcov-report/src/api/controllers/system/accounts.ts.html +0 -148
  73. package/coverage/lcov-report/src/api/controllers/system/environment.ts.html +0 -124
  74. package/coverage/lcov-report/src/api/controllers/system/index.html +0 -191
  75. package/coverage/lcov-report/src/api/controllers/system/migrations.ts.html +0 -124
  76. package/coverage/lcov-report/src/api/controllers/system/restore.ts.html +0 -124
  77. package/coverage/lcov-report/src/api/controllers/system/status.ts.html +0 -133
  78. package/coverage/lcov-report/src/api/controllers/system/tenants.ts.html +0 -154
  79. package/coverage/lcov-report/src/api/index.html +0 -116
  80. package/coverage/lcov-report/src/api/index.ts.html +0 -595
  81. package/coverage/lcov-report/src/api/routes/global/auth.ts.html +0 -349
  82. package/coverage/lcov-report/src/api/routes/global/configs.ts.html +0 -457
  83. package/coverage/lcov-report/src/api/routes/global/email.ts.html +0 -193
  84. package/coverage/lcov-report/src/api/routes/global/events.ts.html +0 -109
  85. package/coverage/lcov-report/src/api/routes/global/index.html +0 -251
  86. package/coverage/lcov-report/src/api/routes/global/license.ts.html +0 -124
  87. package/coverage/lcov-report/src/api/routes/global/roles.ts.html +0 -133
  88. package/coverage/lcov-report/src/api/routes/global/self.ts.html +0 -139
  89. package/coverage/lcov-report/src/api/routes/global/templates.ts.html +0 -196
  90. package/coverage/lcov-report/src/api/routes/global/users.ts.html +0 -475
  91. package/coverage/lcov-report/src/api/routes/global/workspaces.ts.html +0 -196
  92. package/coverage/lcov-report/src/api/routes/index.html +0 -116
  93. package/coverage/lcov-report/src/api/routes/index.ts.html +0 -202
  94. package/coverage/lcov-report/src/api/routes/system/accounts.ts.html +0 -142
  95. package/coverage/lcov-report/src/api/routes/system/environment.ts.html +0 -109
  96. package/coverage/lcov-report/src/api/routes/system/index.html +0 -191
  97. package/coverage/lcov-report/src/api/routes/system/migrations.ts.html +0 -142
  98. package/coverage/lcov-report/src/api/routes/system/restore.ts.html +0 -109
  99. package/coverage/lcov-report/src/api/routes/system/status.ts.html +0 -109
  100. package/coverage/lcov-report/src/api/routes/system/tenants.ts.html +0 -124
  101. package/coverage/lcov-report/src/api/routes/validation/index.html +0 -131
  102. package/coverage/lcov-report/src/api/routes/validation/index.ts.html +0 -88
  103. package/coverage/lcov-report/src/api/routes/validation/users.ts.html +0 -235
  104. package/coverage/lcov-report/src/constants/index.html +0 -116
  105. package/coverage/lcov-report/src/constants/index.ts.html +0 -637
  106. package/coverage/lcov-report/src/constants/templates/index.html +0 -116
  107. package/coverage/lcov-report/src/constants/templates/index.ts.html +0 -316
  108. package/coverage/lcov-report/src/db/index.html +0 -116
  109. package/coverage/lcov-report/src/db/index.ts.html +0 -115
  110. package/coverage/lcov-report/src/environment.ts.html +0 -388
  111. package/coverage/lcov-report/src/index.html +0 -131
  112. package/coverage/lcov-report/src/index.ts.html +0 -394
  113. package/coverage/lcov-report/src/middleware/cloudRestricted.ts.html +0 -139
  114. package/coverage/lcov-report/src/middleware/index.html +0 -116
  115. package/coverage/lcov-report/src/migrations/functions/globalInfoSyncUsers.ts.html +0 -145
  116. package/coverage/lcov-report/src/migrations/functions/index.html +0 -116
  117. package/coverage/lcov-report/src/migrations/index.html +0 -116
  118. package/coverage/lcov-report/src/migrations/index.ts.html +0 -271
  119. package/coverage/lcov-report/src/sdk/accounts/accounts.ts.html +0 -262
  120. package/coverage/lcov-report/src/sdk/accounts/index.html +0 -131
  121. package/coverage/lcov-report/src/sdk/accounts/index.ts.html +0 -88
  122. package/coverage/lcov-report/src/sdk/index.html +0 -116
  123. package/coverage/lcov-report/src/sdk/index.ts.html +0 -106
  124. package/coverage/lcov-report/src/sdk/users/events.ts.html +0 -601
  125. package/coverage/lcov-report/src/sdk/users/index.html +0 -146
  126. package/coverage/lcov-report/src/sdk/users/index.ts.html +0 -88
  127. package/coverage/lcov-report/src/sdk/users/users.ts.html +0 -1999
  128. package/coverage/lcov-report/src/tests/TestConfiguration.ts.html +0 -1075
  129. package/coverage/lcov-report/src/tests/api/accounts.ts.html +0 -160
  130. package/coverage/lcov-report/src/tests/api/auth.ts.html +0 -220
  131. package/coverage/lcov-report/src/tests/api/base.ts.html +0 -133
  132. package/coverage/lcov-report/src/tests/api/configs.ts.html +0 -226
  133. package/coverage/lcov-report/src/tests/api/email.ts.html +0 -148
  134. package/coverage/lcov-report/src/tests/api/environment.ts.html +0 -130
  135. package/coverage/lcov-report/src/tests/api/groups.ts.html +0 -163
  136. package/coverage/lcov-report/src/tests/api/index.html +0 -356
  137. package/coverage/lcov-report/src/tests/api/index.ts.html +0 -238
  138. package/coverage/lcov-report/src/tests/api/license.ts.html +0 -136
  139. package/coverage/lcov-report/src/tests/api/migrations.ts.html +0 -151
  140. package/coverage/lcov-report/src/tests/api/restore.ts.html +0 -127
  141. package/coverage/lcov-report/src/tests/api/roles.ts.html +0 -181
  142. package/coverage/lcov-report/src/tests/api/self.ts.html +0 -163
  143. package/coverage/lcov-report/src/tests/api/status.ts.html +0 -121
  144. package/coverage/lcov-report/src/tests/api/templates.ts.html +0 -175
  145. package/coverage/lcov-report/src/tests/api/tenants.ts.html +0 -130
  146. package/coverage/lcov-report/src/tests/api/users.ts.html +0 -514
  147. package/coverage/lcov-report/src/tests/controllers.ts.html +0 -100
  148. package/coverage/lcov-report/src/tests/index.html +0 -146
  149. package/coverage/lcov-report/src/tests/index.ts.html +0 -103
  150. package/coverage/lcov-report/src/tests/mocks/email.ts.html +0 -115
  151. package/coverage/lcov-report/src/tests/mocks/index.html +0 -131
  152. package/coverage/lcov-report/src/tests/mocks/index.ts.html +0 -106
  153. package/coverage/lcov-report/src/tests/structures/configs.ts.html +0 -313
  154. package/coverage/lcov-report/src/tests/structures/groups.ts.html +0 -118
  155. package/coverage/lcov-report/src/tests/structures/index.html +0 -161
  156. package/coverage/lcov-report/src/tests/structures/index.ts.html +0 -151
  157. package/coverage/lcov-report/src/tests/structures/users.ts.html +0 -196
  158. package/coverage/lcov-report/src/utilities/appService.ts.html +0 -208
  159. package/coverage/lcov-report/src/utilities/email.ts.html +0 -850
  160. package/coverage/lcov-report/src/utilities/fileSystem.ts.html +0 -100
  161. package/coverage/lcov-report/src/utilities/index.html +0 -206
  162. package/coverage/lcov-report/src/utilities/index.ts.html +0 -112
  163. package/coverage/lcov-report/src/utilities/redis.ts.html +0 -424
  164. package/coverage/lcov-report/src/utilities/templates.ts.html +0 -232
  165. package/coverage/lcov-report/src/utilities/users.ts.html +0 -133
  166. package/coverage/lcov.info +0 -4187
  167. package/src/tests/structures/users.ts +0 -37
@@ -0,0 +1,23 @@
1
+ import fs from "fs"
2
+ module FetchMock {
3
+ const fetch = jest.requireActual("node-fetch")
4
+
5
+ const func = async (url: any, opts: any) => {
6
+ if (url.includes("http://someconfigurl")) {
7
+ return {
8
+ ok: true,
9
+ json: () => ({
10
+ issuer: "test",
11
+ authorization_endpoint: "http://localhost/auth",
12
+ token_endpoint: "http://localhost/token",
13
+ userinfo_endpoint: "http://localhost/userinfo",
14
+ }),
15
+ }
16
+ }
17
+ return fetch(url, opts)
18
+ }
19
+
20
+ func.Headers = fetch.Headers
21
+
22
+ module.exports = func
23
+ }
@@ -0,0 +1,8 @@
1
+ const { join } = require("path")
2
+ require("dotenv").config({
3
+ path: join(__dirname, "..", "..", "hosting", ".env"),
4
+ })
5
+
6
+ const jestTestcontainersConfigGenerator = require("../../jestTestcontainersConfigGenerator")
7
+
8
+ module.exports = jestTestcontainersConfigGenerator()
package/jest.config.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { Config } from "@jest/types"
2
2
  import * as fs from "fs"
3
+ const preset = require("ts-jest/jest-preset")
3
4
 
4
5
  const config: Config.InitialOptions = {
5
- testEnvironment: "node",
6
+ ...preset,
7
+ preset: "@trendyol/jest-testcontainers",
6
8
  setupFiles: ["./src/tests/jestEnv.ts"],
7
9
  setupFilesAfterEnv: ["./src/tests/jestSetup.ts"],
8
10
  collectCoverageFrom: ["src/**/*.{js,ts}"],
@@ -10,25 +12,19 @@ const config: Config.InitialOptions = {
10
12
  transform: {
11
13
  "^.+\\.ts?$": "@swc/jest",
12
14
  },
13
- }
14
-
15
- if (!process.env.CI) {
16
- // use sources when not in CI
17
- config.moduleNameMapper = {
15
+ moduleNameMapper: {
18
16
  "@budibase/backend-core/(.*)": "<rootDir>/../backend-core/$1",
19
17
  "@budibase/backend-core": "<rootDir>/../backend-core/src",
20
18
  "@budibase/types": "<rootDir>/../types/src",
21
- "^axios.*$": "<rootDir>/node_modules/axios/lib/axios.js",
22
- }
23
- // add pro sources if they exist
24
- if (fs.existsSync("../../../budibase-pro")) {
25
- config.moduleNameMapper["@budibase/pro/(.*)"] =
26
- "<rootDir>/../../../budibase-pro/packages/pro/$1"
27
- config.moduleNameMapper["@budibase/pro"] =
28
- "<rootDir>/../../../budibase-pro/packages/pro/src"
29
- }
30
- } else {
31
- console.log("Running tests with compiled dependency sources")
19
+ },
20
+ }
21
+
22
+ // add pro sources if they exist
23
+ if (fs.existsSync("../../../budibase-pro")) {
24
+ config.moduleNameMapper["@budibase/pro/(.*)"] =
25
+ "<rootDir>/../../../budibase-pro/packages/pro/$1"
26
+ config.moduleNameMapper["@budibase/pro"] =
27
+ "<rootDir>/../../../budibase-pro/packages/pro/src"
32
28
  }
33
29
 
34
30
  export default config
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/worker",
3
3
  "email": "hi@budibase.com",
4
- "version": "2.3.17",
4
+ "version": "2.3.18-alpha.1",
5
5
  "description": "Budibase background service",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -22,7 +22,7 @@
22
22
  "build:docker": "docker build . -t worker-service --label version=$BUDIBASE_RELEASE_VERSION",
23
23
  "dev:stack:init": "node ./scripts/dev/manage.js init",
24
24
  "dev:builder": "npm run dev:stack:init && nodemon",
25
- "test": "jest --coverage --maxWorkers=2",
25
+ "test": "jest --coverage --runInBand",
26
26
  "test:watch": "jest --watch",
27
27
  "env:multi:enable": "node scripts/multiTenancy.js enable",
28
28
  "env:multi:disable": "node scripts/multiTenancy.js disable",
@@ -36,16 +36,17 @@
36
36
  "author": "Budibase",
37
37
  "license": "GPL-3.0",
38
38
  "dependencies": {
39
- "@budibase/backend-core": "^2.3.17",
40
- "@budibase/pro": "2.3.16",
41
- "@budibase/string-templates": "^2.3.17",
42
- "@budibase/types": "^2.3.17",
39
+ "@budibase/backend-core": "2.3.18-alpha.1",
40
+ "@budibase/pro": "2.3.18-alpha.0",
41
+ "@budibase/string-templates": "2.3.18-alpha.1",
42
+ "@budibase/types": "2.3.18-alpha.1",
43
43
  "@koa/router": "8.0.8",
44
44
  "@sentry/node": "6.17.7",
45
45
  "@techpass/passport-openidconnect": "0.3.2",
46
46
  "@types/global-agent": "2.1.1",
47
47
  "aws-sdk": "2.1030.0",
48
48
  "bcryptjs": "2.4.3",
49
+ "dd-trace": "3.13.2",
49
50
  "dotenv": "8.6.0",
50
51
  "elastic-apm-node": "3.38.0",
51
52
  "global-agent": "3.0.0",
@@ -72,7 +73,8 @@
72
73
  "devDependencies": {
73
74
  "@swc/core": "^1.3.25",
74
75
  "@swc/jest": "^0.2.24",
75
- "@types/jest": "26.0.23",
76
+ "@trendyol/jest-testcontainers": "^2.1.1",
77
+ "@types/jest": "28.1.1",
76
78
  "@types/jsonwebtoken": "8.5.1",
77
79
  "@types/koa": "2.13.4",
78
80
  "@types/koa__router": "8.0.8",
@@ -80,6 +82,7 @@
80
82
  "@types/node-fetch": "2.6.1",
81
83
  "@types/pouchdb": "6.4.0",
82
84
  "@types/server-destroy": "1.0.1",
85
+ "@types/supertest": "2.0.12",
83
86
  "@types/uuid": "8.3.4",
84
87
  "@typescript-eslint/parser": "5.45.0",
85
88
  "copyfiles": "2.4.1",
@@ -97,5 +100,5 @@
97
100
  "typescript": "4.7.3",
98
101
  "update-dotenv": "1.1.1"
99
102
  },
100
- "gitHead": "a57c922b91c1df8dc276588a5ad583a0c1aea52c"
103
+ "gitHead": "865cab09b28f2abcdc0b485437465b167adebdf4"
101
104
  }
@@ -29,6 +29,7 @@ async function init() {
29
29
  SERVICE: "worker-service",
30
30
  DEPLOYMENT_ENVIRONMENT: "development",
31
31
  TENANT_FEATURE_FLAGS: "*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR",
32
+ ENABLE_EMAIL_TEST_MODE: 1,
32
33
  }
33
34
  let envFile = ""
34
35
  Object.keys(envFileJson).forEach(key => {
@@ -1,49 +1,55 @@
1
1
  import {
2
- auth,
2
+ auth as authCore,
3
3
  constants,
4
4
  context,
5
5
  db as dbCore,
6
6
  events,
7
7
  tenancy,
8
- users as usersCore,
9
- utils,
8
+ utils as utilsCore,
10
9
  } from "@budibase/backend-core"
11
- import { EmailTemplatePurpose } from "../../../constants"
12
- import { isEmailConfigured, sendEmail } from "../../../utilities/email"
13
- import { checkResetPasswordCode } from "../../../utilities/redis"
10
+ import {
11
+ ConfigType,
12
+ User,
13
+ Ctx,
14
+ LoginRequest,
15
+ SSOUser,
16
+ PasswordResetRequest,
17
+ PasswordResetUpdateRequest,
18
+ } from "@budibase/types"
14
19
  import env from "../../../environment"
15
- import sdk from "../../../sdk"
16
- import { ConfigType, User } from "@budibase/types"
17
20
 
18
- const { setCookie, getCookie, clearCookie, hash, platformLogout } = utils
19
- const { Cookie, Header } = constants
20
- const { passport, ssoCallbackUrl, google, oidc } = auth
21
+ import * as authSdk from "../../../sdk/auth"
22
+ import * as userSdk from "../../../sdk/users"
21
23
 
22
- export async function googleCallbackUrl(config?: { callbackURL?: string }) {
23
- return ssoCallbackUrl(tenancy.getGlobalDB(), config, ConfigType.GOOGLE)
24
- }
24
+ const { Cookie, Header } = constants
25
+ const { passport, ssoCallbackUrl, google, oidc } = authCore
26
+ const { setCookie, getCookie, clearCookie } = utilsCore
25
27
 
26
- export async function oidcCallbackUrl(config?: { callbackURL?: string }) {
27
- return ssoCallbackUrl(tenancy.getGlobalDB(), config, ConfigType.OIDC)
28
- }
28
+ // LOGIN / LOGOUT
29
29
 
30
- async function authInternal(ctx: any, user: any, err: any = null, info = null) {
30
+ async function passportCallback(
31
+ ctx: Ctx,
32
+ user: User,
33
+ err: any = null,
34
+ info: { message: string } | null = null
35
+ ) {
31
36
  if (err) {
32
37
  console.error("Authentication error")
33
38
  console.error(err)
34
39
  console.trace(err)
35
40
  return ctx.throw(403, info ? info : "Unauthorized")
36
41
  }
37
-
38
42
  if (!user) {
39
43
  console.error("Authentication error - no user provided")
40
44
  return ctx.throw(403, info ? info : "Unauthorized")
41
45
  }
42
46
 
47
+ const token = await authSdk.loginUser(user)
48
+
43
49
  // set a cookie for browser access
44
- setCookie(ctx, user.token, Cookie.Auth, { sign: false })
50
+ setCookie(ctx, token, Cookie.Auth, { sign: false })
45
51
  // set the token in a header as well for APIs
46
- ctx.set(Header.TOKEN, user.token)
52
+ ctx.set(Header.TOKEN, token)
47
53
  // get rid of any app cookies on login
48
54
  // have to check test because this breaks cypress
49
55
  if (!env.isTest()) {
@@ -51,11 +57,18 @@ async function authInternal(ctx: any, user: any, err: any = null, info = null) {
51
57
  }
52
58
  }
53
59
 
54
- export const authenticate = async (ctx: any, next: any) => {
60
+ export const login = async (ctx: Ctx<LoginRequest>, next: any) => {
61
+ const email = ctx.request.body.username
62
+
63
+ const user = await userSdk.getUserByEmail(email)
64
+ if (user && (await userSdk.isPreventSSOPasswords(user))) {
65
+ ctx.throw(400, "SSO user cannot login using password")
66
+ }
67
+
55
68
  return passport.authenticate(
56
69
  "local",
57
70
  async (err: any, user: User, info: any) => {
58
- await authInternal(ctx, user, err, info)
71
+ await passportCallback(ctx, user, err, info)
59
72
  await context.identity.doInUserContext(user, async () => {
60
73
  await events.auth.login("local")
61
74
  })
@@ -64,6 +77,15 @@ export const authenticate = async (ctx: any, next: any) => {
64
77
  )(ctx, next)
65
78
  }
66
79
 
80
+ export const logout = async (ctx: any) => {
81
+ if (ctx.user && ctx.user._id) {
82
+ await authSdk.logout({ ctx, userId: ctx.user._id })
83
+ }
84
+ ctx.body = { message: "User logged out." }
85
+ }
86
+
87
+ // INIT
88
+
67
89
  export const setInitInfo = (ctx: any) => {
68
90
  const initInfo = ctx.request.body
69
91
  setCookie(ctx, initInfo, Cookie.Init)
@@ -79,32 +101,16 @@ export const getInitInfo = (ctx: any) => {
79
101
  }
80
102
  }
81
103
 
104
+ // PASSWORD MANAGEMENT
105
+
82
106
  /**
83
107
  * Reset the user password, used as part of a forgotten password flow.
84
108
  */
85
- export const reset = async (ctx: any) => {
109
+ export const reset = async (ctx: Ctx<PasswordResetRequest>) => {
86
110
  const { email } = ctx.request.body
87
- const configured = await isEmailConfigured()
88
- if (!configured) {
89
- ctx.throw(
90
- 400,
91
- "Please contact your platform administrator, SMTP is not configured."
92
- )
93
- }
94
- try {
95
- const user = (await usersCore.getGlobalUserByEmail(email)) as User
96
- // only if user exists, don't error though if they don't
97
- if (user) {
98
- await sendEmail(email, EmailTemplatePurpose.PASSWORD_RECOVERY, {
99
- user,
100
- subject: "{{ company }} platform password reset",
101
- })
102
- await events.user.passwordResetRequested(user)
103
- }
104
- } catch (err) {
105
- console.log(err)
106
- // don't throw any kind of error to the user, this might give away something
107
- }
111
+
112
+ await authSdk.reset(email)
113
+
108
114
  ctx.body = {
109
115
  message: "Please check your email for a reset link.",
110
116
  }
@@ -113,32 +119,21 @@ export const reset = async (ctx: any) => {
113
119
  /**
114
120
  * Perform the user password update if the provided reset code is valid.
115
121
  */
116
- export const resetUpdate = async (ctx: any) => {
122
+ export const resetUpdate = async (ctx: Ctx<PasswordResetUpdateRequest>) => {
117
123
  const { resetCode, password } = ctx.request.body
118
124
  try {
119
- const { userId } = await checkResetPasswordCode(resetCode)
120
- const db = tenancy.getGlobalDB()
121
- const user = await db.get(userId)
122
- user.password = await hash(password)
123
- await db.put(user)
125
+ await authSdk.resetUpdate(resetCode, password)
124
126
  ctx.body = {
125
127
  message: "password reset successfully.",
126
128
  }
127
- // remove password from the user before sending events
128
- delete user.password
129
- await events.user.passwordReset(user)
130
129
  } catch (err) {
131
- console.error(err)
130
+ console.warn(err)
131
+ // hide any details of the error for security
132
132
  ctx.throw(400, "Cannot reset password.")
133
133
  }
134
134
  }
135
135
 
136
- export const logout = async (ctx: any) => {
137
- if (ctx.user && ctx.user._id) {
138
- await platformLogout({ ctx, userId: ctx.user._id })
139
- }
140
- ctx.body = { message: "User logged out." }
141
- }
136
+ // DATASOURCE
142
137
 
143
138
  export const datasourcePreAuth = async (ctx: any, next: any) => {
144
139
  const provider = ctx.params.provider
@@ -166,6 +161,12 @@ export const datasourceAuth = async (ctx: any, next: any) => {
166
161
  return handler.postAuth(passport, ctx, next)
167
162
  }
168
163
 
164
+ // GOOGLE SSO
165
+
166
+ export async function googleCallbackUrl(config?: { callbackURL?: string }) {
167
+ return ssoCallbackUrl(tenancy.getGlobalDB(), config, ConfigType.GOOGLE)
168
+ }
169
+
169
170
  /**
170
171
  * The initial call that google authentication makes to take you to the google login screen.
171
172
  * On a successful login, you will be redirected to the googleAuth callback route.
@@ -181,7 +182,7 @@ export const googlePreAuth = async (ctx: any, next: any) => {
181
182
  const strategy = await google.strategyFactory(
182
183
  config,
183
184
  callbackUrl,
184
- sdk.users.save
185
+ userSdk.save
185
186
  )
186
187
 
187
188
  return passport.authenticate(strategy, {
@@ -191,7 +192,7 @@ export const googlePreAuth = async (ctx: any, next: any) => {
191
192
  })(ctx, next)
192
193
  }
193
194
 
194
- export const googleAuth = async (ctx: any, next: any) => {
195
+ export const googleCallback = async (ctx: any, next: any) => {
195
196
  const db = tenancy.getGlobalDB()
196
197
 
197
198
  const config = await dbCore.getScopedConfig(db, {
@@ -202,14 +203,14 @@ export const googleAuth = async (ctx: any, next: any) => {
202
203
  const strategy = await google.strategyFactory(
203
204
  config,
204
205
  callbackUrl,
205
- sdk.users.save
206
+ userSdk.save
206
207
  )
207
208
 
208
209
  return passport.authenticate(
209
210
  strategy,
210
211
  { successRedirect: "/", failureRedirect: "/error" },
211
- async (err: any, user: User, info: any) => {
212
- await authInternal(ctx, user, err, info)
212
+ async (err: any, user: SSOUser, info: any) => {
213
+ await passportCallback(ctx, user, err, info)
213
214
  await context.identity.doInUserContext(user, async () => {
214
215
  await events.auth.login("google-internal")
215
216
  })
@@ -218,6 +219,12 @@ export const googleAuth = async (ctx: any, next: any) => {
218
219
  )(ctx, next)
219
220
  }
220
221
 
222
+ // OIDC SSO
223
+
224
+ export async function oidcCallbackUrl(config?: { callbackURL?: string }) {
225
+ return ssoCallbackUrl(tenancy.getGlobalDB(), config, ConfigType.OIDC)
226
+ }
227
+
221
228
  export const oidcStrategyFactory = async (ctx: any, configId: any) => {
222
229
  const db = tenancy.getGlobalDB()
223
230
  const config = await dbCore.getScopedConfig(db, {
@@ -233,7 +240,7 @@ export const oidcStrategyFactory = async (ctx: any, configId: any) => {
233
240
  chosenConfig,
234
241
  callbackUrl
235
242
  )
236
- return oidc.strategyFactory(enrichedConfig, sdk.users.save)
243
+ return oidc.strategyFactory(enrichedConfig, userSdk.save)
237
244
  }
238
245
 
239
246
  /**
@@ -265,15 +272,15 @@ export const oidcPreAuth = async (ctx: any, next: any) => {
265
272
  })(ctx, next)
266
273
  }
267
274
 
268
- export const oidcAuth = async (ctx: any, next: any) => {
275
+ export const oidcCallback = async (ctx: any, next: any) => {
269
276
  const configId = getCookie(ctx, Cookie.OIDC_CONFIG)
270
277
  const strategy = await oidcStrategyFactory(ctx, configId)
271
278
 
272
279
  return passport.authenticate(
273
280
  strategy,
274
281
  { successRedirect: "/", failureRedirect: "/error" },
275
- async (err: any, user: any, info: any) => {
276
- await authInternal(ctx, user, err, info)
282
+ async (err: any, user: SSOUser, info: any) => {
283
+ await passportCallback(ctx, user, err, info)
277
284
  await context.identity.doInUserContext(user, async () => {
278
285
  await events.auth.login("oidc")
279
286
  })
@@ -1,18 +1,22 @@
1
- import sdk from "../../../sdk"
1
+ import * as userSdk from "../../../sdk/users"
2
2
  import {
3
- events,
4
3
  featureFlags,
5
4
  tenancy,
6
5
  constants,
7
6
  db as dbCore,
8
7
  utils,
9
- cache,
10
8
  encryption,
9
+ auth as authCore,
11
10
  } from "@budibase/backend-core"
12
11
  import env from "../../../environment"
13
12
  import { groups } from "@budibase/pro"
14
- const { hash, platformLogout, getCookie, clearCookie, newid } = utils
15
- const { user: userCache } = cache
13
+ import {
14
+ UpdateSelfRequest,
15
+ UpdateSelfResponse,
16
+ UpdateSelf,
17
+ UserCtx,
18
+ } from "@budibase/types"
19
+ const { getCookie, clearCookie, newid } = utils
16
20
 
17
21
  function newTestApiKey() {
18
22
  return env.ENCRYPTED_TEST_PUBLIC_API_KEY
@@ -93,17 +97,6 @@ const addSessionAttributesToUser = (ctx: any) => {
93
97
  ctx.body.csrfToken = ctx.user.csrfToken
94
98
  }
95
99
 
96
- const sanitiseUserUpdate = (ctx: any) => {
97
- const allowed = ["firstName", "lastName", "password", "forceResetPassword"]
98
- const resp: { [key: string]: any } = {}
99
- for (let [key, value] of Object.entries(ctx.request.body)) {
100
- if (allowed.includes(key)) {
101
- resp[key] = value
102
- }
103
- }
104
- return resp
105
- }
106
-
107
100
  export async function getSelf(ctx: any) {
108
101
  if (!ctx.user) {
109
102
  ctx.throw(403, "User not logged in")
@@ -116,7 +109,7 @@ export async function getSelf(ctx: any) {
116
109
  checkCurrentApp(ctx)
117
110
 
118
111
  // get the main body of the user
119
- const user = await sdk.users.getUser(userId)
112
+ const user = await userSdk.getUser(userId)
120
113
  ctx.body = await groups.enrichUserRolesFromGroups(user)
121
114
 
122
115
  // add the feature flags for this tenant
@@ -126,39 +119,30 @@ export async function getSelf(ctx: any) {
126
119
  addSessionAttributesToUser(ctx)
127
120
  }
128
121
 
129
- export async function updateSelf(ctx: any) {
130
- const db = tenancy.getGlobalDB()
131
- const user = await db.get(ctx.user._id)
132
- let passwordChange = false
133
-
134
- const userUpdateObj = sanitiseUserUpdate(ctx)
135
- if (userUpdateObj.password) {
136
- // changing password
137
- passwordChange = true
138
- userUpdateObj.password = await hash(userUpdateObj.password)
122
+ export async function updateSelf(
123
+ ctx: UserCtx<UpdateSelfRequest, UpdateSelfResponse>
124
+ ) {
125
+ const body = ctx.request.body
126
+ const update: UpdateSelf = {
127
+ firstName: body.firstName,
128
+ lastName: body.lastName,
129
+ password: body.password,
130
+ forceResetPassword: body.forceResetPassword,
131
+ }
132
+
133
+ const user = await userSdk.updateSelf(ctx.user._id!, update)
134
+
135
+ if (update.password) {
139
136
  // Log all other sessions out apart from the current one
140
- await platformLogout({
137
+ await authCore.platformLogout({
141
138
  ctx,
142
- userId: ctx.user._id,
139
+ userId: ctx.user._id!,
143
140
  keepActiveSession: true,
144
141
  })
145
142
  }
146
143
 
147
- const response = await db.put({
148
- ...user,
149
- ...userUpdateObj,
150
- })
151
- await userCache.invalidateUser(user._id)
152
144
  ctx.body = {
153
- _id: response.id,
154
- _rev: response.rev,
155
- }
156
-
157
- // remove the old password from the user before sending events
158
- user._rev = response.rev
159
- delete user.password
160
- await events.user.updated(user)
161
- if (passwordChange) {
162
- await events.user.passwordUpdated(user)
145
+ _id: user._id!,
146
+ _rev: user._rev!,
163
147
  }
164
148
  }