Auto login the user after password is set (#14344)
* login after creating super admin user * Allow keyboard enter key in create account from invite * Allow enter key to submit password reset * Min length for password validation should be 12 * Default PASSWORD_MIN_LENGTH to 12 * fix unit tests * Fix unit tests * Add passwordMinLength to admin store
This commit is contained in:
parent
f3f6f8d9b0
commit
c86b1d7ca5
|
@ -1,6 +1,6 @@
|
|||
import env from "../environment"
|
||||
|
||||
export const PASSWORD_MIN_LENGTH = +(env.PASSWORD_MIN_LENGTH || 8)
|
||||
export const PASSWORD_MIN_LENGTH = +(env.PASSWORD_MIN_LENGTH || 12)
|
||||
export const PASSWORD_MAX_LENGTH = +(env.PASSWORD_MAX_LENGTH || 512)
|
||||
|
||||
export function validatePassword(
|
||||
|
|
|
@ -4,7 +4,7 @@ import { PASSWORD_MAX_LENGTH, validatePassword } from "../auth"
|
|||
describe("auth", () => {
|
||||
describe("validatePassword", () => {
|
||||
it("a valid password returns successful", () => {
|
||||
expect(validatePassword("password")).toEqual({ valid: true })
|
||||
expect(validatePassword("password123!")).toEqual({ valid: true })
|
||||
})
|
||||
|
||||
it.each([
|
||||
|
@ -14,7 +14,7 @@ describe("auth", () => {
|
|||
])("%s returns unsuccessful", (_, password) => {
|
||||
expect(validatePassword(password as string)).toEqual({
|
||||
valid: false,
|
||||
error: "Password invalid. Minimum 8 characters.",
|
||||
error: "Password invalid. Minimum 12 characters.",
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ export const user = (userProps?: Partial<Omit<User, "userId">>): User => {
|
|||
_id: userId,
|
||||
userId,
|
||||
email: newEmail(),
|
||||
password: "password",
|
||||
password: "password123!",
|
||||
roles: { app_test: "admin" },
|
||||
firstName: generator.first(),
|
||||
lastName: generator.last(),
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
<script>
|
||||
import { FancyForm, FancyInput } from "@budibase/bbui"
|
||||
import { createValidationStore, requiredValidator } from "helpers/validation"
|
||||
import { admin } from "stores/portal"
|
||||
|
||||
export let password
|
||||
export let passwordForm
|
||||
export let error
|
||||
|
||||
$: passwordMinLength = $admin.passwordMinLength ?? 12
|
||||
|
||||
const validatePassword = value => {
|
||||
if (!value || value.length < 12) {
|
||||
return "Please enter at least 12 characters. We recommend using machine generated or random passwords."
|
||||
if (!value || value.length < passwordMinLength) {
|
||||
return `Please enter at least ${passwordMinLength} characters. We recommend using machine generated or random passwords.`
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
@ -31,7 +34,8 @@
|
|||
!$firstPassword ||
|
||||
!$firstTouched ||
|
||||
!$repeatTouched ||
|
||||
$firstPassword !== $repeatPassword
|
||||
$firstPassword !== $repeatPassword ||
|
||||
firstPasswordError
|
||||
</script>
|
||||
|
||||
<FancyForm bind:this={passwordForm}>
|
||||
|
|
|
@ -14,8 +14,15 @@
|
|||
notifications.error("Failed to update password")
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeydown = evt => {
|
||||
if (evt.key === "Enter" && !error && password) {
|
||||
updatePassword()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={handleKeydown} />
|
||||
<ModalContent
|
||||
title="Update password"
|
||||
confirmText="Update password"
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
let password = null
|
||||
const validation = createValidationStore()
|
||||
validation.addValidatorType("password", "password", true, { minLength: 8 })
|
||||
validation.addValidatorType("password", "password", true, { minLength: 12 })
|
||||
$: validation.observe("password", password)
|
||||
|
||||
const Step = { CONFIG: "config", SET_PASSWORD: "set_password" }
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
let submitted = false
|
||||
|
||||
$: tenantId = $auth.tenantId
|
||||
$: passwordMinLength = $admin.passwordMinLength ?? 12
|
||||
|
||||
async function save() {
|
||||
form.validate()
|
||||
|
@ -35,14 +36,25 @@
|
|||
await API.createAdminUser(adminUser)
|
||||
notifications.success("Admin user created")
|
||||
await admin.init()
|
||||
await auth.login({
|
||||
username: formData?.email.trim(),
|
||||
password: formData?.password,
|
||||
})
|
||||
$goto("../portal")
|
||||
} catch (error) {
|
||||
submitted = false
|
||||
notifications.error(error.message || "Failed to create admin user")
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeydown = evt => {
|
||||
if (evt.key === "Enter") {
|
||||
save()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={handleKeydown} />
|
||||
<TestimonialPage>
|
||||
<Layout gap="M" noPadding>
|
||||
<Layout justifyItems="center" noPadding>
|
||||
|
@ -83,9 +95,15 @@
|
|||
validate={() => {
|
||||
let fieldError = {}
|
||||
|
||||
fieldError["password"] = !formData.password
|
||||
? "Please enter a password"
|
||||
: undefined
|
||||
if (!formData.password) {
|
||||
fieldError["password"] = "Please enter a password"
|
||||
} else if (formData.password.length < passwordMinLength) {
|
||||
fieldError[
|
||||
"password"
|
||||
] = `Password must be at least ${passwordMinLength} characters`
|
||||
} else {
|
||||
fieldError["password"] = undefined
|
||||
}
|
||||
|
||||
fieldError["confirmationPassword"] =
|
||||
!passwordsMatch(
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
FancyInput,
|
||||
} from "@budibase/bbui"
|
||||
import { goto, params } from "@roxi/routify"
|
||||
import { users, organisation, auth } from "stores/portal"
|
||||
import { users, organisation, auth, admin } from "stores/portal"
|
||||
import Logo from "assets/bb-emblem.svg"
|
||||
import { TestimonialPage } from "@budibase/frontend-core/src/components"
|
||||
import { onMount } from "svelte"
|
||||
|
@ -23,6 +23,7 @@
|
|||
let loaded = false
|
||||
|
||||
$: company = $organisation.company || "Budibase"
|
||||
$: passwordMinLength = $admin.passwordMinLength ?? 12
|
||||
|
||||
async function acceptInvite() {
|
||||
form.validate()
|
||||
|
@ -85,8 +86,15 @@
|
|||
notifications.error("Error getting invite config")
|
||||
}
|
||||
})
|
||||
|
||||
const handleKeydown = evt => {
|
||||
if (evt.key === "Enter") {
|
||||
acceptInvite()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={handleKeydown} />
|
||||
{#if loaded}
|
||||
<TestimonialPage>
|
||||
<Layout gap="M" noPadding>
|
||||
|
@ -154,8 +162,8 @@
|
|||
function validatePassword() {
|
||||
if (!formData.password) {
|
||||
return "Please enter a password"
|
||||
} else if (formData.password.length < 8) {
|
||||
return "Please enter at least 8 characters"
|
||||
} else if (formData.password.length < passwordMinLength) {
|
||||
return `Please enter at least ${passwordMinLength} characters`
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ export function createAdminStore() {
|
|||
store.baseUrl = environment.baseUrl
|
||||
store.offlineMode = environment.offlineMode
|
||||
store.maintenance = environment.maintenance
|
||||
store.passwordMinLength = environment.passwordMinLength
|
||||
return store
|
||||
})
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ export const fetch = async (ctx: Ctx) => {
|
|||
baseUrl: env.PLATFORM_URL,
|
||||
isDev: env.isDev() && !env.isTest(),
|
||||
maintenance: [],
|
||||
passwordMinLength: env.PASSWORD_MIN_LENGTH,
|
||||
}
|
||||
|
||||
if (env.SELF_HOSTED) {
|
||||
|
|
|
@ -66,7 +66,7 @@ describe("/api/global/auth", () => {
|
|||
it("should return 403 with incorrect credentials", async () => {
|
||||
const tenantId = config.tenantId!
|
||||
const email = config.user?.email!
|
||||
const password = "incorrect"
|
||||
const password = "incorrect123"
|
||||
|
||||
const response = await config.api.auth.login(
|
||||
tenantId,
|
||||
|
@ -83,7 +83,7 @@ describe("/api/global/auth", () => {
|
|||
it("should return 403 when user doesn't exist", async () => {
|
||||
const tenantId = config.tenantId!
|
||||
const email = "invaliduser@example.com"
|
||||
const password = "password"
|
||||
const password = "password123!"
|
||||
|
||||
const response = await config.api.auth.login(
|
||||
tenantId,
|
||||
|
@ -203,7 +203,7 @@ describe("/api/global/auth", () => {
|
|||
)
|
||||
delete user.password
|
||||
|
||||
const newPassword = "newpassword"
|
||||
const newPassword = "newpassword1"
|
||||
const res = await config.api.auth.updatePassword(code!, newPassword)
|
||||
|
||||
user = (await config.getUser(user.email))!
|
||||
|
|
|
@ -32,7 +32,7 @@ describe("/api/global/self", () => {
|
|||
|
||||
const res = await config.api.self
|
||||
.updateSelf(user, {
|
||||
password: "newPassword",
|
||||
password: "newPassword1",
|
||||
})
|
||||
.expect(200)
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ describe("/api/global/tenant", () => {
|
|||
const tenantInfo: TenantInfo = {
|
||||
owner: {
|
||||
email: "test@example.com",
|
||||
password: "PASSWORD",
|
||||
password: "PASSWORD123!",
|
||||
ssoId: "SSO_ID",
|
||||
givenName: "Jane",
|
||||
familyName: "Doe",
|
||||
|
|
|
@ -26,6 +26,7 @@ const environment = {
|
|||
SALT_ROUNDS: process.env.SALT_ROUNDS,
|
||||
REDIS_PASSWORD: process.env.REDIS_PASSWORD,
|
||||
COOKIE_DOMAIN: process.env.COOKIE_DOMAIN,
|
||||
PASSWORD_MIN_LENGTH: process.env.PASSWORD_MIN_LENGTH,
|
||||
// urls
|
||||
MINIO_URL: process.env.MINIO_URL,
|
||||
COUCH_DB_URL: process.env.COUCH_DB_URL,
|
||||
|
|
|
@ -44,7 +44,7 @@ class TestConfiguration {
|
|||
tenantId: string
|
||||
user?: User
|
||||
apiKey?: string
|
||||
userPassword = "password"
|
||||
userPassword = "password123!"
|
||||
|
||||
constructor(opts: { openServer: boolean } = { openServer: true }) {
|
||||
// default to cloud hosting
|
||||
|
|
|
@ -48,7 +48,7 @@ export class UserAPI extends TestAPI {
|
|||
return this.request
|
||||
.post(`/api/global/users/invite/accept`)
|
||||
.send({
|
||||
password: "newpassword",
|
||||
password: "newpassword1",
|
||||
inviteCode: code,
|
||||
firstName: "Ted",
|
||||
})
|
||||
|
@ -101,7 +101,7 @@ export class UserAPI extends TestAPI {
|
|||
if (!request) {
|
||||
request = {
|
||||
email: structures.email(),
|
||||
password: generator.string({ length: 8 }),
|
||||
password: generator.string({ length: 12 }),
|
||||
tenantId: structures.tenant.id(),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue