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