@budibase/worker 1.2.58-alpha.6 → 1.2.58
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 +6 -7
- package/scripts/jestSetup.js +0 -6
- package/scripts/load/users.js +97 -0
- package/src/api/controllers/global/auth.ts +1 -14
- package/src/api/controllers/global/users.ts +55 -26
- package/src/api/{index.ts → index.js} +16 -12
- package/src/api/routes/global/configs.js +0 -1
- package/src/api/routes/index.js +0 -2
- package/src/api/routes/{global/tests/auth.spec.ts → tests/auth.spec.js} +56 -32
- package/src/api/routes/{global/tests/configs.spec.ts → tests/configs.spec.js} +47 -76
- package/src/api/routes/{global/tests/email.spec.ts → tests/email.spec.js} +15 -7
- package/src/api/routes/{global/tests/realEmail.spec.ts → tests/realEmail.spec.js} +21 -20
- package/src/api/routes/{global/tests/self.spec.ts → tests/self.spec.js} +18 -10
- package/src/api/routes/tests/users.spec.js +390 -0
- package/src/{environment.ts → environment.js} +9 -10
- package/src/index.ts +4 -6
- package/src/sdk/index.ts +0 -1
- package/src/sdk/users/users.ts +77 -271
- package/src/tests/TestConfiguration.js +231 -0
- package/src/tests/index.js +12 -0
- package/src/tests/mocks/index.js +5 -0
- package/src/tests/structures/index.js +14 -0
- package/src/tests/structures/users.ts +4 -12
- package/src/utilities/redis.js +0 -1
- package/src/api/controllers/system/accounts.ts +0 -21
- package/src/api/routes/global/tests/users.spec.ts +0 -512
- package/src/api/routes/system/accounts.ts +0 -19
- package/src/api/routes/system/tests/accounts.spec.ts +0 -57
- package/src/sdk/accounts/accounts.ts +0 -53
- package/src/sdk/accounts/index.ts +0 -1
- package/src/tests/TestConfiguration.ts +0 -273
- package/src/tests/api/accounts.ts +0 -28
- package/src/tests/api/auth.ts +0 -48
- package/src/tests/api/configs.ts +0 -40
- package/src/tests/api/email.ts +0 -24
- package/src/tests/api/index.ts +0 -25
- package/src/tests/api/self.ts +0 -21
- package/src/tests/api/users.ts +0 -111
- package/src/tests/index.ts +0 -14
- package/src/tests/mocks/index.ts +0 -7
- package/src/tests/structures/accounts.ts +0 -24
- package/src/tests/structures/index.ts +0 -20
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/worker",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "1.2.58
|
|
4
|
+
"version": "1.2.58",
|
|
5
5
|
"description": "Budibase background service",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"author": "Budibase",
|
|
36
36
|
"license": "GPL-3.0",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@budibase/backend-core": "1.2.58
|
|
39
|
-
"@budibase/pro": "1.2.
|
|
40
|
-
"@budibase/string-templates": "1.2.58
|
|
41
|
-
"@budibase/types": "1.2.58
|
|
38
|
+
"@budibase/backend-core": "^1.2.58",
|
|
39
|
+
"@budibase/pro": "1.2.57",
|
|
40
|
+
"@budibase/string-templates": "^1.2.58",
|
|
41
|
+
"@budibase/types": "^1.2.58",
|
|
42
42
|
"@koa/router": "8.0.8",
|
|
43
43
|
"@sentry/node": "6.17.7",
|
|
44
44
|
"@techpass/passport-openidconnect": "0.3.2",
|
|
@@ -74,7 +74,6 @@
|
|
|
74
74
|
"@types/koa-router": "7.4.4",
|
|
75
75
|
"@types/koa__router": "8.0.11",
|
|
76
76
|
"@types/node": "14.18.20",
|
|
77
|
-
"@types/uuid": "8.3.4",
|
|
78
77
|
"@typescript-eslint/parser": "5.12.0",
|
|
79
78
|
"copyfiles": "2.4.1",
|
|
80
79
|
"eslint": "6.8.0",
|
|
@@ -103,5 +102,5 @@
|
|
|
103
102
|
"./scripts/jestSetup.js"
|
|
104
103
|
]
|
|
105
104
|
},
|
|
106
|
-
"gitHead": "
|
|
105
|
+
"gitHead": "2922b47620173f41097d36b9dc5b1c0f8f7b063a"
|
|
107
106
|
}
|
package/scripts/jestSetup.js
CHANGED
|
@@ -14,9 +14,3 @@ const tk = require("timekeeper")
|
|
|
14
14
|
tk.freeze(mocks.date.MOCK_DATE)
|
|
15
15
|
|
|
16
16
|
global.console.log = jest.fn() // console.log are ignored in tests
|
|
17
|
-
|
|
18
|
-
if (!process.env.CI) {
|
|
19
|
-
// set a longer timeout in dev for debugging
|
|
20
|
-
// 100 seconds
|
|
21
|
-
jest.setTimeout(100000)
|
|
22
|
-
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// get the JWT secret etc
|
|
2
|
+
require("../../src/environment")
|
|
3
|
+
require("@budibase/backend-core").init()
|
|
4
|
+
const {
|
|
5
|
+
getProdAppID,
|
|
6
|
+
generateGlobalUserID,
|
|
7
|
+
} = require("@budibase/backend-core/db")
|
|
8
|
+
const { doInTenant, getGlobalDB } = require("@budibase/backend-core/tenancy")
|
|
9
|
+
const users = require("../../src/sdk/users")
|
|
10
|
+
const { publicApiUserFix } = require("../../src/utilities/users")
|
|
11
|
+
const { hash } = require("@budibase/backend-core/utils")
|
|
12
|
+
|
|
13
|
+
const USER_LOAD_NUMBER = 10000
|
|
14
|
+
const BATCH_SIZE = 200
|
|
15
|
+
const PASSWORD = "test"
|
|
16
|
+
const TENANT_ID = "default"
|
|
17
|
+
|
|
18
|
+
const APP_ID = process.argv[2]
|
|
19
|
+
|
|
20
|
+
const words = [
|
|
21
|
+
"test",
|
|
22
|
+
"testing",
|
|
23
|
+
"budi",
|
|
24
|
+
"mail",
|
|
25
|
+
"age",
|
|
26
|
+
"risk",
|
|
27
|
+
"load",
|
|
28
|
+
"uno",
|
|
29
|
+
"arm",
|
|
30
|
+
"leg",
|
|
31
|
+
"pen",
|
|
32
|
+
"glass",
|
|
33
|
+
"box",
|
|
34
|
+
"chicken",
|
|
35
|
+
"bottle",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
if (!APP_ID) {
|
|
39
|
+
console.error("Must supply app ID as first CLI option!")
|
|
40
|
+
process.exit(-1)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const WORD_1 = words[Math.floor(Math.random() * words.length)]
|
|
44
|
+
const WORD_2 = words[Math.floor(Math.random() * words.length)]
|
|
45
|
+
let HASHED_PASSWORD
|
|
46
|
+
|
|
47
|
+
function generateUser(count) {
|
|
48
|
+
return {
|
|
49
|
+
_id: generateGlobalUserID(),
|
|
50
|
+
password: HASHED_PASSWORD,
|
|
51
|
+
email: `${WORD_1}${count}@${WORD_2}.com`,
|
|
52
|
+
roles: {
|
|
53
|
+
[getProdAppID(APP_ID)]: "BASIC",
|
|
54
|
+
},
|
|
55
|
+
status: "active",
|
|
56
|
+
forceResetPassword: false,
|
|
57
|
+
firstName: "John",
|
|
58
|
+
lastName: "Smith",
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function run() {
|
|
63
|
+
HASHED_PASSWORD = await hash(PASSWORD)
|
|
64
|
+
return doInTenant(TENANT_ID, async () => {
|
|
65
|
+
const db = getGlobalDB()
|
|
66
|
+
for (let i = 0; i < USER_LOAD_NUMBER; i += BATCH_SIZE) {
|
|
67
|
+
let userSavePromises = []
|
|
68
|
+
for (let j = 0; j < BATCH_SIZE; j++) {
|
|
69
|
+
// like the public API
|
|
70
|
+
const ctx = publicApiUserFix({
|
|
71
|
+
request: {
|
|
72
|
+
body: generateUser(i + j),
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
userSavePromises.push(
|
|
76
|
+
users.save(ctx.request.body, {
|
|
77
|
+
hashPassword: false,
|
|
78
|
+
requirePassword: true,
|
|
79
|
+
bulkCreate: true,
|
|
80
|
+
})
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
const allUsers = await Promise.all(userSavePromises)
|
|
84
|
+
await db.bulkDocs(allUsers)
|
|
85
|
+
console.log(`${i + BATCH_SIZE} users have been created.`)
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
run()
|
|
91
|
+
.then(() => {
|
|
92
|
+
console.log(`Generated ${USER_LOAD_NUMBER} users!`)
|
|
93
|
+
})
|
|
94
|
+
.catch(err => {
|
|
95
|
+
console.error("Failed for reason: ", err)
|
|
96
|
+
process.exit(-1)
|
|
97
|
+
})
|
|
@@ -227,22 +227,9 @@ export const oidcPreAuth = async (ctx: any, next: any) => {
|
|
|
227
227
|
|
|
228
228
|
setCookie(ctx, configId, Cookies.OIDC_CONFIG)
|
|
229
229
|
|
|
230
|
-
const db = getGlobalDB()
|
|
231
|
-
const config = await core.db.getScopedConfig(db, {
|
|
232
|
-
type: Configs.OIDC,
|
|
233
|
-
group: ctx.query.group,
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
const chosenConfig = config.configs.filter((c: any) => c.uuid === configId)[0]
|
|
237
|
-
|
|
238
|
-
let authScopes =
|
|
239
|
-
chosenConfig.scopes?.length > 0
|
|
240
|
-
? chosenConfig.scopes
|
|
241
|
-
: ["profile", "email", "offline_access"]
|
|
242
|
-
|
|
243
230
|
return passport.authenticate(strategy, {
|
|
244
231
|
// required 'openid' scope is added by oidc strategy factory
|
|
245
|
-
scope:
|
|
232
|
+
scope: ["profile", "email", "offline_access"], //auth0 offline_access scope required for the refresh token behaviour.
|
|
246
233
|
})(ctx, next)
|
|
247
234
|
}
|
|
248
235
|
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
+
import { EmailTemplatePurpose } from "../../../constants"
|
|
1
2
|
import { checkInviteCode } from "../../../utilities/redis"
|
|
3
|
+
import { sendEmail } from "../../../utilities/email"
|
|
2
4
|
import { users } from "../../../sdk"
|
|
3
5
|
import env from "../../../environment"
|
|
4
|
-
import {
|
|
5
|
-
BulkDeleteUsersRequest,
|
|
6
|
-
CloudAccount,
|
|
7
|
-
InviteUserRequest,
|
|
8
|
-
InviteUsersRequest,
|
|
9
|
-
User,
|
|
10
|
-
} from "@budibase/types"
|
|
6
|
+
import { CloudAccount, User } from "@budibase/types"
|
|
11
7
|
import {
|
|
12
8
|
accounts,
|
|
13
9
|
cache,
|
|
@@ -50,8 +46,8 @@ export const bulkCreate = async (ctx: any) => {
|
|
|
50
46
|
}
|
|
51
47
|
|
|
52
48
|
try {
|
|
53
|
-
|
|
54
|
-
await groupUtils.bulkSaveGroupUsers(groupsToSave, response
|
|
49
|
+
let response = await users.bulkCreate(newUsersRequested, groups)
|
|
50
|
+
await groupUtils.bulkSaveGroupUsers(groupsToSave, response)
|
|
55
51
|
|
|
56
52
|
ctx.body = response
|
|
57
53
|
} catch (err: any) {
|
|
@@ -142,15 +138,17 @@ export const destroy = async (ctx: any) => {
|
|
|
142
138
|
}
|
|
143
139
|
|
|
144
140
|
export const bulkDelete = async (ctx: any) => {
|
|
145
|
-
const { userIds } = ctx.request.body
|
|
141
|
+
const { userIds } = ctx.request.body
|
|
146
142
|
if (userIds?.indexOf(ctx.user._id) !== -1) {
|
|
147
143
|
ctx.throw(400, "Unable to delete self.")
|
|
148
144
|
}
|
|
149
145
|
|
|
150
146
|
try {
|
|
151
|
-
let
|
|
147
|
+
let usersResponse = await users.bulkDelete(userIds)
|
|
152
148
|
|
|
153
|
-
ctx.body =
|
|
149
|
+
ctx.body = {
|
|
150
|
+
message: `${usersResponse.length} user(s) deleted`,
|
|
151
|
+
}
|
|
154
152
|
} catch (err) {
|
|
155
153
|
ctx.throw(err)
|
|
156
154
|
}
|
|
@@ -195,27 +193,58 @@ export const tenantUserLookup = async (ctx: any) => {
|
|
|
195
193
|
}
|
|
196
194
|
|
|
197
195
|
export const invite = async (ctx: any) => {
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (response.unsuccessful.length) {
|
|
203
|
-
const reason = response.unsuccessful[0].reason
|
|
204
|
-
if (reason === "Unavailable") {
|
|
205
|
-
ctx.throw(400, reason)
|
|
206
|
-
} else {
|
|
207
|
-
ctx.throw(500, reason)
|
|
208
|
-
}
|
|
196
|
+
let { email, userInfo } = ctx.request.body
|
|
197
|
+
const existing = await usersCore.getGlobalUserByEmail(email)
|
|
198
|
+
if (existing) {
|
|
199
|
+
ctx.throw(400, "Email address already in use.")
|
|
209
200
|
}
|
|
210
|
-
|
|
201
|
+
if (!userInfo) {
|
|
202
|
+
userInfo = {}
|
|
203
|
+
}
|
|
204
|
+
userInfo.tenantId = tenancy.getTenantId()
|
|
205
|
+
const opts: any = {
|
|
206
|
+
subject: "{{ company }} platform invitation",
|
|
207
|
+
info: userInfo,
|
|
208
|
+
}
|
|
209
|
+
await sendEmail(email, EmailTemplatePurpose.INVITATION, opts)
|
|
211
210
|
ctx.body = {
|
|
212
211
|
message: "Invitation has been sent.",
|
|
213
212
|
}
|
|
213
|
+
await events.user.invited()
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
export const inviteMultiple = async (ctx: any) => {
|
|
217
|
-
|
|
218
|
-
|
|
217
|
+
let users = ctx.request.body
|
|
218
|
+
let existing = false
|
|
219
|
+
let existingEmail
|
|
220
|
+
for (let user of users) {
|
|
221
|
+
if (await usersCore.getGlobalUserByEmail(user.email)) {
|
|
222
|
+
existing = true
|
|
223
|
+
existingEmail = user.email
|
|
224
|
+
break
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (existing) {
|
|
229
|
+
ctx.throw(400, `${existingEmail} already exists`)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
for (let i = 0; i < users.length; i++) {
|
|
233
|
+
let userInfo = users[i].userInfo
|
|
234
|
+
if (!userInfo) {
|
|
235
|
+
userInfo = {}
|
|
236
|
+
}
|
|
237
|
+
userInfo.tenantId = tenancy.getTenantId()
|
|
238
|
+
const opts: any = {
|
|
239
|
+
subject: "{{ company }} platform invitation",
|
|
240
|
+
info: userInfo,
|
|
241
|
+
}
|
|
242
|
+
await sendEmail(users[i].email, EmailTemplatePurpose.INVITATION, opts)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
ctx.body = {
|
|
246
|
+
message: "Invitations have been sent.",
|
|
247
|
+
}
|
|
219
248
|
}
|
|
220
249
|
|
|
221
250
|
export const inviteAccept = async (ctx: any) => {
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
const Router = require("@koa/router")
|
|
2
2
|
const compress = require("koa-compress")
|
|
3
3
|
const zlib = require("zlib")
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const { routes } = require("./routes")
|
|
5
|
+
const {
|
|
6
|
+
buildAuthMiddleware,
|
|
7
|
+
auditLog,
|
|
8
|
+
buildTenancyMiddleware,
|
|
9
|
+
buildCsrfMiddleware,
|
|
10
|
+
} = require("@budibase/backend-core/auth")
|
|
11
|
+
const { middleware: pro } = require("@budibase/pro")
|
|
12
|
+
const { errors } = require("@budibase/backend-core")
|
|
8
13
|
|
|
9
14
|
const PUBLIC_ENDPOINTS = [
|
|
10
15
|
// old deprecated endpoints kept for backwards compat
|
|
@@ -92,9 +97,9 @@ router
|
|
|
92
97
|
})
|
|
93
98
|
)
|
|
94
99
|
.use("/health", ctx => (ctx.status = 200))
|
|
95
|
-
.use(
|
|
96
|
-
.use(
|
|
97
|
-
.use(
|
|
100
|
+
.use(buildAuthMiddleware(PUBLIC_ENDPOINTS))
|
|
101
|
+
.use(buildTenancyMiddleware(PUBLIC_ENDPOINTS, NO_TENANCY_ENDPOINTS))
|
|
102
|
+
.use(buildCsrfMiddleware({ noCsrfPatterns: NO_CSRF_ENDPOINTS }))
|
|
98
103
|
.use(pro.licensing())
|
|
99
104
|
// for now no public access is allowed to worker (bar health check)
|
|
100
105
|
.use((ctx, next) => {
|
|
@@ -109,22 +114,21 @@ router
|
|
|
109
114
|
}
|
|
110
115
|
return next()
|
|
111
116
|
})
|
|
112
|
-
.use(
|
|
117
|
+
.use(auditLog)
|
|
113
118
|
|
|
114
119
|
// error handling middleware - TODO: This could be moved to backend-core
|
|
115
120
|
router.use(async (ctx, next) => {
|
|
116
121
|
try {
|
|
117
122
|
await next()
|
|
118
|
-
} catch (err
|
|
123
|
+
} catch (err) {
|
|
119
124
|
ctx.log.error(err)
|
|
120
125
|
ctx.status = err.status || err.statusCode || 500
|
|
121
126
|
const error = errors.getPublicError(err)
|
|
122
|
-
|
|
127
|
+
ctx.body = {
|
|
123
128
|
message: err.message,
|
|
124
129
|
status: ctx.status,
|
|
125
130
|
error,
|
|
126
131
|
}
|
|
127
|
-
ctx.body = body
|
|
128
132
|
}
|
|
129
133
|
})
|
|
130
134
|
|
package/src/api/routes/index.js
CHANGED
|
@@ -12,7 +12,6 @@ const statusRoutes = require("./system/status")
|
|
|
12
12
|
const selfRoutes = require("./global/self")
|
|
13
13
|
const licenseRoutes = require("./global/license")
|
|
14
14
|
const migrationRoutes = require("./system/migrations")
|
|
15
|
-
const accountRoutes = require("./system/accounts")
|
|
16
15
|
|
|
17
16
|
let userGroupRoutes = api.groups
|
|
18
17
|
exports.routes = [
|
|
@@ -30,5 +29,4 @@ exports.routes = [
|
|
|
30
29
|
licenseRoutes,
|
|
31
30
|
userGroupRoutes,
|
|
32
31
|
migrationRoutes,
|
|
33
|
-
accountRoutes,
|
|
34
32
|
]
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
jest.mock("nodemailer")
|
|
2
|
-
|
|
2
|
+
const { config, request, mocks, structures } = require("../../../tests")
|
|
3
3
|
const sendMailMock = mocks.email.mock()
|
|
4
|
-
|
|
4
|
+
const { events } = require("@budibase/backend-core")
|
|
5
|
+
|
|
6
|
+
const TENANT_ID = structures.TENANT_ID
|
|
5
7
|
|
|
6
8
|
describe("/api/global/auth", () => {
|
|
7
|
-
const config = new TestConfiguration()
|
|
8
|
-
const api = new API(config)
|
|
9
9
|
|
|
10
10
|
beforeAll(async () => {
|
|
11
11
|
await config.beforeAll()
|
|
@@ -19,32 +19,56 @@ describe("/api/global/auth", () => {
|
|
|
19
19
|
jest.clearAllMocks()
|
|
20
20
|
})
|
|
21
21
|
|
|
22
|
+
const requestPasswordReset = async () => {
|
|
23
|
+
await config.saveSmtpConfig()
|
|
24
|
+
await config.saveSettingsConfig()
|
|
25
|
+
await config.createUser()
|
|
26
|
+
const res = await request
|
|
27
|
+
.post(`/api/global/auth/${TENANT_ID}/reset`)
|
|
28
|
+
.send({
|
|
29
|
+
email: "test@test.com",
|
|
30
|
+
})
|
|
31
|
+
.expect("Content-Type", /json/)
|
|
32
|
+
.expect(200)
|
|
33
|
+
const emailCall = sendMailMock.mock.calls[0][0]
|
|
34
|
+
const parts = emailCall.html.split(`http://localhost:10000/builder/auth/reset?code=`)
|
|
35
|
+
const code = parts[1].split("\"")[0].split("&")[0]
|
|
36
|
+
return { code, res }
|
|
37
|
+
}
|
|
38
|
+
|
|
22
39
|
it("should logout", async () => {
|
|
23
|
-
await
|
|
40
|
+
await request
|
|
41
|
+
.post("/api/global/auth/logout")
|
|
42
|
+
.set(config.defaultHeaders())
|
|
43
|
+
.expect(200)
|
|
24
44
|
expect(events.auth.logout).toBeCalledTimes(1)
|
|
25
45
|
})
|
|
26
46
|
|
|
27
47
|
it("should be able to generate password reset email", async () => {
|
|
28
|
-
const { res, code } = await
|
|
48
|
+
const { res, code } = await requestPasswordReset()
|
|
29
49
|
const user = await config.getUser("test@test.com")
|
|
30
50
|
|
|
31
|
-
expect(res.body).toEqual({
|
|
32
|
-
message: "Please check your email for a reset link.",
|
|
33
|
-
})
|
|
51
|
+
expect(res.body).toEqual({ message: "Please check your email for a reset link." })
|
|
34
52
|
expect(sendMailMock).toHaveBeenCalled()
|
|
35
|
-
|
|
53
|
+
|
|
36
54
|
expect(code).toBeDefined()
|
|
37
55
|
expect(events.user.passwordResetRequested).toBeCalledTimes(1)
|
|
38
56
|
expect(events.user.passwordResetRequested).toBeCalledWith(user)
|
|
39
57
|
})
|
|
40
58
|
|
|
41
59
|
it("should allow resetting user password with code", async () => {
|
|
42
|
-
const { code } = await
|
|
60
|
+
const { code } = await requestPasswordReset()
|
|
43
61
|
const user = await config.getUser("test@test.com")
|
|
44
|
-
delete user.password
|
|
45
|
-
|
|
46
|
-
const res = await api.auth.updatePassword(code)
|
|
62
|
+
delete user.password
|
|
47
63
|
|
|
64
|
+
const res = await request
|
|
65
|
+
.post(`/api/global/auth/${TENANT_ID}/reset/update`)
|
|
66
|
+
.send({
|
|
67
|
+
password: "newpassword",
|
|
68
|
+
resetCode: code,
|
|
69
|
+
})
|
|
70
|
+
.expect("Content-Type", /json/)
|
|
71
|
+
.expect(200)
|
|
48
72
|
expect(res.body).toEqual({ message: "password reset successfully." })
|
|
49
73
|
expect(events.user.passwordReset).toBeCalledTimes(1)
|
|
50
74
|
expect(events.user.passwordReset).toBeCalledWith(user)
|
|
@@ -55,15 +79,15 @@ describe("/api/global/auth", () => {
|
|
|
55
79
|
|
|
56
80
|
const passportSpy = jest.spyOn(auth.passport, "authenticate")
|
|
57
81
|
let oidcConf
|
|
58
|
-
let chosenConfig
|
|
59
|
-
let configId
|
|
82
|
+
let chosenConfig
|
|
83
|
+
let configId
|
|
60
84
|
|
|
61
85
|
// mock the oidc strategy implementation and return value
|
|
62
86
|
let strategyFactory = jest.fn()
|
|
63
87
|
let mockStrategyReturn = jest.fn()
|
|
64
88
|
let mockStrategyConfig = jest.fn()
|
|
65
89
|
auth.oidc.fetchStrategyConfig = mockStrategyConfig
|
|
66
|
-
|
|
90
|
+
|
|
67
91
|
strategyFactory.mockReturnValue(mockStrategyReturn)
|
|
68
92
|
auth.oidc.strategyFactory = strategyFactory
|
|
69
93
|
|
|
@@ -75,34 +99,34 @@ describe("/api/global/auth", () => {
|
|
|
75
99
|
})
|
|
76
100
|
|
|
77
101
|
afterEach(() => {
|
|
78
|
-
expect(strategyFactory).toBeCalledWith(
|
|
102
|
+
expect(strategyFactory).toBeCalledWith(
|
|
103
|
+
chosenConfig,
|
|
104
|
+
expect.any(Function)
|
|
105
|
+
)
|
|
79
106
|
})
|
|
80
107
|
|
|
81
108
|
describe("oidc configs", () => {
|
|
82
109
|
it("should load strategy and delegate to passport", async () => {
|
|
83
|
-
await api
|
|
110
|
+
await request.get(`/api/global/auth/${TENANT_ID}/oidc/configs/${configId}`)
|
|
84
111
|
|
|
85
112
|
expect(passportSpy).toBeCalledWith(mockStrategyReturn, {
|
|
86
|
-
scope: ["profile", "email", "offline_access"]
|
|
113
|
+
scope: ["profile", "email", "offline_access"]
|
|
87
114
|
})
|
|
88
|
-
expect(passportSpy.mock.calls.length).toBe(1)
|
|
115
|
+
expect(passportSpy.mock.calls.length).toBe(1);
|
|
89
116
|
})
|
|
90
117
|
})
|
|
91
118
|
|
|
92
119
|
describe("oidc callback", () => {
|
|
93
120
|
it("should load strategy and delegate to passport", async () => {
|
|
94
|
-
await
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
},
|
|
102
|
-
expect.anything()
|
|
103
|
-
)
|
|
104
|
-
expect(passportSpy.mock.calls.length).toBe(1)
|
|
121
|
+
await request.get(`/api/global/auth/${TENANT_ID}/oidc/callback`)
|
|
122
|
+
.set(config.getOIDConfigCookie(configId))
|
|
123
|
+
|
|
124
|
+
expect(passportSpy).toBeCalledWith(mockStrategyReturn, {
|
|
125
|
+
successRedirect: "/", failureRedirect: "/error"
|
|
126
|
+
}, expect.anything())
|
|
127
|
+
expect(passportSpy.mock.calls.length).toBe(1);
|
|
105
128
|
})
|
|
106
129
|
})
|
|
130
|
+
|
|
107
131
|
})
|
|
108
132
|
})
|