@budibase/backend-core 2.9.19 → 2.9.20

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 (241) hide show
  1. package/dist/package.json +19 -4
  2. package/dist/src/security/permissions.d.ts +1 -1
  3. package/package.json +19 -4
  4. package/dist/tsconfig.build.tsbuildinfo +0 -1
  5. package/src/accounts/accounts.ts +0 -82
  6. package/src/accounts/api.ts +0 -59
  7. package/src/accounts/index.ts +0 -1
  8. package/src/auth/auth.ts +0 -208
  9. package/src/auth/index.ts +0 -1
  10. package/src/auth/tests/auth.spec.ts +0 -14
  11. package/src/blacklist/blacklist.ts +0 -54
  12. package/src/blacklist/index.ts +0 -1
  13. package/src/blacklist/tests/blacklist.spec.ts +0 -46
  14. package/src/cache/appMetadata.ts +0 -88
  15. package/src/cache/base/index.ts +0 -92
  16. package/src/cache/generic.ts +0 -30
  17. package/src/cache/index.ts +0 -5
  18. package/src/cache/tests/writethrough.spec.ts +0 -138
  19. package/src/cache/user.ts +0 -69
  20. package/src/cache/writethrough.ts +0 -133
  21. package/src/configs/configs.ts +0 -257
  22. package/src/configs/index.ts +0 -1
  23. package/src/configs/tests/configs.spec.ts +0 -184
  24. package/src/constants/db.ts +0 -63
  25. package/src/constants/index.ts +0 -2
  26. package/src/constants/misc.ts +0 -50
  27. package/src/context/Context.ts +0 -14
  28. package/src/context/identity.ts +0 -58
  29. package/src/context/index.ts +0 -3
  30. package/src/context/mainContext.ts +0 -310
  31. package/src/context/tests/index.spec.ts +0 -147
  32. package/src/context/types.ts +0 -11
  33. package/src/db/Replication.ts +0 -84
  34. package/src/db/constants.ts +0 -10
  35. package/src/db/couch/DatabaseImpl.ts +0 -238
  36. package/src/db/couch/connections.ts +0 -77
  37. package/src/db/couch/index.ts +0 -5
  38. package/src/db/couch/pouchDB.ts +0 -97
  39. package/src/db/couch/pouchDump.ts +0 -0
  40. package/src/db/couch/utils.ts +0 -50
  41. package/src/db/db.ts +0 -39
  42. package/src/db/errors.ts +0 -14
  43. package/src/db/index.ts +0 -12
  44. package/src/db/lucene.ts +0 -732
  45. package/src/db/searchIndexes/index.ts +0 -1
  46. package/src/db/searchIndexes/searchIndexes.ts +0 -62
  47. package/src/db/tests/index.spec.js +0 -25
  48. package/src/db/tests/lucene.spec.ts +0 -298
  49. package/src/db/tests/pouch.spec.js +0 -62
  50. package/src/db/tests/utils.spec.ts +0 -63
  51. package/src/db/utils.ts +0 -207
  52. package/src/db/views.ts +0 -241
  53. package/src/docIds/conversions.ts +0 -59
  54. package/src/docIds/ids.ts +0 -113
  55. package/src/docIds/index.ts +0 -2
  56. package/src/docIds/newid.ts +0 -5
  57. package/src/docIds/params.ts +0 -174
  58. package/src/docUpdates/index.ts +0 -29
  59. package/src/environment.ts +0 -201
  60. package/src/errors/errors.ts +0 -119
  61. package/src/errors/index.ts +0 -1
  62. package/src/events/analytics.ts +0 -6
  63. package/src/events/asyncEvents/index.ts +0 -2
  64. package/src/events/asyncEvents/publisher.ts +0 -12
  65. package/src/events/asyncEvents/queue.ts +0 -22
  66. package/src/events/backfill.ts +0 -183
  67. package/src/events/documentId.ts +0 -56
  68. package/src/events/events.ts +0 -40
  69. package/src/events/identification.ts +0 -310
  70. package/src/events/index.ts +0 -14
  71. package/src/events/processors/AnalyticsProcessor.ts +0 -64
  72. package/src/events/processors/AuditLogsProcessor.ts +0 -93
  73. package/src/events/processors/LoggingProcessor.ts +0 -37
  74. package/src/events/processors/Processors.ts +0 -52
  75. package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -43
  76. package/src/events/processors/index.ts +0 -19
  77. package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
  78. package/src/events/processors/posthog/index.ts +0 -2
  79. package/src/events/processors/posthog/rateLimiting.ts +0 -106
  80. package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -168
  81. package/src/events/processors/types.ts +0 -1
  82. package/src/events/publishers/account.ts +0 -35
  83. package/src/events/publishers/app.ts +0 -155
  84. package/src/events/publishers/auditLog.ts +0 -26
  85. package/src/events/publishers/auth.ts +0 -73
  86. package/src/events/publishers/automation.ts +0 -110
  87. package/src/events/publishers/backfill.ts +0 -74
  88. package/src/events/publishers/backup.ts +0 -42
  89. package/src/events/publishers/datasource.ts +0 -48
  90. package/src/events/publishers/email.ts +0 -17
  91. package/src/events/publishers/environmentVariable.ts +0 -38
  92. package/src/events/publishers/group.ts +0 -99
  93. package/src/events/publishers/index.ts +0 -24
  94. package/src/events/publishers/installation.ts +0 -38
  95. package/src/events/publishers/layout.ts +0 -26
  96. package/src/events/publishers/license.ts +0 -84
  97. package/src/events/publishers/org.ts +0 -37
  98. package/src/events/publishers/plugin.ts +0 -47
  99. package/src/events/publishers/query.ts +0 -88
  100. package/src/events/publishers/role.ts +0 -62
  101. package/src/events/publishers/rows.ts +0 -29
  102. package/src/events/publishers/screen.ts +0 -36
  103. package/src/events/publishers/serve.ts +0 -43
  104. package/src/events/publishers/table.ts +0 -70
  105. package/src/events/publishers/user.ts +0 -202
  106. package/src/events/publishers/view.ts +0 -107
  107. package/src/featureFlags/index.ts +0 -77
  108. package/src/featureFlags/tests/featureFlags.spec.ts +0 -85
  109. package/src/helpers.ts +0 -9
  110. package/src/index.ts +0 -53
  111. package/src/installation.ts +0 -107
  112. package/src/logging/alerts.ts +0 -26
  113. package/src/logging/correlation/correlation.ts +0 -13
  114. package/src/logging/correlation/index.ts +0 -1
  115. package/src/logging/correlation/middleware.ts +0 -17
  116. package/src/logging/index.ts +0 -4
  117. package/src/logging/pino/logger.ts +0 -232
  118. package/src/logging/pino/middleware.ts +0 -45
  119. package/src/logging/system.ts +0 -81
  120. package/src/logging/tests/system.spec.ts +0 -61
  121. package/src/middleware/adminOnly.ts +0 -9
  122. package/src/middleware/auditLog.ts +0 -6
  123. package/src/middleware/authenticated.ts +0 -193
  124. package/src/middleware/builderOnly.ts +0 -20
  125. package/src/middleware/builderOrAdmin.ts +0 -20
  126. package/src/middleware/csrf.ts +0 -81
  127. package/src/middleware/errorHandling.ts +0 -29
  128. package/src/middleware/index.ts +0 -21
  129. package/src/middleware/internalApi.ts +0 -23
  130. package/src/middleware/joi-validator.ts +0 -45
  131. package/src/middleware/matchers.ts +0 -47
  132. package/src/middleware/passport/datasource/google.ts +0 -95
  133. package/src/middleware/passport/local.ts +0 -54
  134. package/src/middleware/passport/sso/google.ts +0 -77
  135. package/src/middleware/passport/sso/oidc.ts +0 -154
  136. package/src/middleware/passport/sso/sso.ts +0 -165
  137. package/src/middleware/passport/sso/tests/google.spec.ts +0 -67
  138. package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -152
  139. package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
  140. package/src/middleware/passport/utils.ts +0 -38
  141. package/src/middleware/querystringToBody.ts +0 -28
  142. package/src/middleware/tenancy.ts +0 -36
  143. package/src/middleware/tests/builder.spec.ts +0 -180
  144. package/src/middleware/tests/matchers.spec.ts +0 -134
  145. package/src/migrations/definitions.ts +0 -40
  146. package/src/migrations/index.ts +0 -2
  147. package/src/migrations/migrations.ts +0 -191
  148. package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
  149. package/src/migrations/tests/migrations.spec.ts +0 -64
  150. package/src/objectStore/buckets/app.ts +0 -40
  151. package/src/objectStore/buckets/global.ts +0 -29
  152. package/src/objectStore/buckets/index.ts +0 -3
  153. package/src/objectStore/buckets/plugins.ts +0 -71
  154. package/src/objectStore/buckets/tests/app.spec.ts +0 -171
  155. package/src/objectStore/buckets/tests/global.spec.ts +0 -74
  156. package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
  157. package/src/objectStore/cloudfront.ts +0 -41
  158. package/src/objectStore/index.ts +0 -3
  159. package/src/objectStore/objectStore.ts +0 -440
  160. package/src/objectStore/utils.ts +0 -27
  161. package/src/platform/index.ts +0 -3
  162. package/src/platform/platformDb.ts +0 -6
  163. package/src/platform/tenants.ts +0 -101
  164. package/src/platform/tests/tenants.spec.ts +0 -26
  165. package/src/platform/users.ts +0 -90
  166. package/src/plugin/index.ts +0 -1
  167. package/src/plugin/tests/validation.spec.ts +0 -83
  168. package/src/plugin/utils.ts +0 -156
  169. package/src/queue/constants.ts +0 -6
  170. package/src/queue/inMemoryQueue.ts +0 -141
  171. package/src/queue/index.ts +0 -2
  172. package/src/queue/listeners.ts +0 -195
  173. package/src/queue/queue.ts +0 -54
  174. package/src/redis/index.ts +0 -6
  175. package/src/redis/init.ts +0 -86
  176. package/src/redis/redis.ts +0 -308
  177. package/src/redis/redlockImpl.ts +0 -139
  178. package/src/redis/utils.ts +0 -117
  179. package/src/security/encryption.ts +0 -179
  180. package/src/security/permissions.ts +0 -159
  181. package/src/security/roles.ts +0 -420
  182. package/src/security/sessions.ts +0 -120
  183. package/src/security/tests/encryption.spec.ts +0 -31
  184. package/src/security/tests/permissions.spec.ts +0 -145
  185. package/src/security/tests/sessions.spec.ts +0 -12
  186. package/src/tenancy/db.ts +0 -6
  187. package/src/tenancy/index.ts +0 -2
  188. package/src/tenancy/tenancy.ts +0 -140
  189. package/src/tenancy/tests/tenancy.spec.ts +0 -184
  190. package/src/timers/index.ts +0 -1
  191. package/src/timers/timers.ts +0 -22
  192. package/src/users/db.ts +0 -460
  193. package/src/users/events.ts +0 -176
  194. package/src/users/index.ts +0 -4
  195. package/src/users/lookup.ts +0 -102
  196. package/src/users/users.ts +0 -276
  197. package/src/users/utils.ts +0 -55
  198. package/src/utils/hashing.ts +0 -14
  199. package/src/utils/index.ts +0 -3
  200. package/src/utils/stringUtils.ts +0 -8
  201. package/src/utils/tests/utils.spec.ts +0 -191
  202. package/src/utils/utils.ts +0 -239
  203. package/tests/core/logging.ts +0 -34
  204. package/tests/core/utilities/index.ts +0 -6
  205. package/tests/core/utilities/jestUtils.ts +0 -30
  206. package/tests/core/utilities/mocks/alerts.ts +0 -3
  207. package/tests/core/utilities/mocks/date.ts +0 -2
  208. package/tests/core/utilities/mocks/events.ts +0 -131
  209. package/tests/core/utilities/mocks/fetch.ts +0 -17
  210. package/tests/core/utilities/mocks/index.ts +0 -10
  211. package/tests/core/utilities/mocks/licenses.ts +0 -107
  212. package/tests/core/utilities/mocks/posthog.ts +0 -7
  213. package/tests/core/utilities/structures/Chance.ts +0 -20
  214. package/tests/core/utilities/structures/accounts.ts +0 -115
  215. package/tests/core/utilities/structures/apps.ts +0 -21
  216. package/tests/core/utilities/structures/common.ts +0 -7
  217. package/tests/core/utilities/structures/db.ts +0 -12
  218. package/tests/core/utilities/structures/documents/index.ts +0 -1
  219. package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
  220. package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
  221. package/tests/core/utilities/structures/generator.ts +0 -2
  222. package/tests/core/utilities/structures/index.ts +0 -15
  223. package/tests/core/utilities/structures/koa.ts +0 -16
  224. package/tests/core/utilities/structures/licenses.ts +0 -167
  225. package/tests/core/utilities/structures/plugins.ts +0 -19
  226. package/tests/core/utilities/structures/quotas.ts +0 -67
  227. package/tests/core/utilities/structures/scim.ts +0 -80
  228. package/tests/core/utilities/structures/shared.ts +0 -19
  229. package/tests/core/utilities/structures/sso.ts +0 -119
  230. package/tests/core/utilities/structures/tenants.ts +0 -5
  231. package/tests/core/utilities/structures/userGroups.ts +0 -10
  232. package/tests/core/utilities/structures/users.ts +0 -73
  233. package/tests/core/utilities/testContainerUtils.ts +0 -98
  234. package/tests/core/utilities/utils/index.ts +0 -1
  235. package/tests/core/utilities/utils/time.ts +0 -3
  236. package/tests/extra/DBTestConfiguration.ts +0 -36
  237. package/tests/extra/index.ts +0 -2
  238. package/tests/extra/testEnv.ts +0 -95
  239. package/tests/index.ts +0 -1
  240. package/tests/jestEnv.ts +0 -6
  241. package/tests/jestSetup.ts +0 -28
@@ -1,165 +0,0 @@
1
- import { generateGlobalUserID } from "../../../db"
2
- import { authError } from "../utils"
3
- import * as users from "../../../users"
4
- import * as context from "../../../context"
5
- import fetch from "node-fetch"
6
- import {
7
- SaveSSOUserFunction,
8
- SaveUserOpts,
9
- SSOAuthDetails,
10
- SSOUser,
11
- User,
12
- } from "@budibase/types"
13
-
14
- // no-op function for user save
15
- // - this allows datasource auth and access token refresh to work correctly
16
- // - prefer no-op over an optional argument to ensure function is provided to login flows
17
- export const ssoSaveUserNoOp: SaveSSOUserFunction = (
18
- user: SSOUser,
19
- opts: SaveUserOpts
20
- ) => Promise.resolve(user)
21
-
22
- /**
23
- * Common authentication logic for third parties. e.g. OAuth, OIDC.
24
- */
25
- export async function authenticate(
26
- details: SSOAuthDetails,
27
- requireLocalAccount: boolean = true,
28
- done: any,
29
- saveUserFn: SaveSSOUserFunction
30
- ) {
31
- if (!saveUserFn) {
32
- throw new Error("Save user function must be provided")
33
- }
34
- if (!details.userId) {
35
- return authError(done, "sso user id required")
36
- }
37
- if (!details.email) {
38
- return authError(done, "sso user email required")
39
- }
40
-
41
- // use the third party id
42
- const userId = generateGlobalUserID(details.userId)
43
-
44
- let dbUser: User | undefined
45
-
46
- // try to load by id
47
- try {
48
- dbUser = await users.getById(userId)
49
- } catch (err: any) {
50
- // abort when not 404 error
51
- if (!err.status || err.status !== 404) {
52
- return authError(
53
- done,
54
- "Unexpected error when retrieving existing user",
55
- err
56
- )
57
- }
58
- }
59
-
60
- // fallback to loading by email
61
- if (!dbUser) {
62
- dbUser = await users.getGlobalUserByEmail(details.email)
63
- }
64
-
65
- // exit early if there is still no user and auto creation is disabled
66
- if (!dbUser && requireLocalAccount) {
67
- return authError(
68
- done,
69
- "Email does not yet exist. You must set up your local budibase account first."
70
- )
71
- }
72
-
73
- // first time creation
74
- if (!dbUser) {
75
- // setup a blank user using the third party id
76
- dbUser = {
77
- _id: userId,
78
- email: details.email,
79
- roles: {},
80
- tenantId: context.getTenantId(),
81
- }
82
- }
83
-
84
- let ssoUser = await syncUser(dbUser, details)
85
- // never prompt for password reset
86
- ssoUser.forceResetPassword = false
87
-
88
- try {
89
- // don't try to re-save any existing password
90
- delete ssoUser.password
91
- // create or sync the user
92
- ssoUser = (await saveUserFn(ssoUser, {
93
- hashPassword: false,
94
- requirePassword: false,
95
- })) as SSOUser
96
- } catch (err: any) {
97
- return authError(done, "Error saving user", err)
98
- }
99
-
100
- return done(null, ssoUser)
101
- }
102
-
103
- async function getProfilePictureUrl(user: User, details: SSOAuthDetails) {
104
- const pictureUrl = details.profile?._json.picture
105
- if (pictureUrl) {
106
- const response = await fetch(pictureUrl)
107
- if (response.status === 200) {
108
- const type = response.headers.get("content-type") as string
109
- if (type.startsWith("image/")) {
110
- return pictureUrl
111
- }
112
- }
113
- }
114
- }
115
-
116
- /**
117
- * @returns a user that has been sync'd with third party information
118
- */
119
- async function syncUser(user: User, details: SSOAuthDetails): Promise<SSOUser> {
120
- let firstName
121
- let lastName
122
- let pictureUrl
123
- let oauth2
124
- let thirdPartyProfile
125
-
126
- if (details.profile) {
127
- const profile = details.profile
128
-
129
- if (profile.name) {
130
- const name = profile.name
131
- // first name
132
- if (name.givenName) {
133
- firstName = name.givenName
134
- }
135
- // last name
136
- if (name.familyName) {
137
- lastName = name.familyName
138
- }
139
- }
140
-
141
- pictureUrl = await getProfilePictureUrl(user, details)
142
-
143
- thirdPartyProfile = {
144
- ...profile._json,
145
- }
146
- }
147
-
148
- // oauth tokens for future use
149
- if (details.oauth2) {
150
- oauth2 = {
151
- ...details.oauth2,
152
- }
153
- }
154
-
155
- return {
156
- ...user,
157
- provider: details.provider,
158
- providerType: details.providerType,
159
- firstName,
160
- lastName,
161
- thirdPartyProfile,
162
- pictureUrl,
163
- oauth2,
164
- }
165
- }
@@ -1,67 +0,0 @@
1
- import { generator, structures } from "../../../../../tests"
2
- import { SSOProviderType } from "@budibase/types"
3
-
4
- jest.mock("passport-google-oauth")
5
- const mockStrategy = require("passport-google-oauth").OAuth2Strategy
6
-
7
- jest.mock("../sso")
8
- import * as _sso from "../sso"
9
- const sso = jest.mocked(_sso)
10
-
11
- const mockSaveUserFn = jest.fn()
12
- const mockDone = jest.fn()
13
-
14
- import * as google from "../google"
15
-
16
- describe("google", () => {
17
- describe("strategyFactory", () => {
18
- const googleConfig = structures.sso.googleConfig()
19
- const callbackUrl = generator.url()
20
-
21
- it("should create successfully create a google strategy", async () => {
22
- await google.strategyFactory(googleConfig, callbackUrl, mockSaveUserFn)
23
-
24
- const expectedOptions = {
25
- clientID: googleConfig.clientID,
26
- clientSecret: googleConfig.clientSecret,
27
- callbackURL: callbackUrl,
28
- }
29
-
30
- expect(mockStrategy).toHaveBeenCalledWith(
31
- expectedOptions,
32
- expect.anything()
33
- )
34
- })
35
- })
36
-
37
- describe("authenticate", () => {
38
- const details = structures.sso.authDetails()
39
- details.provider = "google"
40
- details.providerType = SSOProviderType.GOOGLE
41
-
42
- const profile = details.profile!
43
- profile.provider = "google"
44
-
45
- beforeEach(() => {
46
- jest.clearAllMocks()
47
- })
48
-
49
- it("delegates authentication to third party common", async () => {
50
- const authenticate = await google.buildVerifyFn(mockSaveUserFn)
51
-
52
- await authenticate(
53
- details.oauth2.accessToken,
54
- details.oauth2.refreshToken!,
55
- profile,
56
- mockDone
57
- )
58
-
59
- expect(sso.authenticate).toHaveBeenCalledWith(
60
- details,
61
- true,
62
- mockDone,
63
- mockSaveUserFn
64
- )
65
- })
66
- })
67
- })
@@ -1,152 +0,0 @@
1
- import { generator, mocks, structures } from "../../../../../tests"
2
- import {
3
- JwtClaims,
4
- OIDCInnerConfig,
5
- SSOAuthDetails,
6
- SSOProviderType,
7
- } from "@budibase/types"
8
- import * as _sso from "../sso"
9
- import * as oidc from "../oidc"
10
-
11
- jest.mock("@techpass/passport-openidconnect")
12
- const mockStrategy = require("@techpass/passport-openidconnect").Strategy
13
-
14
- jest.mock("../sso")
15
- const sso = jest.mocked(_sso)
16
-
17
- const mockSaveUser = jest.fn()
18
- const mockDone = jest.fn()
19
-
20
- describe("oidc", () => {
21
- const callbackUrl = generator.url()
22
- const oidcConfig: OIDCInnerConfig = structures.sso.oidcConfig()
23
- const wellKnownConfig = structures.sso.oidcWellKnownConfig()
24
-
25
- function mockRetrieveWellKnownConfig() {
26
- // mock the request to retrieve the oidc configuration
27
- mocks.fetch.mockReturnValue({
28
- ok: true,
29
- json: () => wellKnownConfig,
30
- })
31
- }
32
-
33
- beforeEach(() => {
34
- mockRetrieveWellKnownConfig()
35
- })
36
-
37
- describe("strategyFactory", () => {
38
- it("should create successfully create an oidc strategy", async () => {
39
- const strategyConfiguration = await oidc.fetchStrategyConfig(
40
- oidcConfig,
41
- callbackUrl
42
- )
43
- await oidc.strategyFactory(strategyConfiguration, mockSaveUser)
44
-
45
- expect(mocks.fetch).toHaveBeenCalledWith(oidcConfig.configUrl)
46
-
47
- const expectedOptions = {
48
- issuer: wellKnownConfig.issuer,
49
- authorizationURL: wellKnownConfig.authorization_endpoint,
50
- tokenURL: wellKnownConfig.token_endpoint,
51
- userInfoURL: wellKnownConfig.userinfo_endpoint,
52
- clientID: oidcConfig.clientID,
53
- clientSecret: oidcConfig.clientSecret,
54
- callbackURL: callbackUrl,
55
- }
56
- expect(mockStrategy).toHaveBeenCalledWith(
57
- expectedOptions,
58
- expect.anything()
59
- )
60
- })
61
- })
62
-
63
- describe("authenticate", () => {
64
- const details: SSOAuthDetails = structures.sso.authDetails()
65
- details.providerType = SSOProviderType.OIDC
66
- const profile = details.profile!
67
- const issuer = profile.provider
68
-
69
- const sub = generator.string()
70
- const idToken = generator.string()
71
- const params = {}
72
-
73
- let authenticateFn: any
74
- let jwtClaims: JwtClaims
75
-
76
- beforeEach(async () => {
77
- jest.clearAllMocks()
78
- authenticateFn = await oidc.buildVerifyFn(mockSaveUser)
79
- })
80
-
81
- async function authenticate() {
82
- await authenticateFn(
83
- issuer,
84
- sub,
85
- profile,
86
- jwtClaims,
87
- details.oauth2.accessToken,
88
- details.oauth2.refreshToken,
89
- idToken,
90
- params,
91
- mockDone
92
- )
93
- }
94
-
95
- it("passes auth details to sso module", async () => {
96
- await authenticate()
97
-
98
- expect(sso.authenticate).toHaveBeenCalledWith(
99
- details,
100
- false,
101
- mockDone,
102
- mockSaveUser
103
- )
104
- })
105
-
106
- it("uses JWT email to get email", async () => {
107
- delete profile._json.email
108
-
109
- jwtClaims = {
110
- email: details.email,
111
- }
112
-
113
- await authenticate()
114
-
115
- expect(sso.authenticate).toHaveBeenCalledWith(
116
- details,
117
- false,
118
- mockDone,
119
- mockSaveUser
120
- )
121
- })
122
-
123
- it("uses JWT username to get email", async () => {
124
- delete profile._json.email
125
-
126
- jwtClaims = {
127
- email: details.email,
128
- }
129
-
130
- await authenticate()
131
-
132
- expect(sso.authenticate).toHaveBeenCalledWith(
133
- details,
134
- false,
135
- mockDone,
136
- mockSaveUser
137
- )
138
- })
139
-
140
- it("uses JWT invalid username to get email", async () => {
141
- delete profile._json.email
142
-
143
- jwtClaims = {
144
- preferred_username: "invalidUsername",
145
- }
146
-
147
- await expect(authenticate()).rejects.toThrow(
148
- "Could not determine user email from profile"
149
- )
150
- })
151
- })
152
- })
@@ -1,197 +0,0 @@
1
- import { structures, mocks } from "../../../../../tests"
2
- import { testEnv } from "../../../../../tests/extra"
3
- import { SSOAuthDetails, User } from "@budibase/types"
4
-
5
- import { HTTPError } from "../../../../errors"
6
- import * as sso from "../sso"
7
- import * as context from "../../../../context"
8
-
9
- const mockDone = jest.fn()
10
- const mockSaveUser = jest.fn()
11
-
12
- jest.mock("../../../../users")
13
- import * as _users from "../../../../users"
14
- const users = jest.mocked(_users)
15
-
16
- const getErrorMessage = () => {
17
- return mockDone.mock.calls[0][2].message
18
- }
19
-
20
- describe("sso", () => {
21
- describe("authenticate", () => {
22
- beforeEach(() => {
23
- jest.clearAllMocks()
24
- testEnv.singleTenant()
25
- })
26
-
27
- describe("validation", () => {
28
- const testValidation = async (
29
- details: SSOAuthDetails,
30
- message: string
31
- ) => {
32
- await sso.authenticate(details, false, mockDone, mockSaveUser)
33
-
34
- expect(mockDone.mock.calls.length).toBe(1)
35
- expect(getErrorMessage()).toContain(message)
36
- }
37
-
38
- it("user id fails", async () => {
39
- const details = structures.sso.authDetails()
40
- details.userId = undefined!
41
-
42
- await testValidation(details, "sso user id required")
43
- })
44
-
45
- it("email fails", async () => {
46
- const details = structures.sso.authDetails()
47
- details.email = undefined!
48
-
49
- await testValidation(details, "sso user email required")
50
- })
51
- })
52
-
53
- function mockGetProfilePicture() {
54
- mocks.fetch.mockReturnValueOnce(
55
- Promise.resolve({
56
- status: 200,
57
- headers: { get: () => "image/" },
58
- })
59
- )
60
- }
61
-
62
- describe("when the user doesn't exist", () => {
63
- let user: User
64
- let details: SSOAuthDetails
65
-
66
- beforeEach(() => {
67
- users.getById.mockImplementationOnce(() => {
68
- throw new HTTPError("", 404)
69
- })
70
- mockGetProfilePicture()
71
-
72
- user = structures.users.user()
73
- delete user._rev
74
- delete user._id
75
-
76
- details = structures.sso.authDetails(user)
77
- details.userId = structures.uuid()
78
- })
79
-
80
- describe("when a local account is required", () => {
81
- it("returns an error message", async () => {
82
- const details = structures.sso.authDetails()
83
-
84
- await sso.authenticate(details, true, mockDone, mockSaveUser)
85
-
86
- expect(mockDone.mock.calls.length).toBe(1)
87
- expect(getErrorMessage()).toContain(
88
- "Email does not yet exist. You must set up your local budibase account first."
89
- )
90
- })
91
- })
92
-
93
- describe("when a local account isn't required", () => {
94
- it("creates and authenticates the user", async () => {
95
- const ssoUser = structures.users.ssoUser({ user, details })
96
- mockSaveUser.mockReturnValueOnce(ssoUser)
97
-
98
- await sso.authenticate(details, false, mockDone, mockSaveUser)
99
-
100
- // default roles for new user
101
- ssoUser.roles = {}
102
-
103
- // modified external id to match user format
104
- ssoUser._id = "us_" + details.userId
105
-
106
- // new sso user won't have a password
107
- delete ssoUser.password
108
-
109
- // new user isn't saved with rev
110
- delete ssoUser._rev
111
-
112
- // tenant id added
113
- ssoUser.tenantId = context.getTenantId()
114
-
115
- expect(mockSaveUser).toBeCalledWith(ssoUser, {
116
- hashPassword: false,
117
- requirePassword: false,
118
- })
119
- expect(mockDone).toBeCalledWith(null, ssoUser)
120
- })
121
- })
122
- })
123
-
124
- describe("when the user exists", () => {
125
- let existingUser: User
126
- let details: SSOAuthDetails
127
-
128
- beforeEach(() => {
129
- existingUser = structures.users.user()
130
- existingUser._id = structures.uuid()
131
- details = structures.sso.authDetails(existingUser)
132
- mockGetProfilePicture()
133
- })
134
-
135
- describe("exists by email", () => {
136
- beforeEach(() => {
137
- users.getById.mockImplementationOnce(() => {
138
- throw new HTTPError("", 404)
139
- })
140
- users.getGlobalUserByEmail.mockReturnValueOnce(
141
- Promise.resolve(existingUser)
142
- )
143
- })
144
-
145
- it("syncs and authenticates the user", async () => {
146
- const ssoUser = structures.users.ssoUser({
147
- user: existingUser,
148
- details,
149
- })
150
- mockSaveUser.mockReturnValueOnce(ssoUser)
151
-
152
- await sso.authenticate(details, true, mockDone, mockSaveUser)
153
-
154
- // roles preserved
155
- ssoUser.roles = existingUser.roles
156
-
157
- // existing id preserved
158
- ssoUser._id = existingUser._id
159
-
160
- expect(mockSaveUser).toBeCalledWith(ssoUser, {
161
- hashPassword: false,
162
- requirePassword: false,
163
- })
164
- expect(mockDone).toBeCalledWith(null, ssoUser)
165
- })
166
- })
167
-
168
- describe("exists by id", () => {
169
- beforeEach(() => {
170
- users.getById.mockReturnValueOnce(Promise.resolve(existingUser))
171
- })
172
-
173
- it("syncs and authenticates the user", async () => {
174
- const ssoUser = structures.users.ssoUser({
175
- user: existingUser,
176
- details,
177
- })
178
- mockSaveUser.mockReturnValueOnce(ssoUser)
179
-
180
- await sso.authenticate(details, true, mockDone, mockSaveUser)
181
-
182
- // roles preserved
183
- ssoUser.roles = existingUser.roles
184
-
185
- // existing id preserved
186
- ssoUser._id = existingUser._id
187
-
188
- expect(mockSaveUser).toBeCalledWith(ssoUser, {
189
- hashPassword: false,
190
- requirePassword: false,
191
- })
192
- expect(mockDone).toBeCalledWith(null, ssoUser)
193
- })
194
- })
195
- })
196
- })
197
- })
@@ -1,38 +0,0 @@
1
- import { getTenantId, isMultiTenant } from "../../context"
2
- import * as configs from "../../configs"
3
- import { ConfigType, GoogleInnerConfig } from "@budibase/types"
4
-
5
- /**
6
- * Utility to handle authentication errors.
7
- *
8
- * @param {*} done The passport callback.
9
- * @param {*} message Message that will be returned in the response body
10
- * @param {*} err (Optional) error that will be logged
11
- */
12
-
13
- export function authError(done: Function, message: string, err?: any) {
14
- return done(
15
- err,
16
- null, // never return a user
17
- { message: message }
18
- )
19
- }
20
-
21
- export async function ssoCallbackUrl(
22
- type: ConfigType,
23
- config?: GoogleInnerConfig
24
- ) {
25
- // incase there is a callback URL from before
26
- if (config && (config as GoogleInnerConfig).callbackURL) {
27
- return (config as GoogleInnerConfig).callbackURL as string
28
- }
29
- const settingsConfig = await configs.getSettingsConfig()
30
-
31
- let callbackUrl = `/api/global/auth`
32
- if (isMultiTenant()) {
33
- callbackUrl += `/${getTenantId()}`
34
- }
35
- callbackUrl += `/${type}/callback`
36
-
37
- return `${settingsConfig.platformUrl}${callbackUrl}`
38
- }
@@ -1,28 +0,0 @@
1
- import { Ctx } from "@budibase/types"
2
-
3
- /**
4
- * Expects a standard "query" query string property which is the JSON body
5
- * of the request, which has to be sent via query string due to the requirement
6
- * of making an endpoint a GET request e.g. downloading a file stream.
7
- */
8
- export default function (ctx: Ctx, next: any) {
9
- const queryString = ctx.request.query?.query as string | undefined
10
- if (ctx.request.method.toLowerCase() !== "get") {
11
- ctx.throw(
12
- 500,
13
- "Query to download middleware can only be used for get requests."
14
- )
15
- }
16
- if (!queryString) {
17
- return next()
18
- }
19
- const decoded = decodeURIComponent(queryString)
20
- let json
21
- try {
22
- json = JSON.parse(decoded)
23
- } catch (err) {
24
- return next()
25
- }
26
- ctx.request.body = json
27
- return next()
28
- }
@@ -1,36 +0,0 @@
1
- import { doInTenant } from "../context"
2
- import { getTenantIDFromCtx } from "../tenancy"
3
- import { buildMatcherRegex, matches } from "./matchers"
4
- import { Header } from "../constants"
5
- import {
6
- BBContext,
7
- EndpointMatcher,
8
- GetTenantIdOptions,
9
- TenantResolutionStrategy,
10
- } from "@budibase/types"
11
-
12
- export default function (
13
- allowQueryStringPatterns: EndpointMatcher[],
14
- noTenancyPatterns: EndpointMatcher[],
15
- opts: { noTenancyRequired?: boolean } = { noTenancyRequired: false }
16
- ) {
17
- const allowQsOptions = buildMatcherRegex(allowQueryStringPatterns)
18
- const noTenancyOptions = buildMatcherRegex(noTenancyPatterns)
19
-
20
- return async function (ctx: BBContext | any, next: any) {
21
- const allowNoTenant =
22
- opts.noTenancyRequired || !!matches(ctx, noTenancyOptions)
23
- const tenantOpts: GetTenantIdOptions = {
24
- allowNoTenant,
25
- }
26
-
27
- const allowQs = !!matches(ctx, allowQsOptions)
28
- if (!allowQs) {
29
- tenantOpts.excludeStrategies = [TenantResolutionStrategy.QUERY]
30
- }
31
-
32
- const tenantId = getTenantIDFromCtx(ctx, tenantOpts)
33
- ctx.set(Header.TENANT_ID, tenantId as string)
34
- return doInTenant(tenantId, next)
35
- }
36
- }