@budibase/backend-core 2.9.19 → 2.9.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 (250) hide show
  1. package/dist/index.js +266 -324
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +19 -4
  5. package/dist/plugins.js +1 -1
  6. package/dist/plugins.js.map +1 -1
  7. package/dist/plugins.js.meta.json +1 -1
  8. package/dist/src/security/permissions.d.ts +1 -1
  9. package/dist/tests.js +222 -260
  10. package/dist/tests.js.map +4 -4
  11. package/dist/tests.js.meta.json +1 -1
  12. package/package.json +19 -4
  13. package/dist/tsconfig.build.tsbuildinfo +0 -1
  14. package/src/accounts/accounts.ts +0 -82
  15. package/src/accounts/api.ts +0 -59
  16. package/src/accounts/index.ts +0 -1
  17. package/src/auth/auth.ts +0 -208
  18. package/src/auth/index.ts +0 -1
  19. package/src/auth/tests/auth.spec.ts +0 -14
  20. package/src/blacklist/blacklist.ts +0 -54
  21. package/src/blacklist/index.ts +0 -1
  22. package/src/blacklist/tests/blacklist.spec.ts +0 -46
  23. package/src/cache/appMetadata.ts +0 -88
  24. package/src/cache/base/index.ts +0 -92
  25. package/src/cache/generic.ts +0 -30
  26. package/src/cache/index.ts +0 -5
  27. package/src/cache/tests/writethrough.spec.ts +0 -138
  28. package/src/cache/user.ts +0 -69
  29. package/src/cache/writethrough.ts +0 -133
  30. package/src/configs/configs.ts +0 -257
  31. package/src/configs/index.ts +0 -1
  32. package/src/configs/tests/configs.spec.ts +0 -184
  33. package/src/constants/db.ts +0 -63
  34. package/src/constants/index.ts +0 -2
  35. package/src/constants/misc.ts +0 -50
  36. package/src/context/Context.ts +0 -14
  37. package/src/context/identity.ts +0 -58
  38. package/src/context/index.ts +0 -3
  39. package/src/context/mainContext.ts +0 -310
  40. package/src/context/tests/index.spec.ts +0 -147
  41. package/src/context/types.ts +0 -11
  42. package/src/db/Replication.ts +0 -84
  43. package/src/db/constants.ts +0 -10
  44. package/src/db/couch/DatabaseImpl.ts +0 -238
  45. package/src/db/couch/connections.ts +0 -77
  46. package/src/db/couch/index.ts +0 -5
  47. package/src/db/couch/pouchDB.ts +0 -97
  48. package/src/db/couch/pouchDump.ts +0 -0
  49. package/src/db/couch/utils.ts +0 -50
  50. package/src/db/db.ts +0 -39
  51. package/src/db/errors.ts +0 -14
  52. package/src/db/index.ts +0 -12
  53. package/src/db/lucene.ts +0 -732
  54. package/src/db/searchIndexes/index.ts +0 -1
  55. package/src/db/searchIndexes/searchIndexes.ts +0 -62
  56. package/src/db/tests/index.spec.js +0 -25
  57. package/src/db/tests/lucene.spec.ts +0 -298
  58. package/src/db/tests/pouch.spec.js +0 -62
  59. package/src/db/tests/utils.spec.ts +0 -63
  60. package/src/db/utils.ts +0 -207
  61. package/src/db/views.ts +0 -241
  62. package/src/docIds/conversions.ts +0 -59
  63. package/src/docIds/ids.ts +0 -113
  64. package/src/docIds/index.ts +0 -2
  65. package/src/docIds/newid.ts +0 -5
  66. package/src/docIds/params.ts +0 -174
  67. package/src/docUpdates/index.ts +0 -29
  68. package/src/environment.ts +0 -201
  69. package/src/errors/errors.ts +0 -119
  70. package/src/errors/index.ts +0 -1
  71. package/src/events/analytics.ts +0 -6
  72. package/src/events/asyncEvents/index.ts +0 -2
  73. package/src/events/asyncEvents/publisher.ts +0 -12
  74. package/src/events/asyncEvents/queue.ts +0 -22
  75. package/src/events/backfill.ts +0 -183
  76. package/src/events/documentId.ts +0 -56
  77. package/src/events/events.ts +0 -40
  78. package/src/events/identification.ts +0 -310
  79. package/src/events/index.ts +0 -14
  80. package/src/events/processors/AnalyticsProcessor.ts +0 -64
  81. package/src/events/processors/AuditLogsProcessor.ts +0 -93
  82. package/src/events/processors/LoggingProcessor.ts +0 -37
  83. package/src/events/processors/Processors.ts +0 -52
  84. package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -43
  85. package/src/events/processors/index.ts +0 -19
  86. package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
  87. package/src/events/processors/posthog/index.ts +0 -2
  88. package/src/events/processors/posthog/rateLimiting.ts +0 -106
  89. package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -168
  90. package/src/events/processors/types.ts +0 -1
  91. package/src/events/publishers/account.ts +0 -35
  92. package/src/events/publishers/app.ts +0 -155
  93. package/src/events/publishers/auditLog.ts +0 -26
  94. package/src/events/publishers/auth.ts +0 -73
  95. package/src/events/publishers/automation.ts +0 -110
  96. package/src/events/publishers/backfill.ts +0 -74
  97. package/src/events/publishers/backup.ts +0 -42
  98. package/src/events/publishers/datasource.ts +0 -48
  99. package/src/events/publishers/email.ts +0 -17
  100. package/src/events/publishers/environmentVariable.ts +0 -38
  101. package/src/events/publishers/group.ts +0 -99
  102. package/src/events/publishers/index.ts +0 -24
  103. package/src/events/publishers/installation.ts +0 -38
  104. package/src/events/publishers/layout.ts +0 -26
  105. package/src/events/publishers/license.ts +0 -84
  106. package/src/events/publishers/org.ts +0 -37
  107. package/src/events/publishers/plugin.ts +0 -47
  108. package/src/events/publishers/query.ts +0 -88
  109. package/src/events/publishers/role.ts +0 -62
  110. package/src/events/publishers/rows.ts +0 -29
  111. package/src/events/publishers/screen.ts +0 -36
  112. package/src/events/publishers/serve.ts +0 -43
  113. package/src/events/publishers/table.ts +0 -70
  114. package/src/events/publishers/user.ts +0 -202
  115. package/src/events/publishers/view.ts +0 -107
  116. package/src/featureFlags/index.ts +0 -77
  117. package/src/featureFlags/tests/featureFlags.spec.ts +0 -85
  118. package/src/helpers.ts +0 -9
  119. package/src/index.ts +0 -53
  120. package/src/installation.ts +0 -107
  121. package/src/logging/alerts.ts +0 -26
  122. package/src/logging/correlation/correlation.ts +0 -13
  123. package/src/logging/correlation/index.ts +0 -1
  124. package/src/logging/correlation/middleware.ts +0 -17
  125. package/src/logging/index.ts +0 -4
  126. package/src/logging/pino/logger.ts +0 -232
  127. package/src/logging/pino/middleware.ts +0 -45
  128. package/src/logging/system.ts +0 -81
  129. package/src/logging/tests/system.spec.ts +0 -61
  130. package/src/middleware/adminOnly.ts +0 -9
  131. package/src/middleware/auditLog.ts +0 -6
  132. package/src/middleware/authenticated.ts +0 -193
  133. package/src/middleware/builderOnly.ts +0 -20
  134. package/src/middleware/builderOrAdmin.ts +0 -20
  135. package/src/middleware/csrf.ts +0 -81
  136. package/src/middleware/errorHandling.ts +0 -29
  137. package/src/middleware/index.ts +0 -21
  138. package/src/middleware/internalApi.ts +0 -23
  139. package/src/middleware/joi-validator.ts +0 -45
  140. package/src/middleware/matchers.ts +0 -47
  141. package/src/middleware/passport/datasource/google.ts +0 -95
  142. package/src/middleware/passport/local.ts +0 -54
  143. package/src/middleware/passport/sso/google.ts +0 -77
  144. package/src/middleware/passport/sso/oidc.ts +0 -154
  145. package/src/middleware/passport/sso/sso.ts +0 -165
  146. package/src/middleware/passport/sso/tests/google.spec.ts +0 -67
  147. package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -152
  148. package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
  149. package/src/middleware/passport/utils.ts +0 -38
  150. package/src/middleware/querystringToBody.ts +0 -28
  151. package/src/middleware/tenancy.ts +0 -36
  152. package/src/middleware/tests/builder.spec.ts +0 -180
  153. package/src/middleware/tests/matchers.spec.ts +0 -134
  154. package/src/migrations/definitions.ts +0 -40
  155. package/src/migrations/index.ts +0 -2
  156. package/src/migrations/migrations.ts +0 -191
  157. package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
  158. package/src/migrations/tests/migrations.spec.ts +0 -64
  159. package/src/objectStore/buckets/app.ts +0 -40
  160. package/src/objectStore/buckets/global.ts +0 -29
  161. package/src/objectStore/buckets/index.ts +0 -3
  162. package/src/objectStore/buckets/plugins.ts +0 -71
  163. package/src/objectStore/buckets/tests/app.spec.ts +0 -171
  164. package/src/objectStore/buckets/tests/global.spec.ts +0 -74
  165. package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
  166. package/src/objectStore/cloudfront.ts +0 -41
  167. package/src/objectStore/index.ts +0 -3
  168. package/src/objectStore/objectStore.ts +0 -440
  169. package/src/objectStore/utils.ts +0 -27
  170. package/src/platform/index.ts +0 -3
  171. package/src/platform/platformDb.ts +0 -6
  172. package/src/platform/tenants.ts +0 -101
  173. package/src/platform/tests/tenants.spec.ts +0 -26
  174. package/src/platform/users.ts +0 -90
  175. package/src/plugin/index.ts +0 -1
  176. package/src/plugin/tests/validation.spec.ts +0 -83
  177. package/src/plugin/utils.ts +0 -156
  178. package/src/queue/constants.ts +0 -6
  179. package/src/queue/inMemoryQueue.ts +0 -141
  180. package/src/queue/index.ts +0 -2
  181. package/src/queue/listeners.ts +0 -195
  182. package/src/queue/queue.ts +0 -54
  183. package/src/redis/index.ts +0 -6
  184. package/src/redis/init.ts +0 -86
  185. package/src/redis/redis.ts +0 -308
  186. package/src/redis/redlockImpl.ts +0 -139
  187. package/src/redis/utils.ts +0 -117
  188. package/src/security/encryption.ts +0 -179
  189. package/src/security/permissions.ts +0 -159
  190. package/src/security/roles.ts +0 -420
  191. package/src/security/sessions.ts +0 -120
  192. package/src/security/tests/encryption.spec.ts +0 -31
  193. package/src/security/tests/permissions.spec.ts +0 -145
  194. package/src/security/tests/sessions.spec.ts +0 -12
  195. package/src/tenancy/db.ts +0 -6
  196. package/src/tenancy/index.ts +0 -2
  197. package/src/tenancy/tenancy.ts +0 -140
  198. package/src/tenancy/tests/tenancy.spec.ts +0 -184
  199. package/src/timers/index.ts +0 -1
  200. package/src/timers/timers.ts +0 -22
  201. package/src/users/db.ts +0 -460
  202. package/src/users/events.ts +0 -176
  203. package/src/users/index.ts +0 -4
  204. package/src/users/lookup.ts +0 -102
  205. package/src/users/users.ts +0 -276
  206. package/src/users/utils.ts +0 -55
  207. package/src/utils/hashing.ts +0 -14
  208. package/src/utils/index.ts +0 -3
  209. package/src/utils/stringUtils.ts +0 -8
  210. package/src/utils/tests/utils.spec.ts +0 -191
  211. package/src/utils/utils.ts +0 -239
  212. package/tests/core/logging.ts +0 -34
  213. package/tests/core/utilities/index.ts +0 -6
  214. package/tests/core/utilities/jestUtils.ts +0 -30
  215. package/tests/core/utilities/mocks/alerts.ts +0 -3
  216. package/tests/core/utilities/mocks/date.ts +0 -2
  217. package/tests/core/utilities/mocks/events.ts +0 -131
  218. package/tests/core/utilities/mocks/fetch.ts +0 -17
  219. package/tests/core/utilities/mocks/index.ts +0 -10
  220. package/tests/core/utilities/mocks/licenses.ts +0 -107
  221. package/tests/core/utilities/mocks/posthog.ts +0 -7
  222. package/tests/core/utilities/structures/Chance.ts +0 -20
  223. package/tests/core/utilities/structures/accounts.ts +0 -115
  224. package/tests/core/utilities/structures/apps.ts +0 -21
  225. package/tests/core/utilities/structures/common.ts +0 -7
  226. package/tests/core/utilities/structures/db.ts +0 -12
  227. package/tests/core/utilities/structures/documents/index.ts +0 -1
  228. package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
  229. package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
  230. package/tests/core/utilities/structures/generator.ts +0 -2
  231. package/tests/core/utilities/structures/index.ts +0 -15
  232. package/tests/core/utilities/structures/koa.ts +0 -16
  233. package/tests/core/utilities/structures/licenses.ts +0 -167
  234. package/tests/core/utilities/structures/plugins.ts +0 -19
  235. package/tests/core/utilities/structures/quotas.ts +0 -67
  236. package/tests/core/utilities/structures/scim.ts +0 -80
  237. package/tests/core/utilities/structures/shared.ts +0 -19
  238. package/tests/core/utilities/structures/sso.ts +0 -119
  239. package/tests/core/utilities/structures/tenants.ts +0 -5
  240. package/tests/core/utilities/structures/userGroups.ts +0 -10
  241. package/tests/core/utilities/structures/users.ts +0 -73
  242. package/tests/core/utilities/testContainerUtils.ts +0 -98
  243. package/tests/core/utilities/utils/index.ts +0 -1
  244. package/tests/core/utilities/utils/time.ts +0 -3
  245. package/tests/extra/DBTestConfiguration.ts +0 -36
  246. package/tests/extra/index.ts +0 -2
  247. package/tests/extra/testEnv.ts +0 -95
  248. package/tests/index.ts +0 -1
  249. package/tests/jestEnv.ts +0 -6
  250. 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
- }