@budibase/worker 3.12.5 → 3.12.7
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/nodemon.json +2 -1
- package/package.json +6 -16
- package/src/api/controllers/global/configs.ts +78 -41
- package/src/api/controllers/global/users.ts +28 -13
- package/src/api/routes/global/tests/configs.spec.ts +122 -84
- package/src/api/routes/global/tests/users.spec.ts +18 -0
- package/src/environment.ts +8 -2
- package/src/index.ts +8 -6
- package/src/tests/TestConfiguration.ts +26 -9
- package/src/tests/api/configs.ts +8 -3
- package/src/tests/api/users.ts +8 -2
- package/src/tests/structures/configs.ts +9 -4
- package/scripts/account.js +0 -8
- package/scripts/dev/manage.js +0 -54
- package/scripts/localdomain.js +0 -52
- package/scripts/multiTenancy.js +0 -8
- package/scripts/selfhost.js +0 -8
package/nodemon.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/worker",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "3.12.
|
|
4
|
+
"version": "3.12.7",
|
|
5
5
|
"description": "Budibase background service",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -21,19 +21,10 @@
|
|
|
21
21
|
"run:docker": "node dist/index.js",
|
|
22
22
|
"debug": "yarn build && node --expose-gc --inspect=9223 dist/index.js",
|
|
23
23
|
"run:docker:cluster": "pm2-runtime start pm2.config.js",
|
|
24
|
-
"dev
|
|
25
|
-
"dev": "
|
|
26
|
-
"dev:built": "yarn run dev:stack:init && yarn run run:docker",
|
|
24
|
+
"dev": "nodemon",
|
|
25
|
+
"dev:built": "yarn run run:docker",
|
|
27
26
|
"test": "bash scripts/test.sh",
|
|
28
|
-
"test:watch": "jest --watch"
|
|
29
|
-
"env:multi:enable": "node scripts/multiTenancy.js enable",
|
|
30
|
-
"env:multi:disable": "node scripts/multiTenancy.js disable",
|
|
31
|
-
"env:selfhost:enable": "node scripts/selfhost.js enable",
|
|
32
|
-
"env:selfhost:disable": "node scripts/selfhost.js disable",
|
|
33
|
-
"env:localdomain:enable": "node scripts/localdomain.js enable",
|
|
34
|
-
"env:localdomain:disable": "node scripts/localdomain.js disable",
|
|
35
|
-
"env:account:enable": "node scripts/account.js enable",
|
|
36
|
-
"env:account:disable": "node scripts/account.js disable"
|
|
27
|
+
"test:watch": "jest --watch"
|
|
37
28
|
},
|
|
38
29
|
"author": "Budibase",
|
|
39
30
|
"license": "GPL-3.0",
|
|
@@ -102,8 +93,7 @@
|
|
|
102
93
|
"superagent": "^10.1.1",
|
|
103
94
|
"supertest": "6.3.3",
|
|
104
95
|
"timekeeper": "2.2.0",
|
|
105
|
-
"typescript": "5.7.2"
|
|
106
|
-
"update-dotenv": "1.1.1"
|
|
96
|
+
"typescript": "5.7.2"
|
|
107
97
|
},
|
|
108
98
|
"resolutions": {
|
|
109
99
|
"@budibase/pro": "npm:@budibase/pro@latest"
|
|
@@ -123,5 +113,5 @@
|
|
|
123
113
|
}
|
|
124
114
|
}
|
|
125
115
|
},
|
|
126
|
-
"gitHead": "
|
|
116
|
+
"gitHead": "87d0fd4e2bfa88a5f45312ce133670856957b97b"
|
|
127
117
|
}
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
} from "@budibase/backend-core"
|
|
14
14
|
import { checkAnyUserExists } from "../../../utilities/users"
|
|
15
15
|
import {
|
|
16
|
-
AIConfig,
|
|
17
16
|
AIInnerConfig,
|
|
18
17
|
Config,
|
|
19
18
|
ConfigChecklistResponse,
|
|
@@ -36,6 +35,7 @@ import {
|
|
|
36
35
|
SaveConfigResponse,
|
|
37
36
|
SettingsBrandingConfig,
|
|
38
37
|
SettingsInnerConfig,
|
|
38
|
+
SMTPInnerConfig,
|
|
39
39
|
SSOConfig,
|
|
40
40
|
SSOConfigType,
|
|
41
41
|
UploadConfigFileResponse,
|
|
@@ -158,7 +158,23 @@ async function hasActivatedConfig(ssoConfigs?: SSOConfigs) {
|
|
|
158
158
|
return !!Object.values(ssoConfigs).find(c => c?.activated)
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
async function
|
|
161
|
+
async function processSMTPConfig(
|
|
162
|
+
config: SMTPInnerConfig,
|
|
163
|
+
existingConfig?: SMTPInnerConfig
|
|
164
|
+
) {
|
|
165
|
+
await email.verifyConfig(config)
|
|
166
|
+
if (config.auth?.pass === PASSWORD_REPLACEMENT) {
|
|
167
|
+
// if the password is being replaced, use the existing password
|
|
168
|
+
if (existingConfig && existingConfig.auth?.pass) {
|
|
169
|
+
config.auth.pass = existingConfig.auth.pass
|
|
170
|
+
} else {
|
|
171
|
+
// otherwise, throw an error
|
|
172
|
+
throw new BadRequestError("SMTP password is required")
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function processSettingsConfig(
|
|
162
178
|
config: SettingsInnerConfig & SettingsBrandingConfig,
|
|
163
179
|
existingConfig?: SettingsInnerConfig & SettingsBrandingConfig
|
|
164
180
|
) {
|
|
@@ -203,19 +219,37 @@ async function verifySSOConfig(type: SSOConfigType, config: SSOConfig) {
|
|
|
203
219
|
}
|
|
204
220
|
}
|
|
205
221
|
|
|
206
|
-
async function
|
|
222
|
+
async function processGoogleConfig(
|
|
223
|
+
config: GoogleInnerConfig,
|
|
224
|
+
existing?: GoogleInnerConfig
|
|
225
|
+
) {
|
|
207
226
|
await verifySSOConfig(ConfigType.GOOGLE, config)
|
|
227
|
+
|
|
228
|
+
if (existing && config.clientSecret === PASSWORD_REPLACEMENT) {
|
|
229
|
+
config.clientSecret = existing.clientSecret
|
|
230
|
+
}
|
|
208
231
|
}
|
|
209
232
|
|
|
210
|
-
async function
|
|
233
|
+
async function processOIDCConfig(config: OIDCConfigs, existing?: OIDCConfigs) {
|
|
211
234
|
await verifySSOConfig(ConfigType.OIDC, config.configs[0])
|
|
235
|
+
|
|
236
|
+
if (existing) {
|
|
237
|
+
for (const c of config.configs) {
|
|
238
|
+
const existingConfig = existing.configs.find(e => e.uuid === c.uuid)
|
|
239
|
+
if (!existingConfig) {
|
|
240
|
+
continue
|
|
241
|
+
}
|
|
242
|
+
if (c.clientSecret === PASSWORD_REPLACEMENT) {
|
|
243
|
+
c.clientSecret = existingConfig.clientSecret
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
212
247
|
}
|
|
213
248
|
|
|
214
249
|
export async function processAIConfig(
|
|
215
250
|
newConfig: AIInnerConfig,
|
|
216
251
|
existingConfig: AIInnerConfig
|
|
217
252
|
) {
|
|
218
|
-
// ensure that the redacted API keys are not overwritten in the DB
|
|
219
253
|
for (const key in existingConfig) {
|
|
220
254
|
if (newConfig[key]?.apiKey === PASSWORD_REPLACEMENT) {
|
|
221
255
|
newConfig[key].apiKey = existingConfig[key].apiKey
|
|
@@ -256,16 +290,16 @@ export async function save(
|
|
|
256
290
|
try {
|
|
257
291
|
switch (type) {
|
|
258
292
|
case ConfigType.SMTP:
|
|
259
|
-
await
|
|
293
|
+
await processSMTPConfig(config, existingConfig?.config)
|
|
260
294
|
break
|
|
261
295
|
case ConfigType.SETTINGS:
|
|
262
|
-
await
|
|
296
|
+
await processSettingsConfig(config, existingConfig?.config)
|
|
263
297
|
break
|
|
264
298
|
case ConfigType.GOOGLE:
|
|
265
|
-
await
|
|
299
|
+
await processGoogleConfig(config, existingConfig?.config)
|
|
266
300
|
break
|
|
267
301
|
case ConfigType.OIDC:
|
|
268
|
-
await
|
|
302
|
+
await processOIDCConfig(config, existingConfig?.config)
|
|
269
303
|
break
|
|
270
304
|
case ConfigType.AI:
|
|
271
305
|
if (existingConfig) {
|
|
@@ -353,45 +387,48 @@ async function enrichOIDCLogos(oidcLogos: OIDCLogosConfig) {
|
|
|
353
387
|
}
|
|
354
388
|
|
|
355
389
|
export async function find(ctx: UserCtx<void, FindConfigResponse>) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
let scopedConfig = await configs.getConfig(type)
|
|
360
|
-
|
|
361
|
-
if (scopedConfig) {
|
|
362
|
-
await handleConfigType(type, scopedConfig)
|
|
363
|
-
} else if (type === ConfigType.AI) {
|
|
364
|
-
scopedConfig = { type: ConfigType.AI, config: {} }
|
|
365
|
-
await handleAIConfig(scopedConfig)
|
|
366
|
-
} else {
|
|
367
|
-
// If no config found and not AI type, just return an empty body
|
|
368
|
-
ctx.body = {}
|
|
369
|
-
return
|
|
370
|
-
}
|
|
390
|
+
// Find the config with the most granular scope based on context
|
|
391
|
+
const type = ctx.params.type
|
|
392
|
+
let config = await configs.getConfig(type)
|
|
371
393
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
394
|
+
if (!config && type === ConfigType.AI) {
|
|
395
|
+
config = { type: ConfigType.AI, config: {} }
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (!config) {
|
|
399
|
+
ctx.body = {}
|
|
400
|
+
return
|
|
375
401
|
}
|
|
376
|
-
}
|
|
377
402
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
403
|
+
switch (type) {
|
|
404
|
+
case ConfigType.OIDC_LOGOS:
|
|
405
|
+
await enrichOIDCLogos(config)
|
|
406
|
+
break
|
|
407
|
+
case ConfigType.AI:
|
|
408
|
+
await pro.sdk.ai.enrichAIConfig(config)
|
|
409
|
+
break
|
|
383
410
|
}
|
|
384
|
-
}
|
|
385
411
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
stripApiKeys(config)
|
|
412
|
+
stripSecrets(config)
|
|
413
|
+
ctx.body = config
|
|
389
414
|
}
|
|
390
415
|
|
|
391
|
-
function
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
config.config[key].apiKey
|
|
416
|
+
function stripSecrets(config: Config) {
|
|
417
|
+
if (isAIConfig(config)) {
|
|
418
|
+
for (const key in config.config) {
|
|
419
|
+
if (config.config[key].apiKey) {
|
|
420
|
+
config.config[key].apiKey = PASSWORD_REPLACEMENT
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
} else if (isSMTPConfig(config)) {
|
|
424
|
+
if (config.config.auth?.pass) {
|
|
425
|
+
config.config.auth.pass = PASSWORD_REPLACEMENT
|
|
426
|
+
}
|
|
427
|
+
} else if (isGoogleConfig(config)) {
|
|
428
|
+
config.config.clientSecret = PASSWORD_REPLACEMENT
|
|
429
|
+
} else if (isOIDCConfig(config)) {
|
|
430
|
+
for (const c of config.config.configs) {
|
|
431
|
+
c.clientSecret = PASSWORD_REPLACEMENT
|
|
395
432
|
}
|
|
396
433
|
}
|
|
397
434
|
}
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
SaveUserResponse,
|
|
34
34
|
SearchUsersRequest,
|
|
35
35
|
SearchUsersResponse,
|
|
36
|
+
StrippedUser,
|
|
36
37
|
UnsavedUser,
|
|
37
38
|
UpdateInviteRequest,
|
|
38
39
|
UpdateInviteResponse,
|
|
@@ -66,6 +67,15 @@ const generatePassword = (length: number) => {
|
|
|
66
67
|
.slice(0, length)
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
const stripUsers = (users: (User | StrippedUser)[]): StrippedUser[] => {
|
|
71
|
+
return users.map(user => ({
|
|
72
|
+
_id: user._id,
|
|
73
|
+
email: user.email,
|
|
74
|
+
tenantId: user.tenantId,
|
|
75
|
+
userId: user.userId,
|
|
76
|
+
}))
|
|
77
|
+
}
|
|
78
|
+
|
|
69
79
|
export const save = async (ctx: UserCtx<UnsavedUser, SaveUserResponse>) => {
|
|
70
80
|
try {
|
|
71
81
|
const currentUserId = ctx.user?._id
|
|
@@ -249,18 +259,8 @@ export const destroy = async (ctx: UserCtx<void, DeleteUserResponse>) => {
|
|
|
249
259
|
}
|
|
250
260
|
}
|
|
251
261
|
|
|
252
|
-
export const getAppUsers = async (ctx: Ctx<SearchUsersRequest>) => {
|
|
253
|
-
const body = ctx.request.body
|
|
254
|
-
const users = await userSdk.db.getUsersByAppAccess({
|
|
255
|
-
appId: body.appId,
|
|
256
|
-
limit: body.limit,
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
ctx.body = { data: users }
|
|
260
|
-
}
|
|
261
|
-
|
|
262
262
|
export const search = async (
|
|
263
|
-
ctx:
|
|
263
|
+
ctx: UserCtx<SearchUsersRequest, SearchUsersResponse>
|
|
264
264
|
) => {
|
|
265
265
|
const body = ctx.request.body
|
|
266
266
|
|
|
@@ -287,8 +287,13 @@ export const search = async (
|
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
+
let response: SearchUsersResponse = { data: [] }
|
|
291
|
+
|
|
290
292
|
if (body.paginate === false) {
|
|
291
|
-
await
|
|
293
|
+
response.data = await userSdk.db.getUsersByAppAccess({
|
|
294
|
+
appId: body.appId,
|
|
295
|
+
limit: body.limit,
|
|
296
|
+
})
|
|
292
297
|
} else {
|
|
293
298
|
const paginated = await userSdk.core.paginatedUsers(body)
|
|
294
299
|
// user hashed password shouldn't ever be returned
|
|
@@ -297,8 +302,18 @@ export const search = async (
|
|
|
297
302
|
delete user.password
|
|
298
303
|
}
|
|
299
304
|
}
|
|
300
|
-
|
|
305
|
+
response = {
|
|
306
|
+
data: paginated.data,
|
|
307
|
+
hasNextPage: paginated.hasNextPage,
|
|
308
|
+
nextPage: paginated.nextPage,
|
|
309
|
+
}
|
|
301
310
|
}
|
|
311
|
+
|
|
312
|
+
if (!users.hasBuilderPermissions(ctx.user)) {
|
|
313
|
+
response.data = stripUsers(response.data)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
ctx.body = response
|
|
302
317
|
}
|
|
303
318
|
|
|
304
319
|
// called internally by app server user fetch
|
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
// mock the email system
|
|
2
1
|
jest.mock("nodemailer")
|
|
3
2
|
import { TestConfiguration, structures, mocks } from "../../../../tests"
|
|
4
3
|
|
|
5
4
|
mocks.email.mock()
|
|
6
|
-
import { events } from "@budibase/backend-core"
|
|
5
|
+
import { configs, events } from "@budibase/backend-core"
|
|
7
6
|
import { GetPublicSettingsResponse, Config, ConfigType } from "@budibase/types"
|
|
8
7
|
|
|
8
|
+
const { google, smtp, settings, oidc } = structures.configs
|
|
9
|
+
|
|
9
10
|
describe("configs", () => {
|
|
10
11
|
const config = new TestConfiguration()
|
|
11
12
|
|
|
12
13
|
beforeEach(async () => {
|
|
13
14
|
await config.beforeAll()
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
15
|
jest.clearAllMocks()
|
|
18
16
|
})
|
|
19
17
|
|
|
@@ -22,38 +20,20 @@ describe("configs", () => {
|
|
|
22
20
|
})
|
|
23
21
|
|
|
24
22
|
const saveConfig = async (conf: Config, _id?: string, _rev?: string) => {
|
|
25
|
-
const data = {
|
|
26
|
-
...conf,
|
|
27
|
-
_id,
|
|
28
|
-
_rev,
|
|
29
|
-
}
|
|
23
|
+
const data = { ...conf, _id, _rev }
|
|
30
24
|
const res = await config.api.configs.saveConfig(data)
|
|
31
25
|
return { ...data, ...res }
|
|
32
26
|
}
|
|
33
27
|
|
|
34
|
-
const saveSettingsConfig = async (
|
|
35
|
-
conf?: any,
|
|
36
|
-
_id?: string,
|
|
37
|
-
_rev?: string
|
|
38
|
-
) => {
|
|
39
|
-
const settingsConfig = structures.configs.settings(conf)
|
|
40
|
-
return saveConfig(settingsConfig, _id, _rev)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
28
|
describe("POST /api/global/configs", () => {
|
|
44
29
|
describe("google", () => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
_rev?: string
|
|
49
|
-
) => {
|
|
50
|
-
const googleConfig = structures.configs.google(conf)
|
|
51
|
-
return saveConfig(googleConfig, _id, _rev)
|
|
52
|
-
}
|
|
30
|
+
afterEach(async () => {
|
|
31
|
+
await config.deleteConfig(ConfigType.GOOGLE)
|
|
32
|
+
})
|
|
53
33
|
|
|
54
34
|
describe("create", () => {
|
|
55
35
|
it("should create activated google config", async () => {
|
|
56
|
-
await
|
|
36
|
+
await saveConfig(google())
|
|
57
37
|
expect(events.auth.SSOCreated).toHaveBeenCalledTimes(1)
|
|
58
38
|
expect(events.auth.SSOCreated).toHaveBeenCalledWith(ConfigType.GOOGLE)
|
|
59
39
|
expect(events.auth.SSODeactivated).not.toHaveBeenCalled()
|
|
@@ -61,25 +41,23 @@ describe("configs", () => {
|
|
|
61
41
|
expect(events.auth.SSOActivated).toHaveBeenCalledWith(
|
|
62
42
|
ConfigType.GOOGLE
|
|
63
43
|
)
|
|
64
|
-
await config.deleteConfig(ConfigType.GOOGLE)
|
|
65
44
|
})
|
|
66
45
|
|
|
67
46
|
it("should create deactivated google config", async () => {
|
|
68
|
-
await
|
|
47
|
+
await saveConfig(google({ activated: false }))
|
|
69
48
|
expect(events.auth.SSOCreated).toHaveBeenCalledTimes(1)
|
|
70
49
|
expect(events.auth.SSOCreated).toHaveBeenCalledWith(ConfigType.GOOGLE)
|
|
71
50
|
expect(events.auth.SSOActivated).not.toHaveBeenCalled()
|
|
72
51
|
expect(events.auth.SSODeactivated).not.toHaveBeenCalled()
|
|
73
|
-
await config.deleteConfig(ConfigType.GOOGLE)
|
|
74
52
|
})
|
|
75
53
|
})
|
|
76
54
|
|
|
77
55
|
describe("update", () => {
|
|
78
56
|
it("should update google config to deactivated", async () => {
|
|
79
|
-
const googleConf = await
|
|
57
|
+
const googleConf = await saveConfig(google())
|
|
80
58
|
jest.clearAllMocks()
|
|
81
|
-
await
|
|
82
|
-
{
|
|
59
|
+
await saveConfig(
|
|
60
|
+
google({ activated: false }),
|
|
83
61
|
googleConf._id,
|
|
84
62
|
googleConf._rev
|
|
85
63
|
)
|
|
@@ -90,14 +68,13 @@ describe("configs", () => {
|
|
|
90
68
|
expect(events.auth.SSODeactivated).toHaveBeenCalledWith(
|
|
91
69
|
ConfigType.GOOGLE
|
|
92
70
|
)
|
|
93
|
-
await config.deleteConfig(ConfigType.GOOGLE)
|
|
94
71
|
})
|
|
95
72
|
|
|
96
73
|
it("should update google config to activated", async () => {
|
|
97
|
-
const googleConf = await
|
|
74
|
+
const googleConf = await saveConfig(google({ activated: false }))
|
|
98
75
|
jest.clearAllMocks()
|
|
99
|
-
await
|
|
100
|
-
{
|
|
76
|
+
await saveConfig(
|
|
77
|
+
google({ activated: true }),
|
|
101
78
|
googleConf._id,
|
|
102
79
|
googleConf._rev
|
|
103
80
|
)
|
|
@@ -108,48 +85,64 @@ describe("configs", () => {
|
|
|
108
85
|
expect(events.auth.SSOActivated).toHaveBeenCalledWith(
|
|
109
86
|
ConfigType.GOOGLE
|
|
110
87
|
)
|
|
111
|
-
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it("should not overwrite secret when updating google config", async () => {
|
|
91
|
+
await saveConfig(google({ clientSecret: "spooky" }))
|
|
92
|
+
|
|
93
|
+
const conf = await config.api.configs.getConfig(ConfigType.GOOGLE)
|
|
94
|
+
await saveConfig(conf)
|
|
95
|
+
|
|
96
|
+
await config.doInTenant(async () => {
|
|
97
|
+
const rawConf = await configs.getGoogleConfig()
|
|
98
|
+
expect(rawConf!.clientSecret).toEqual("spooky")
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
describe("get", () => {
|
|
104
|
+
it("should not leak credentials", async () => {
|
|
105
|
+
await saveConfig(google())
|
|
106
|
+
const conf = await config.api.configs.getConfig(ConfigType.GOOGLE)
|
|
107
|
+
expect(conf.config.clientSecret).toEqual("--secret-value--")
|
|
112
108
|
})
|
|
113
109
|
})
|
|
114
110
|
})
|
|
115
111
|
|
|
116
112
|
describe("oidc", () => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
) => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
113
|
+
beforeEach(async () => {
|
|
114
|
+
await config.deleteConfig(ConfigType.OIDC)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
afterEach(async () => {
|
|
118
|
+
await config.deleteConfig(ConfigType.OIDC)
|
|
119
|
+
})
|
|
125
120
|
|
|
126
121
|
describe("create", () => {
|
|
127
122
|
it("should create activated OIDC config", async () => {
|
|
128
|
-
await
|
|
123
|
+
await saveConfig(oidc())
|
|
129
124
|
expect(events.auth.SSOCreated).toHaveBeenCalledTimes(1)
|
|
130
125
|
expect(events.auth.SSOCreated).toHaveBeenCalledWith(ConfigType.OIDC)
|
|
131
126
|
expect(events.auth.SSODeactivated).not.toHaveBeenCalled()
|
|
132
127
|
expect(events.auth.SSOActivated).toHaveBeenCalledTimes(1)
|
|
133
128
|
expect(events.auth.SSOActivated).toHaveBeenCalledWith(ConfigType.OIDC)
|
|
134
|
-
await config.deleteConfig(ConfigType.OIDC)
|
|
135
129
|
})
|
|
136
130
|
|
|
137
131
|
it("should create deactivated OIDC config", async () => {
|
|
138
|
-
await
|
|
132
|
+
await saveConfig(oidc({ activated: false }))
|
|
139
133
|
expect(events.auth.SSOCreated).toHaveBeenCalledTimes(1)
|
|
140
134
|
expect(events.auth.SSOCreated).toHaveBeenCalledWith(ConfigType.OIDC)
|
|
141
135
|
expect(events.auth.SSOActivated).not.toHaveBeenCalled()
|
|
142
136
|
expect(events.auth.SSODeactivated).not.toHaveBeenCalled()
|
|
143
|
-
await config.deleteConfig(ConfigType.OIDC)
|
|
144
137
|
})
|
|
145
138
|
})
|
|
146
139
|
|
|
147
140
|
describe("update", () => {
|
|
148
141
|
it("should update OIDC config to deactivated", async () => {
|
|
149
|
-
const oidcConf = await
|
|
142
|
+
const oidcConf = await saveConfig(oidc())
|
|
150
143
|
jest.clearAllMocks()
|
|
151
|
-
await
|
|
152
|
-
{
|
|
144
|
+
await saveConfig(
|
|
145
|
+
oidc({ activated: false }),
|
|
153
146
|
oidcConf._id,
|
|
154
147
|
oidcConf._rev
|
|
155
148
|
)
|
|
@@ -160,14 +153,13 @@ describe("configs", () => {
|
|
|
160
153
|
expect(events.auth.SSODeactivated).toHaveBeenCalledWith(
|
|
161
154
|
ConfigType.OIDC
|
|
162
155
|
)
|
|
163
|
-
await config.deleteConfig(ConfigType.OIDC)
|
|
164
156
|
})
|
|
165
157
|
|
|
166
158
|
it("should update OIDC config to activated", async () => {
|
|
167
|
-
const oidcConf = await
|
|
159
|
+
const oidcConf = await saveConfig(oidc({ activated: false }))
|
|
168
160
|
jest.clearAllMocks()
|
|
169
|
-
await
|
|
170
|
-
{
|
|
161
|
+
await saveConfig(
|
|
162
|
+
oidc({ activated: true }),
|
|
171
163
|
oidcConf._id,
|
|
172
164
|
oidcConf._rev
|
|
173
165
|
)
|
|
@@ -176,50 +168,88 @@ describe("configs", () => {
|
|
|
176
168
|
expect(events.auth.SSODeactivated).not.toHaveBeenCalled()
|
|
177
169
|
expect(events.auth.SSOActivated).toHaveBeenCalledTimes(1)
|
|
178
170
|
expect(events.auth.SSOActivated).toHaveBeenCalledWith(ConfigType.OIDC)
|
|
179
|
-
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it("should not overwrite secret when updating OIDC config", async () => {
|
|
174
|
+
await saveConfig(oidc({ clientSecret: "spooky" }))
|
|
175
|
+
const conf = await config.api.configs.getConfig(ConfigType.OIDC)
|
|
176
|
+
await saveConfig(conf)
|
|
177
|
+
await config.doInTenant(async () => {
|
|
178
|
+
const rawConf = await configs.getOIDCConfig()
|
|
179
|
+
expect(rawConf!.clientSecret).toEqual("spooky")
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
describe("get", () => {
|
|
185
|
+
it("should not leak credentials", async () => {
|
|
186
|
+
await saveConfig(oidc({ clientSecret: "spooky" }))
|
|
187
|
+
const conf = await config.api.configs.getConfig(ConfigType.OIDC)
|
|
188
|
+
expect(conf.config.configs[0].clientSecret).toEqual(
|
|
189
|
+
"--secret-value--"
|
|
190
|
+
)
|
|
180
191
|
})
|
|
181
192
|
})
|
|
182
193
|
})
|
|
183
194
|
|
|
184
195
|
describe("smtp", () => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
) => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
196
|
+
beforeEach(async () => {
|
|
197
|
+
await config.deleteConfig(ConfigType.SMTP)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
afterEach(async () => {
|
|
201
|
+
await config.deleteConfig(ConfigType.SMTP)
|
|
202
|
+
})
|
|
193
203
|
|
|
194
204
|
describe("create", () => {
|
|
195
205
|
it("should create SMTP config", async () => {
|
|
196
|
-
await
|
|
197
|
-
await saveSMTPConfig()
|
|
206
|
+
await saveConfig(smtp())
|
|
198
207
|
expect(events.email.SMTPUpdated).not.toHaveBeenCalled()
|
|
199
208
|
expect(events.email.SMTPCreated).toHaveBeenCalledTimes(1)
|
|
200
|
-
await config.deleteConfig(ConfigType.SMTP)
|
|
201
209
|
})
|
|
202
210
|
})
|
|
203
211
|
|
|
204
212
|
describe("update", () => {
|
|
205
213
|
it("should update SMTP config", async () => {
|
|
206
|
-
const smtpConf = await
|
|
214
|
+
const smtpConf = await saveConfig(smtp())
|
|
207
215
|
jest.clearAllMocks()
|
|
208
|
-
await
|
|
216
|
+
await saveConfig(smtp({ secure: true }), smtpConf._id, smtpConf._rev)
|
|
209
217
|
expect(events.email.SMTPCreated).not.toHaveBeenCalled()
|
|
210
218
|
expect(events.email.SMTPUpdated).toHaveBeenCalledTimes(1)
|
|
211
|
-
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it("should not overwrite secret when updating SMTP config", async () => {
|
|
222
|
+
await saveConfig(smtp({ auth: { user: "jeff", pass: "spooky" } }))
|
|
223
|
+
const conf = await config.api.configs.getConfig(ConfigType.SMTP)
|
|
224
|
+
await saveConfig(conf)
|
|
225
|
+
await config.doInTenant(async () => {
|
|
226
|
+
const rawConf = await configs.getSMTPConfig()
|
|
227
|
+
expect(rawConf!.auth!.pass).toEqual("spooky")
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
describe("get", () => {
|
|
233
|
+
it("should not leak credentials", async () => {
|
|
234
|
+
await saveConfig(smtp({ auth: { user: "jeff", pass: "spooky" } }))
|
|
235
|
+
const conf = await config.api.configs.getConfig(ConfigType.SMTP)
|
|
236
|
+
expect(conf.config.auth!.pass).toEqual("--secret-value--")
|
|
212
237
|
})
|
|
213
238
|
})
|
|
214
239
|
})
|
|
215
240
|
|
|
216
241
|
describe("settings", () => {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
242
|
+
beforeEach(async () => {
|
|
243
|
+
await config.deleteConfig(ConfigType.SETTINGS)
|
|
244
|
+
})
|
|
220
245
|
|
|
221
|
-
|
|
246
|
+
afterEach(async () => {
|
|
247
|
+
await config.deleteConfig(ConfigType.SETTINGS)
|
|
248
|
+
})
|
|
222
249
|
|
|
250
|
+
describe("create", () => {
|
|
251
|
+
it("should create settings config with default settings", async () => {
|
|
252
|
+
await saveConfig(settings())
|
|
223
253
|
expect(events.org.nameUpdated).not.toHaveBeenCalled()
|
|
224
254
|
expect(events.org.logoUpdated).not.toHaveBeenCalled()
|
|
225
255
|
expect(events.org.platformURLUpdated).not.toHaveBeenCalled()
|
|
@@ -234,7 +264,7 @@ describe("configs", () => {
|
|
|
234
264
|
platformUrl: "http://example.com",
|
|
235
265
|
}
|
|
236
266
|
|
|
237
|
-
await
|
|
267
|
+
await saveConfig(settings(conf))
|
|
238
268
|
|
|
239
269
|
expect(events.org.nameUpdated).toHaveBeenCalledTimes(1)
|
|
240
270
|
expect(events.org.logoUpdated).toHaveBeenCalledTimes(1)
|
|
@@ -247,13 +277,13 @@ describe("configs", () => {
|
|
|
247
277
|
it("should update settings config", async () => {
|
|
248
278
|
config.selfHosted()
|
|
249
279
|
await config.deleteConfig(ConfigType.SETTINGS)
|
|
250
|
-
const settingsConfig = await
|
|
280
|
+
const settingsConfig = await saveConfig(settings())
|
|
251
281
|
settingsConfig.config.company = "acme"
|
|
252
282
|
settingsConfig.config.logoUrl = "http://example.com"
|
|
253
283
|
settingsConfig.config.platformUrl = "http://example.com"
|
|
254
284
|
|
|
255
|
-
await
|
|
256
|
-
settingsConfig
|
|
285
|
+
await saveConfig(
|
|
286
|
+
settingsConfig,
|
|
257
287
|
settingsConfig._id,
|
|
258
288
|
settingsConfig._rev
|
|
259
289
|
)
|
|
@@ -282,16 +312,24 @@ describe("configs", () => {
|
|
|
282
312
|
})
|
|
283
313
|
|
|
284
314
|
describe("GET /api/global/configs/public", () => {
|
|
315
|
+
beforeEach(async () => {
|
|
316
|
+
await config.deleteConfig(ConfigType.SETTINGS)
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
afterEach(async () => {
|
|
320
|
+
await config.deleteConfig(ConfigType.SETTINGS)
|
|
321
|
+
})
|
|
322
|
+
|
|
285
323
|
it("should return the expected public settings", async () => {
|
|
286
|
-
await
|
|
324
|
+
await saveConfig(settings())
|
|
287
325
|
mocks.pro.features.isSSOEnforced.mockResolvedValue(false)
|
|
288
326
|
|
|
289
327
|
const res = await config.api.configs.getPublicSettings()
|
|
290
328
|
const body = res.body as GetPublicSettingsResponse
|
|
291
329
|
|
|
292
330
|
const expected = {
|
|
293
|
-
_id:
|
|
294
|
-
type:
|
|
331
|
+
_id: `config_${ConfigType.SETTINGS}`,
|
|
332
|
+
type: ConfigType.SETTINGS,
|
|
295
333
|
config: {
|
|
296
334
|
company: "Budibase",
|
|
297
335
|
emailBrandingEnabled: true,
|
|
@@ -704,6 +704,24 @@ describe("/api/global/users", () => {
|
|
|
704
704
|
expect(response.body.data.length).toBe(1)
|
|
705
705
|
expect(response.body.data[0].email).toBe(user.email)
|
|
706
706
|
})
|
|
707
|
+
|
|
708
|
+
it("should strip users if accessing as an end user", async () => {
|
|
709
|
+
const user = await config.createUser({
|
|
710
|
+
admin: { global: false },
|
|
711
|
+
builder: { global: false },
|
|
712
|
+
})
|
|
713
|
+
const response = await config.api.users.searchUsers(
|
|
714
|
+
{
|
|
715
|
+
query: {},
|
|
716
|
+
},
|
|
717
|
+
{ useHeaders: await config.login(user) }
|
|
718
|
+
)
|
|
719
|
+
for (let user of response.body.data) {
|
|
720
|
+
expect(user.roles).toBeUndefined()
|
|
721
|
+
expect(user.builder).toBeUndefined()
|
|
722
|
+
expect(user.admin).toBeUndefined()
|
|
723
|
+
}
|
|
724
|
+
})
|
|
707
725
|
})
|
|
708
726
|
|
|
709
727
|
describe("DELETE /api/global/users/:userId", () => {
|
package/src/environment.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { env as coreEnv } from "@budibase/backend-core"
|
|
2
2
|
import { ServiceType } from "@budibase/types"
|
|
3
|
-
import { join } from "path"
|
|
3
|
+
import { join, resolve } from "path"
|
|
4
4
|
import cloneDeep from "lodash/cloneDeep"
|
|
5
5
|
|
|
6
6
|
coreEnv._set("SERVICE_TYPE", ServiceType.WORKER)
|
|
7
7
|
|
|
8
|
+
const TOP_LEVEL_PATH =
|
|
9
|
+
process.env.TOP_LEVEL_PATH ||
|
|
10
|
+
process.env.WORKER_TOP_LEVEL_PATH ||
|
|
11
|
+
resolve(join(__dirname, "..", "..", ".."))
|
|
8
12
|
let LOADED = false
|
|
9
13
|
if (!LOADED && coreEnv.isDev() && !coreEnv.isTest()) {
|
|
10
14
|
require("dotenv").config({
|
|
11
|
-
path: join(
|
|
15
|
+
path: join(TOP_LEVEL_PATH, ".env"),
|
|
12
16
|
})
|
|
13
17
|
LOADED = true
|
|
14
18
|
}
|
|
@@ -40,6 +44,7 @@ const environment = {
|
|
|
40
44
|
// prefer worker port to generic port
|
|
41
45
|
PORT: process.env.WORKER_PORT || process.env.PORT,
|
|
42
46
|
CLUSTER_PORT: process.env.CLUSTER_PORT,
|
|
47
|
+
WORKER_SERVICE: process.env.WORKER_SERVICE,
|
|
43
48
|
// flags
|
|
44
49
|
NODE_ENV: process.env.NODE_ENV,
|
|
45
50
|
SELF_HOSTED: !!parseInt(process.env.SELF_HOSTED || ""),
|
|
@@ -59,6 +64,7 @@ const environment = {
|
|
|
59
64
|
SESSION_UPDATE_PERIOD: process.env.SESSION_UPDATE_PERIOD,
|
|
60
65
|
ENCRYPTED_TEST_PUBLIC_API_KEY: process.env.ENCRYPTED_TEST_PUBLIC_API_KEY,
|
|
61
66
|
SESSION_EXPIRY_SECONDS: process.env.SESSION_EXPIRY_SECONDS,
|
|
67
|
+
TOP_LEVEL_PATH: TOP_LEVEL_PATH,
|
|
62
68
|
/**
|
|
63
69
|
* Mock the email service in use - links to ethereal hosted emails are logged instead.
|
|
64
70
|
*/
|
package/src/index.ts
CHANGED
|
@@ -85,10 +85,12 @@ app.use(api.routes())
|
|
|
85
85
|
|
|
86
86
|
const server = http.createServer(app.callback())
|
|
87
87
|
|
|
88
|
-
const shutdown = async () => {
|
|
89
|
-
console.log(
|
|
88
|
+
const shutdown = async (signal?: string) => {
|
|
89
|
+
console.log(
|
|
90
|
+
`Worker service shutting down gracefully... ${signal ? `Signal: ${signal}` : ""}`
|
|
91
|
+
)
|
|
90
92
|
timers.cleanup()
|
|
91
|
-
events.shutdown()
|
|
93
|
+
await events.shutdown()
|
|
92
94
|
await redis.clients.shutdown()
|
|
93
95
|
await queue.shutdown()
|
|
94
96
|
}
|
|
@@ -97,7 +99,7 @@ gracefulShutdown(server, {
|
|
|
97
99
|
signals: "SIGINT SIGTERM",
|
|
98
100
|
timeout: 30000,
|
|
99
101
|
onShutdown: shutdown,
|
|
100
|
-
forceExit: !env.isTest,
|
|
102
|
+
forceExit: !env.isTest(),
|
|
101
103
|
finally: () => {
|
|
102
104
|
console.log("Worker service shutdown complete")
|
|
103
105
|
},
|
|
@@ -106,7 +108,7 @@ gracefulShutdown(server, {
|
|
|
106
108
|
process.on("uncaughtException", async err => {
|
|
107
109
|
logging.logAlert("Uncaught exception.", err)
|
|
108
110
|
await shutdown()
|
|
109
|
-
if (!env.isTest) {
|
|
111
|
+
if (!env.isTest()) {
|
|
110
112
|
process.exit(1)
|
|
111
113
|
}
|
|
112
114
|
})
|
|
@@ -114,7 +116,7 @@ process.on("uncaughtException", async err => {
|
|
|
114
116
|
process.on("unhandledRejection", async reason => {
|
|
115
117
|
logging.logAlert("Unhandled Promise Rejection", reason as Error)
|
|
116
118
|
await shutdown()
|
|
117
|
-
if (!env.isTest) {
|
|
119
|
+
if (!env.isTest()) {
|
|
118
120
|
process.exit(1)
|
|
119
121
|
}
|
|
120
122
|
})
|
|
@@ -37,15 +37,20 @@ import {
|
|
|
37
37
|
} from "@budibase/types"
|
|
38
38
|
import API from "./api"
|
|
39
39
|
import jwt, { Secret } from "jsonwebtoken"
|
|
40
|
+
import http from "http"
|
|
40
41
|
|
|
41
42
|
class TestConfiguration {
|
|
42
|
-
server:
|
|
43
|
-
|
|
43
|
+
server: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> =
|
|
44
|
+
undefined!
|
|
45
|
+
|
|
46
|
+
request: supertest.SuperTest<supertest.Test> = undefined!
|
|
47
|
+
|
|
44
48
|
api: API
|
|
45
49
|
tenantId: string
|
|
46
50
|
user?: User
|
|
47
51
|
apiKey?: string
|
|
48
52
|
userPassword = "password123!"
|
|
53
|
+
sessions: string[] = []
|
|
49
54
|
|
|
50
55
|
constructor(opts: { openServer: boolean } = { openServer: true }) {
|
|
51
56
|
// default to cloud hosting
|
|
@@ -185,12 +190,19 @@ class TestConfiguration {
|
|
|
185
190
|
})
|
|
186
191
|
}
|
|
187
192
|
|
|
193
|
+
hasSession(user: User) {
|
|
194
|
+
return this.sessions.includes(user._id!)
|
|
195
|
+
}
|
|
196
|
+
|
|
188
197
|
async createSession(user: User) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
198
|
+
if (!this.hasSession(user)) {
|
|
199
|
+
this.sessions.push(user._id!)
|
|
200
|
+
return this._createSession({
|
|
201
|
+
userId: user._id!,
|
|
202
|
+
tenantId: user.tenantId,
|
|
203
|
+
email: user.email,
|
|
204
|
+
})
|
|
205
|
+
}
|
|
194
206
|
}
|
|
195
207
|
|
|
196
208
|
cookieHeader(cookies: any) {
|
|
@@ -212,6 +224,11 @@ class TestConfiguration {
|
|
|
212
224
|
}
|
|
213
225
|
}
|
|
214
226
|
|
|
227
|
+
async login(user: User) {
|
|
228
|
+
await this.createSession(user)
|
|
229
|
+
return this.authHeaders(user)
|
|
230
|
+
}
|
|
231
|
+
|
|
215
232
|
authHeaders(user: User) {
|
|
216
233
|
const authToken: AuthToken = {
|
|
217
234
|
userId: user._id!,
|
|
@@ -279,10 +296,10 @@ class TestConfiguration {
|
|
|
279
296
|
})
|
|
280
297
|
}
|
|
281
298
|
|
|
282
|
-
async createUser(
|
|
299
|
+
async createUser(userCfg?: Partial<User>) {
|
|
283
300
|
let user = structures.users.user()
|
|
284
301
|
if (user) {
|
|
285
|
-
user = { ...user, ...
|
|
302
|
+
user = { ...user, ...userCfg }
|
|
286
303
|
}
|
|
287
304
|
const response = await this._req(user, null, controllers.users.save)
|
|
288
305
|
const body = response as SaveUserResponse
|
package/src/tests/api/configs.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
ConfigType,
|
|
3
|
+
ConfigTypeToConfig,
|
|
3
4
|
SaveConfigRequest,
|
|
4
5
|
SaveConfigResponse,
|
|
5
6
|
} from "@budibase/types"
|
|
@@ -23,12 +24,16 @@ export class ConfigAPI extends TestAPI {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
getAIConfig = async () => {
|
|
27
|
+
return await this.getConfig(ConfigType.AI)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getConfig = async <T extends ConfigType>(type: T) => {
|
|
26
31
|
const resp = await this.request
|
|
27
|
-
.get(`/api/global/configs
|
|
32
|
+
.get(`/api/global/configs/${type}`)
|
|
28
33
|
.set(this.config.defaultHeaders())
|
|
29
34
|
.expect(200)
|
|
30
35
|
.expect("Content-Type", /json/)
|
|
31
|
-
return resp.body as
|
|
36
|
+
return resp.body as ConfigTypeToConfig<T>
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
saveConfig = async (
|
package/src/tests/api/users.ts
CHANGED
|
@@ -152,14 +152,20 @@ export class UserAPI extends TestAPI {
|
|
|
152
152
|
|
|
153
153
|
searchUsers = (
|
|
154
154
|
{ query }: { query?: SearchFilters },
|
|
155
|
-
opts?: {
|
|
155
|
+
opts?: {
|
|
156
|
+
status?: number
|
|
157
|
+
noHeaders?: boolean
|
|
158
|
+
useHeaders?: Record<string, string>
|
|
159
|
+
}
|
|
156
160
|
) => {
|
|
157
161
|
const req = this.request
|
|
158
162
|
.post("/api/global/users/search")
|
|
159
163
|
.send({ query })
|
|
160
164
|
.expect("Content-Type", /json/)
|
|
161
165
|
.expect(opts?.status ? opts.status : 200)
|
|
162
|
-
if (
|
|
166
|
+
if (opts?.useHeaders) {
|
|
167
|
+
req.set(opts.useHeaders)
|
|
168
|
+
} else if (!opts?.noHeaders) {
|
|
163
169
|
req.set(this.config.defaultHeaders())
|
|
164
170
|
}
|
|
165
171
|
return req
|
|
@@ -5,9 +5,13 @@ import {
|
|
|
5
5
|
SMTPConfig,
|
|
6
6
|
GoogleConfig,
|
|
7
7
|
OIDCConfig,
|
|
8
|
+
GoogleInnerConfig,
|
|
9
|
+
OIDCInnerConfig,
|
|
10
|
+
SMTPInnerConfig,
|
|
11
|
+
SettingsInnerConfig,
|
|
8
12
|
} from "@budibase/types"
|
|
9
13
|
|
|
10
|
-
export function oidc(conf?:
|
|
14
|
+
export function oidc(conf?: Partial<OIDCInnerConfig>): OIDCConfig {
|
|
11
15
|
return {
|
|
12
16
|
type: ConfigType.OIDC,
|
|
13
17
|
config: {
|
|
@@ -20,6 +24,7 @@ export function oidc(conf?: any): OIDCConfig {
|
|
|
20
24
|
name: "Active Directory",
|
|
21
25
|
uuid: utils.newid(),
|
|
22
26
|
activated: true,
|
|
27
|
+
scopes: [],
|
|
23
28
|
...conf,
|
|
24
29
|
},
|
|
25
30
|
],
|
|
@@ -27,7 +32,7 @@ export function oidc(conf?: any): OIDCConfig {
|
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
|
|
30
|
-
export function google(conf?:
|
|
35
|
+
export function google(conf?: Partial<GoogleInnerConfig>): GoogleConfig {
|
|
31
36
|
return {
|
|
32
37
|
type: ConfigType.GOOGLE,
|
|
33
38
|
config: {
|
|
@@ -39,7 +44,7 @@ export function google(conf?: any): GoogleConfig {
|
|
|
39
44
|
}
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
export function smtp(conf?:
|
|
47
|
+
export function smtp(conf?: Partial<SMTPInnerConfig>): SMTPConfig {
|
|
43
48
|
return {
|
|
44
49
|
type: ConfigType.SMTP,
|
|
45
50
|
config: {
|
|
@@ -70,7 +75,7 @@ export function smtpEthereal(): SMTPConfig {
|
|
|
70
75
|
}
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
export function settings(conf?:
|
|
78
|
+
export function settings(conf?: Partial<SettingsInnerConfig>): SettingsConfig {
|
|
74
79
|
return {
|
|
75
80
|
type: ConfigType.SETTINGS,
|
|
76
81
|
config: {
|
package/scripts/account.js
DELETED
package/scripts/dev/manage.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const { parsed: existingConfig } = require("dotenv").config()
|
|
3
|
-
const updateDotEnv = require("update-dotenv")
|
|
4
|
-
|
|
5
|
-
async function init() {
|
|
6
|
-
let config = {
|
|
7
|
-
SELF_HOSTED: "1",
|
|
8
|
-
PORT: "4002",
|
|
9
|
-
CLUSTER_PORT: "10000",
|
|
10
|
-
JWT_SECRET: "testsecret",
|
|
11
|
-
INTERNAL_API_KEY: "budibase",
|
|
12
|
-
MINIO_ACCESS_KEY: "budibase",
|
|
13
|
-
MINIO_SECRET_KEY: "budibase",
|
|
14
|
-
REDIS_URL: "localhost:6379",
|
|
15
|
-
REDIS_PASSWORD: "budibase",
|
|
16
|
-
MINIO_URL: "http://localhost:4004",
|
|
17
|
-
COUCH_DB_URL: "http://budibase:budibase@localhost:4005",
|
|
18
|
-
COUCH_DB_USERNAME: "budibase",
|
|
19
|
-
COUCH_DB_PASSWORD: "budibase",
|
|
20
|
-
// empty string is false
|
|
21
|
-
MULTI_TENANCY: "",
|
|
22
|
-
DISABLE_ACCOUNT_PORTAL: "1",
|
|
23
|
-
ACCOUNT_PORTAL_URL: "http://localhost:10001",
|
|
24
|
-
PLATFORM_URL: "http://localhost:10000",
|
|
25
|
-
APPS_URL: "http://localhost:4001",
|
|
26
|
-
SERVICE: "worker-service",
|
|
27
|
-
DEPLOYMENT_ENVIRONMENT: "development",
|
|
28
|
-
ENABLE_EMAIL_TEST_MODE: "1",
|
|
29
|
-
HTTP_LOGGING: "0",
|
|
30
|
-
VERSION: "0.0.0+local",
|
|
31
|
-
PASSWORD_MIN_LENGTH: "1",
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
config = { ...config, ...existingConfig }
|
|
35
|
-
|
|
36
|
-
await updateDotEnv(config)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// if more than init required use this to determine the command type
|
|
40
|
-
//const managementCommand = process.argv.slice(2)[0]
|
|
41
|
-
|
|
42
|
-
// for now only one command
|
|
43
|
-
let command = init
|
|
44
|
-
|
|
45
|
-
command()
|
|
46
|
-
.then(() => {
|
|
47
|
-
console.log("Done! 🎉")
|
|
48
|
-
})
|
|
49
|
-
.catch(err => {
|
|
50
|
-
console.error(
|
|
51
|
-
"Something went wrong while managing budibase dev worker:",
|
|
52
|
-
err.message
|
|
53
|
-
)
|
|
54
|
-
})
|
package/scripts/localdomain.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const updateDotEnv = require("update-dotenv")
|
|
3
|
-
|
|
4
|
-
const arg = process.argv.slice(2)[0]
|
|
5
|
-
const isEnable = arg === "enable"
|
|
6
|
-
|
|
7
|
-
let domain = process.argv.slice(2)[1]
|
|
8
|
-
if (!domain) {
|
|
9
|
-
domain = "local.com"
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const getAccountPortalUrl = () => {
|
|
13
|
-
if (isEnable) {
|
|
14
|
-
return `http://account.${domain}:10001`
|
|
15
|
-
} else {
|
|
16
|
-
return `http://localhost:10001`
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const getBudibaseUrl = () => {
|
|
21
|
-
if (isEnable) {
|
|
22
|
-
return `http://${domain}:10000`
|
|
23
|
-
} else {
|
|
24
|
-
return `http://localhost:10000`
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const getCookieDomain = () => {
|
|
29
|
-
if (isEnable) {
|
|
30
|
-
return `.${domain}`
|
|
31
|
-
} else {
|
|
32
|
-
return ""
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* For testing multi tenancy sub domains locally.
|
|
38
|
-
*
|
|
39
|
-
* Relies on an entry in /etc/hosts e.g:
|
|
40
|
-
*
|
|
41
|
-
* 127.0.0.1 local.com
|
|
42
|
-
*
|
|
43
|
-
* and an entry for each tenant you wish to test locally e.g:
|
|
44
|
-
*
|
|
45
|
-
* 127.0.0.1 t1.local.com
|
|
46
|
-
* 127.0.0.1 t2.local.com
|
|
47
|
-
*/
|
|
48
|
-
updateDotEnv({
|
|
49
|
-
ACCOUNT_PORTAL_URL: getAccountPortalUrl(),
|
|
50
|
-
COOKIE_DOMAIN: getCookieDomain(),
|
|
51
|
-
PLATFORM_URL: getBudibaseUrl(),
|
|
52
|
-
}).then(() => console.log("Updated worker!"))
|
package/scripts/multiTenancy.js
DELETED