@budibase/worker 1.3.19-alpha.7 → 1.3.20

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": "1.3.19-alpha.7",
4
+ "version": "1.3.20",
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": "1.3.19-alpha.7",
40
- "@budibase/pro": "1.3.19-alpha.6",
41
- "@budibase/string-templates": "1.3.19-alpha.7",
42
- "@budibase/types": "1.3.19-alpha.7",
39
+ "@budibase/backend-core": "^1.3.20",
40
+ "@budibase/pro": "1.3.19",
41
+ "@budibase/string-templates": "^1.3.20",
42
+ "@budibase/types": "^1.3.20",
43
43
  "@koa/router": "8.0.8",
44
44
  "@sentry/node": "6.17.7",
45
45
  "@techpass/passport-openidconnect": "0.3.2",
@@ -104,5 +104,5 @@
104
104
  "./scripts/jestSetup.js"
105
105
  ]
106
106
  },
107
- "gitHead": "b86121efe78de689182f6024391eef2e8659dd1a"
107
+ "gitHead": "463d6238d270324638761183110f61dd0e448508"
108
108
  }
@@ -17,9 +17,7 @@ const arg = process.argv.slice(2)[0]
17
17
  */
18
18
  updateDotEnv({
19
19
  ACCOUNT_PORTAL_URL:
20
- arg === "enable"
21
- ? "http://account.local.com:10001"
22
- : "http://localhost:10001",
20
+ arg === "enable" ? "http://local.com:10001" : "http://localhost:10001",
23
21
  COOKIE_DOMAIN: arg === "enable" ? ".local.com" : "",
24
22
  PLATFORM_URL:
25
23
  arg === "enable" ? "http://local.com:10000" : "http://localhost:10000",
@@ -16,11 +16,6 @@ const { newid } = require("@budibase/backend-core/utils")
16
16
  const { users } = require("../../../sdk")
17
17
  const { Cookies } = require("@budibase/backend-core/constants")
18
18
  const { events, featureFlags } = require("@budibase/backend-core")
19
- const env = require("../../../environment")
20
-
21
- function newTestApiKey() {
22
- return env.ENCRYPTED_TEST_PUBLIC_API_KEY
23
- }
24
19
 
25
20
  function newApiKey() {
26
21
  return encrypt(`${getTenantId()}${SEPARATOR}${newid()}`)
@@ -34,25 +29,15 @@ function cleanupDevInfo(info) {
34
29
  }
35
30
 
36
31
  exports.generateAPIKey = async ctx => {
37
- let userId
38
- let apiKey
39
- if (env.isTest() && ctx.request.body.userId) {
40
- userId = ctx.request.body.userId
41
- apiKey = newTestApiKey()
42
- } else {
43
- userId = ctx.user._id
44
- apiKey = newApiKey()
45
- }
46
-
47
32
  const db = getGlobalDB()
48
- const id = generateDevInfoID(userId)
33
+ const id = generateDevInfoID(ctx.user._id)
49
34
  let devInfo
50
35
  try {
51
36
  devInfo = await db.get(id)
52
37
  } catch (err) {
53
- devInfo = { _id: id, userId }
38
+ devInfo = { _id: id, userId: ctx.user._id }
54
39
  }
55
- devInfo.apiKey = await apiKey
40
+ devInfo.apiKey = await newApiKey()
56
41
  await db.put(devInfo)
57
42
  ctx.body = cleanupDevInfo(devInfo)
58
43
  }
@@ -95,16 +80,15 @@ const addSessionAttributesToUser = ctx => {
95
80
  ctx.body.csrfToken = ctx.user.csrfToken
96
81
  }
97
82
 
98
- /**
99
- * Remove the attributes that are session based from the current user,
100
- * so that stale values are not written to the db
101
- */
102
- const removeSessionAttributesFromUser = ctx => {
103
- delete ctx.request.body.csrfToken
104
- delete ctx.request.body.account
105
- delete ctx.request.body.accountPortalAccess
106
- delete ctx.request.body.budibaseAccess
107
- delete ctx.request.body.license
83
+ const sanitiseUserUpdate = ctx => {
84
+ const allowed = ["firstName", "lastName", "password", "forceResetPassword"]
85
+ const resp = {}
86
+ for (let [key, value] of Object.entries(ctx.request.body)) {
87
+ if (allowed.includes(key)) {
88
+ resp[key] = value
89
+ }
90
+ }
91
+ return resp
108
92
  }
109
93
 
110
94
  exports.getSelf = async ctx => {
@@ -132,10 +116,12 @@ exports.updateSelf = async ctx => {
132
116
  const db = getGlobalDB()
133
117
  const user = await db.get(ctx.user._id)
134
118
  let passwordChange = false
135
- if (ctx.request.body.password) {
119
+
120
+ const userUpdateObj = sanitiseUserUpdate(ctx)
121
+ if (userUpdateObj.password) {
136
122
  // changing password
137
123
  passwordChange = true
138
- ctx.request.body.password = await hash(ctx.request.body.password)
124
+ userUpdateObj.password = await hash(userUpdateObj.password)
139
125
  // Log all other sessions out apart from the current one
140
126
  await platformLogout({
141
127
  ctx,
@@ -143,14 +129,10 @@ exports.updateSelf = async ctx => {
143
129
  keepActiveSession: true,
144
130
  })
145
131
  }
146
- // don't allow sending up an ID/Rev, always use the existing one
147
- delete ctx.request.body._id
148
- delete ctx.request.body._rev
149
- removeSessionAttributesFromUser(ctx)
150
132
 
151
133
  const response = await db.put({
152
134
  ...user,
153
- ...ctx.request.body,
135
+ ...userUpdateObj,
154
136
  })
155
137
  await userCache.invalidateUser(user._id)
156
138
  ctx.body = {
@@ -159,7 +141,6 @@ exports.updateSelf = async ctx => {
159
141
  }
160
142
 
161
143
  // remove the old password from the user before sending events
162
- user._rev = response.rev
163
144
  delete user.password
164
145
  await events.user.updated(user)
165
146
  if (passwordChange) {
@@ -14,7 +14,6 @@ import {
14
14
  errors,
15
15
  events,
16
16
  tenancy,
17
- users as usersCore,
18
17
  } from "@budibase/backend-core"
19
18
  import { checkAnyUserExists } from "../../../utilities/users"
20
19
  import { groups as groupUtils } from "@budibase/pro"
@@ -148,9 +147,7 @@ export const bulkDelete = async (ctx: any) => {
148
147
  }
149
148
 
150
149
  try {
151
- let response = await users.bulkDelete(userIds)
152
-
153
- ctx.body = response
150
+ ctx.body = await users.bulkDelete(userIds)
154
151
  } catch (err) {
155
152
  ctx.throw(err)
156
153
  }
@@ -1,5 +1,5 @@
1
1
  jest.mock("nodemailer")
2
- import { TestConfiguration, API, mocks } from "../../../../tests"
2
+ import { TestConfiguration, API } from "../../../../tests"
3
3
  import { events } from "@budibase/backend-core"
4
4
 
5
5
  describe("/api/global/self", () => {
@@ -26,9 +26,6 @@ describe("/api/global/self", () => {
26
26
  delete user.password
27
27
  const res = await api.self.updateSelf(user)
28
28
 
29
- const dbUser = await config.getUser(user.email)
30
- user._rev = dbUser._rev
31
- user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString()
32
29
  expect(res.body._id).toBe(user._id)
33
30
  expect(events.user.updated).toBeCalledTimes(1)
34
31
  expect(events.user.updated).toBeCalledWith(user)
@@ -42,9 +39,6 @@ describe("/api/global/self", () => {
42
39
  user.password = "newPassword"
43
40
  const res = await api.self.updateSelf(user)
44
41
 
45
- const dbUser = await config.getUser(user.email)
46
- user._rev = dbUser._rev
47
- user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString()
48
42
  delete user.password
49
43
  expect(res.body._id).toBe(user._id)
50
44
  expect(events.user.updated).toBeCalledTimes(1)
@@ -63,7 +63,6 @@ const env = {
63
63
  // other
64
64
  CHECKLIST_CACHE_TTL: parseIntSafe(process.env.CHECKLIST_CACHE_TTL) || 3600,
65
65
  SESSION_UPDATE_PERIOD: process.env.SESSION_UPDATE_PERIOD,
66
- ENCRYPTED_TEST_PUBLIC_API_KEY: process.env.ENCRYPTED_TEST_PUBLIC_API_KEY,
67
66
  _set(key: any, value: any) {
68
67
  process.env[key] = value
69
68
  module.exports[key] = value
@@ -1,7 +1,6 @@
1
1
  import env from "../../environment"
2
2
  import { events, accounts, tenancy } from "@budibase/backend-core"
3
3
  import { User, UserRoles, CloudAccount } from "@budibase/types"
4
- import { users as pro } from "@budibase/pro"
5
4
 
6
5
  export const handleDeleteEvents = async (user: any) => {
7
6
  await events.user.deleted(user)
@@ -52,10 +51,7 @@ const handleAppRoleEvents = async (user: any, existingUser: any) => {
52
51
  await unassignAppRoleEvents(user, roles, existingRoles)
53
52
  }
54
53
 
55
- export const handleSaveEvents = async (
56
- user: User,
57
- existingUser: User | undefined
58
- ) => {
54
+ export const handleSaveEvents = async (user: any, existingUser: any) => {
59
55
  const tenantId = tenancy.getTenantId()
60
56
  let tenantAccount: CloudAccount | undefined
61
57
  if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
@@ -1,35 +1,37 @@
1
1
  import env from "../../environment"
2
+ import { quotas } from "@budibase/pro"
2
3
  import * as apps from "../../utilities/appService"
3
4
  import * as eventHelpers from "./events"
4
5
  import {
5
- accounts,
6
- cache,
7
- constants,
6
+ tenancy,
7
+ utils,
8
8
  db as dbUtils,
9
+ constants,
10
+ cache,
11
+ users as usersCore,
9
12
  deprovisioning,
10
- events,
13
+ sessions,
11
14
  HTTPError,
15
+ accounts,
12
16
  migrations,
13
- sessions,
14
- tenancy,
15
- users as usersCore,
16
- utils,
17
+ StaticDatabases,
17
18
  ViewName,
19
+ events,
18
20
  } from "@budibase/backend-core"
19
21
  import {
20
- AccountMetadata,
21
- AllDocsResponse,
22
+ MigrationType,
23
+ PlatformUserByEmail,
24
+ User,
22
25
  BulkCreateUsersResponse,
26
+ CreateUserResponse,
23
27
  BulkDeleteUsersResponse,
24
- BulkDocsResponse,
25
28
  CloudAccount,
26
- CreateUserResponse,
29
+ AllDocsResponse,
30
+ RowResponse,
31
+ BulkDocsResponse,
32
+ AccountMetadata,
27
33
  InviteUsersRequest,
28
34
  InviteUsersResponse,
29
- MigrationType,
30
- PlatformUserByEmail,
31
- RowResponse,
32
- User,
33
35
  } from "@budibase/types"
34
36
  import { groups as groupUtils } from "@budibase/pro"
35
37
  import { sendEmail } from "../../utilities/email"
@@ -118,7 +120,7 @@ interface SaveUserOpts {
118
120
  }
119
121
 
120
122
  const buildUser = async (
121
- user: User,
123
+ user: any,
122
124
  opts: SaveUserOpts = {
123
125
  hashPassword: true,
124
126
  requirePassword: true,
@@ -228,7 +230,16 @@ export const save = async (
228
230
 
229
231
  try {
230
232
  // save the user to db
231
- let response = await db.put(builtUser)
233
+ let response
234
+ const putUserFn = () => {
235
+ return db.put(builtUser)
236
+ }
237
+
238
+ if (eventHelpers.isAddingBuilder(builtUser, dbUser)) {
239
+ response = await quotas.addDeveloper(putUserFn)
240
+ } else {
241
+ response = await putUserFn()
242
+ }
232
243
  builtUser._rev = response.rev
233
244
 
234
245
  await eventHelpers.handleSaveEvents(builtUser, dbUser)
@@ -377,8 +388,13 @@ export const bulkCreate = async (
377
388
  newUsers.push(newUser)
378
389
  }
379
390
 
380
- // create the promises array that will be called by bulkDocs
391
+ // Figure out how many builders we are adding and create the promises
392
+ // array that will be called by bulkDocs
393
+ let builderCount = 0
381
394
  newUsers.forEach((user: any) => {
395
+ if (eventHelpers.isAddingBuilder(user, null)) {
396
+ builderCount++
397
+ }
382
398
  usersToSave.push(
383
399
  buildUser(
384
400
  user,
@@ -392,14 +408,14 @@ export const bulkCreate = async (
392
408
  })
393
409
 
394
410
  const usersToBulkSave = await Promise.all(usersToSave)
395
- await db.bulkDocs(usersToBulkSave)
411
+ await quotas.addDevelopers(() => db.bulkDocs(usersToBulkSave), builderCount)
396
412
 
397
413
  // Post processing of bulk added users, i.e events and cache operations
398
414
  for (const user of usersToBulkSave) {
399
415
  // TODO: Refactor to bulk insert users into the info db
400
416
  // instead of relying on looping tenant creation
401
417
  await addTenant(tenantId, user._id, user.email)
402
- await eventHelpers.handleSaveEvents(user, undefined)
418
+ await eventHelpers.handleSaveEvents(user, null)
403
419
  await apps.syncUserInApps(user._id)
404
420
  }
405
421
 
@@ -459,6 +475,8 @@ export const bulkDelete = async (
459
475
  }
460
476
 
461
477
  let groupsToModify: any = {}
478
+ let builderCount = 0
479
+
462
480
  // Get users and delete
463
481
  const allDocsResponse: AllDocsResponse<User> = await db.allDocs({
464
482
  include_docs: true,
@@ -479,6 +497,11 @@ export const bulkDelete = async (
479
497
  }
480
498
  }
481
499
 
500
+ // Also figure out how many builders are being deleted
501
+ if (eventHelpers.isAddingBuilder(user.doc, null)) {
502
+ builderCount++
503
+ }
504
+
482
505
  return user.doc
483
506
  }
484
507
  )
@@ -496,6 +519,7 @@ export const bulkDelete = async (
496
519
  for (let user of usersToDelete) {
497
520
  await bulkDeleteProcessing(user)
498
521
  }
522
+ await quotas.removeDevelopers(builderCount)
499
523
 
500
524
  // Build Response
501
525
  // index users by id
@@ -550,6 +574,7 @@ export const destroy = async (id: string, currentUser: any) => {
550
574
  }
551
575
 
552
576
  await eventHelpers.handleDeleteEvents(dbUser)
577
+ await quotas.removeUser(dbUser)
553
578
  await cache.user.invalidateUser(userId)
554
579
  await sessions.invalidateSessions(userId, { reason: "deletion" })
555
580
  // let server know to sync user
@@ -2,9 +2,10 @@ import {
2
2
  BulkCreateUsersRequest,
3
3
  BulkCreateUsersResponse,
4
4
  BulkDeleteUsersRequest,
5
- BulkDeleteUsersResponse,
5
+ CreateUserResponse,
6
6
  InviteUsersRequest,
7
7
  User,
8
+ UserDetails,
8
9
  } from "@budibase/types"
9
10
  import TestConfiguration from "../TestConfiguration"
10
11