Skip to content

Implement password verification during setup #302

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function ConnectUploadThing() {
to visit UploadThing. Create an app and copy and paste your API key
below.
</Paragraph>
<Alert variant="info" className="mt-4">
<Alert variant="info">
<AlertTitle>Good to know:</AlertTitle>
<AlertDescription>
Your UploadThing account is unique to you, meaning that no one else
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { SignUpForm } from '~/app/(blobs)/(setup)/_components/SignUpForm';
import { Alert, AlertDescription, AlertTitle } from '~/components/ui/Alert';
import Heading from '~/components/ui/typography/Heading';
import Paragraph from '~/components/ui/typography/Paragraph';

Expand All @@ -13,6 +14,14 @@ function CreateAccount() {
administrator account can be created.
</Paragraph>
</div>
<Alert variant="warning">
<AlertTitle>Important</AlertTitle>
<AlertDescription>
It is not possible to recover the account details if they are lost.
Make sure to store the account details in a safe place, such as a
password manager.
</AlertDescription>
</Alert>
<SignUpForm />
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function ConfigureStudy() {
the dashboard.
</Paragraph>
<ProtocolUploader
className="m-14 p-6"
className="m-10 p-8"
buttonVariant="outline"
buttonSize="lg"
hideCancelButton
Expand Down
6 changes: 3 additions & 3 deletions app/(blobs)/(setup)/_components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ function OnboardSteps({ steps }: { steps: string[] }) {
>
<div
className={cn(
'text-md flex h-10 w-10 items-center justify-center rounded-full border border-primary/[.06] font-bold',
'border-primary/[.06] flex h-10 w-10 items-center justify-center rounded-full border text-sm font-bold',
index < currentStep - 1 &&
'border-teal-400 bg-success text-white',
'bg-success border-teal-400 text-white',
index === currentStep - 1 &&
'border-primary bg-primary text-white',
)}
Expand All @@ -39,7 +39,7 @@ function OnboardSteps({ steps }: { steps: string[] }) {
)}
</div>
<div className="flex flex-col">
<Heading variant={'h4-all-caps'} className="m-0">
<Heading variant={'h4-all-caps'} className="m-0 text-xs">
{step}
</Heading>
</div>
Expand Down
25 changes: 23 additions & 2 deletions app/(blobs)/(setup)/_components/SignUpForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@ export const SignUpForm = () => {
const {
register,
handleSubmit,
watch,
trigger,
formState: { errors, isValid, isSubmitting },
} = useZodForm({
schema: createUserSchema,
mode: 'onTouched',
});

const onSubmit = async (data: unknown) => {
await signup(data);
};

const password = watch('password');

return (
<form
className="flex flex-col"
Expand All @@ -34,19 +39,35 @@ export const SignUpForm = () => {
placeholder="username..."
autoComplete="do-not-autofill"
error={errors.username?.message}
{...register('username')}
{...register('username', {})}
/>
</div>
<div className="mb-6 flex flex-wrap">
<Input
className="w-full"
label="Password"
hint="Your password must be at least 8 characters long, and contain at least one each of lowercase, uppercase, number and symbol characters."
type="password"
placeholder="******************"
autoComplete="do-not-autofill"
error={errors.password?.message}
{...register('password')}
{...register('password', {
onChange: () => trigger('password'),
})}
/>
{password && password.length > 0 && (
<Input
className="w-full"
label="Confirm password"
type="password"
placeholder="******************"
autoComplete="do-not-autofill"
error={errors.confirmPassword?.message}
{...register('confirmPassword', {
onChange: () => trigger('confirmPassword'),
})}
/>
)}
</div>
<div className="flex flex-wrap justify-end">
<Button disabled={isSubmitting || !isValid} type="submit">
Expand Down
4 changes: 3 additions & 1 deletion components/ui/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Heading from './typography/Heading';
import { paragraphVariants } from './typography/Paragraph';

const alertVariants = cva(
'relative w-full bg-card text-foreground rounded-lg border p-4 [&>svg~*]:pl-6 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground',
'relative w-full bg-card text-foreground rounded-lg border p-4 [&>svg~*]:pl-6 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground gap-2 grid my-6',
{
variants: {
variant: {
Expand All @@ -17,6 +17,8 @@ const alertVariants = cva(
'bg-destructive/5 border-destructive text-destructive [&>svg]:text-destructive [--color-link:var(--color-destructive)]',
success:
'bg-success/5 border-success text-success [&>svg]:text-success [--color-link:var(--color-success)]',
warning:
'bg-warning/2 border-warning text-warning [--color-link:var(--color-warning)]',
},
},
defaultVariants: {
Expand Down
49 changes: 30 additions & 19 deletions schemas/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,36 @@ import { isStrongPassword } from 'validator';
import { z } from 'zod';
import { zfd } from 'zod-form-data';

export const createUserSchema = z.object({
username: z
.string()
.min(4, { message: 'Username must be at least 4 characters' })
.refine((s) => !s.includes(' '), 'Username cannot contain spaces'),
password: z.string().refine(
(password) =>
isStrongPassword(password, {
minLowercase: 1,
minUppercase: 1,
minNumbers: 1,
minSymbols: 1,
}),
{
message:
'Password must contain at least 1 lowercase, 1 uppercase, 1 number, and 1 symbol',
},
),
});
export const createUserSchema = z
.object({
username: z
.string()
.min(4, { message: 'Username must be at least 4 characters' })
.refine((s) => !s.includes(' '), 'Username cannot contain spaces'),
password: z.string().refine(
(password) =>
isStrongPassword(password, {
minLowercase: 1,
minUppercase: 1,
minNumbers: 1,
minSymbols: 1,
}),
{
message:
'Password must contain at least 1 lowercase, 1 uppercase, 1 number, and 1 symbol',
},
),
confirmPassword: z.string().min(1),
})
.superRefine((val, ctx) => {
if (val.password !== val.confirmPassword) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Passwords do not match',
path: ['confirmPassword'],
});
}
});

export const createUserFormDataSchema = zfd.formData(createUserSchema);

Expand Down
7 changes: 5 additions & 2 deletions styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
--color-info: hsl(var(--info));
--color-info-foreground: hsl(var(--info-foreground));

--color-warning: hsl(var(--warning));
--color-warning-foreground: hsl(var(--warning-foreground));

--color-muted: hsl(var(--muted));
--color-muted-foreground: hsl(var(--muted-foreground));

Expand Down Expand Up @@ -322,8 +325,8 @@
calc(var(--kiwi-lightness) - var(--dark-mod));

--neon-carrot-hue: 32;
--neon-carrot-saturation: 90%;
--neon-carrot-lightness: 55%;
--neon-carrot-saturation: 92%;
--neon-carrot-lightness: 52%;
--neon-carrot: var(--neon-carrot-hue) var(--neon-carrot-saturation)
var(--neon-carrot-lightness);
--neon-carrot--dark: var(--neon-carrot-hue) var(--neon-carrot-saturation)
Expand Down
Loading