@budibase/worker 2.3.20 → 2.3.21-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 (180) hide show
  1. package/__mocks__/node-fetch.ts +23 -0
  2. package/jest-testcontainers-config.js +8 -0
  3. package/jest.config.ts +14 -18
  4. package/package.json +12 -8
  5. package/scripts/dev/manage.js +1 -0
  6. package/scripts/test.sh +12 -0
  7. package/src/api/controllers/global/auth.ts +109 -111
  8. package/src/api/controllers/global/configs.ts +150 -142
  9. package/src/api/controllers/global/self.ts +28 -44
  10. package/src/api/controllers/global/users.ts +211 -32
  11. package/src/api/controllers/system/accounts.ts +7 -5
  12. package/src/api/controllers/system/tenants.ts +4 -8
  13. package/src/api/index.ts +4 -20
  14. package/src/api/routes/global/auth.ts +10 -7
  15. package/src/api/routes/global/configs.ts +6 -12
  16. package/src/api/routes/global/tests/auditLogs.spec.ts +111 -0
  17. package/src/api/routes/global/tests/auth.spec.ts +217 -18
  18. package/src/api/routes/global/tests/configs.spec.ts +93 -65
  19. package/src/api/routes/global/tests/realEmail.spec.ts +1 -0
  20. package/src/api/routes/global/tests/roles.spec.ts +20 -14
  21. package/src/api/routes/global/tests/self.spec.ts +3 -4
  22. package/src/api/routes/global/tests/users.spec.ts +29 -28
  23. package/src/api/routes/global/users.ts +19 -14
  24. package/src/api/routes/index.ts +3 -0
  25. package/src/api/routes/system/tenants.ts +1 -1
  26. package/src/api/routes/system/tests/accounts.spec.ts +4 -4
  27. package/src/api/routes/system/tests/migrations.spec.ts +2 -2
  28. package/src/api/routes/system/tests/restore.spec.ts +2 -2
  29. package/src/api/routes/system/tests/status.spec.ts +5 -5
  30. package/src/db/index.ts +8 -2
  31. package/src/ddApm.ts +7 -0
  32. package/src/elasticApm.ts +10 -0
  33. package/src/environment.ts +4 -0
  34. package/src/index.ts +29 -8
  35. package/src/middleware/tests/tenancy.spec.ts +4 -4
  36. package/src/migrations/functions/globalInfoSyncUsers.ts +4 -3
  37. package/src/sdk/accounts/index.ts +2 -1
  38. package/src/sdk/accounts/{accounts.ts → metadata.ts} +0 -1
  39. package/src/sdk/auth/auth.ts +86 -0
  40. package/src/sdk/auth/index.ts +1 -0
  41. package/src/sdk/tenants/index.ts +1 -0
  42. package/src/sdk/tenants/tenants.ts +76 -0
  43. package/src/sdk/users/events.ts +4 -0
  44. package/src/sdk/users/index.ts +1 -0
  45. package/src/sdk/users/tests/users.spec.ts +76 -0
  46. package/src/sdk/users/users.ts +86 -53
  47. package/src/tests/TestConfiguration.ts +41 -62
  48. package/src/tests/api/auditLogs.ts +26 -0
  49. package/src/tests/api/auth.ts +44 -14
  50. package/src/tests/api/base.ts +2 -1
  51. package/src/tests/api/configs.ts +9 -1
  52. package/src/tests/api/email.ts +1 -0
  53. package/src/tests/api/index.ts +3 -0
  54. package/src/tests/api/restore.ts +1 -0
  55. package/src/tests/api/users.ts +2 -2
  56. package/src/tests/jestEnv.ts +2 -1
  57. package/src/tests/jestSetup.ts +10 -6
  58. package/src/tests/logging.ts +34 -0
  59. package/src/tests/structures/configs.ts +20 -13
  60. package/src/tests/structures/index.ts +0 -4
  61. package/src/utilities/email.ts +22 -68
  62. package/src/utilities/redis.ts +42 -2
  63. package/src/utilities/templates.ts +4 -9
  64. package/coverage/clover.xml +0 -2199
  65. package/coverage/coverage-final.json +0 -84
  66. package/coverage/lcov-report/base.css +0 -224
  67. package/coverage/lcov-report/block-navigation.js +0 -87
  68. package/coverage/lcov-report/favicon.png +0 -0
  69. package/coverage/lcov-report/index.html +0 -431
  70. package/coverage/lcov-report/prettify.css +0 -1
  71. package/coverage/lcov-report/prettify.js +0 -2
  72. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  73. package/coverage/lcov-report/sorter.js +0 -196
  74. package/coverage/lcov-report/src/api/controllers/global/auth.ts.html +0 -934
  75. package/coverage/lcov-report/src/api/controllers/global/configs.ts.html +0 -1348
  76. package/coverage/lcov-report/src/api/controllers/global/email.ts.html +0 -196
  77. package/coverage/lcov-report/src/api/controllers/global/events.ts.html +0 -136
  78. package/coverage/lcov-report/src/api/controllers/global/index.html +0 -251
  79. package/coverage/lcov-report/src/api/controllers/global/license.ts.html +0 -187
  80. package/coverage/lcov-report/src/api/controllers/global/roles.ts.html +0 -283
  81. package/coverage/lcov-report/src/api/controllers/global/self.ts.html +0 -577
  82. package/coverage/lcov-report/src/api/controllers/global/templates.ts.html +0 -316
  83. package/coverage/lcov-report/src/api/controllers/global/users.ts.html +0 -838
  84. package/coverage/lcov-report/src/api/controllers/global/workspaces.ts.html +0 -244
  85. package/coverage/lcov-report/src/api/controllers/system/accounts.ts.html +0 -148
  86. package/coverage/lcov-report/src/api/controllers/system/environment.ts.html +0 -124
  87. package/coverage/lcov-report/src/api/controllers/system/index.html +0 -191
  88. package/coverage/lcov-report/src/api/controllers/system/migrations.ts.html +0 -124
  89. package/coverage/lcov-report/src/api/controllers/system/restore.ts.html +0 -124
  90. package/coverage/lcov-report/src/api/controllers/system/status.ts.html +0 -133
  91. package/coverage/lcov-report/src/api/controllers/system/tenants.ts.html +0 -154
  92. package/coverage/lcov-report/src/api/index.html +0 -116
  93. package/coverage/lcov-report/src/api/index.ts.html +0 -595
  94. package/coverage/lcov-report/src/api/routes/global/auth.ts.html +0 -349
  95. package/coverage/lcov-report/src/api/routes/global/configs.ts.html +0 -457
  96. package/coverage/lcov-report/src/api/routes/global/email.ts.html +0 -193
  97. package/coverage/lcov-report/src/api/routes/global/events.ts.html +0 -109
  98. package/coverage/lcov-report/src/api/routes/global/index.html +0 -251
  99. package/coverage/lcov-report/src/api/routes/global/license.ts.html +0 -124
  100. package/coverage/lcov-report/src/api/routes/global/roles.ts.html +0 -133
  101. package/coverage/lcov-report/src/api/routes/global/self.ts.html +0 -139
  102. package/coverage/lcov-report/src/api/routes/global/templates.ts.html +0 -196
  103. package/coverage/lcov-report/src/api/routes/global/users.ts.html +0 -475
  104. package/coverage/lcov-report/src/api/routes/global/workspaces.ts.html +0 -196
  105. package/coverage/lcov-report/src/api/routes/index.html +0 -116
  106. package/coverage/lcov-report/src/api/routes/index.ts.html +0 -202
  107. package/coverage/lcov-report/src/api/routes/system/accounts.ts.html +0 -142
  108. package/coverage/lcov-report/src/api/routes/system/environment.ts.html +0 -109
  109. package/coverage/lcov-report/src/api/routes/system/index.html +0 -191
  110. package/coverage/lcov-report/src/api/routes/system/migrations.ts.html +0 -142
  111. package/coverage/lcov-report/src/api/routes/system/restore.ts.html +0 -109
  112. package/coverage/lcov-report/src/api/routes/system/status.ts.html +0 -109
  113. package/coverage/lcov-report/src/api/routes/system/tenants.ts.html +0 -124
  114. package/coverage/lcov-report/src/api/routes/validation/index.html +0 -131
  115. package/coverage/lcov-report/src/api/routes/validation/index.ts.html +0 -88
  116. package/coverage/lcov-report/src/api/routes/validation/users.ts.html +0 -235
  117. package/coverage/lcov-report/src/constants/index.html +0 -116
  118. package/coverage/lcov-report/src/constants/index.ts.html +0 -637
  119. package/coverage/lcov-report/src/constants/templates/index.html +0 -116
  120. package/coverage/lcov-report/src/constants/templates/index.ts.html +0 -316
  121. package/coverage/lcov-report/src/db/index.html +0 -116
  122. package/coverage/lcov-report/src/db/index.ts.html +0 -115
  123. package/coverage/lcov-report/src/environment.ts.html +0 -388
  124. package/coverage/lcov-report/src/index.html +0 -131
  125. package/coverage/lcov-report/src/index.ts.html +0 -394
  126. package/coverage/lcov-report/src/middleware/cloudRestricted.ts.html +0 -139
  127. package/coverage/lcov-report/src/middleware/index.html +0 -116
  128. package/coverage/lcov-report/src/migrations/functions/globalInfoSyncUsers.ts.html +0 -145
  129. package/coverage/lcov-report/src/migrations/functions/index.html +0 -116
  130. package/coverage/lcov-report/src/migrations/index.html +0 -116
  131. package/coverage/lcov-report/src/migrations/index.ts.html +0 -271
  132. package/coverage/lcov-report/src/sdk/accounts/accounts.ts.html +0 -262
  133. package/coverage/lcov-report/src/sdk/accounts/index.html +0 -131
  134. package/coverage/lcov-report/src/sdk/accounts/index.ts.html +0 -88
  135. package/coverage/lcov-report/src/sdk/index.html +0 -116
  136. package/coverage/lcov-report/src/sdk/index.ts.html +0 -106
  137. package/coverage/lcov-report/src/sdk/users/events.ts.html +0 -601
  138. package/coverage/lcov-report/src/sdk/users/index.html +0 -146
  139. package/coverage/lcov-report/src/sdk/users/index.ts.html +0 -88
  140. package/coverage/lcov-report/src/sdk/users/users.ts.html +0 -1999
  141. package/coverage/lcov-report/src/tests/TestConfiguration.ts.html +0 -1075
  142. package/coverage/lcov-report/src/tests/api/accounts.ts.html +0 -160
  143. package/coverage/lcov-report/src/tests/api/auth.ts.html +0 -220
  144. package/coverage/lcov-report/src/tests/api/base.ts.html +0 -133
  145. package/coverage/lcov-report/src/tests/api/configs.ts.html +0 -226
  146. package/coverage/lcov-report/src/tests/api/email.ts.html +0 -148
  147. package/coverage/lcov-report/src/tests/api/environment.ts.html +0 -130
  148. package/coverage/lcov-report/src/tests/api/groups.ts.html +0 -163
  149. package/coverage/lcov-report/src/tests/api/index.html +0 -356
  150. package/coverage/lcov-report/src/tests/api/index.ts.html +0 -238
  151. package/coverage/lcov-report/src/tests/api/license.ts.html +0 -136
  152. package/coverage/lcov-report/src/tests/api/migrations.ts.html +0 -151
  153. package/coverage/lcov-report/src/tests/api/restore.ts.html +0 -127
  154. package/coverage/lcov-report/src/tests/api/roles.ts.html +0 -181
  155. package/coverage/lcov-report/src/tests/api/self.ts.html +0 -163
  156. package/coverage/lcov-report/src/tests/api/status.ts.html +0 -121
  157. package/coverage/lcov-report/src/tests/api/templates.ts.html +0 -175
  158. package/coverage/lcov-report/src/tests/api/tenants.ts.html +0 -130
  159. package/coverage/lcov-report/src/tests/api/users.ts.html +0 -514
  160. package/coverage/lcov-report/src/tests/controllers.ts.html +0 -100
  161. package/coverage/lcov-report/src/tests/index.html +0 -146
  162. package/coverage/lcov-report/src/tests/index.ts.html +0 -103
  163. package/coverage/lcov-report/src/tests/mocks/email.ts.html +0 -115
  164. package/coverage/lcov-report/src/tests/mocks/index.html +0 -131
  165. package/coverage/lcov-report/src/tests/mocks/index.ts.html +0 -106
  166. package/coverage/lcov-report/src/tests/structures/configs.ts.html +0 -313
  167. package/coverage/lcov-report/src/tests/structures/groups.ts.html +0 -118
  168. package/coverage/lcov-report/src/tests/structures/index.html +0 -161
  169. package/coverage/lcov-report/src/tests/structures/index.ts.html +0 -151
  170. package/coverage/lcov-report/src/tests/structures/users.ts.html +0 -196
  171. package/coverage/lcov-report/src/utilities/appService.ts.html +0 -208
  172. package/coverage/lcov-report/src/utilities/email.ts.html +0 -850
  173. package/coverage/lcov-report/src/utilities/fileSystem.ts.html +0 -100
  174. package/coverage/lcov-report/src/utilities/index.html +0 -206
  175. package/coverage/lcov-report/src/utilities/index.ts.html +0 -112
  176. package/coverage/lcov-report/src/utilities/redis.ts.html +0 -424
  177. package/coverage/lcov-report/src/utilities/templates.ts.html +0 -232
  178. package/coverage/lcov-report/src/utilities/users.ts.html +0 -133
  179. package/coverage/lcov.info +0 -4187
  180. 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,34 +1,30 @@
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
- collectCoverageFrom: ["src/**/*.{js,ts}"],
10
+ collectCoverageFrom: ["src/**/*.{js,ts}", "../backend-core/src/**/*.{js,ts}"],
9
11
  coverageReporters: ["lcov", "json", "clover"],
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.20",
4
+ "version": "2.3.21-alpha.0",
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": "bash scripts/test.sh",
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.20",
40
- "@budibase/pro": "2.3.19",
41
- "@budibase/string-templates": "^2.3.20",
42
- "@budibase/types": "^2.3.20",
39
+ "@budibase/backend-core": "2.3.21-alpha.0",
40
+ "@budibase/pro": "2.3.20",
41
+ "@budibase/string-templates": "2.3.21-alpha.0",
42
+ "@budibase/types": "2.3.21-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",
@@ -59,6 +60,7 @@
59
60
  "koa-send": "5.0.1",
60
61
  "koa-session": "5.13.1",
61
62
  "koa-static": "5.0.0",
63
+ "koa-useragent": "^4.1.0",
62
64
  "node-fetch": "2.6.7",
63
65
  "nodemailer": "6.7.2",
64
66
  "passport-google-oauth": "2.0.0",
@@ -72,7 +74,8 @@
72
74
  "devDependencies": {
73
75
  "@swc/core": "^1.3.25",
74
76
  "@swc/jest": "^0.2.24",
75
- "@types/jest": "26.0.23",
77
+ "@trendyol/jest-testcontainers": "^2.1.1",
78
+ "@types/jest": "28.1.1",
76
79
  "@types/jsonwebtoken": "8.5.1",
77
80
  "@types/koa": "2.13.4",
78
81
  "@types/koa__router": "8.0.8",
@@ -80,6 +83,7 @@
80
83
  "@types/node-fetch": "2.6.1",
81
84
  "@types/pouchdb": "6.4.0",
82
85
  "@types/server-destroy": "1.0.1",
86
+ "@types/supertest": "2.0.12",
83
87
  "@types/uuid": "8.3.4",
84
88
  "@typescript-eslint/parser": "5.45.0",
85
89
  "copyfiles": "2.4.1",
@@ -97,5 +101,5 @@
97
101
  "typescript": "4.7.3",
98
102
  "update-dotenv": "1.1.1"
99
103
  },
100
- "gitHead": "6963c46ab30c99df435ec7674b515f714ea5f896"
104
+ "gitHead": "e07c36dd8ca5d1fcfcf18961457dc539016535ca"
101
105
  }
@@ -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 => {
@@ -0,0 +1,12 @@
1
+ #!/bin/bash
2
+
3
+ if [[ -n $CI ]]
4
+ then
5
+ # --runInBand performs better in ci where resources are limited
6
+ echo "jest --coverage --runInBand"
7
+ jest --coverage --runInBand
8
+ else
9
+ # --maxWorkers performs better in development
10
+ echo "jest --coverage --maxWorkers=2"
11
+ jest --coverage --maxWorkers=2
12
+ fi
@@ -1,49 +1,55 @@
1
1
  import {
2
- auth,
2
+ auth as authCore,
3
3
  constants,
4
4
  context,
5
- db as dbCore,
6
5
  events,
7
- tenancy,
8
- users as usersCore,
9
- utils,
6
+ utils as utilsCore,
7
+ configs,
10
8
  } from "@budibase/backend-core"
11
- import { EmailTemplatePurpose } from "../../../constants"
12
- import { isEmailConfigured, sendEmail } from "../../../utilities/email"
13
- import { checkResetPasswordCode } from "../../../utilities/redis"
9
+ import {
10
+ ConfigType,
11
+ User,
12
+ Ctx,
13
+ LoginRequest,
14
+ SSOUser,
15
+ PasswordResetRequest,
16
+ PasswordResetUpdateRequest,
17
+ GoogleInnerConfig,
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,19 +57,35 @@ 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.isPreventPasswordActions(user))) {
65
+ ctx.throw(403, "Invalid credentials")
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)
59
- await context.identity.doInUserContext(user, async () => {
60
- await events.auth.login("local")
71
+ await passportCallback(ctx, user, err, info)
72
+ await context.identity.doInUserContext(user, ctx, async () => {
73
+ await events.auth.login("local", user.email)
61
74
  })
62
75
  ctx.status = 200
63
76
  }
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,22 +161,26 @@ 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?: GoogleInnerConfig) {
167
+ return ssoCallbackUrl(ConfigType.GOOGLE, config)
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.
172
173
  */
173
174
  export const googlePreAuth = async (ctx: any, next: any) => {
174
- const db = tenancy.getGlobalDB()
175
-
176
- const config = await dbCore.getScopedConfig(db, {
177
- type: ConfigType.GOOGLE,
178
- workspace: ctx.query.workspace,
179
- })
175
+ const config = await configs.getGoogleConfig()
176
+ if (!config) {
177
+ return ctx.throw(400, "Google config not found")
178
+ }
180
179
  let callbackUrl = await googleCallbackUrl(config)
181
180
  const strategy = await google.strategyFactory(
182
181
  config,
183
182
  callbackUrl,
184
- sdk.users.save
183
+ userSdk.save
185
184
  )
186
185
 
187
186
  return passport.authenticate(strategy, {
@@ -191,72 +190,71 @@ export const googlePreAuth = async (ctx: any, next: any) => {
191
190
  })(ctx, next)
192
191
  }
193
192
 
194
- export const googleAuth = async (ctx: any, next: any) => {
195
- const db = tenancy.getGlobalDB()
196
-
197
- const config = await dbCore.getScopedConfig(db, {
198
- type: ConfigType.GOOGLE,
199
- workspace: ctx.query.workspace,
200
- })
193
+ export const googleCallback = async (ctx: any, next: any) => {
194
+ const config = await configs.getGoogleConfig()
195
+ if (!config) {
196
+ return ctx.throw(400, "Google config not found")
197
+ }
201
198
  const callbackUrl = await googleCallbackUrl(config)
202
199
  const strategy = await google.strategyFactory(
203
200
  config,
204
201
  callbackUrl,
205
- sdk.users.save
202
+ userSdk.save
206
203
  )
207
204
 
208
205
  return passport.authenticate(
209
206
  strategy,
210
207
  { successRedirect: "/", failureRedirect: "/error" },
211
- async (err: any, user: User, info: any) => {
212
- await authInternal(ctx, user, err, info)
213
- await context.identity.doInUserContext(user, async () => {
214
- await events.auth.login("google-internal")
208
+ async (err: any, user: SSOUser, info: any) => {
209
+ await passportCallback(ctx, user, err, info)
210
+ await context.identity.doInUserContext(user, ctx, async () => {
211
+ await events.auth.login("google-internal", user.email)
215
212
  })
216
213
  ctx.redirect("/")
217
214
  }
218
215
  )(ctx, next)
219
216
  }
220
217
 
218
+ // OIDC SSO
219
+
220
+ export async function oidcCallbackUrl() {
221
+ return ssoCallbackUrl(ConfigType.OIDC)
222
+ }
223
+
221
224
  export const oidcStrategyFactory = async (ctx: any, configId: any) => {
222
- const db = tenancy.getGlobalDB()
223
- const config = await dbCore.getScopedConfig(db, {
224
- type: ConfigType.OIDC,
225
- group: ctx.query.group,
226
- })
225
+ const config = await configs.getOIDCConfig()
226
+ if (!config) {
227
+ return ctx.throw(400, "OIDC config not found")
228
+ }
227
229
 
228
- const chosenConfig = config.configs.filter((c: any) => c.uuid === configId)[0]
229
- let callbackUrl = await oidcCallbackUrl(chosenConfig)
230
+ let callbackUrl = await oidcCallbackUrl()
230
231
 
231
232
  //Remote Config
232
- const enrichedConfig = await oidc.fetchStrategyConfig(
233
- chosenConfig,
234
- callbackUrl
235
- )
236
- return oidc.strategyFactory(enrichedConfig, sdk.users.save)
233
+ const enrichedConfig = await oidc.fetchStrategyConfig(config, callbackUrl)
234
+ return oidc.strategyFactory(enrichedConfig, userSdk.save)
237
235
  }
238
236
 
239
237
  /**
240
238
  * The initial call that OIDC authentication makes to take you to the configured OIDC login screen.
241
239
  * On a successful login, you will be redirected to the oidcAuth callback route.
242
240
  */
243
- export const oidcPreAuth = async (ctx: any, next: any) => {
241
+ export const oidcPreAuth = async (ctx: Ctx, next: any) => {
244
242
  const { configId } = ctx.params
243
+ if (!configId) {
244
+ ctx.throw(400, "OIDC config id is required")
245
+ }
245
246
  const strategy = await oidcStrategyFactory(ctx, configId)
246
247
 
247
248
  setCookie(ctx, configId, Cookie.OIDC_CONFIG)
248
249
 
249
- const db = tenancy.getGlobalDB()
250
- const config = await dbCore.getScopedConfig(db, {
251
- type: ConfigType.OIDC,
252
- group: ctx.query.group,
253
- })
254
-
255
- const chosenConfig = config.configs.filter((c: any) => c.uuid === configId)[0]
250
+ const config = await configs.getOIDCConfigById(configId)
251
+ if (!config) {
252
+ return ctx.throw(400, "OIDC config not found")
253
+ }
256
254
 
257
255
  let authScopes =
258
- chosenConfig.scopes?.length > 0
259
- ? chosenConfig.scopes
256
+ config.scopes?.length > 0
257
+ ? config.scopes
260
258
  : ["profile", "email", "offline_access"]
261
259
 
262
260
  return passport.authenticate(strategy, {
@@ -265,17 +263,17 @@ export const oidcPreAuth = async (ctx: any, next: any) => {
265
263
  })(ctx, next)
266
264
  }
267
265
 
268
- export const oidcAuth = async (ctx: any, next: any) => {
266
+ export const oidcCallback = async (ctx: any, next: any) => {
269
267
  const configId = getCookie(ctx, Cookie.OIDC_CONFIG)
270
268
  const strategy = await oidcStrategyFactory(ctx, configId)
271
269
 
272
270
  return passport.authenticate(
273
271
  strategy,
274
272
  { successRedirect: "/", failureRedirect: "/error" },
275
- async (err: any, user: any, info: any) => {
276
- await authInternal(ctx, user, err, info)
277
- await context.identity.doInUserContext(user, async () => {
278
- await events.auth.login("oidc")
273
+ async (err: any, user: SSOUser, info: any) => {
274
+ await passportCallback(ctx, user, err, info)
275
+ await context.identity.doInUserContext(user, ctx, async () => {
276
+ await events.auth.login("oidc", user.email)
279
277
  })
280
278
  ctx.redirect("/")
281
279
  }