@budibase/worker 3.18.2 → 3.18.4
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 +2 -2
- package/src/api/controllers/global/roles.ts +5 -5
- package/src/api/controllers/global/self.ts +0 -10
- package/src/api/controllers/system/environment.ts +7 -3
- package/src/api/routes/global/roles.ts +3 -2
- package/src/api/routes/global/tests/roles.spec.ts +27 -4
- package/src/api/routes/global/tests/users.spec.ts +42 -3
- package/src/api/routes/global/users.ts +9 -7
- package/src/api/routes/system/tests/environment.spec.ts +3 -1
- package/src/environment.ts +2 -1
- package/src/sdk/tenants/tenants.ts +3 -3
- package/src/tests/TestConfiguration.ts +14 -14
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/worker",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "3.18.
|
|
4
|
+
"version": "3.18.4",
|
|
5
5
|
"description": "Budibase background service",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -109,5 +109,5 @@
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
},
|
|
112
|
-
"gitHead": "
|
|
112
|
+
"gitHead": "b82c05d3d0949d198b49415d20980e72cc61ca5b"
|
|
113
113
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
+
cache,
|
|
3
|
+
context,
|
|
2
4
|
db as dbCore,
|
|
3
5
|
roles,
|
|
4
|
-
context,
|
|
5
|
-
cache,
|
|
6
6
|
tenancy,
|
|
7
7
|
} from "@budibase/backend-core"
|
|
8
|
-
import sdk from "../../../sdk"
|
|
9
8
|
import {
|
|
10
9
|
Ctx,
|
|
11
|
-
App,
|
|
12
10
|
FetchGlobalRolesResponse,
|
|
13
11
|
FindGlobalRoleResponse,
|
|
14
12
|
RemoveAppRoleResponse,
|
|
13
|
+
Workspace,
|
|
15
14
|
} from "@budibase/types"
|
|
15
|
+
import sdk from "../../../sdk"
|
|
16
16
|
|
|
17
17
|
export async function fetch(ctx: Ctx<void, FetchGlobalRolesResponse>) {
|
|
18
18
|
const tenantId = ctx.user!.tenantId
|
|
@@ -43,7 +43,7 @@ export async function find(ctx: Ctx<void, FindGlobalRoleResponse>) {
|
|
|
43
43
|
const appId = ctx.params.appId
|
|
44
44
|
await context.doInAppContext(dbCore.getDevAppID(appId), async () => {
|
|
45
45
|
const db = context.getAppDB()
|
|
46
|
-
const app = await db.get<
|
|
46
|
+
const app = await db.get<Workspace>(dbCore.DocumentType.APP_METADATA)
|
|
47
47
|
ctx.body = {
|
|
48
48
|
roles: await roles.getAllRoles(),
|
|
49
49
|
name: app.name,
|
|
@@ -15,9 +15,6 @@ import {
|
|
|
15
15
|
GenerateAPIKeyRequest,
|
|
16
16
|
GenerateAPIKeyResponse,
|
|
17
17
|
GetGlobalSelfResponse,
|
|
18
|
-
QuotaType,
|
|
19
|
-
QuotaUsageType,
|
|
20
|
-
StaticQuotaName,
|
|
21
18
|
UpdateSelfRequest,
|
|
22
19
|
UpdateSelfResponse,
|
|
23
20
|
User,
|
|
@@ -126,13 +123,6 @@ export async function getSelf(ctx: UserCtx<void, GetGlobalSelfResponse>) {
|
|
|
126
123
|
}
|
|
127
124
|
: undefined
|
|
128
125
|
|
|
129
|
-
if (flags?.WORKSPACES) {
|
|
130
|
-
// TODO: once the flag is clean, we should rename the original object instead
|
|
131
|
-
sessionAttributes.license.quotas[QuotaType.USAGE][QuotaUsageType.STATIC][
|
|
132
|
-
StaticQuotaName.APPS
|
|
133
|
-
].name = "Workspaces"
|
|
134
|
-
}
|
|
135
|
-
|
|
136
126
|
ctx.body = {
|
|
137
127
|
...enrichedUser,
|
|
138
128
|
...sessionAttributes,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Ctx, GetEnvironmentResponse, MaintenanceType } from "@budibase/types"
|
|
2
|
-
import env from "../../../environment"
|
|
3
1
|
import { env as coreEnv, db as dbCore } from "@budibase/backend-core"
|
|
4
|
-
import nodeFetch from "node-fetch"
|
|
5
2
|
import { helpers } from "@budibase/shared-core"
|
|
3
|
+
import { Ctx, GetEnvironmentResponse, MaintenanceType } from "@budibase/types"
|
|
4
|
+
import nodeFetch from "node-fetch"
|
|
5
|
+
import env from "../../../environment"
|
|
6
6
|
|
|
7
7
|
let sqsAvailable: boolean
|
|
8
8
|
async function isSqsAvailable() {
|
|
@@ -49,6 +49,10 @@ export const fetch = async (ctx: Ctx<void, GetEnvironmentResponse>) => {
|
|
|
49
49
|
isDev: env.isDev() && !env.isTest(),
|
|
50
50
|
maintenance: [],
|
|
51
51
|
passwordMinLength: env.PASSWORD_MIN_LENGTH,
|
|
52
|
+
serveDevClientFromStorage:
|
|
53
|
+
env.DEV_USE_CLIENT_FROM_STORAGE !== undefined
|
|
54
|
+
? !!env.DEV_USE_CLIENT_FROM_STORAGE
|
|
55
|
+
: false,
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
if (env.SELF_HOSTED) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as controller from "../../controllers/global/roles"
|
|
2
|
-
import { builderOrAdminRoutes } from "../endpointGroups"
|
|
2
|
+
import { adminRoutes, builderOrAdminRoutes } from "../endpointGroups"
|
|
3
3
|
|
|
4
4
|
builderOrAdminRoutes
|
|
5
5
|
.get("/api/global/roles", controller.fetch)
|
|
6
6
|
.get("/api/global/roles/:appId", controller.find)
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
adminRoutes.delete("/api/global/roles/:appId", controller.removeAppRole)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { structures, TestConfiguration } from "../../../../tests"
|
|
2
1
|
import { context, db, roles } from "@budibase/backend-core"
|
|
3
2
|
import {
|
|
4
|
-
App,
|
|
5
|
-
Database,
|
|
6
3
|
BuiltinPermissionID,
|
|
4
|
+
Database,
|
|
7
5
|
WithoutDocMetadata,
|
|
6
|
+
Workspace,
|
|
8
7
|
} from "@budibase/types"
|
|
8
|
+
import { structures, TestConfiguration } from "../../../../tests"
|
|
9
9
|
|
|
10
10
|
jest.mock("@budibase/backend-core", () => {
|
|
11
11
|
const core = jest.requireActual("@budibase/backend-core")
|
|
@@ -35,7 +35,9 @@ async function addAppMetadata() {
|
|
|
35
35
|
})
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
async function updateAppMetadata(
|
|
38
|
+
async function updateAppMetadata(
|
|
39
|
+
update: Partial<WithoutDocMetadata<Workspace>>
|
|
40
|
+
) {
|
|
39
41
|
const app = await appDb.get("app_metadata")
|
|
40
42
|
await appDb.put({
|
|
41
43
|
...app,
|
|
@@ -140,6 +142,18 @@ describe("/api/global/roles", () => {
|
|
|
140
142
|
})
|
|
141
143
|
|
|
142
144
|
describe("DELETE /api/global/roles/:appId", () => {
|
|
145
|
+
async function createBuilderUser() {
|
|
146
|
+
const saveResponse = await config.api.users.saveUser(
|
|
147
|
+
structures.users.builderUser(),
|
|
148
|
+
200
|
|
149
|
+
)
|
|
150
|
+
const { body: user } = await config.api.users.getUser(
|
|
151
|
+
saveResponse.body._id
|
|
152
|
+
)
|
|
153
|
+
await config.login(user)
|
|
154
|
+
return user
|
|
155
|
+
}
|
|
156
|
+
|
|
143
157
|
it("removes an app role", async () => {
|
|
144
158
|
let user = structures.users.user()
|
|
145
159
|
user.roles = {
|
|
@@ -151,5 +165,14 @@ describe("/api/global/roles", () => {
|
|
|
151
165
|
expect(updatedUser.body.roles).not.toHaveProperty(appId)
|
|
152
166
|
expect(res.body.message).toEqual("App role removed from all users")
|
|
153
167
|
})
|
|
168
|
+
|
|
169
|
+
it("should not allow creator users to remove app roles", async () => {
|
|
170
|
+
const builderUser = await createBuilderUser()
|
|
171
|
+
|
|
172
|
+
const res = await config.withUser(builderUser, () =>
|
|
173
|
+
config.api.roles.remove(appId, { status: 403 })
|
|
174
|
+
)
|
|
175
|
+
expect(res.body.message).toBe("Admin user only endpoint.")
|
|
176
|
+
})
|
|
154
177
|
})
|
|
155
178
|
})
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { InviteUsersResponse,
|
|
1
|
+
import { InviteUsersResponse, OIDCUser, User } from "@budibase/types"
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { events, tenancy, accounts as _accounts } from "@budibase/backend-core"
|
|
3
|
+
import { accounts as _accounts, events, tenancy } from "@budibase/backend-core"
|
|
5
4
|
import * as userSdk from "../../../../sdk/users"
|
|
5
|
+
import { TestConfiguration, mocks, structures } from "../../../../tests"
|
|
6
6
|
|
|
7
7
|
jest.mock("nodemailer")
|
|
8
8
|
const sendMailMock = mocks.email.mock()
|
|
@@ -24,6 +24,16 @@ describe("/api/global/users", () => {
|
|
|
24
24
|
jest.clearAllMocks()
|
|
25
25
|
})
|
|
26
26
|
|
|
27
|
+
async function createBuilderUser() {
|
|
28
|
+
const saveResponse = await config.api.users.saveUser(
|
|
29
|
+
structures.users.builderUser(),
|
|
30
|
+
200
|
|
31
|
+
)
|
|
32
|
+
const { body: user } = await config.api.users.getUser(saveResponse.body._id)
|
|
33
|
+
await config.login(user)
|
|
34
|
+
return user
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
describe("POST /api/global/users/invite", () => {
|
|
28
38
|
it("should be able to generate an invitation", async () => {
|
|
29
39
|
const email = structures.users.newEmail()
|
|
@@ -73,6 +83,19 @@ describe("/api/global/users", () => {
|
|
|
73
83
|
expect(events.user.invited).toHaveBeenCalledTimes(0)
|
|
74
84
|
})
|
|
75
85
|
|
|
86
|
+
it("should not allow creator users to access single invite endpoint", async () => {
|
|
87
|
+
const user = await createBuilderUser()
|
|
88
|
+
|
|
89
|
+
const { res } = await config.withUser(user, () =>
|
|
90
|
+
config.api.users.sendUserInvite(
|
|
91
|
+
sendMailMock,
|
|
92
|
+
structures.users.newEmail(),
|
|
93
|
+
403
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
expect(res.body.message).toBe("Admin user only endpoint.")
|
|
97
|
+
})
|
|
98
|
+
|
|
76
99
|
it("should be able to create new user from invite", async () => {
|
|
77
100
|
const email = structures.users.newEmail()
|
|
78
101
|
const { code } = await config.api.users.sendUserInvite(
|
|
@@ -137,6 +160,22 @@ describe("/api/global/users", () => {
|
|
|
137
160
|
expect(sendMailMock).toHaveBeenCalledTimes(0)
|
|
138
161
|
expect(events.user.invited).toHaveBeenCalledTimes(0)
|
|
139
162
|
})
|
|
163
|
+
|
|
164
|
+
it("should not allow creator users to access multi-invite endpoint", async () => {
|
|
165
|
+
const user = await createBuilderUser()
|
|
166
|
+
|
|
167
|
+
const request = [
|
|
168
|
+
{
|
|
169
|
+
email: structures.users.newEmail(),
|
|
170
|
+
userInfo: { admin: { global: true } },
|
|
171
|
+
},
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
const res = await config.withUser(user, () =>
|
|
175
|
+
config.api.users.sendMultiUserInvite(request, 403)
|
|
176
|
+
)
|
|
177
|
+
expect(res.body.message).toBe("Admin user only endpoint.")
|
|
178
|
+
})
|
|
140
179
|
})
|
|
141
180
|
|
|
142
181
|
describe("POST /api/global/users/bulk", () => {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import * as controller from "../../controllers/global/users"
|
|
2
1
|
import { auth } from "@budibase/backend-core"
|
|
3
2
|
import Joi from "joi"
|
|
4
|
-
import
|
|
3
|
+
import * as controller from "../../controllers/global/users"
|
|
5
4
|
import {
|
|
6
|
-
loggedInRoutes,
|
|
7
|
-
cloudRestrictedRoutes,
|
|
8
|
-
builderOrAdminRoutes,
|
|
9
5
|
adminRoutes,
|
|
6
|
+
builderOrAdminRoutes,
|
|
7
|
+
cloudRestrictedRoutes,
|
|
8
|
+
loggedInRoutes,
|
|
10
9
|
} from "../endpointGroups"
|
|
10
|
+
import { users } from "../validation"
|
|
11
11
|
|
|
12
12
|
const OPTIONAL_STRING = Joi.string().optional().allow(null).allow("")
|
|
13
13
|
|
|
@@ -100,6 +100,10 @@ adminRoutes
|
|
|
100
100
|
builderOrAdminRoutes
|
|
101
101
|
.get("/api/global/users", controller.fetch)
|
|
102
102
|
.get("/api/global/users/count/:appId", controller.countByApp)
|
|
103
|
+
.get("/api/global/users/invites", controller.getUserInvites)
|
|
104
|
+
.get("/api/global/users/:id", controller.find)
|
|
105
|
+
|
|
106
|
+
adminRoutes
|
|
103
107
|
.post("/api/global/users/invite", buildInviteValidation(), controller.invite)
|
|
104
108
|
.post(
|
|
105
109
|
"/api/global/users/onboard",
|
|
@@ -116,8 +120,6 @@ builderOrAdminRoutes
|
|
|
116
120
|
controller.removeMultipleInvites
|
|
117
121
|
)
|
|
118
122
|
.post("/api/global/users/invite/update/:code", controller.updateInvite)
|
|
119
|
-
.get("/api/global/users/invites", controller.getUserInvites)
|
|
120
|
-
.get("/api/global/users/:id", controller.find)
|
|
121
123
|
|
|
122
124
|
loggedInRoutes
|
|
123
125
|
// search can be used by any user now, to retrieve users for user column
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { TestConfiguration } from "../../../../tests"
|
|
2
1
|
import { withEnv } from "../../../../environment"
|
|
2
|
+
import { TestConfiguration } from "../../../../tests"
|
|
3
3
|
|
|
4
4
|
jest.unmock("node-fetch")
|
|
5
5
|
|
|
@@ -29,6 +29,7 @@ describe("/api/system/environment", () => {
|
|
|
29
29
|
baseUrl: "http://localhost:10000",
|
|
30
30
|
offlineMode: false,
|
|
31
31
|
maintenance: [],
|
|
32
|
+
serveDevClientFromStorage: false,
|
|
32
33
|
})
|
|
33
34
|
})
|
|
34
35
|
|
|
@@ -43,6 +44,7 @@ describe("/api/system/environment", () => {
|
|
|
43
44
|
baseUrl: "http://localhost:10000",
|
|
44
45
|
offlineMode: false,
|
|
45
46
|
maintenance: [],
|
|
47
|
+
serveDevClientFromStorage: false,
|
|
46
48
|
})
|
|
47
49
|
})
|
|
48
50
|
})
|
package/src/environment.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { env as coreEnv } from "@budibase/backend-core"
|
|
2
2
|
import { ServiceType } from "@budibase/types"
|
|
3
|
-
import { join, resolve } from "path"
|
|
4
3
|
import cloneDeep from "lodash/cloneDeep"
|
|
4
|
+
import { join, resolve } from "path"
|
|
5
5
|
|
|
6
6
|
coreEnv._set("SERVICE_TYPE", ServiceType.WORKER)
|
|
7
7
|
|
|
@@ -55,6 +55,7 @@ const environment = {
|
|
|
55
55
|
SMTP_FALLBACK_ENABLED: process.env.SMTP_FALLBACK_ENABLED,
|
|
56
56
|
DISABLE_DEVELOPER_LICENSE: process.env.DISABLE_DEVELOPER_LICENSE,
|
|
57
57
|
BUDIBASE_ENVIRONMENT: process.env.BUDIBASE_ENVIRONMENT,
|
|
58
|
+
DEV_USE_CLIENT_FROM_STORAGE: process.env.DEV_USE_CLIENT_FROM_STORAGE,
|
|
58
59
|
// smtp
|
|
59
60
|
SMTP_USER: process.env.SMTP_USER,
|
|
60
61
|
SMTP_PASSWORD: process.env.SMTP_PASSWORD,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { tenancy, db as dbCore, platform } from "@budibase/backend-core"
|
|
1
|
+
import { db as dbCore, platform, tenancy } from "@budibase/backend-core"
|
|
3
2
|
import { quotas } from "@budibase/pro"
|
|
3
|
+
import { Workspace } from "@budibase/types"
|
|
4
4
|
|
|
5
5
|
export async function deleteTenant(tenantId: string) {
|
|
6
6
|
await quotas.bustCache()
|
|
@@ -21,7 +21,7 @@ async function removeGlobalDB(tenantId: string) {
|
|
|
21
21
|
|
|
22
22
|
async function removeTenantApps(tenantId: string) {
|
|
23
23
|
try {
|
|
24
|
-
const apps = (await dbCore.getAllApps({ all: true })) as
|
|
24
|
+
const apps = (await dbCore.getAllApps({ all: true })) as Workspace[]
|
|
25
25
|
const destroyPromises = apps.map(app => {
|
|
26
26
|
const db = dbCore.getDB(app.appId)
|
|
27
27
|
return db.destroy()
|
|
@@ -7,37 +7,37 @@ mocks.licenses.init(mocks.pro)
|
|
|
7
7
|
mocks.licenses.useUnlimited()
|
|
8
8
|
|
|
9
9
|
import * as dbConfig from "../db"
|
|
10
|
-
|
|
11
|
-
dbConfig.init()
|
|
12
10
|
import env from "../environment"
|
|
13
11
|
import * as controllers from "./controllers"
|
|
14
12
|
|
|
13
|
+
dbConfig.init()
|
|
14
|
+
|
|
15
15
|
import supertest from "supertest"
|
|
16
16
|
|
|
17
|
-
import { Config } from "../constants"
|
|
18
17
|
import {
|
|
19
|
-
users,
|
|
20
|
-
context,
|
|
21
|
-
sessions,
|
|
22
18
|
constants,
|
|
19
|
+
context,
|
|
23
20
|
env as coreEnv,
|
|
24
21
|
db as dbCore,
|
|
25
22
|
encryption,
|
|
23
|
+
sessions,
|
|
24
|
+
users,
|
|
26
25
|
utils,
|
|
27
26
|
} from "@budibase/backend-core"
|
|
28
|
-
import structures, { CSRF_TOKEN } from "./structures"
|
|
29
27
|
import {
|
|
30
|
-
SaveUserResponse,
|
|
31
|
-
User,
|
|
32
28
|
AuthToken,
|
|
33
|
-
SCIMConfig,
|
|
34
29
|
ConfigType,
|
|
30
|
+
SaveUserResponse,
|
|
31
|
+
SCIMConfig,
|
|
35
32
|
SMTPConfig,
|
|
36
33
|
SMTPInnerConfig,
|
|
34
|
+
User,
|
|
37
35
|
} from "@budibase/types"
|
|
38
|
-
import API from "./api"
|
|
39
|
-
import jwt, { Secret } from "jsonwebtoken"
|
|
40
36
|
import http from "http"
|
|
37
|
+
import jwt, { Secret } from "jsonwebtoken"
|
|
38
|
+
import { Config } from "../constants"
|
|
39
|
+
import API from "./api"
|
|
40
|
+
import structures, { CSRF_TOKEN } from "./structures"
|
|
41
41
|
|
|
42
42
|
class TestConfiguration {
|
|
43
43
|
server: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> =
|
|
@@ -223,11 +223,11 @@ class TestConfiguration {
|
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
-
async withUser(user: User, f: () => Promise<
|
|
226
|
+
async withUser<T>(user: User, f: () => Promise<T>): Promise<T> {
|
|
227
227
|
const oldUser = this.user
|
|
228
228
|
this.user = user
|
|
229
229
|
try {
|
|
230
|
-
await f()
|
|
230
|
+
return await f()
|
|
231
231
|
} finally {
|
|
232
232
|
this.user = oldUser
|
|
233
233
|
}
|