@budibase/worker 2.30.1 → 2.30.3

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.30.1",
4
+ "version": "2.30.3",
5
5
  "description": "Budibase background service",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -37,10 +37,10 @@
37
37
  "author": "Budibase",
38
38
  "license": "GPL-3.0",
39
39
  "dependencies": {
40
- "@budibase/backend-core": "2.30.1",
41
- "@budibase/pro": "2.30.1",
42
- "@budibase/string-templates": "2.30.1",
43
- "@budibase/types": "2.30.1",
40
+ "@budibase/backend-core": "2.30.3",
41
+ "@budibase/pro": "2.30.3",
42
+ "@budibase/string-templates": "2.30.3",
43
+ "@budibase/types": "2.30.3",
44
44
  "@koa/router": "8.0.8",
45
45
  "@techpass/passport-openidconnect": "0.3.3",
46
46
  "@types/global-agent": "2.1.1",
@@ -107,5 +107,5 @@
107
107
  }
108
108
  }
109
109
  },
110
- "gitHead": "7cc008950eaf62e5a3cad99d0b9df362facc3ca2"
110
+ "gitHead": "bb6092e58b80d4343bf3b720881f2dc01a30d1c9"
111
111
  }
@@ -104,7 +104,7 @@ export async function getSelf(ctx: any) {
104
104
  ctx.body = await groups.enrichUserRolesFromGroups(user)
105
105
 
106
106
  // add the feature flags for this tenant
107
- const flags = await features.fetch()
107
+ const flags = await features.flags.fetch()
108
108
  ctx.body.flags = flags
109
109
 
110
110
  addSessionAttributesToUser(ctx)
@@ -41,6 +41,14 @@ import { BpmStatusKey, BpmStatusValue } from "@budibase/shared-core"
41
41
 
42
42
  const MAX_USERS_UPLOAD_LIMIT = 1000
43
43
 
44
+ const generatePassword = (length: number) => {
45
+ const array = new Uint8Array(length)
46
+ crypto.getRandomValues(array)
47
+ return Array.from(array, byte => byte.toString(36).padStart(2, "0"))
48
+ .join("")
49
+ .slice(0, length)
50
+ }
51
+
44
52
  export const save = async (ctx: UserCtx<User, SaveUserResponse>) => {
45
53
  try {
46
54
  const currentUserId = ctx.user?._id
@@ -296,7 +304,7 @@ export const onboardUsers = async (
296
304
 
297
305
  let createdPasswords: Record<string, string> = {}
298
306
  const users: User[] = ctx.request.body.map(invite => {
299
- let password = Math.random().toString(36).substring(2, 22)
307
+ const password = generatePassword(12)
300
308
  createdPasswords[invite.email] = password
301
309
 
302
310
  return {
@@ -42,6 +42,7 @@ export const fetch = async (ctx: Ctx) => {
42
42
  baseUrl: env.PLATFORM_URL,
43
43
  isDev: env.isDev() && !env.isTest(),
44
44
  maintenance: [],
45
+ passwordMinLength: env.PASSWORD_MIN_LENGTH,
45
46
  }
46
47
 
47
48
  if (env.SELF_HOSTED) {
@@ -66,7 +66,7 @@ describe("/api/global/auth", () => {
66
66
  it("should return 403 with incorrect credentials", async () => {
67
67
  const tenantId = config.tenantId!
68
68
  const email = config.user?.email!
69
- const password = "incorrect"
69
+ const password = "incorrect123"
70
70
 
71
71
  const response = await config.api.auth.login(
72
72
  tenantId,
@@ -83,7 +83,7 @@ describe("/api/global/auth", () => {
83
83
  it("should return 403 when user doesn't exist", async () => {
84
84
  const tenantId = config.tenantId!
85
85
  const email = "invaliduser@example.com"
86
- const password = "password"
86
+ const password = "password123!"
87
87
 
88
88
  const response = await config.api.auth.login(
89
89
  tenantId,
@@ -203,7 +203,7 @@ describe("/api/global/auth", () => {
203
203
  )
204
204
  delete user.password
205
205
 
206
- const newPassword = "newpassword"
206
+ const newPassword = "newpassword1"
207
207
  const res = await config.api.auth.updatePassword(code!, newPassword)
208
208
 
209
209
  user = (await config.getUser(user.email))!
@@ -292,9 +292,9 @@ describe("/api/global/auth", () => {
292
292
  it("redirects to auth provider", async () => {
293
293
  nock("http://someconfigurl").get("/").times(1).reply(200, {
294
294
  issuer: "test",
295
- authorization_endpoint: "http://localhost/auth",
296
- token_endpoint: "http://localhost/token",
297
- userinfo_endpoint: "http://localhost/userinfo",
295
+ authorization_endpoint: "http://example.com/auth",
296
+ token_endpoint: "http://example.com/token",
297
+ userinfo_endpoint: "http://example.com/userinfo",
298
298
  })
299
299
 
300
300
  const configId = await generateOidcConfig()
@@ -305,7 +305,7 @@ describe("/api/global/auth", () => {
305
305
  const location: string = res.get("location")
306
306
  expect(
307
307
  location.startsWith(
308
- `http://localhost/auth?response_type=code&client_id=clientId&redirect_uri=http%3A%2F%2Flocalhost%3A10000%2Fapi%2Fglobal%2Fauth%2F${config.tenantId}%2Foidc%2Fcallback&scope=openid%20profile%20email%20offline_access`
308
+ `http://example.com/auth?response_type=code&client_id=clientId&redirect_uri=http%3A%2F%2Flocalhost%3A10000%2Fapi%2Fglobal%2Fauth%2F${config.tenantId}%2Foidc%2Fcallback&scope=openid%20profile%20email%20offline_access`
309
309
  )
310
310
  ).toBe(true)
311
311
  })
@@ -313,11 +313,13 @@ describe("/api/global/auth", () => {
313
313
 
314
314
  describe("GET /api/global/auth/:tenantId/oidc/callback", () => {
315
315
  it("logs in", async () => {
316
+ const email = `${generator.guid()}@example.com`
317
+
316
318
  nock("http://someconfigurl").get("/").times(2).reply(200, {
317
319
  issuer: "test",
318
- authorization_endpoint: "http://localhost/auth",
319
- token_endpoint: "http://localhost/token",
320
- userinfo_endpoint: "http://localhost/userinfo",
320
+ authorization_endpoint: "http://example.com/auth",
321
+ token_endpoint: "http://example.com/token",
322
+ userinfo_endpoint: "http://example.com/userinfo",
321
323
  })
322
324
 
323
325
  const token = jwt.sign(
@@ -326,20 +328,20 @@ describe("/api/global/auth", () => {
326
328
  sub: "sub",
327
329
  aud: "clientId",
328
330
  exp: Math.floor(Date.now() / 1000) + 60 * 60,
329
- email: "oauth@example.com",
331
+ email,
330
332
  },
331
333
  "secret"
332
334
  )
333
335
 
334
- nock("http://localhost").post("/token").reply(200, {
336
+ nock("http://example.com").post("/token").reply(200, {
335
337
  access_token: "access",
336
338
  refresh_token: "refresh",
337
339
  id_token: token,
338
340
  })
339
341
 
340
- nock("http://localhost").get("/userinfo?schema=openid").reply(200, {
342
+ nock("http://example.com").get("/userinfo?schema=openid").reply(200, {
341
343
  sub: "sub",
342
- email: "oauth@example.com",
344
+ email,
343
345
  })
344
346
 
345
347
  const configId = await generateOidcConfig()
@@ -351,10 +353,7 @@ describe("/api/global/auth", () => {
351
353
  )
352
354
  }
353
355
 
354
- expect(events.auth.login).toHaveBeenCalledWith(
355
- "oidc",
356
- "oauth@example.com"
357
- )
356
+ expect(events.auth.login).toHaveBeenCalledWith("oidc", email)
358
357
  expect(events.auth.login).toHaveBeenCalledTimes(1)
359
358
  expect(res.status).toBe(302)
360
359
  const location: string = res.get("location")
@@ -12,6 +12,33 @@ const nodemailer = require("nodemailer")
12
12
  // for the real email tests give them a long time to try complete/fail
13
13
  jest.setTimeout(30000)
14
14
 
15
+ function cancelableTimeout(timeout: number): [Promise<unknown>, () => void] {
16
+ let timeoutId: NodeJS.Timeout
17
+ return [
18
+ new Promise((resolve, reject) => {
19
+ timeoutId = setTimeout(() => {
20
+ reject({
21
+ status: 301,
22
+ errno: "ETIME",
23
+ })
24
+ }, timeout)
25
+ }),
26
+ () => {
27
+ clearTimeout(timeoutId)
28
+ },
29
+ ]
30
+ }
31
+
32
+ async function withTimeout<T>(
33
+ timeout: number,
34
+ promise: Promise<T>
35
+ ): Promise<T> {
36
+ const [timeoutPromise, cancel] = cancelableTimeout(timeout)
37
+ const result = (await Promise.race([promise, timeoutPromise])) as T
38
+ cancel()
39
+ return result
40
+ }
41
+
15
42
  describe("/api/global/email", () => {
16
43
  const config = new TestConfiguration()
17
44
 
@@ -30,19 +57,8 @@ describe("/api/global/email", () => {
30
57
  ) {
31
58
  let response, text
32
59
  try {
33
- const timeout = () =>
34
- new Promise((resolve, reject) =>
35
- setTimeout(
36
- () =>
37
- reject({
38
- status: 301,
39
- errno: "ETIME",
40
- }),
41
- 20000
42
- )
43
- )
44
- await Promise.race([config.saveEtherealSmtpConfig(), timeout()])
45
- await Promise.race([config.saveSettingsConfig(), timeout()])
60
+ await withTimeout(20000, config.saveEtherealSmtpConfig())
61
+ await withTimeout(20000, config.saveSettingsConfig())
46
62
  let res
47
63
  if (attachments) {
48
64
  res = await config.api.emails
@@ -32,7 +32,7 @@ describe("/api/global/self", () => {
32
32
 
33
33
  const res = await config.api.self
34
34
  .updateSelf(user, {
35
- password: "newPassword",
35
+ password: "newPassword1",
36
36
  })
37
37
  .expect(200)
38
38
 
@@ -29,7 +29,7 @@ describe("/api/global/tenant", () => {
29
29
  const tenantInfo: TenantInfo = {
30
30
  owner: {
31
31
  email: "test@example.com",
32
- password: "PASSWORD",
32
+ password: "PASSWORD123!",
33
33
  ssoId: "SSO_ID",
34
34
  givenName: "Jane",
35
35
  familyName: "Doe",
@@ -26,6 +26,7 @@ const environment = {
26
26
  SALT_ROUNDS: process.env.SALT_ROUNDS,
27
27
  REDIS_PASSWORD: process.env.REDIS_PASSWORD,
28
28
  COOKIE_DOMAIN: process.env.COOKIE_DOMAIN,
29
+ PASSWORD_MIN_LENGTH: process.env.PASSWORD_MIN_LENGTH,
29
30
  // urls
30
31
  MINIO_URL: process.env.MINIO_URL,
31
32
  COUCH_DB_URL: process.env.COUCH_DB_URL,
package/src/index.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  timers,
19
19
  redis,
20
20
  cache,
21
+ features,
21
22
  } from "@budibase/backend-core"
22
23
 
23
24
  db.init()
@@ -95,6 +96,7 @@ export default server.listen(parseInt(env.PORT || "4002"), async () => {
95
96
  console.log(startupLog)
96
97
  await initPro()
97
98
  await redis.clients.init()
99
+ features.init()
98
100
  cache.docWritethrough.init()
99
101
  // configure events to use the pro audit log write
100
102
  // can't integrate directly into backend-core due to cyclic issues
@@ -44,7 +44,7 @@ class TestConfiguration {
44
44
  tenantId: string
45
45
  user?: User
46
46
  apiKey?: string
47
- userPassword = "password"
47
+ userPassword = "password123!"
48
48
 
49
49
  constructor(opts: { openServer: boolean } = { openServer: true }) {
50
50
  // default to cloud hosting
@@ -40,7 +40,7 @@ export class ConfigAPI extends TestAPI {
40
40
  const sessionContent = JSON.parse(
41
41
  Buffer.from(koaSession, "base64").toString("utf-8")
42
42
  )
43
- const handle = sessionContent["openidconnect:localhost"].state.handle
43
+ const handle = sessionContent["openidconnect:example.com"].state.handle
44
44
  return this.request
45
45
  .get(`/api/global/auth/${this.config.getTenantId()}/oidc/callback`)
46
46
  .query({ code: "test", state: handle })
@@ -48,7 +48,7 @@ export class UserAPI extends TestAPI {
48
48
  return this.request
49
49
  .post(`/api/global/users/invite/accept`)
50
50
  .send({
51
- password: "newpassword",
51
+ password: "newpassword1",
52
52
  inviteCode: code,
53
53
  firstName: "Ted",
54
54
  })
@@ -101,7 +101,7 @@ export class UserAPI extends TestAPI {
101
101
  if (!request) {
102
102
  request = {
103
103
  email: structures.email(),
104
- password: generator.string({ length: 8 }),
104
+ password: generator.string({ length: 12 }),
105
105
  tenantId: structures.tenant.id(),
106
106
  }
107
107
  }
@@ -1,13 +1,21 @@
1
1
  import { mocks, testContainerUtils } from "@budibase/backend-core/tests"
2
2
  import env from "../environment"
3
3
  import { env as coreEnv, timers } from "@budibase/backend-core"
4
-
5
- // must explicitly enable fetch mock
6
- mocks.fetch.enable()
4
+ import nock from "nock"
7
5
 
8
6
  // mock all dates to 2020-01-01T00:00:00.000Z
9
7
  // use tk.reset() to use real dates in individual tests
10
- const tk = require("timekeeper")
8
+ import tk from "timekeeper"
9
+
10
+ nock.disableNetConnect()
11
+ nock.enableNetConnect(host => {
12
+ return (
13
+ host.includes("localhost") ||
14
+ host.includes("127.0.0.1") ||
15
+ host.includes("::1") ||
16
+ host.includes("ethereal.email") // used in realEmail.spec.ts
17
+ )
18
+ })
11
19
 
12
20
  tk.freeze(mocks.date.MOCK_DATE)
13
21