@budibase/worker 2.3.17 → 2.3.18-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 (166) hide show
  1. package/__mocks__/node-fetch.ts +23 -0
  2. package/jest-testcontainers-config.js +8 -0
  3. package/jest.config.ts +3 -2
  4. package/package.json +10 -7
  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/coverage/clover.xml +0 -2199
  51. package/coverage/coverage-final.json +0 -84
  52. package/coverage/lcov-report/base.css +0 -224
  53. package/coverage/lcov-report/block-navigation.js +0 -87
  54. package/coverage/lcov-report/favicon.png +0 -0
  55. package/coverage/lcov-report/index.html +0 -431
  56. package/coverage/lcov-report/prettify.css +0 -1
  57. package/coverage/lcov-report/prettify.js +0 -2
  58. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  59. package/coverage/lcov-report/sorter.js +0 -196
  60. package/coverage/lcov-report/src/api/controllers/global/auth.ts.html +0 -934
  61. package/coverage/lcov-report/src/api/controllers/global/configs.ts.html +0 -1348
  62. package/coverage/lcov-report/src/api/controllers/global/email.ts.html +0 -196
  63. package/coverage/lcov-report/src/api/controllers/global/events.ts.html +0 -136
  64. package/coverage/lcov-report/src/api/controllers/global/index.html +0 -251
  65. package/coverage/lcov-report/src/api/controllers/global/license.ts.html +0 -187
  66. package/coverage/lcov-report/src/api/controllers/global/roles.ts.html +0 -283
  67. package/coverage/lcov-report/src/api/controllers/global/self.ts.html +0 -577
  68. package/coverage/lcov-report/src/api/controllers/global/templates.ts.html +0 -316
  69. package/coverage/lcov-report/src/api/controllers/global/users.ts.html +0 -838
  70. package/coverage/lcov-report/src/api/controllers/global/workspaces.ts.html +0 -244
  71. package/coverage/lcov-report/src/api/controllers/system/accounts.ts.html +0 -148
  72. package/coverage/lcov-report/src/api/controllers/system/environment.ts.html +0 -124
  73. package/coverage/lcov-report/src/api/controllers/system/index.html +0 -191
  74. package/coverage/lcov-report/src/api/controllers/system/migrations.ts.html +0 -124
  75. package/coverage/lcov-report/src/api/controllers/system/restore.ts.html +0 -124
  76. package/coverage/lcov-report/src/api/controllers/system/status.ts.html +0 -133
  77. package/coverage/lcov-report/src/api/controllers/system/tenants.ts.html +0 -154
  78. package/coverage/lcov-report/src/api/index.html +0 -116
  79. package/coverage/lcov-report/src/api/index.ts.html +0 -595
  80. package/coverage/lcov-report/src/api/routes/global/auth.ts.html +0 -349
  81. package/coverage/lcov-report/src/api/routes/global/configs.ts.html +0 -457
  82. package/coverage/lcov-report/src/api/routes/global/email.ts.html +0 -193
  83. package/coverage/lcov-report/src/api/routes/global/events.ts.html +0 -109
  84. package/coverage/lcov-report/src/api/routes/global/index.html +0 -251
  85. package/coverage/lcov-report/src/api/routes/global/license.ts.html +0 -124
  86. package/coverage/lcov-report/src/api/routes/global/roles.ts.html +0 -133
  87. package/coverage/lcov-report/src/api/routes/global/self.ts.html +0 -139
  88. package/coverage/lcov-report/src/api/routes/global/templates.ts.html +0 -196
  89. package/coverage/lcov-report/src/api/routes/global/users.ts.html +0 -475
  90. package/coverage/lcov-report/src/api/routes/global/workspaces.ts.html +0 -196
  91. package/coverage/lcov-report/src/api/routes/index.html +0 -116
  92. package/coverage/lcov-report/src/api/routes/index.ts.html +0 -202
  93. package/coverage/lcov-report/src/api/routes/system/accounts.ts.html +0 -142
  94. package/coverage/lcov-report/src/api/routes/system/environment.ts.html +0 -109
  95. package/coverage/lcov-report/src/api/routes/system/index.html +0 -191
  96. package/coverage/lcov-report/src/api/routes/system/migrations.ts.html +0 -142
  97. package/coverage/lcov-report/src/api/routes/system/restore.ts.html +0 -109
  98. package/coverage/lcov-report/src/api/routes/system/status.ts.html +0 -109
  99. package/coverage/lcov-report/src/api/routes/system/tenants.ts.html +0 -124
  100. package/coverage/lcov-report/src/api/routes/validation/index.html +0 -131
  101. package/coverage/lcov-report/src/api/routes/validation/index.ts.html +0 -88
  102. package/coverage/lcov-report/src/api/routes/validation/users.ts.html +0 -235
  103. package/coverage/lcov-report/src/constants/index.html +0 -116
  104. package/coverage/lcov-report/src/constants/index.ts.html +0 -637
  105. package/coverage/lcov-report/src/constants/templates/index.html +0 -116
  106. package/coverage/lcov-report/src/constants/templates/index.ts.html +0 -316
  107. package/coverage/lcov-report/src/db/index.html +0 -116
  108. package/coverage/lcov-report/src/db/index.ts.html +0 -115
  109. package/coverage/lcov-report/src/environment.ts.html +0 -388
  110. package/coverage/lcov-report/src/index.html +0 -131
  111. package/coverage/lcov-report/src/index.ts.html +0 -394
  112. package/coverage/lcov-report/src/middleware/cloudRestricted.ts.html +0 -139
  113. package/coverage/lcov-report/src/middleware/index.html +0 -116
  114. package/coverage/lcov-report/src/migrations/functions/globalInfoSyncUsers.ts.html +0 -145
  115. package/coverage/lcov-report/src/migrations/functions/index.html +0 -116
  116. package/coverage/lcov-report/src/migrations/index.html +0 -116
  117. package/coverage/lcov-report/src/migrations/index.ts.html +0 -271
  118. package/coverage/lcov-report/src/sdk/accounts/accounts.ts.html +0 -262
  119. package/coverage/lcov-report/src/sdk/accounts/index.html +0 -131
  120. package/coverage/lcov-report/src/sdk/accounts/index.ts.html +0 -88
  121. package/coverage/lcov-report/src/sdk/index.html +0 -116
  122. package/coverage/lcov-report/src/sdk/index.ts.html +0 -106
  123. package/coverage/lcov-report/src/sdk/users/events.ts.html +0 -601
  124. package/coverage/lcov-report/src/sdk/users/index.html +0 -146
  125. package/coverage/lcov-report/src/sdk/users/index.ts.html +0 -88
  126. package/coverage/lcov-report/src/sdk/users/users.ts.html +0 -1999
  127. package/coverage/lcov-report/src/tests/TestConfiguration.ts.html +0 -1075
  128. package/coverage/lcov-report/src/tests/api/accounts.ts.html +0 -160
  129. package/coverage/lcov-report/src/tests/api/auth.ts.html +0 -220
  130. package/coverage/lcov-report/src/tests/api/base.ts.html +0 -133
  131. package/coverage/lcov-report/src/tests/api/configs.ts.html +0 -226
  132. package/coverage/lcov-report/src/tests/api/email.ts.html +0 -148
  133. package/coverage/lcov-report/src/tests/api/environment.ts.html +0 -130
  134. package/coverage/lcov-report/src/tests/api/groups.ts.html +0 -163
  135. package/coverage/lcov-report/src/tests/api/index.html +0 -356
  136. package/coverage/lcov-report/src/tests/api/index.ts.html +0 -238
  137. package/coverage/lcov-report/src/tests/api/license.ts.html +0 -136
  138. package/coverage/lcov-report/src/tests/api/migrations.ts.html +0 -151
  139. package/coverage/lcov-report/src/tests/api/restore.ts.html +0 -127
  140. package/coverage/lcov-report/src/tests/api/roles.ts.html +0 -181
  141. package/coverage/lcov-report/src/tests/api/self.ts.html +0 -163
  142. package/coverage/lcov-report/src/tests/api/status.ts.html +0 -121
  143. package/coverage/lcov-report/src/tests/api/templates.ts.html +0 -175
  144. package/coverage/lcov-report/src/tests/api/tenants.ts.html +0 -130
  145. package/coverage/lcov-report/src/tests/api/users.ts.html +0 -514
  146. package/coverage/lcov-report/src/tests/controllers.ts.html +0 -100
  147. package/coverage/lcov-report/src/tests/index.html +0 -146
  148. package/coverage/lcov-report/src/tests/index.ts.html +0 -103
  149. package/coverage/lcov-report/src/tests/mocks/email.ts.html +0 -115
  150. package/coverage/lcov-report/src/tests/mocks/index.html +0 -131
  151. package/coverage/lcov-report/src/tests/mocks/index.ts.html +0 -106
  152. package/coverage/lcov-report/src/tests/structures/configs.ts.html +0 -313
  153. package/coverage/lcov-report/src/tests/structures/groups.ts.html +0 -118
  154. package/coverage/lcov-report/src/tests/structures/index.html +0 -161
  155. package/coverage/lcov-report/src/tests/structures/index.ts.html +0 -151
  156. package/coverage/lcov-report/src/tests/structures/users.ts.html +0 -196
  157. package/coverage/lcov-report/src/utilities/appService.ts.html +0 -208
  158. package/coverage/lcov-report/src/utilities/email.ts.html +0 -850
  159. package/coverage/lcov-report/src/utilities/fileSystem.ts.html +0 -100
  160. package/coverage/lcov-report/src/utilities/index.html +0 -206
  161. package/coverage/lcov-report/src/utilities/index.ts.html +0 -112
  162. package/coverage/lcov-report/src/utilities/redis.ts.html +0 -424
  163. package/coverage/lcov-report/src/utilities/templates.ts.html +0 -232
  164. package/coverage/lcov-report/src/utilities/users.ts.html +0 -133
  165. package/coverage/lcov.info +0 -4187
  166. 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}"],
@@ -18,7 +20,6 @@ if (!process.env.CI) {
18
20
  "@budibase/backend-core/(.*)": "<rootDir>/../backend-core/$1",
19
21
  "@budibase/backend-core": "<rootDir>/../backend-core/src",
20
22
  "@budibase/types": "<rootDir>/../types/src",
21
- "^axios.*$": "<rootDir>/node_modules/axios/lib/axios.js",
22
23
  }
23
24
  // add pro sources if they exist
24
25
  if (fs.existsSync("../../../budibase-pro")) {
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.0",
5
5
  "description": "Budibase background service",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -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.0",
40
+ "@budibase/pro": "2.3.17",
41
+ "@budibase/string-templates": "2.3.18-alpha.0",
42
+ "@budibase/types": "2.3.18-alpha.0",
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": "f4dd710b75eb0a7a65e6f9d8b8f709d3b76c435b"
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
  }