Merge branch 'master' into BUDI-7656/add-multiple-relationships-dev-script
This commit is contained in:
commit
f4d70ad7f3
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.13.50",
|
||||
"version": "2.13.51",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*",
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e46a352a6326a838faa00f912de069aee95d7300
|
||||
Subproject commit d6a1f89aa543bdce7acde5fbe4ce650a1344e2fe
|
|
@ -1,6 +1,6 @@
|
|||
import * as redis from "../redis/init"
|
||||
import * as utils from "../utils"
|
||||
import { Duration, DurationType } from "../utils"
|
||||
import { Duration } from "../utils"
|
||||
|
||||
const TTL_SECONDS = Duration.fromHours(1).toSeconds()
|
||||
|
||||
|
@ -32,7 +32,18 @@ export async function getCode(code: string): Promise<PasswordReset> {
|
|||
const client = await redis.getPasswordResetClient()
|
||||
const value = (await client.get(code)) as PasswordReset | undefined
|
||||
if (!value) {
|
||||
throw "Provided information is not valid, cannot reset password - please try again."
|
||||
throw new Error(
|
||||
"Provided information is not valid, cannot reset password - please try again."
|
||||
)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a reset code this will invalidate it.
|
||||
* @param code The code provided via the email link.
|
||||
*/
|
||||
export async function invalidateCode(code: string): Promise<void> {
|
||||
const client = await redis.getPasswordResetClient()
|
||||
await client.delete(code)
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ export function createQueue<T>(
|
|||
cleanupInterval = timers.set(cleanup, CLEANUP_PERIOD_MS)
|
||||
// fire off an initial cleanup
|
||||
cleanup().catch(err => {
|
||||
console.error(`Unable to cleanup automation queue initially - ${err}`)
|
||||
console.error(`Unable to cleanup ${jobQueue} initially - ${err}`)
|
||||
})
|
||||
}
|
||||
return queue
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
SelectableDatabase,
|
||||
getRedisConnectionDetails,
|
||||
} from "./utils"
|
||||
import { logAlert } from "../logging"
|
||||
import * as timers from "../timers"
|
||||
|
||||
const RETRY_PERIOD_MS = 2000
|
||||
|
@ -39,21 +40,16 @@ function pickClient(selectDb: number): any {
|
|||
return CLIENTS[selectDb]
|
||||
}
|
||||
|
||||
function connectionError(
|
||||
selectDb: number,
|
||||
timeout: NodeJS.Timeout,
|
||||
err: Error | string
|
||||
) {
|
||||
function connectionError(timeout: NodeJS.Timeout, err: Error | string) {
|
||||
// manually shut down, ignore errors
|
||||
if (CLOSED) {
|
||||
return
|
||||
}
|
||||
pickClient(selectDb).disconnect()
|
||||
CLOSED = true
|
||||
// always clear this on error
|
||||
clearTimeout(timeout)
|
||||
CONNECTED = false
|
||||
console.error("Redis connection failed - " + err)
|
||||
logAlert("Redis connection failed", err)
|
||||
setTimeout(() => {
|
||||
init()
|
||||
}, RETRY_PERIOD_MS)
|
||||
|
@ -79,11 +75,7 @@ function init(selectDb = DEFAULT_SELECT_DB) {
|
|||
// start the timer - only allowed 5 seconds to connect
|
||||
timeout = setTimeout(() => {
|
||||
if (!CONNECTED) {
|
||||
connectionError(
|
||||
selectDb,
|
||||
timeout,
|
||||
"Did not successfully connect in timeout"
|
||||
)
|
||||
connectionError(timeout, "Did not successfully connect in timeout")
|
||||
}
|
||||
}, STARTUP_TIMEOUT_MS)
|
||||
|
||||
|
@ -106,12 +98,13 @@ function init(selectDb = DEFAULT_SELECT_DB) {
|
|||
// allow the process to exit
|
||||
return
|
||||
}
|
||||
connectionError(selectDb, timeout, err)
|
||||
connectionError(timeout, err)
|
||||
})
|
||||
client.on("error", (err: Error) => {
|
||||
connectionError(selectDb, timeout, err)
|
||||
connectionError(timeout, err)
|
||||
})
|
||||
client.on("connect", () => {
|
||||
console.log(`Connected to Redis DB: ${selectDb}`)
|
||||
clearTimeout(timeout)
|
||||
CONNECTED = true
|
||||
})
|
||||
|
|
|
@ -2,7 +2,7 @@ import env from "../environment"
|
|||
import * as eventHelpers from "./events"
|
||||
import * as accountSdk from "../accounts"
|
||||
import * as cache from "../cache"
|
||||
import { doInTenant, getGlobalDB, getIdentity, getTenantId } from "../context"
|
||||
import { getGlobalDB, getIdentity, getTenantId } from "../context"
|
||||
import * as dbUtils from "../db"
|
||||
import { EmailUnavailableError, HTTPError } from "../errors"
|
||||
import * as platform from "../platform"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import tk from "timekeeper"
|
||||
import _ from "lodash"
|
||||
import { mocks, structures } from "@budibase/backend-core/tests"
|
||||
import { generator, mocks, structures } from "@budibase/backend-core/tests"
|
||||
import {
|
||||
ScimCreateUserRequest,
|
||||
ScimGroupResponse,
|
||||
|
@ -14,9 +14,14 @@ import { events } from "@budibase/backend-core"
|
|||
jest.retryTimes(2, { logErrorsBeforeRetry: true })
|
||||
jest.setTimeout(30000)
|
||||
|
||||
mocks.licenses.useScimIntegration()
|
||||
|
||||
describe("scim", () => {
|
||||
beforeAll(async () => {
|
||||
tk.freeze(mocks.date.MOCK_DATE)
|
||||
mocks.licenses.useScimIntegration()
|
||||
|
||||
await config.setSCIMConfig(true)
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.resetAllMocks()
|
||||
tk.freeze(mocks.date.MOCK_DATE)
|
||||
|
@ -570,8 +575,15 @@ describe("scim", () => {
|
|||
beforeAll(async () => {
|
||||
groups = []
|
||||
|
||||
for (let i = 0; i < groupCount; i++) {
|
||||
const body = structures.scim.createGroupRequest()
|
||||
const groupNames = generator.unique(
|
||||
() => generator.word(),
|
||||
groupCount
|
||||
)
|
||||
|
||||
for (const groupName of groupNames) {
|
||||
const body = structures.scim.createGroupRequest({
|
||||
displayName: groupName,
|
||||
})
|
||||
groups.push(await config.api.scimGroupsAPI.post({ body }))
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,9 @@ export const resetUpdate = async (resetCode: string, password: string) => {
|
|||
user.password = password
|
||||
user = await userSdk.db.save(user)
|
||||
|
||||
await cache.passwordReset.invalidateCode(resetCode)
|
||||
await sessions.invalidateSessions(userId)
|
||||
|
||||
// remove password from the user before sending events
|
||||
delete user.password
|
||||
await events.user.passwordReset(user)
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
import { cache, context, sessions, utils } from "@budibase/backend-core"
|
||||
import { loginUser, resetUpdate } from "../auth"
|
||||
import { generator, structures } from "@budibase/backend-core/tests"
|
||||
import { TestConfiguration } from "../../../tests"
|
||||
|
||||
describe("auth", () => {
|
||||
const config = new TestConfiguration()
|
||||
|
||||
describe("resetUpdate", () => {
|
||||
it("providing a valid code will update the password", async () => {
|
||||
await context.doInTenant(structures.tenant.id(), async () => {
|
||||
const user = await config.createUser()
|
||||
const previousPassword = user.password
|
||||
|
||||
const code = await cache.passwordReset.createCode(user._id!, {})
|
||||
const newPassword = generator.hash()
|
||||
|
||||
await resetUpdate(code, newPassword)
|
||||
|
||||
const persistedUser = await config.getUser(user.email)
|
||||
expect(persistedUser.password).not.toBe(previousPassword)
|
||||
expect(
|
||||
await utils.compare(newPassword, persistedUser.password!)
|
||||
).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
it("wrong code will not allow to reset the password", async () => {
|
||||
await context.doInTenant(structures.tenant.id(), async () => {
|
||||
const code = generator.hash()
|
||||
const newPassword = generator.hash()
|
||||
|
||||
await expect(resetUpdate(code, newPassword)).rejects.toThrow(
|
||||
"Provided information is not valid, cannot reset password - please try again."
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it("the same code cannot be used twice", async () => {
|
||||
await context.doInTenant(structures.tenant.id(), async () => {
|
||||
const user = await config.createUser()
|
||||
|
||||
const code = await cache.passwordReset.createCode(user._id!, {})
|
||||
const newPassword = generator.hash()
|
||||
|
||||
await resetUpdate(code, newPassword)
|
||||
await expect(resetUpdate(code, newPassword)).rejects.toThrow(
|
||||
"Provided information is not valid, cannot reset password - please try again."
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it("updating the password will invalidate all the sessions", async () => {
|
||||
await context.doInTenant(structures.tenant.id(), async () => {
|
||||
const user = await config.createUser()
|
||||
|
||||
await loginUser(user)
|
||||
|
||||
expect(await sessions.getSessionsForUser(user._id!)).toHaveLength(1)
|
||||
|
||||
const code = await cache.passwordReset.createCode(user._id!, {})
|
||||
const newPassword = generator.hash()
|
||||
|
||||
await resetUpdate(code, newPassword)
|
||||
|
||||
expect(await sessions.getSessionsForUser(user._id!)).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,6 +1,5 @@
|
|||
import { structures, mocks } from "../../../tests"
|
||||
import { env, context } from "@budibase/backend-core"
|
||||
import * as users from "../users"
|
||||
import { db as userDb } from "../"
|
||||
import { CloudAccount } from "@budibase/types"
|
||||
|
||||
|
|
Loading…
Reference in New Issue