@budibase/worker 2.4.44-alpha.4 → 2.5.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.
- package/package.json +6 -8
- package/src/api/controllers/global/users.ts +2 -2
- package/src/api/routes/global/configs.ts +1 -9
- package/src/api/routes/index.ts +6 -4
- package/src/index.ts +0 -5
- package/src/sdk/users/users.ts +41 -3
- package/src/tests/TestConfiguration.ts +1 -50
- package/src/tests/api/index.ts +0 -7
- package/src/api/routes/global/tests/scim.spec.ts +0 -892
- package/src/initPro.ts +0 -13
- package/src/middleware/handleScimBody.ts +0 -12
- package/src/tests/api/scim/groups.ts +0 -94
- package/src/tests/api/scim/shared.ts +0 -43
- package/src/tests/api/scim/users.ts +0 -94
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/worker",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.5.0",
|
|
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.
|
|
40
|
-
"@budibase/pro": "2.4.44
|
|
41
|
-
"@budibase/string-templates": "2.
|
|
42
|
-
"@budibase/types": "2.
|
|
39
|
+
"@budibase/backend-core": "^2.5.0",
|
|
40
|
+
"@budibase/pro": "2.4.44",
|
|
41
|
+
"@budibase/string-templates": "^2.5.0",
|
|
42
|
+
"@budibase/types": "^2.5.0",
|
|
43
43
|
"@koa/router": "8.0.8",
|
|
44
44
|
"@sentry/node": "6.17.7",
|
|
45
45
|
"@techpass/passport-openidconnect": "0.3.2",
|
|
@@ -79,7 +79,6 @@
|
|
|
79
79
|
"@types/jsonwebtoken": "8.5.1",
|
|
80
80
|
"@types/koa": "2.13.4",
|
|
81
81
|
"@types/koa__router": "8.0.8",
|
|
82
|
-
"@types/lodash": "^4.14.191",
|
|
83
82
|
"@types/node": "14.18.20",
|
|
84
83
|
"@types/node-fetch": "2.6.1",
|
|
85
84
|
"@types/pouchdb": "6.4.0",
|
|
@@ -90,7 +89,6 @@
|
|
|
90
89
|
"copyfiles": "2.4.1",
|
|
91
90
|
"eslint": "6.8.0",
|
|
92
91
|
"jest": "28.1.1",
|
|
93
|
-
"lodash": "4.17.21",
|
|
94
92
|
"nodemon": "2.0.15",
|
|
95
93
|
"pouchdb-adapter-memory": "7.2.2",
|
|
96
94
|
"prettier": "2.3.1",
|
|
@@ -103,5 +101,5 @@
|
|
|
103
101
|
"typescript": "4.7.3",
|
|
104
102
|
"update-dotenv": "1.1.1"
|
|
105
103
|
},
|
|
106
|
-
"gitHead": "
|
|
104
|
+
"gitHead": "aa8ddde74c69b49755866666204c79a27c6c8a2c"
|
|
107
105
|
}
|
|
@@ -177,7 +177,7 @@ export const destroy = async (ctx: any) => {
|
|
|
177
177
|
ctx.throw(400, "Unable to delete self.")
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
await userSdk.destroy(id)
|
|
180
|
+
await userSdk.destroy(id, ctx.user)
|
|
181
181
|
|
|
182
182
|
ctx.body = {
|
|
183
183
|
message: `User ${id} deleted.`,
|
|
@@ -197,7 +197,7 @@ export const search = async (ctx: any) => {
|
|
|
197
197
|
if (body.paginated === false) {
|
|
198
198
|
await getAppUsers(ctx)
|
|
199
199
|
} else {
|
|
200
|
-
const paginated = await userSdk.
|
|
200
|
+
const paginated = await userSdk.paginatedUsers(body)
|
|
201
201
|
// user hashed password shouldn't ever be returned
|
|
202
202
|
for (let user of paginated.data) {
|
|
203
203
|
if (user) {
|
|
@@ -58,13 +58,6 @@ function oidcValidation() {
|
|
|
58
58
|
}).unknown(true)
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
function scimValidation() {
|
|
62
|
-
// prettier-ignore
|
|
63
|
-
return Joi.object({
|
|
64
|
-
enabled: Joi.boolean().required(),
|
|
65
|
-
}).unknown(true)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
61
|
function buildConfigSaveValidation() {
|
|
69
62
|
// prettier-ignore
|
|
70
63
|
return auth.joiValidator.body(Joi.object({
|
|
@@ -81,8 +74,7 @@ function buildConfigSaveValidation() {
|
|
|
81
74
|
{ is: ConfigType.SETTINGS, then: settingValidation() },
|
|
82
75
|
{ is: ConfigType.ACCOUNT, then: Joi.object().unknown(true) },
|
|
83
76
|
{ is: ConfigType.GOOGLE, then: googleValidation() },
|
|
84
|
-
{ is: ConfigType.OIDC, then: oidcValidation() }
|
|
85
|
-
{ is: ConfigType.SCIM, then: scimValidation() }
|
|
77
|
+
{ is: ConfigType.OIDC, then: oidcValidation() }
|
|
86
78
|
],
|
|
87
79
|
}),
|
|
88
80
|
}).required().unknown(true),
|
package/src/api/routes/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Router from "@koa/router"
|
|
2
|
-
import { api
|
|
2
|
+
import { api } from "@budibase/pro"
|
|
3
3
|
import userRoutes from "./global/users"
|
|
4
4
|
import configRoutes from "./global/configs"
|
|
5
5
|
import workspaceRoutes from "./global/workspaces"
|
|
@@ -17,6 +17,9 @@ import migrationRoutes from "./system/migrations"
|
|
|
17
17
|
import accountRoutes from "./system/accounts"
|
|
18
18
|
import restoreRoutes from "./system/restore"
|
|
19
19
|
|
|
20
|
+
let userGroupRoutes = api.groups
|
|
21
|
+
let auditLogRoutes = api.auditLogs
|
|
22
|
+
|
|
20
23
|
export const routes: Router[] = [
|
|
21
24
|
configRoutes,
|
|
22
25
|
userRoutes,
|
|
@@ -30,11 +33,10 @@ export const routes: Router[] = [
|
|
|
30
33
|
statusRoutes,
|
|
31
34
|
selfRoutes,
|
|
32
35
|
licenseRoutes,
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
userGroupRoutes,
|
|
37
|
+
auditLogRoutes,
|
|
35
38
|
migrationRoutes,
|
|
36
39
|
accountRoutes,
|
|
37
40
|
restoreRoutes,
|
|
38
41
|
eventRoutes,
|
|
39
|
-
pro.scim,
|
|
40
42
|
]
|
package/src/index.ts
CHANGED
|
@@ -35,8 +35,6 @@ const logger = require("koa-pino-logger")
|
|
|
35
35
|
const { userAgent } = require("koa-useragent")
|
|
36
36
|
|
|
37
37
|
import destroyable from "server-destroy"
|
|
38
|
-
import { initPro } from "./initPro"
|
|
39
|
-
import { handleScimBody } from "./middleware/handleScimBody"
|
|
40
38
|
|
|
41
39
|
// configure events to use the pro audit log write
|
|
42
40
|
// can't integrate directly into backend-core due to cyclic issues
|
|
@@ -56,9 +54,7 @@ const app: Application = new Koa()
|
|
|
56
54
|
app.keys = ["secret", "key"]
|
|
57
55
|
|
|
58
56
|
// set up top level koa middleware
|
|
59
|
-
app.use(handleScimBody)
|
|
60
57
|
app.use(koaBody({ multipart: true }))
|
|
61
|
-
|
|
62
58
|
app.use(koaSession(app))
|
|
63
59
|
app.use(middleware.logging)
|
|
64
60
|
app.use(logger(logging.pinoSettings()))
|
|
@@ -112,7 +108,6 @@ const shutdown = () => {
|
|
|
112
108
|
|
|
113
109
|
export default server.listen(parseInt(env.PORT || "4002"), async () => {
|
|
114
110
|
console.log(`Worker running on ${JSON.stringify(server.address())}`)
|
|
115
|
-
await initPro()
|
|
116
111
|
await redis.init()
|
|
117
112
|
})
|
|
118
113
|
|
package/src/sdk/users/users.ts
CHANGED
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
utils,
|
|
16
16
|
ViewName,
|
|
17
17
|
env as coreEnv,
|
|
18
|
-
context,
|
|
19
18
|
} from "@budibase/backend-core"
|
|
20
19
|
import {
|
|
21
20
|
AccountMetadata,
|
|
@@ -38,6 +37,8 @@ import { EmailTemplatePurpose } from "../../constants"
|
|
|
38
37
|
import * as pro from "@budibase/pro"
|
|
39
38
|
import * as accountSdk from "../accounts"
|
|
40
39
|
|
|
40
|
+
const PAGE_LIMIT = 8
|
|
41
|
+
|
|
41
42
|
export const allUsers = async () => {
|
|
42
43
|
const db = tenancy.getGlobalDB()
|
|
43
44
|
const response = await db.allDocs(
|
|
@@ -67,6 +68,43 @@ export const getUsersByAppAccess = async (appId?: string) => {
|
|
|
67
68
|
return response
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
export const paginatedUsers = async ({
|
|
72
|
+
page,
|
|
73
|
+
email,
|
|
74
|
+
appId,
|
|
75
|
+
}: SearchUsersRequest = {}) => {
|
|
76
|
+
const db = tenancy.getGlobalDB()
|
|
77
|
+
// get one extra document, to have the next page
|
|
78
|
+
const opts: any = {
|
|
79
|
+
include_docs: true,
|
|
80
|
+
limit: PAGE_LIMIT + 1,
|
|
81
|
+
}
|
|
82
|
+
// add a startkey if the page was specified (anchor)
|
|
83
|
+
if (page) {
|
|
84
|
+
opts.startkey = page
|
|
85
|
+
}
|
|
86
|
+
// property specifies what to use for the page/anchor
|
|
87
|
+
let userList,
|
|
88
|
+
property = "_id",
|
|
89
|
+
getKey
|
|
90
|
+
if (appId) {
|
|
91
|
+
userList = await usersCore.searchGlobalUsersByApp(appId, opts)
|
|
92
|
+
getKey = (doc: any) => usersCore.getGlobalUserByAppPage(appId, doc)
|
|
93
|
+
} else if (email) {
|
|
94
|
+
userList = await usersCore.searchGlobalUsersByEmail(email, opts)
|
|
95
|
+
property = "email"
|
|
96
|
+
} else {
|
|
97
|
+
// no search, query allDocs
|
|
98
|
+
const response = await db.allDocs(dbUtils.getGlobalUserParams(null, opts))
|
|
99
|
+
userList = response.rows.map((row: any) => row.doc)
|
|
100
|
+
}
|
|
101
|
+
return dbUtils.pagination(userList, PAGE_LIMIT, {
|
|
102
|
+
paginate: true,
|
|
103
|
+
property,
|
|
104
|
+
getKey,
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
70
108
|
export async function getUserByEmail(email: string) {
|
|
71
109
|
return usersCore.getGlobalUserByEmail(email)
|
|
72
110
|
}
|
|
@@ -538,7 +576,7 @@ export const bulkDelete = async (
|
|
|
538
576
|
return response
|
|
539
577
|
}
|
|
540
578
|
|
|
541
|
-
export const destroy = async (id: string) => {
|
|
579
|
+
export const destroy = async (id: string, currentUser: any) => {
|
|
542
580
|
const db = tenancy.getGlobalDB()
|
|
543
581
|
const dbUser = (await db.get(id)) as User
|
|
544
582
|
const userId = dbUser._id as string
|
|
@@ -548,7 +586,7 @@ export const destroy = async (id: string) => {
|
|
|
548
586
|
const email = dbUser.email
|
|
549
587
|
const account = await accounts.getAccount(email)
|
|
550
588
|
if (account) {
|
|
551
|
-
if (
|
|
589
|
+
if (email === currentUser.email) {
|
|
552
590
|
throw new HTTPError('Please visit "Account" to delete this user', 400)
|
|
553
591
|
} else {
|
|
554
592
|
throw new HTTPError("Account holder cannot be deleted", 400)
|
|
@@ -20,18 +20,9 @@ import {
|
|
|
20
20
|
auth,
|
|
21
21
|
constants,
|
|
22
22
|
env as coreEnv,
|
|
23
|
-
db as dbCore,
|
|
24
|
-
encryption,
|
|
25
|
-
utils,
|
|
26
23
|
} from "@budibase/backend-core"
|
|
27
24
|
import structures, { CSRF_TOKEN } from "./structures"
|
|
28
|
-
import {
|
|
29
|
-
SaveUserResponse,
|
|
30
|
-
User,
|
|
31
|
-
AuthToken,
|
|
32
|
-
SCIMConfig,
|
|
33
|
-
ConfigType,
|
|
34
|
-
} from "@budibase/types"
|
|
25
|
+
import { SaveUserResponse, User, AuthToken } from "@budibase/types"
|
|
35
26
|
import API from "./api"
|
|
36
27
|
|
|
37
28
|
class TestConfiguration {
|
|
@@ -40,7 +31,6 @@ class TestConfiguration {
|
|
|
40
31
|
api: API
|
|
41
32
|
tenantId: string
|
|
42
33
|
user?: User
|
|
43
|
-
apiKey?: string
|
|
44
34
|
userPassword = "test"
|
|
45
35
|
|
|
46
36
|
constructor(opts: { openServer: boolean } = { openServer: true }) {
|
|
@@ -59,12 +49,6 @@ class TestConfiguration {
|
|
|
59
49
|
this.api = new API(this)
|
|
60
50
|
}
|
|
61
51
|
|
|
62
|
-
async useNewTenant() {
|
|
63
|
-
this.tenantId = structures.tenant.id()
|
|
64
|
-
|
|
65
|
-
await this.beforeAll()
|
|
66
|
-
}
|
|
67
|
-
|
|
68
52
|
getRequest() {
|
|
69
53
|
return this.request
|
|
70
54
|
}
|
|
@@ -217,12 +201,6 @@ class TestConfiguration {
|
|
|
217
201
|
return { [constants.Header.API_KEY]: coreEnv.INTERNAL_API_KEY }
|
|
218
202
|
}
|
|
219
203
|
|
|
220
|
-
bearerAPIHeaders() {
|
|
221
|
-
return {
|
|
222
|
-
[constants.Header.AUTHORIZATION]: `Bearer ${this.apiKey}`,
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
204
|
adminOnlyResponse = () => {
|
|
227
205
|
return { message: "Admin user only endpoint.", status: 403 }
|
|
228
206
|
}
|
|
@@ -235,20 +213,6 @@ class TestConfiguration {
|
|
|
235
213
|
})
|
|
236
214
|
await context.doInTenant(this.tenantId!, async () => {
|
|
237
215
|
this.user = await this.createUser(user)
|
|
238
|
-
|
|
239
|
-
const db = context.getGlobalDB()
|
|
240
|
-
|
|
241
|
-
const id = dbCore.generateDevInfoID(this.user._id)
|
|
242
|
-
// TODO: dry
|
|
243
|
-
this.apiKey = encryption.encrypt(
|
|
244
|
-
`${this.tenantId}${dbCore.SEPARATOR}${utils.newid()}`
|
|
245
|
-
)
|
|
246
|
-
const devInfo = {
|
|
247
|
-
_id: id,
|
|
248
|
-
userId: this.user._id,
|
|
249
|
-
apiKey: this.apiKey,
|
|
250
|
-
}
|
|
251
|
-
await db.put(devInfo)
|
|
252
216
|
})
|
|
253
217
|
}
|
|
254
218
|
|
|
@@ -341,19 +305,6 @@ class TestConfiguration {
|
|
|
341
305
|
controllers.config.save
|
|
342
306
|
)
|
|
343
307
|
}
|
|
344
|
-
|
|
345
|
-
// CONFIGS - SCIM
|
|
346
|
-
|
|
347
|
-
async setSCIMConfig(enabled: boolean) {
|
|
348
|
-
await this.deleteConfig(Config.SCIM)
|
|
349
|
-
const config: SCIMConfig = {
|
|
350
|
-
type: ConfigType.SCIM,
|
|
351
|
-
config: { enabled },
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
await this._req(config, null, controllers.config.save)
|
|
355
|
-
return config
|
|
356
|
-
}
|
|
357
308
|
}
|
|
358
309
|
|
|
359
310
|
export default TestConfiguration
|
package/src/tests/api/index.ts
CHANGED
|
@@ -15,9 +15,6 @@ import { RolesAPI } from "./roles"
|
|
|
15
15
|
import { TemplatesAPI } from "./templates"
|
|
16
16
|
import { LicenseAPI } from "./license"
|
|
17
17
|
import { AuditLogAPI } from "./auditLogs"
|
|
18
|
-
import { ScimUsersAPI } from "./scim/users"
|
|
19
|
-
import { ScimGroupsAPI } from "./scim/groups"
|
|
20
|
-
|
|
21
18
|
export default class API {
|
|
22
19
|
accounts: AccountAPI
|
|
23
20
|
auth: AuthAPI
|
|
@@ -35,8 +32,6 @@ export default class API {
|
|
|
35
32
|
templates: TemplatesAPI
|
|
36
33
|
license: LicenseAPI
|
|
37
34
|
auditLogs: AuditLogAPI
|
|
38
|
-
scimUsersAPI: ScimUsersAPI
|
|
39
|
-
scimGroupsAPI: ScimGroupsAPI
|
|
40
35
|
|
|
41
36
|
constructor(config: TestConfiguration) {
|
|
42
37
|
this.accounts = new AccountAPI(config)
|
|
@@ -55,7 +50,5 @@ export default class API {
|
|
|
55
50
|
this.templates = new TemplatesAPI(config)
|
|
56
51
|
this.license = new LicenseAPI(config)
|
|
57
52
|
this.auditLogs = new AuditLogAPI(config)
|
|
58
|
-
this.scimUsersAPI = new ScimUsersAPI(config)
|
|
59
|
-
this.scimGroupsAPI = new ScimGroupsAPI(config)
|
|
60
53
|
}
|
|
61
54
|
}
|