From 743b177c893986ac279cb2331600c93d5b246dcc Mon Sep 17 00:00:00 2001 From: opencode Date: Mon, 3 Aug 2026 08:01:52 +0200 Subject: [PATCH] fix(auth): password min length 6 + show/hide toggle on password inputs --- artifacts/api-server/src/routes/auth.ts | 2 +- artifacts/api-server/src/routes/users.ts | 2 +- .../src/components/password-input.tsx | 25 +++++++++++++++++++ .../toolrate/src/components/user-menu.tsx | 15 +++++------ artifacts/toolrate/src/pages/admin.tsx | 12 ++++----- artifacts/toolrate/src/pages/login.tsx | 4 +-- .../src/generated/api.schemas.ts | 4 +-- lib/api-spec/openapi.yaml | 4 +-- lib/api-zod/src/generated/api.ts | 4 +-- .../generated/types/changePasswordInput.ts | 2 +- .../src/generated/types/setPasswordInput.ts | 2 +- 11 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 artifacts/toolrate/src/components/password-input.tsx diff --git a/artifacts/api-server/src/routes/auth.ts b/artifacts/api-server/src/routes/auth.ts index 6a31037..e628dd8 100644 --- a/artifacts/api-server/src/routes/auth.ts +++ b/artifacts/api-server/src/routes/auth.ts @@ -293,7 +293,7 @@ router.get("/auth/password-redirect", async (req, res): Promise => { const ChangePasswordSchema = z.object({ currentPassword: z.string().min(1), - newPassword: z.string().min(8), + newPassword: z.string().min(6), }); router.post("/auth/me/password", passwordRateLimit, async (req, res): Promise => { diff --git a/artifacts/api-server/src/routes/users.ts b/artifacts/api-server/src/routes/users.ts index bc42437..7a633ab 100644 --- a/artifacts/api-server/src/routes/users.ts +++ b/artifacts/api-server/src/routes/users.ts @@ -25,7 +25,7 @@ const UserUpdateSchema = z.object({ }); const SetPasswordSchema = z.object({ - password: z.string().min(8), + password: z.string().min(6), }); router.patch("/users/:id/password", requireAdmin, passwordRateLimit, async (req, res): Promise => { diff --git a/artifacts/toolrate/src/components/password-input.tsx b/artifacts/toolrate/src/components/password-input.tsx new file mode 100644 index 0000000..92654dd --- /dev/null +++ b/artifacts/toolrate/src/components/password-input.tsx @@ -0,0 +1,25 @@ +import { useState } from "react"; +import { Eye, EyeOff } from "lucide-react"; +import { Input } from "@/components/ui/input"; +import { cn } from "@/lib/utils"; + +export function PasswordInput({ + className, + ...props +}: Omit, "type">) { + const [visible, setVisible] = useState(false); + return ( +
+ + +
+ ); +} \ No newline at end of file diff --git a/artifacts/toolrate/src/components/user-menu.tsx b/artifacts/toolrate/src/components/user-menu.tsx index e21dc97..d964dd6 100644 --- a/artifacts/toolrate/src/components/user-menu.tsx +++ b/artifacts/toolrate/src/components/user-menu.tsx @@ -15,8 +15,8 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { PasswordInput } from "@/components/password-input"; import { useToast } from "@/hooks/use-toast"; import { useChangeMyPassword, useGetPasswordRedirect, getGetPasswordRedirectQueryKey } from "@workspace/api-client-react"; import { useQueryClient } from "@tanstack/react-query"; @@ -182,8 +182,7 @@ export function UserMenu() {
- setCurrentPassword(e.target.value)} data-testid="input-current-password" @@ -191,18 +190,16 @@ export function UserMenu() {
- setNewPassword(e.target.value)} - placeholder="min. 8 characters" + placeholder="min. 6 characters" data-testid="input-new-password" />
- setConfirmPassword(e.target.value)} data-testid="input-confirm-password" @@ -219,7 +216,7 @@ export function UserMenu() { toast({ title: t("auth.pwMismatch"), variant: "destructive" }); return; } - if (newPassword.length < 8) { + if (newPassword.length < 6) { toast({ title: t("auth.pwTooShort"), variant: "destructive" }); return; } diff --git a/artifacts/toolrate/src/pages/admin.tsx b/artifacts/toolrate/src/pages/admin.tsx index 10c8063..315d8cc 100644 --- a/artifacts/toolrate/src/pages/admin.tsx +++ b/artifacts/toolrate/src/pages/admin.tsx @@ -17,6 +17,7 @@ import { useAuth } from "@/hooks/use-auth"; import { Layout } from "@/components/layout"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; +import { PasswordInput } from "@/components/password-input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; @@ -115,8 +116,8 @@ export default function Admin() { const handleSetUserPassword = () => { if (!editUser || !editPassword) return; - if (editPassword.length < 8) { - toast({ title: "Password too short", description: "Minimum 8 characters.", variant: "destructive" }); + if (editPassword.length < 6) { + toast({ title: "Password too short", description: "Minimum 6 characters.", variant: "destructive" }); return; } setUserPassword.mutate( @@ -367,7 +368,7 @@ export default function Admin() {
- setNewPassword(e.target.value)} placeholder="min. 6 characters" /> + setNewPassword(e.target.value)} placeholder="min. 6 characters" />
@@ -448,11 +449,10 @@ export default function Admin() { {editUser?.authProvider !== "oidc" ? (
- setEditPassword(e.target.value)} - placeholder="min. 8 characters" + placeholder="min. 6 characters" data-testid="input-set-password" />

Resets the user's password immediately.

diff --git a/artifacts/toolrate/src/pages/login.tsx b/artifacts/toolrate/src/pages/login.tsx index 20ad8bc..838c78c 100644 --- a/artifacts/toolrate/src/pages/login.tsx +++ b/artifacts/toolrate/src/pages/login.tsx @@ -5,6 +5,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { PasswordInput } from "@/components/password-input"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { ThemeToggle } from "@/components/theme-toggle"; import { Wrench, AlertCircle } from "lucide-react"; @@ -76,9 +77,8 @@ export default function Login() {
- setPassword(e.target.value)} required diff --git a/lib/api-client-react/src/generated/api.schemas.ts b/lib/api-client-react/src/generated/api.schemas.ts index f065a7b..635892d 100644 --- a/lib/api-client-react/src/generated/api.schemas.ts +++ b/lib/api-client-react/src/generated/api.schemas.ts @@ -123,12 +123,12 @@ export interface UserRoleUpdate { export interface ChangePasswordInput { /** @minLength 1 */ currentPassword: string; - /** @minLength 8 */ + /** @minLength 6 */ newPassword: string; } export interface SetPasswordInput { - /** @minLength 8 */ + /** @minLength 6 */ password: string; } diff --git a/lib/api-spec/openapi.yaml b/lib/api-spec/openapi.yaml index a7786b0..8932905 100644 --- a/lib/api-spec/openapi.yaml +++ b/lib/api-spec/openapi.yaml @@ -1013,7 +1013,7 @@ components: minLength: 1 newPassword: type: string - minLength: 8 + minLength: 6 SetPasswordInput: type: object @@ -1021,7 +1021,7 @@ components: properties: password: type: string - minLength: 8 + minLength: 6 PasswordRedirect: type: object diff --git a/lib/api-zod/src/generated/api.ts b/lib/api-zod/src/generated/api.ts index 615ed1d..aca536e 100644 --- a/lib/api-zod/src/generated/api.ts +++ b/lib/api-zod/src/generated/api.ts @@ -484,7 +484,7 @@ export const GetMeResponse = zod.object({ * @summary Change own password (local users only) */ -export const changeMyPasswordBodyNewPasswordMin = 8; +export const changeMyPasswordBodyNewPasswordMin = 6; @@ -626,7 +626,7 @@ export const SetUserPasswordParams = zod.object({ "id": zod.coerce.number() }) -export const setUserPasswordBodyPasswordMin = 8; +export const setUserPasswordBodyPasswordMin = 6; diff --git a/lib/api-zod/src/generated/types/changePasswordInput.ts b/lib/api-zod/src/generated/types/changePasswordInput.ts index a64a691..fee75af 100644 --- a/lib/api-zod/src/generated/types/changePasswordInput.ts +++ b/lib/api-zod/src/generated/types/changePasswordInput.ts @@ -9,6 +9,6 @@ export interface ChangePasswordInput { /** @minLength 1 */ currentPassword: string; - /** @minLength 8 */ + /** @minLength 6 */ newPassword: string; } diff --git a/lib/api-zod/src/generated/types/setPasswordInput.ts b/lib/api-zod/src/generated/types/setPasswordInput.ts index 95e8e73..73681fa 100644 --- a/lib/api-zod/src/generated/types/setPasswordInput.ts +++ b/lib/api-zod/src/generated/types/setPasswordInput.ts @@ -7,6 +7,6 @@ */ export interface SetPasswordInput { - /** @minLength 8 */ + /** @minLength 6 */ password: string; }