@budibase/worker 1.0.219-alpha.7 → 1.0.219
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 +6 -6
- package/src/api/controllers/global/auth.ts +34 -14
- package/src/api/controllers/global/configs.js +8 -3
- package/src/api/controllers/global/roles.js +3 -3
- package/src/api/controllers/global/users.ts +12 -15
- package/src/api/routes/global/users.js +0 -1
- package/src/api/routes/tests/auth.spec.js +7 -10
- package/src/sdk/users/users.ts +3 -33
- package/src/utilities/users.js +0 -17
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/worker",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "1.0.219
|
|
4
|
+
"version": "1.0.219",
|
|
5
5
|
"description": "Budibase background service",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -34,10 +34,9 @@
|
|
|
34
34
|
"author": "Budibase",
|
|
35
35
|
"license": "GPL-3.0",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@budibase/backend-core": "^1.0.219
|
|
38
|
-
"@budibase/pro": "1.0.
|
|
39
|
-
"@budibase/string-templates": "^1.0.219
|
|
40
|
-
"@budibase/types": "^1.0.219-alpha.7",
|
|
37
|
+
"@budibase/backend-core": "^1.0.219",
|
|
38
|
+
"@budibase/pro": "1.0.218",
|
|
39
|
+
"@budibase/string-templates": "^1.0.219",
|
|
41
40
|
"@koa/router": "8.0.8",
|
|
42
41
|
"@sentry/node": "6.17.7",
|
|
43
42
|
"@techpass/passport-openidconnect": "0.3.2",
|
|
@@ -67,6 +66,7 @@
|
|
|
67
66
|
"server-destroy": "1.0.1"
|
|
68
67
|
},
|
|
69
68
|
"devDependencies": {
|
|
69
|
+
"@budibase/types": "^1.0.219",
|
|
70
70
|
"@types/jest": "26.0.23",
|
|
71
71
|
"@types/koa": "2.13.4",
|
|
72
72
|
"@types/koa-router": "7.4.4",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"./scripts/jestSetup.js"
|
|
101
101
|
]
|
|
102
102
|
},
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "231b038a3c99f730dd27a595f870663dd84b7837"
|
|
104
104
|
}
|
|
@@ -1,22 +1,49 @@
|
|
|
1
1
|
const core = require("@budibase/backend-core")
|
|
2
|
+
const { getScopedConfig } = require("@budibase/backend-core/db")
|
|
3
|
+
const { google } = require("@budibase/backend-core/middleware")
|
|
4
|
+
const { oidc } = require("@budibase/backend-core/middleware")
|
|
2
5
|
const { Configs, EmailTemplatePurpose } = require("../../../constants")
|
|
3
6
|
const { sendEmail, isEmailConfigured } = require("../../../utilities/email")
|
|
4
7
|
const { setCookie, getCookie, clearCookie, hash, platformLogout } = core.utils
|
|
5
8
|
const { Cookies, Headers } = core.constants
|
|
6
|
-
const { passport
|
|
9
|
+
const { passport } = core.auth
|
|
7
10
|
const { checkResetPasswordCode } = require("../../../utilities/redis")
|
|
8
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
getGlobalDB,
|
|
13
|
+
getTenantId,
|
|
14
|
+
isMultiTenant,
|
|
15
|
+
} = require("@budibase/backend-core/tenancy")
|
|
9
16
|
const env = require("../../../environment")
|
|
10
17
|
import { events, users as usersCore, context } from "@budibase/backend-core"
|
|
11
18
|
import { users } from "../../../sdk"
|
|
12
19
|
import { User } from "@budibase/types"
|
|
13
20
|
|
|
21
|
+
const ssoCallbackUrl = async (config: any, type: any) => {
|
|
22
|
+
// incase there is a callback URL from before
|
|
23
|
+
if (config && config.callbackURL) {
|
|
24
|
+
return config.callbackURL
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const db = getGlobalDB()
|
|
28
|
+
const publicConfig = await getScopedConfig(db, {
|
|
29
|
+
type: Configs.SETTINGS,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
let callbackUrl = `/api/global/auth`
|
|
33
|
+
if (isMultiTenant()) {
|
|
34
|
+
callbackUrl += `/${getTenantId()}`
|
|
35
|
+
}
|
|
36
|
+
callbackUrl += `/${type}/callback`
|
|
37
|
+
|
|
38
|
+
return `${publicConfig.platformUrl}${callbackUrl}`
|
|
39
|
+
}
|
|
40
|
+
|
|
14
41
|
export const googleCallbackUrl = async (config: any) => {
|
|
15
|
-
return ssoCallbackUrl(
|
|
42
|
+
return ssoCallbackUrl(config, "google")
|
|
16
43
|
}
|
|
17
44
|
|
|
18
45
|
export const oidcCallbackUrl = async (config: any) => {
|
|
19
|
-
return ssoCallbackUrl(
|
|
46
|
+
return ssoCallbackUrl(config, "oidc")
|
|
20
47
|
}
|
|
21
48
|
|
|
22
49
|
async function authInternal(ctx: any, user: any, err = null, info = null) {
|
|
@@ -171,8 +198,6 @@ export const googlePreAuth = async (ctx: any, next: any) => {
|
|
|
171
198
|
|
|
172
199
|
return passport.authenticate(strategy, {
|
|
173
200
|
scope: ["profile", "email"],
|
|
174
|
-
accessType: "offline",
|
|
175
|
-
prompt: "consent",
|
|
176
201
|
})(ctx, next)
|
|
177
202
|
}
|
|
178
203
|
|
|
@@ -199,7 +224,7 @@ export const googleAuth = async (ctx: any, next: any) => {
|
|
|
199
224
|
)(ctx, next)
|
|
200
225
|
}
|
|
201
226
|
|
|
202
|
-
|
|
227
|
+
async function oidcStrategyFactory(ctx: any, configId: any) {
|
|
203
228
|
const db = getGlobalDB()
|
|
204
229
|
const config = await core.db.getScopedConfig(db, {
|
|
205
230
|
type: Configs.OIDC,
|
|
@@ -209,12 +234,7 @@ export const oidcStrategyFactory = async (ctx: any, configId: any) => {
|
|
|
209
234
|
const chosenConfig = config.configs.filter((c: any) => c.uuid === configId)[0]
|
|
210
235
|
let callbackUrl = await exports.oidcCallbackUrl(chosenConfig)
|
|
211
236
|
|
|
212
|
-
|
|
213
|
-
const enrichedConfig = await oidc.fetchStrategyConfig(
|
|
214
|
-
chosenConfig,
|
|
215
|
-
callbackUrl
|
|
216
|
-
)
|
|
217
|
-
return oidc.strategyFactory(enrichedConfig, users.save)
|
|
237
|
+
return oidc.strategyFactory(chosenConfig, callbackUrl, users.save)
|
|
218
238
|
}
|
|
219
239
|
|
|
220
240
|
/**
|
|
@@ -229,7 +249,7 @@ export const oidcPreAuth = async (ctx: any, next: any) => {
|
|
|
229
249
|
|
|
230
250
|
return passport.authenticate(strategy, {
|
|
231
251
|
// required 'openid' scope is added by oidc strategy factory
|
|
232
|
-
scope: ["profile", "email"
|
|
252
|
+
scope: ["profile", "email"],
|
|
233
253
|
})(ctx, next)
|
|
234
254
|
}
|
|
235
255
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const {
|
|
2
2
|
generateConfigID,
|
|
3
3
|
getConfigParams,
|
|
4
|
+
getGlobalUserParams,
|
|
4
5
|
getScopedFullConfig,
|
|
5
6
|
getAllApps,
|
|
6
7
|
} = require("@budibase/backend-core/db")
|
|
@@ -19,7 +20,6 @@ const {
|
|
|
19
20
|
bustCache,
|
|
20
21
|
} = require("@budibase/backend-core/cache")
|
|
21
22
|
const { events } = require("@budibase/backend-core")
|
|
22
|
-
const { checkAnyUserExists } = require("../../../utilities/users")
|
|
23
23
|
|
|
24
24
|
const BB_TENANT_CDN = "https://tenants.cdn.budi.live"
|
|
25
25
|
|
|
@@ -405,7 +405,12 @@ exports.configChecklist = async function (ctx) {
|
|
|
405
405
|
})
|
|
406
406
|
|
|
407
407
|
// They have set up an global user
|
|
408
|
-
const
|
|
408
|
+
const users = await db.allDocs(
|
|
409
|
+
getGlobalUserParams(null, {
|
|
410
|
+
include_docs: true,
|
|
411
|
+
limit: 1,
|
|
412
|
+
})
|
|
413
|
+
)
|
|
409
414
|
return {
|
|
410
415
|
apps: {
|
|
411
416
|
checked: apps.length > 0,
|
|
@@ -418,7 +423,7 @@ exports.configChecklist = async function (ctx) {
|
|
|
418
423
|
link: "/builder/portal/manage/email",
|
|
419
424
|
},
|
|
420
425
|
adminUser: {
|
|
421
|
-
checked:
|
|
426
|
+
checked: users && users.rows.length >= 1,
|
|
422
427
|
label: "Create your first user",
|
|
423
428
|
link: "/builder/portal/manage/users",
|
|
424
429
|
},
|
|
@@ -7,7 +7,7 @@ const {
|
|
|
7
7
|
const { doInAppContext, getAppDB } = require("@budibase/backend-core/context")
|
|
8
8
|
const { user: userCache } = require("@budibase/backend-core/cache")
|
|
9
9
|
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
|
10
|
-
const {
|
|
10
|
+
const { users } = require("../../../sdk")
|
|
11
11
|
|
|
12
12
|
exports.fetch = async ctx => {
|
|
13
13
|
const tenantId = ctx.user.tenantId
|
|
@@ -49,10 +49,10 @@ exports.find = async ctx => {
|
|
|
49
49
|
exports.removeAppRole = async ctx => {
|
|
50
50
|
const { appId } = ctx.params
|
|
51
51
|
const db = getGlobalDB()
|
|
52
|
-
const
|
|
52
|
+
const allUsers = await users.allUsers(ctx)
|
|
53
53
|
const bulk = []
|
|
54
54
|
const cacheInvalidations = []
|
|
55
|
-
for (let user of
|
|
55
|
+
for (let user of allUsers) {
|
|
56
56
|
if (user.roles[appId]) {
|
|
57
57
|
cacheInvalidations.push(userCache.invalidateUser(user._id))
|
|
58
58
|
delete user.roles[appId]
|
|
@@ -8,15 +8,16 @@ import {
|
|
|
8
8
|
events,
|
|
9
9
|
errors,
|
|
10
10
|
accounts,
|
|
11
|
+
db as dbUtils,
|
|
11
12
|
users as usersCore,
|
|
12
13
|
tenancy,
|
|
13
14
|
cache,
|
|
14
15
|
} from "@budibase/backend-core"
|
|
15
|
-
import { checkAnyUserExists } from "../../../utilities/users"
|
|
16
16
|
|
|
17
17
|
export const save = async (ctx: any) => {
|
|
18
18
|
try {
|
|
19
|
-
|
|
19
|
+
const user = await users.save(ctx.request.body)
|
|
20
|
+
ctx.body = user
|
|
20
21
|
} catch (err: any) {
|
|
21
22
|
ctx.throw(err.status || 400, err)
|
|
22
23
|
}
|
|
@@ -38,8 +39,15 @@ export const adminUser = async (ctx: any) => {
|
|
|
38
39
|
ctx.throw(403, "Organisation already exists.")
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
const
|
|
42
|
-
|
|
42
|
+
const response = await tenancy.doWithGlobalDB(tenantId, async (db: any) => {
|
|
43
|
+
return db.allDocs(
|
|
44
|
+
dbUtils.getGlobalUserParams(null, {
|
|
45
|
+
include_docs: true,
|
|
46
|
+
})
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
if (response.rows.some((row: any) => row.doc.admin)) {
|
|
43
51
|
ctx.throw(
|
|
44
52
|
403,
|
|
45
53
|
"You cannot initialise once an global user has been created."
|
|
@@ -88,17 +96,6 @@ export const destroy = async (ctx: any) => {
|
|
|
88
96
|
}
|
|
89
97
|
}
|
|
90
98
|
|
|
91
|
-
export const search = async (ctx: any) => {
|
|
92
|
-
const paginated = await users.paginatedUsers(ctx.request.body)
|
|
93
|
-
// user hashed password shouldn't ever be returned
|
|
94
|
-
for (let user of paginated.data) {
|
|
95
|
-
if (user) {
|
|
96
|
-
delete user.password
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
ctx.body = paginated
|
|
100
|
-
}
|
|
101
|
-
|
|
102
99
|
// called internally by app server user fetch
|
|
103
100
|
export const fetch = async (ctx: any) => {
|
|
104
101
|
const all = await users.allUsers()
|
|
@@ -46,7 +46,6 @@ router
|
|
|
46
46
|
controller.save
|
|
47
47
|
)
|
|
48
48
|
.get("/api/global/users", builderOrAdmin, controller.fetch)
|
|
49
|
-
.post("/api/global/users/search", builderOrAdmin, controller.search)
|
|
50
49
|
.delete("/api/global/users/:id", adminOnly, controller.destroy)
|
|
51
50
|
.get("/api/global/roles/:appId")
|
|
52
51
|
.post(
|
|
@@ -77,30 +77,27 @@ describe("/api/global/auth", () => {
|
|
|
77
77
|
describe("oidc", () => {
|
|
78
78
|
const auth = require("@budibase/backend-core/auth")
|
|
79
79
|
|
|
80
|
-
const passportSpy = jest.spyOn(auth.passport, "authenticate")
|
|
81
|
-
let oidcConf
|
|
82
|
-
let chosenConfig
|
|
83
|
-
let configId
|
|
84
|
-
|
|
85
80
|
// mock the oidc strategy implementation and return value
|
|
86
81
|
let strategyFactory = jest.fn()
|
|
87
82
|
let mockStrategyReturn = jest.fn()
|
|
88
|
-
let mockStrategyConfig = jest.fn()
|
|
89
|
-
auth.oidc.fetchStrategyConfig = mockStrategyConfig
|
|
90
|
-
|
|
91
83
|
strategyFactory.mockReturnValue(mockStrategyReturn)
|
|
92
84
|
auth.oidc.strategyFactory = strategyFactory
|
|
93
85
|
|
|
86
|
+
const passportSpy = jest.spyOn(auth.passport, "authenticate")
|
|
87
|
+
let oidcConf
|
|
88
|
+
let chosenConfig
|
|
89
|
+
let configId
|
|
90
|
+
|
|
94
91
|
beforeEach(async () => {
|
|
95
92
|
oidcConf = await config.saveOIDCConfig()
|
|
96
93
|
chosenConfig = oidcConf.config.configs[0]
|
|
97
94
|
configId = chosenConfig.uuid
|
|
98
|
-
mockStrategyConfig.mockReturnValue(chosenConfig)
|
|
99
95
|
})
|
|
100
96
|
|
|
101
97
|
afterEach(() => {
|
|
102
98
|
expect(strategyFactory).toBeCalledWith(
|
|
103
99
|
chosenConfig,
|
|
100
|
+
`http://localhost:10000/api/global/auth/${TENANT_ID}/oidc/callback`,
|
|
104
101
|
expect.any(Function)
|
|
105
102
|
)
|
|
106
103
|
})
|
|
@@ -110,7 +107,7 @@ describe("/api/global/auth", () => {
|
|
|
110
107
|
await request.get(`/api/global/auth/${TENANT_ID}/oidc/configs/${configId}`)
|
|
111
108
|
|
|
112
109
|
expect(passportSpy).toBeCalledWith(mockStrategyReturn, {
|
|
113
|
-
scope: ["profile", "email",
|
|
110
|
+
scope: ["profile", "email"],
|
|
114
111
|
})
|
|
115
112
|
expect(passportSpy.mock.calls.length).toBe(1);
|
|
116
113
|
})
|
package/src/sdk/users/users.ts
CHANGED
|
@@ -17,8 +17,9 @@ import {
|
|
|
17
17
|
} from "@budibase/backend-core"
|
|
18
18
|
import { MigrationType } from "@budibase/types"
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Retrieves all users from the current tenancy.
|
|
22
|
+
*/
|
|
22
23
|
export const allUsers = async () => {
|
|
23
24
|
const db = tenancy.getGlobalDB()
|
|
24
25
|
const response = await db.allDocs(
|
|
@@ -29,37 +30,6 @@ export const allUsers = async () => {
|
|
|
29
30
|
return response.rows.map((row: any) => row.doc)
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
export const paginatedUsers = async ({
|
|
33
|
-
page,
|
|
34
|
-
search,
|
|
35
|
-
}: { page?: string; search?: string } = {}) => {
|
|
36
|
-
const db = tenancy.getGlobalDB()
|
|
37
|
-
// get one extra document, to have the next page
|
|
38
|
-
const opts: any = {
|
|
39
|
-
include_docs: true,
|
|
40
|
-
limit: PAGE_LIMIT + 1,
|
|
41
|
-
}
|
|
42
|
-
// add a startkey if the page was specified (anchor)
|
|
43
|
-
if (page) {
|
|
44
|
-
opts.startkey = page
|
|
45
|
-
}
|
|
46
|
-
// property specifies what to use for the page/anchor
|
|
47
|
-
let userList, property
|
|
48
|
-
// no search, query allDocs
|
|
49
|
-
if (!search) {
|
|
50
|
-
const response = await db.allDocs(dbUtils.getGlobalUserParams(null, opts))
|
|
51
|
-
userList = response.rows.map((row: any) => row.doc)
|
|
52
|
-
property = "_id"
|
|
53
|
-
} else {
|
|
54
|
-
userList = await usersCore.searchGlobalUsersByEmail(search, opts)
|
|
55
|
-
property = "email"
|
|
56
|
-
}
|
|
57
|
-
return dbUtils.pagination(userList, PAGE_LIMIT, {
|
|
58
|
-
paginate: true,
|
|
59
|
-
property,
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
|
|
63
33
|
/**
|
|
64
34
|
* Gets a user by ID from the global database, based on the current tenancy.
|
|
65
35
|
*/
|
package/src/utilities/users.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
|
2
|
-
const { getGlobalUserParams } = require("@budibase/backend-core/db")
|
|
3
|
-
|
|
4
|
-
exports.checkAnyUserExists = async () => {
|
|
5
|
-
try {
|
|
6
|
-
const db = getGlobalDB()
|
|
7
|
-
const users = await db.allDocs(
|
|
8
|
-
getGlobalUserParams(null, {
|
|
9
|
-
include_docs: true,
|
|
10
|
-
limit: 1,
|
|
11
|
-
})
|
|
12
|
-
)
|
|
13
|
-
return users && users.rows.length >= 1
|
|
14
|
-
} catch (err) {
|
|
15
|
-
throw new Error("Unable to retrieve user list")
|
|
16
|
-
}
|
|
17
|
-
}
|