@budibase/worker 2.3.18-alpha.15 → 2.3.18-alpha.16

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.
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.18-alpha.15",
4
+ "version": "2.3.18-alpha.16",
5
5
  "description": "Budibase background service",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -36,10 +36,10 @@
36
36
  "author": "Budibase",
37
37
  "license": "GPL-3.0",
38
38
  "dependencies": {
39
- "@budibase/backend-core": "2.3.18-alpha.15",
40
- "@budibase/pro": "2.3.18-alpha.14",
41
- "@budibase/string-templates": "2.3.18-alpha.15",
42
- "@budibase/types": "2.3.18-alpha.15",
39
+ "@budibase/backend-core": "2.3.18-alpha.16",
40
+ "@budibase/pro": "2.3.18-alpha.15",
41
+ "@budibase/string-templates": "2.3.18-alpha.16",
42
+ "@budibase/types": "2.3.18-alpha.16",
43
43
  "@koa/router": "8.0.8",
44
44
  "@sentry/node": "6.17.7",
45
45
  "@techpass/passport-openidconnect": "0.3.2",
@@ -101,5 +101,5 @@
101
101
  "typescript": "4.7.3",
102
102
  "update-dotenv": "1.1.1"
103
103
  },
104
- "gitHead": "78287e11da6973374962afac59b35c598a54efc3"
104
+ "gitHead": "c350c15ae0869875936c804b89fcd46e4da4d8bb"
105
105
  }
@@ -17,10 +17,15 @@ import {
17
17
  Ctx,
18
18
  GetPublicOIDCConfigResponse,
19
19
  GetPublicSettingsResponse,
20
+ GoogleInnerConfig,
20
21
  isGoogleConfig,
21
22
  isOIDCConfig,
22
23
  isSettingsConfig,
23
24
  isSMTPConfig,
25
+ OIDCConfigs,
26
+ SettingsInnerConfig,
27
+ SSOConfig,
28
+ SSOConfigType,
24
29
  UserCtx,
25
30
  } from "@budibase/types"
26
31
  import * as pro from "@budibase/pro"
@@ -119,6 +124,61 @@ const getEventFns = async (config: Config, existing?: Config) => {
119
124
  return fns
120
125
  }
121
126
 
127
+ type SSOConfigs = { [key in SSOConfigType]: SSOConfig | undefined }
128
+
129
+ async function getSSOConfigs(): Promise<SSOConfigs> {
130
+ const google = await configs.getGoogleConfig()
131
+ const oidc = await configs.getOIDCConfig()
132
+ return {
133
+ [ConfigType.GOOGLE]: google,
134
+ [ConfigType.OIDC]: oidc,
135
+ }
136
+ }
137
+
138
+ async function hasActivatedConfig(ssoConfigs?: SSOConfigs) {
139
+ if (!ssoConfigs) {
140
+ ssoConfigs = await getSSOConfigs()
141
+ }
142
+ return !!Object.values(ssoConfigs).find(c => c?.activated)
143
+ }
144
+
145
+ async function verifySettingsConfig(config: SettingsInnerConfig) {
146
+ if (config.isSSOEnforced) {
147
+ const valid = await hasActivatedConfig()
148
+ if (!valid) {
149
+ throw new Error("Cannot enforce SSO without an activated configuration")
150
+ }
151
+ }
152
+ }
153
+
154
+ async function verifySSOConfig(type: SSOConfigType, config: SSOConfig) {
155
+ const settings = await configs.getSettingsConfig()
156
+ if (settings.isSSOEnforced && !config.activated) {
157
+ // config is being saved as deactivated
158
+ // ensure there is at least one other activated sso config
159
+ const ssoConfigs = await getSSOConfigs()
160
+
161
+ // overwrite the config being updated
162
+ // to reflect the desired state
163
+ ssoConfigs[type] = config
164
+
165
+ const activated = await hasActivatedConfig(ssoConfigs)
166
+ if (!activated) {
167
+ throw new Error(
168
+ "Configuration cannot be deactivated while SSO is enforced"
169
+ )
170
+ }
171
+ }
172
+ }
173
+
174
+ async function verifyGoogleConfig(config: GoogleInnerConfig) {
175
+ await verifySSOConfig(ConfigType.GOOGLE, config)
176
+ }
177
+
178
+ async function verifyOIDCConfig(config: OIDCConfigs) {
179
+ await verifySSOConfig(ConfigType.OIDC, config.configs[0])
180
+ }
181
+
122
182
  export async function save(ctx: UserCtx<Config>) {
123
183
  const body = ctx.request.body
124
184
  const type = body.type
@@ -133,10 +193,19 @@ export async function save(ctx: UserCtx<Config>) {
133
193
 
134
194
  try {
135
195
  // verify the configuration
136
- switch (config.type) {
196
+ switch (type) {
137
197
  case ConfigType.SMTP:
138
198
  await email.verifyConfig(config)
139
199
  break
200
+ case ConfigType.SETTINGS:
201
+ await verifySettingsConfig(config)
202
+ break
203
+ case ConfigType.GOOGLE:
204
+ await verifyGoogleConfig(config)
205
+ break
206
+ case ConfigType.OIDC:
207
+ await verifyOIDCConfig(config)
208
+ break
140
209
  }
141
210
  } catch (err: any) {
142
211
  ctx.throw(400, err)
@@ -34,8 +34,8 @@ function settingValidation() {
34
34
  function googleValidation() {
35
35
  // prettier-ignore
36
36
  return Joi.object({
37
- clientID: Joi.when('activated', { is: true, then: Joi.string().required() }),
38
- clientSecret: Joi.when('activated', { is: true, then: Joi.string().required() }),
37
+ clientID: Joi.string().required(),
38
+ clientSecret: Joi.string().required(),
39
39
  activated: Joi.boolean().required(),
40
40
  }).unknown(true)
41
41
  }
@@ -45,12 +45,12 @@ function oidcValidation() {
45
45
  return Joi.object({
46
46
  configs: Joi.array().items(
47
47
  Joi.object({
48
- clientID: Joi.when('activated', { is: true, then: Joi.string().required() }),
49
- clientSecret: Joi.when('activated', { is: true, then: Joi.string().required() }),
50
- configUrl: Joi.when('activated', { is: true, then: Joi.string().required() }),
48
+ clientID: Joi.string().required(),
49
+ clientSecret: Joi.string().required(),
50
+ configUrl: Joi.string().required(),
51
51
  logo: Joi.string().allow("", null),
52
52
  name: Joi.string().allow("", null),
53
- uuid: Joi.when('activated', { is: true, then: Joi.string().required() }),
53
+ uuid: Joi.string().required(),
54
54
  activated: Joi.boolean().required(),
55
55
  scopes: Joi.array().optional()
56
56
  })
@@ -203,7 +203,7 @@ export async function sendEmail(
203
203
  * @param {object} config an SMTP configuration - this is based on the nodemailer API.
204
204
  * @return {Promise<boolean>} returns true if the configuration is valid.
205
205
  */
206
- export async function verifyConfig(config: any) {
206
+ export async function verifyConfig(config: SMTPInnerConfig) {
207
207
  const transport = createSMTPTransport(config)
208
208
  await transport.verify()
209
209
  }