@budibase/worker 1.0.123 → 1.0.125

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/nodemon.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "watch": ["src", "../backend-core"],
2
+ "watch": ["src", "../backend-core", "../../../budibase-pro/packages/pro"],
3
3
  "ext": "js,ts,json",
4
4
  "ignore": ["src/**/*.spec.ts", "src/**/*.spec.js"],
5
5
  "exec": "ts-node src/index.ts"
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.123",
4
+ "version": "1.0.125",
5
5
  "description": "Budibase background service",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -31,14 +31,17 @@
31
31
  "author": "Budibase",
32
32
  "license": "GPL-3.0",
33
33
  "dependencies": {
34
- "@budibase/backend-core": "^1.0.123",
35
- "@budibase/string-templates": "^1.0.123",
34
+ "@budibase/backend-core": "^1.0.125",
35
+ "@budibase/pro": "1.0.124-alpha.0",
36
+ "@budibase/string-templates": "^1.0.125",
36
37
  "@koa/router": "^8.0.0",
37
- "@sentry/node": "^6.0.0",
38
+ "@sentry/node": "6.17.7",
38
39
  "@techpass/passport-openidconnect": "^0.3.0",
40
+ "@types/global-agent": "^2.1.1",
39
41
  "aws-sdk": "^2.811.0",
40
42
  "bcryptjs": "^2.4.3",
41
43
  "dotenv": "^8.2.0",
44
+ "global-agent": "^3.0.0",
42
45
  "got": "^11.8.1",
43
46
  "joi": "^17.4.0",
44
47
  "koa": "^2.7.0",
@@ -63,7 +66,9 @@
63
66
  "@types/jest": "^26.0.23",
64
67
  "@types/koa": "^2.13.3",
65
68
  "@types/koa-router": "^7.4.2",
69
+ "@types/koa__router": "^8.0.11",
66
70
  "@types/node": "^15.12.4",
71
+ "@typescript-eslint/parser": "5.12.0",
67
72
  "copyfiles": "^2.4.1",
68
73
  "eslint": "^6.8.0",
69
74
  "jest": "^27.0.5",
@@ -74,7 +79,7 @@
74
79
  "supertest": "^6.1.3",
75
80
  "ts-jest": "^27.0.3",
76
81
  "ts-node": "^10.0.0",
77
- "typescript": "4.3.5",
82
+ "typescript": "4.5.5",
78
83
  "update-dotenv": "^1.1.1"
79
84
  },
80
85
  "jest": {
@@ -84,5 +89,5 @@
84
89
  "./scripts/jestSetup.js"
85
90
  ]
86
91
  },
87
- "gitHead": "db99c31b53d0dbbb788335126e45d1cc2f39fbf0"
92
+ "gitHead": "e96d44823de430b3f487705d18d34954f8fb9bf7"
88
93
  }
@@ -21,8 +21,9 @@ const {
21
21
  isMultiTenant,
22
22
  } = require("@budibase/backend-core/tenancy")
23
23
  const env = require("../../../environment")
24
+ import { users } from "@budibase/pro"
24
25
 
25
- const ssoCallbackUrl = async (config, type) => {
26
+ const ssoCallbackUrl = async (config: any, type: any) => {
26
27
  // incase there is a callback URL from before
27
28
  if (config && config.callbackURL) {
28
29
  return config.callbackURL
@@ -42,15 +43,15 @@ const ssoCallbackUrl = async (config, type) => {
42
43
  return `${publicConfig.platformUrl}${callbackUrl}`
43
44
  }
44
45
 
45
- exports.googleCallbackUrl = async config => {
46
+ export const googleCallbackUrl = async (config: any) => {
46
47
  return ssoCallbackUrl(config, "google")
47
48
  }
48
49
 
49
- exports.oidcCallbackUrl = async config => {
50
+ export const oidcCallbackUrl = async (config: any) => {
50
51
  return ssoCallbackUrl(config, "oidc")
51
52
  }
52
53
 
53
- async function authInternal(ctx, user, err = null, info = null) {
54
+ async function authInternal(ctx: any, user: any, err = null, info = null) {
54
55
  if (err) {
55
56
  console.error("Authentication error", err)
56
57
  return ctx.throw(403, info ? info : "Unauthorized")
@@ -71,20 +72,23 @@ async function authInternal(ctx, user, err = null, info = null) {
71
72
  }
72
73
  }
73
74
 
74
- exports.authenticate = async (ctx, next) => {
75
- return passport.authenticate("local", async (err, user, info) => {
76
- await authInternal(ctx, user, err, info)
77
- ctx.status = 200
78
- })(ctx, next)
75
+ export const authenticate = async (ctx: any, next: any) => {
76
+ return passport.authenticate(
77
+ "local",
78
+ async (err: any, user: any, info: any) => {
79
+ await authInternal(ctx, user, err, info)
80
+ ctx.status = 200
81
+ }
82
+ )(ctx, next)
79
83
  }
80
84
 
81
- exports.setInitInfo = ctx => {
85
+ export const setInitInfo = (ctx: any) => {
82
86
  const initInfo = ctx.request.body
83
87
  setCookie(ctx, initInfo, Cookies.Init)
84
88
  ctx.status = 200
85
89
  }
86
90
 
87
- exports.getInitInfo = ctx => {
91
+ export const getInitInfo = (ctx: any) => {
88
92
  try {
89
93
  ctx.body = getCookie(ctx, Cookies.Init) || {}
90
94
  } catch (err) {
@@ -96,7 +100,7 @@ exports.getInitInfo = ctx => {
96
100
  /**
97
101
  * Reset the user password, used as part of a forgotten password flow.
98
102
  */
99
- exports.reset = async ctx => {
103
+ export const reset = async (ctx: any) => {
100
104
  const { email } = ctx.request.body
101
105
  const configured = await isEmailConfigured()
102
106
  if (!configured) {
@@ -126,7 +130,7 @@ exports.reset = async ctx => {
126
130
  /**
127
131
  * Perform the user password update if the provided reset code is valid.
128
132
  */
129
- exports.resetUpdate = async ctx => {
133
+ export const resetUpdate = async (ctx: any) => {
130
134
  const { resetCode, password } = ctx.request.body
131
135
  try {
132
136
  const { userId } = await checkResetPasswordCode(resetCode)
@@ -142,14 +146,14 @@ exports.resetUpdate = async ctx => {
142
146
  }
143
147
  }
144
148
 
145
- exports.logout = async ctx => {
149
+ export const logout = async (ctx: any) => {
146
150
  if (ctx.user && ctx.user._id) {
147
151
  await platformLogout({ ctx, userId: ctx.user._id })
148
152
  }
149
153
  ctx.body = { message: "User logged out." }
150
154
  }
151
155
 
152
- exports.datasourcePreAuth = async (ctx, next) => {
156
+ export const datasourcePreAuth = async (ctx: any, next: any) => {
153
157
  const provider = ctx.params.provider
154
158
  const middleware = require(`@budibase/backend-core/middleware`)
155
159
  const handler = middleware.datasource[provider]
@@ -167,7 +171,7 @@ exports.datasourcePreAuth = async (ctx, next) => {
167
171
  return handler.preAuth(passport, ctx, next)
168
172
  }
169
173
 
170
- exports.datasourceAuth = async (ctx, next) => {
174
+ export const datasourceAuth = async (ctx: any, next: any) => {
171
175
  const authStateCookie = getCookie(ctx, Cookies.DatasourceAuth)
172
176
  const provider = authStateCookie.provider
173
177
  const middleware = require(`@budibase/backend-core/middleware`)
@@ -179,7 +183,7 @@ exports.datasourceAuth = async (ctx, next) => {
179
183
  * The initial call that google authentication makes to take you to the google login screen.
180
184
  * On a successful login, you will be redirected to the googleAuth callback route.
181
185
  */
182
- exports.googlePreAuth = async (ctx, next) => {
186
+ export const googlePreAuth = async (ctx: any, next: any) => {
183
187
  const db = getGlobalDB()
184
188
 
185
189
  const config = await core.db.getScopedConfig(db, {
@@ -187,14 +191,14 @@ exports.googlePreAuth = async (ctx, next) => {
187
191
  workspace: ctx.query.workspace,
188
192
  })
189
193
  let callbackUrl = await exports.googleCallbackUrl(config)
190
- const strategy = await google.strategyFactory(config, callbackUrl)
194
+ const strategy = await google.strategyFactory(config, callbackUrl, users.save)
191
195
 
192
196
  return passport.authenticate(strategy, {
193
197
  scope: ["profile", "email"],
194
198
  })(ctx, next)
195
199
  }
196
200
 
197
- exports.googleAuth = async (ctx, next) => {
201
+ export const googleAuth = async (ctx: any, next: any) => {
198
202
  const db = getGlobalDB()
199
203
 
200
204
  const config = await core.db.getScopedConfig(db, {
@@ -202,12 +206,12 @@ exports.googleAuth = async (ctx, next) => {
202
206
  workspace: ctx.query.workspace,
203
207
  })
204
208
  const callbackUrl = await exports.googleCallbackUrl(config)
205
- const strategy = await google.strategyFactory(config, callbackUrl)
209
+ const strategy = await google.strategyFactory(config, callbackUrl, users.save)
206
210
 
207
211
  return passport.authenticate(
208
212
  strategy,
209
213
  { successRedirect: "/", failureRedirect: "/error" },
210
- async (err, user, info) => {
214
+ async (err: any, user: any, info: any) => {
211
215
  await authInternal(ctx, user, err, info)
212
216
 
213
217
  ctx.redirect("/")
@@ -215,24 +219,24 @@ exports.googleAuth = async (ctx, next) => {
215
219
  )(ctx, next)
216
220
  }
217
221
 
218
- async function oidcStrategyFactory(ctx, configId) {
222
+ async function oidcStrategyFactory(ctx: any, configId: any) {
219
223
  const db = getGlobalDB()
220
224
  const config = await core.db.getScopedConfig(db, {
221
225
  type: Configs.OIDC,
222
226
  group: ctx.query.group,
223
227
  })
224
228
 
225
- const chosenConfig = config.configs.filter(c => c.uuid === configId)[0]
229
+ const chosenConfig = config.configs.filter((c: any) => c.uuid === configId)[0]
226
230
  let callbackUrl = await exports.oidcCallbackUrl(chosenConfig)
227
231
 
228
- return oidc.strategyFactory(chosenConfig, callbackUrl)
232
+ return oidc.strategyFactory(chosenConfig, callbackUrl, users.save)
229
233
  }
230
234
 
231
235
  /**
232
236
  * The initial call that OIDC authentication makes to take you to the configured OIDC login screen.
233
237
  * On a successful login, you will be redirected to the oidcAuth callback route.
234
238
  */
235
- exports.oidcPreAuth = async (ctx, next) => {
239
+ export const oidcPreAuth = async (ctx: any, next: any) => {
236
240
  const { configId } = ctx.params
237
241
  const strategy = await oidcStrategyFactory(ctx, configId)
238
242
 
@@ -244,14 +248,14 @@ exports.oidcPreAuth = async (ctx, next) => {
244
248
  })(ctx, next)
245
249
  }
246
250
 
247
- exports.oidcAuth = async (ctx, next) => {
251
+ export const oidcAuth = async (ctx: any, next: any) => {
248
252
  const configId = getCookie(ctx, Cookies.OIDC_CONFIG)
249
253
  const strategy = await oidcStrategyFactory(ctx, configId)
250
254
 
251
255
  return passport.authenticate(
252
256
  strategy,
253
257
  { successRedirect: "/", failureRedirect: "/error" },
254
- async (err, user, info) => {
258
+ async (err: any, user: any, info: any) => {
255
259
  await authInternal(ctx, user, err, info)
256
260
 
257
261
  ctx.redirect("/")
@@ -0,0 +1,30 @@
1
+ import { licensing, quotas } from "@budibase/pro"
2
+
3
+ export const activate = async (ctx: any) => {
4
+ const { licenseKey } = ctx.request.body
5
+ if (!licenseKey) {
6
+ ctx.throw(400, "licenseKey is required")
7
+ }
8
+
9
+ await licensing.activateLicenseKey(licenseKey)
10
+ ctx.status = 200
11
+ }
12
+
13
+ export const refresh = async (ctx: any) => {
14
+ await licensing.cache.refresh()
15
+ ctx.status = 200
16
+ }
17
+
18
+ export const getInfo = async (ctx: any) => {
19
+ const licenseInfo = await licensing.getLicenseInfo()
20
+ if (licenseInfo) {
21
+ licenseInfo.licenseKey = "*"
22
+ ctx.body = licenseInfo
23
+ }
24
+ ctx.status = 200
25
+ }
26
+
27
+ export const getQuotaUsage = async (ctx: any) => {
28
+ const usage = await quotas.getQuotaUsage()
29
+ ctx.body = usage
30
+ }
@@ -15,6 +15,7 @@ const { encrypt } = require("@budibase/backend-core/encryption")
15
15
  const { newid } = require("@budibase/backend-core/utils")
16
16
  const { getUser } = require("../../utilities")
17
17
  const { Cookies } = require("@budibase/backend-core/constants")
18
+ const { featureFlags } = require("@budibase/backend-core")
18
19
 
19
20
  function newApiKey() {
20
21
  return encrypt(`${getTenantId()}${SEPARATOR}${newid()}`)
@@ -68,6 +69,29 @@ const checkCurrentApp = ctx => {
68
69
  }
69
70
  }
70
71
 
72
+ /**
73
+ * Add the attributes that are session based to the current user.
74
+ */
75
+ const addSessionAttributesToUser = ctx => {
76
+ ctx.body.account = ctx.user.account
77
+ ctx.body.license = ctx.user.license
78
+ ctx.body.budibaseAccess = ctx.user.budibaseAccess
79
+ ctx.body.accountPortalAccess = ctx.user.accountPortalAccess
80
+ ctx.body.csrfToken = ctx.user.csrfToken
81
+ }
82
+
83
+ /**
84
+ * Remove the attributes that are session based from the current user,
85
+ * so that stale values are not written to the db
86
+ */
87
+ const removeSessionAttributesFromUser = ctx => {
88
+ delete ctx.request.body.csrfToken
89
+ delete ctx.request.body.account
90
+ delete ctx.request.body.accountPortalAccess
91
+ delete ctx.request.body.budibaseAccess
92
+ delete ctx.request.body.license
93
+ }
94
+
71
95
  exports.getSelf = async ctx => {
72
96
  if (!ctx.user) {
73
97
  ctx.throw(403, "User not logged in")
@@ -81,11 +105,12 @@ exports.getSelf = async ctx => {
81
105
 
82
106
  // get the main body of the user
83
107
  ctx.body = await getUser(userId)
84
- // forward session information not found in db
85
- ctx.body.account = ctx.user.account
86
- ctx.body.budibaseAccess = ctx.user.budibaseAccess
87
- ctx.body.accountPortalAccess = ctx.user.accountPortalAccess
88
- ctx.body.csrfToken = ctx.user.csrfToken
108
+
109
+ // add the feature flags for this tenant
110
+ const tenantId = getTenantId()
111
+ ctx.body.featureFlags = featureFlags.getTenantFeatureFlags(tenantId)
112
+
113
+ addSessionAttributesToUser(ctx)
89
114
  }
90
115
 
91
116
  exports.updateSelf = async ctx => {
@@ -104,8 +129,8 @@ exports.updateSelf = async ctx => {
104
129
  // don't allow sending up an ID/Rev, always use the existing one
105
130
  delete ctx.request.body._id
106
131
  delete ctx.request.body._rev
107
- // don't allow setting the csrf token
108
- delete ctx.request.body.csrfToken
132
+ removeSessionAttributesFromUser(ctx)
133
+
109
134
  const response = await db.put({
110
135
  ...user,
111
136
  ...ctx.request.body,
@@ -1,15 +1,11 @@
1
1
  const {
2
2
  getGlobalUserParams,
3
3
  StaticDatabases,
4
- generateNewUsageQuotaDoc,
5
4
  } = require("@budibase/backend-core/db")
6
- const {
7
- getGlobalUserByEmail,
8
- saveUser,
9
- } = require("@budibase/backend-core/utils")
10
- const { EmailTemplatePurpose } = require("../../../constants")
11
- const { checkInviteCode } = require("../../../utilities/redis")
12
- const { sendEmail } = require("../../../utilities/email")
5
+ const { getGlobalUserByEmail } = require("@budibase/backend-core/utils")
6
+ import { EmailTemplatePurpose } from "../../../constants"
7
+ import { checkInviteCode } from "../../../utilities/redis"
8
+ import { sendEmail } from "../../../utilities/email"
13
9
  const { user: userCache } = require("@budibase/backend-core/cache")
14
10
  const { invalidateSessions } = require("@budibase/backend-core/sessions")
15
11
  const accounts = require("@budibase/backend-core/accounts")
@@ -21,26 +17,28 @@ const {
21
17
  doesTenantExist,
22
18
  } = require("@budibase/backend-core/tenancy")
23
19
  const { removeUserFromInfoDB } = require("@budibase/backend-core/deprovision")
24
- const env = require("../../../environment")
25
- const { syncUserInApps } = require("../../../utilities/appService")
26
- const { allUsers, getUser } = require("../../utilities")
20
+ import env from "../../../environment"
21
+ import { syncUserInApps } from "../../../utilities/appService"
22
+ import { quotas, users } from "@budibase/pro"
23
+ const { errors } = require("@budibase/backend-core")
24
+ import { allUsers, getUser } from "../../utilities"
27
25
 
28
- exports.save = async ctx => {
26
+ export const save = async (ctx: any) => {
29
27
  try {
30
- const user = await saveUser(ctx.request.body, getTenantId())
28
+ const user: any = await users.save(ctx.request.body, getTenantId())
31
29
  // let server know to sync user
32
30
  await syncUserInApps(user._id)
33
31
  ctx.body = user
34
- } catch (err) {
32
+ } catch (err: any) {
35
33
  ctx.throw(err.status || 400, err)
36
34
  }
37
35
  }
38
36
 
39
- const parseBooleanParam = param => {
37
+ const parseBooleanParam = (param: any) => {
40
38
  return !(param && param === "false")
41
39
  }
42
40
 
43
- exports.adminUser = async ctx => {
41
+ export const adminUser = async (ctx: any) => {
44
42
  const { email, password, tenantId } = ctx.request.body
45
43
 
46
44
  // account portal sends a pre-hashed password - honour param to prevent double hashing
@@ -52,7 +50,7 @@ exports.adminUser = async ctx => {
52
50
  ctx.throw(403, "Organisation already exists.")
53
51
  }
54
52
 
55
- const response = await doWithGlobalDB(tenantId, async db => {
53
+ const response = await doWithGlobalDB(tenantId, async (db: any) => {
56
54
  const response = await db.allDocs(
57
55
  getGlobalUserParams(null, {
58
56
  include_docs: true,
@@ -69,12 +67,12 @@ exports.adminUser = async ctx => {
69
67
  } catch (err) {
70
68
  // don't worry about errors
71
69
  }
72
- await db.put(generateNewUsageQuotaDoc())
70
+ await db.put(quotas.generateNewQuotaUsage())
73
71
  }
74
72
  return response
75
73
  })
76
74
 
77
- if (response.rows.some(row => row.doc.admin)) {
75
+ if (response.rows.some((row: any) => row.doc.admin)) {
78
76
  ctx.throw(
79
77
  403,
80
78
  "You cannot initialise once an global user has been created."
@@ -95,13 +93,13 @@ exports.adminUser = async ctx => {
95
93
  tenantId,
96
94
  }
97
95
  try {
98
- ctx.body = await saveUser(user, tenantId, hashPassword, requirePassword)
99
- } catch (err) {
96
+ ctx.body = await users.save(user, tenantId, hashPassword, requirePassword)
97
+ } catch (err: any) {
100
98
  ctx.throw(err.status || 400, err)
101
99
  }
102
100
  }
103
101
 
104
- exports.destroy = async ctx => {
102
+ export const destroy = async (ctx: any) => {
105
103
  const db = getGlobalDB()
106
104
  const dbUser = await db.get(ctx.params.id)
107
105
 
@@ -120,6 +118,7 @@ exports.destroy = async ctx => {
120
118
 
121
119
  await removeUserFromInfoDB(dbUser)
122
120
  await db.remove(dbUser._id, dbUser._rev)
121
+ await quotas.removeUser(dbUser)
123
122
  await userCache.invalidateUser(dbUser._id)
124
123
  await invalidateSessions(dbUser._id)
125
124
  // let server know to sync user
@@ -130,23 +129,23 @@ exports.destroy = async ctx => {
130
129
  }
131
130
 
132
131
  // called internally by app server user fetch
133
- exports.fetch = async ctx => {
134
- const users = await allUsers(ctx)
132
+ export const fetch = async (ctx: any) => {
133
+ const all = await allUsers()
135
134
  // user hashed password shouldn't ever be returned
136
- for (let user of users) {
135
+ for (let user of all) {
137
136
  if (user) {
138
137
  delete user.password
139
138
  }
140
139
  }
141
- ctx.body = users
140
+ ctx.body = all
142
141
  }
143
142
 
144
143
  // called internally by app server user find
145
- exports.find = async ctx => {
144
+ export const find = async (ctx: any) => {
146
145
  ctx.body = await getUser(ctx.params.id)
147
146
  }
148
147
 
149
- exports.tenantUserLookup = async ctx => {
148
+ export const tenantUserLookup = async (ctx: any) => {
150
149
  const id = ctx.params.id
151
150
  const user = await getTenantUser(id)
152
151
  if (user) {
@@ -156,7 +155,7 @@ exports.tenantUserLookup = async ctx => {
156
155
  }
157
156
  }
158
157
 
159
- exports.invite = async ctx => {
158
+ export const invite = async (ctx: any) => {
160
159
  let { email, userInfo } = ctx.request.body
161
160
  const existing = await getGlobalUserByEmail(email)
162
161
  if (existing) {
@@ -166,21 +165,22 @@ exports.invite = async ctx => {
166
165
  userInfo = {}
167
166
  }
168
167
  userInfo.tenantId = getTenantId()
169
- await sendEmail(email, EmailTemplatePurpose.INVITATION, {
168
+ const opts: any = {
170
169
  subject: "{{ company }} platform invitation",
171
170
  info: userInfo,
172
- })
171
+ }
172
+ await sendEmail(email, EmailTemplatePurpose.INVITATION, opts)
173
173
  ctx.body = {
174
174
  message: "Invitation has been sent.",
175
175
  }
176
176
  }
177
177
 
178
- exports.inviteAccept = async ctx => {
178
+ export const inviteAccept = async (ctx: any) => {
179
179
  const { inviteCode, password, firstName, lastName } = ctx.request.body
180
180
  try {
181
181
  // info is an extension of the user object that was stored by global
182
- const { email, info } = await checkInviteCode(inviteCode)
183
- ctx.body = await saveUser(
182
+ const { email, info }: any = await checkInviteCode(inviteCode)
183
+ ctx.body = await users.save(
184
184
  {
185
185
  firstName,
186
186
  lastName,
@@ -190,7 +190,11 @@ exports.inviteAccept = async ctx => {
190
190
  },
191
191
  info.tenantId
192
192
  )
193
- } catch (err) {
193
+ } catch (err: any) {
194
+ if (err.code === errors.codes.USAGE_LIMIT_EXCEEDED) {
195
+ // explicitly re-throw limit exceeded errors
196
+ ctx.throw(400, err)
197
+ }
194
198
  ctx.throw(400, "Unable to create new user, invitation invalid.")
195
199
  }
196
200
  }
package/src/api/index.js CHANGED
@@ -8,6 +8,8 @@ const {
8
8
  buildTenancyMiddleware,
9
9
  buildCsrfMiddleware,
10
10
  } = require("@budibase/backend-core/auth")
11
+ const { middleware: pro } = require("@budibase/pro")
12
+ const { errors } = require("@budibase/backend-core")
11
13
 
12
14
  const PUBLIC_ENDPOINTS = [
13
15
  // old deprecated endpoints kept for backwards compat
@@ -98,6 +100,7 @@ router
98
100
  .use(buildAuthMiddleware(PUBLIC_ENDPOINTS))
99
101
  .use(buildTenancyMiddleware(PUBLIC_ENDPOINTS, NO_TENANCY_ENDPOINTS))
100
102
  .use(buildCsrfMiddleware({ noCsrfPatterns: NO_CSRF_ENDPOINTS }))
103
+ .use(pro.licensing())
101
104
  // for now no public access is allowed to worker (bar health check)
102
105
  .use((ctx, next) => {
103
106
  if (ctx.publicEndpoint) {
@@ -110,16 +113,18 @@ router
110
113
  })
111
114
  .use(auditLog)
112
115
 
113
- // error handling middleware
116
+ // error handling middleware - TODO: This could be moved to backend-core
114
117
  router.use(async (ctx, next) => {
115
118
  try {
116
119
  await next()
117
120
  } catch (err) {
118
121
  ctx.log.error(err)
119
122
  ctx.status = err.status || err.statusCode || 500
123
+ const error = errors.getPublicError(err)
120
124
  ctx.body = {
121
125
  message: err.message,
122
126
  status: ctx.status,
127
+ error,
123
128
  }
124
129
  }
125
130
  })
@@ -0,0 +1,12 @@
1
+ import Router from "@koa/router"
2
+ import * as controller from "../../controllers/global/license"
3
+
4
+ const router = new Router()
5
+
6
+ router
7
+ .post("/api/global/license/activate", controller.activate)
8
+ .post("/api/global/license/refresh", controller.refresh)
9
+ .get("/api/global/license/info", controller.getInfo)
10
+ .get("/api/global/license/usage", controller.getQuotaUsage)
11
+
12
+ export = router
@@ -10,6 +10,7 @@ const environmentRoutes = require("./system/environment")
10
10
  const tenantsRoutes = require("./system/tenants")
11
11
  const statusRoutes = require("./system/status")
12
12
  const selfRoutes = require("./global/self")
13
+ const licenseRoutes = require("./global/license")
13
14
 
14
15
  exports.routes = [
15
16
  configRoutes,
@@ -24,4 +25,5 @@ exports.routes = [
24
25
  environmentRoutes,
25
26
  statusRoutes,
26
27
  selfRoutes,
28
+ licenseRoutes,
27
29
  ]
@@ -75,7 +75,8 @@ describe("/api/global/auth", () => {
75
75
  afterEach(() => {
76
76
  expect(strategyFactory).toBeCalledWith(
77
77
  chosenConfig,
78
- `http://localhost:10000/api/global/auth/${TENANT_ID}/oidc/callback`
78
+ `http://localhost:10000/api/global/auth/${TENANT_ID}/oidc/callback`,
79
+ expect.any(Function)
79
80
  )
80
81
  })
81
82
 
@@ -19,7 +19,7 @@ if (!LOADED && isDev() && !isTest()) {
19
19
  module.exports = {
20
20
  NODE_ENV: process.env.NODE_ENV,
21
21
  SELF_HOSTED: !!parseInt(process.env.SELF_HOSTED),
22
- PORT: process.env.PORT,
22
+ PORT: process.env.PORT || process.env.WORKER_PORT,
23
23
  CLUSTER_PORT: process.env.CLUSTER_PORT,
24
24
  MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY,
25
25
  MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY,
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  import { Scope } from "@sentry/node"
3
3
  import { Event } from "@sentry/types/dist/event"
4
4
  import Application from "koa"
5
+ import { bootstrap } from "global-agent"
5
6
 
6
7
  const env = require("./environment")
7
8
  import db from "./db"
@@ -17,6 +18,9 @@ const api = require("./api")
17
18
  const redis = require("./utilities/redis")
18
19
  const Sentry = require("@sentry/node")
19
20
 
21
+ // this will setup http and https proxies form env variables
22
+ bootstrap()
23
+
20
24
  const app: Application = new Koa()
21
25
 
22
26
  app.keys = ["secret", "key"]