Skip to content

Commit 31a8966

Browse files
authored
🐛 Bugfix: Fix no password check when creating tenant admin (#3061)
1 parent 1e2bb04 commit 31a8966

4 files changed

Lines changed: 134 additions & 6 deletions

File tree

frontend/app/[locale]/models/components/model/ModelAddDialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,7 +1706,7 @@ export const ModelAddDialog = ({
17061706
)}
17071707
{isSTTModel && (
17081708
<>
1709-
<Tooltip title={t("model.provider.volengine")}>
1709+
<Tooltip title={t("model.provider.volcengine")}>
17101710
<a
17111711
href={PROVIDER_LINKS.volcengine}
17121712
target="_blank"
@@ -1736,7 +1736,7 @@ export const ModelAddDialog = ({
17361736
)}
17371737
{isTTSModel && (
17381738
<>
1739-
<Tooltip title={t("model.provider.volengine")}>
1739+
<Tooltip title={t("model.provider.volcengine")}>
17401740
<a
17411741
href={PROVIDER_LINKS.volcengine}
17421742
target="_blank"

frontend/app/[locale]/tenant-resources/components/UserManageComp.tsx

Lines changed: 130 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import { useAuthorizationContext } from "@/components/providers/AuthorizationPro
4848
import { USER_ROLES } from "@/const/auth";
4949
import { Can } from "@/components/permission/Can";
5050
import { Tooltip } from "@/components/ui/tooltip";
51+
import { getPasswordChecks, getStrengthLevel, validatePassword as validatePasswordUtil } from "@/lib/utils";
5152

5253
// Default page size for pagination
5354
const DEFAULT_PAGE_SIZE = 20;
@@ -108,6 +109,13 @@ function TenantList({
108109
// Tracks which skills have completed installation in the current session
109110
const [installedSkills, setInstalledSkills] = useState<Set<string>>(new Set());
110111

112+
// Password validation state for admin account
113+
const [adminPasswordValue, setAdminPasswordValue] = useState("");
114+
const [adminPasswordError, setAdminPasswordError] = useState<{
115+
target: "adminPassword" | "confirmAdminPassword" | "";
116+
message: string;
117+
}>({ target: "", message: "" });
118+
111119
// Fetch official skills when install switch is toggled on
112120
useEffect(() => {
113121
if (!installOfficialSkills) return;
@@ -148,6 +156,8 @@ function TenantList({
148156
setSelectedSkillIds(new Set<string>());
149157
setInstallingSkills(new Set<string>());
150158
setInstalledSkills(new Set<string>());
159+
setAdminPasswordValue("");
160+
setAdminPasswordError({ target: "", message: "" });
151161
setModalVisible(true);
152162
};
153163

@@ -215,6 +225,54 @@ function TenantList({
215225
setTenantUsers([]);
216226
};
217227

228+
// Handle admin password input change
229+
const handleAdminPasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
230+
const value = e.target.value;
231+
setAdminPasswordValue(value);
232+
233+
if (value && !validatePasswordUtil(value)) {
234+
setAdminPasswordError({
235+
target: "adminPassword",
236+
message: t("auth.passwordStrengthError") || "Password must contain uppercase, lowercase, and digit",
237+
});
238+
return;
239+
}
240+
241+
setAdminPasswordError({ target: "", message: "" });
242+
const confirmPassword = form.getFieldValue("confirmAdminPassword");
243+
if (confirmPassword && confirmPassword !== value) {
244+
setAdminPasswordError({
245+
target: "confirmAdminPassword",
246+
message: t("auth.passwordsDoNotMatch"),
247+
});
248+
}
249+
};
250+
251+
// Handle confirm admin password input change
252+
const handleConfirmAdminPasswordChange = (
253+
e: React.ChangeEvent<HTMLInputElement>
254+
) => {
255+
const value = e.target.value;
256+
const password = form.getFieldValue("adminPassword");
257+
258+
if (password && !validatePasswordUtil(password)) {
259+
setAdminPasswordError({
260+
target: "adminPassword",
261+
message: t("auth.passwordStrengthError") || "Password must contain uppercase, lowercase, and digit",
262+
});
263+
return;
264+
}
265+
266+
if (value && value !== password) {
267+
setAdminPasswordError({
268+
target: "confirmAdminPassword",
269+
message: t("auth.passwordsDoNotMatch"),
270+
});
271+
} else {
272+
setAdminPasswordError({ target: "", message: "" });
273+
}
274+
};
275+
218276
const handleSubmit = async () => {
219277
try {
220278
const values = await form.validateFields();
@@ -495,26 +553,86 @@ function TenantList({
495553
<Form.Item
496554
name="adminPassword"
497555
label={t("tenantResources.tenants.adminPassword")}
556+
validateStatus={
557+
adminPasswordError.target === "adminPassword"
558+
? "error"
559+
: ""
560+
}
561+
help={
562+
form.getFieldError("adminPassword").length
563+
? undefined
564+
: adminPasswordError.target === "adminPassword"
565+
? adminPasswordError.message
566+
: undefined
567+
}
498568
rules={[
499569
{
500570
required: true,
501571
message: t("tenantResources.tenants.adminPasswordRequired"),
502572
},
503573
{
504-
min: 6,
505-
message: t("tenantResources.tenants.weakPassword"),
574+
validator: (_, value) => {
575+
if (!value) return Promise.resolve();
576+
if (!validatePasswordUtil(value)) {
577+
return Promise.reject(
578+
new Error(t("auth.passwordStrengthError") || "Password must contain uppercase, lowercase, and digit")
579+
);
580+
}
581+
return Promise.resolve();
582+
},
506583
},
507584
]}
585+
hasFeedback
508586
>
509587
<Input.Password
510588
placeholder={t("tenantResources.tenants.adminPassword")}
511589
autoComplete="new-password"
590+
onChange={handleAdminPasswordChange}
512591
/>
513592
</Form.Item>
514593

594+
{/* Password Strength Indicator */}
595+
{adminPasswordValue && generateAdminAccount && (() => {
596+
const checks = getPasswordChecks(adminPasswordValue);
597+
const levelInfo = getStrengthLevel(adminPasswordValue, t);
598+
return (
599+
<div className="mb-4">
600+
<div className="flex items-center justify-between mb-1">
601+
<span className="text-xs text-gray-500">{t("auth.passwordStrength") || "Password strength"}</span>
602+
<span className="text-xs font-medium" style={{ color: levelInfo.color }}>
603+
{levelInfo.label}
604+
</span>
605+
</div>
606+
<div className="flex gap-1">
607+
{[0, 1, 2, 3].map((level) => (
608+
<div
609+
key={level}
610+
className="h-1 flex-1 rounded-full transition-colors"
611+
style={{
612+
backgroundColor: level <= levelInfo.level ? levelInfo.color : "#e5e7eb",
613+
}}
614+
/>
615+
))}
616+
</div>
617+
</div>
618+
);
619+
})()}
620+
515621
<Form.Item
516622
name="confirmAdminPassword"
517623
label={t("tenantResources.tenants.confirmAdminPassword")}
624+
validateStatus={
625+
adminPasswordError.target === "confirmAdminPassword"
626+
? "error"
627+
: ""
628+
}
629+
help={
630+
form.getFieldError("confirmAdminPassword").length
631+
? undefined
632+
: adminPasswordError.target === "confirmAdminPassword"
633+
? adminPasswordError.message
634+
: undefined
635+
}
518636
dependencies={["adminPassword"]}
519637
rules={[
520638
{
@@ -523,17 +641,27 @@ function TenantList({
523641
},
524642
({ getFieldValue }) => ({
525643
validator(_, value) {
644+
const password = getFieldValue("adminPassword");
645+
if (password && !validatePasswordUtil(password)) {
646+
setAdminPasswordError({
647+
target: "adminPassword",
648+
message: t("auth.passwordStrengthError") || "Password must contain uppercase, lowercase, and digit",
649+
});
650+
return Promise.reject(new Error(t("auth.passwordStrengthError") || "Password must contain uppercase, lowercase, and digit"));
651+
}
526652
if (!value || getFieldValue("adminPassword") === value) {
527653
return Promise.resolve();
528654
}
529655
return Promise.reject(new Error(t("tenantResources.tenants.passwordsDoNotMatch")));
530656
},
531657
}),
532658
]}
659+
hasFeedback
533660
>
534661
<Input.Password
535662
placeholder={t("tenantResources.tenants.confirmAdminPassword")}
536663
autoComplete="new-password"
664+
onChange={handleConfirmAdminPasswordChange}
537665
/>
538666
</Form.Item>
539667
</>

frontend/public/locales/en/common.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1712,7 +1712,6 @@
17121712
"tenantResources.tenants.adminPasswordRequired": "Please enter tenant admin password",
17131713
"tenantResources.tenants.invalidEmailFormat": "Invalid email format",
17141714
"tenantResources.tenants.emailAlreadyExists": "Email already exists",
1715-
"tenantResources.tenants.weakPassword": "Password must be at least 6 characters",
17161715
"tenantResources.tenants.passwordsDoNotMatch": "Passwords do not match",
17171716
"tenantResources.tenants.confirmAdminPassword": "Confirm Password",
17181717
"tenantResources.tenants.adminAccountCreated": "Tenant admin account created",
@@ -1732,6 +1731,7 @@
17321731
"tenantResources.tenants.noSkillsAvailable": "No official skills available",
17331732
"tenantResources.tenants.skillsLoading": "Loading skills...",
17341733
"tenantResources.tenantDeleteFailed": "Failed to delete tenant",
1734+
"tenantResources.tenantOperationFailed": "Tenant operation failed",
17351735
"tenantResources.skills.installOfficialSkills": "Install Official Skills",
17361736
"tenantResources.skills.installModal.title": "Install Official Skills",
17371737
"tenantResources.skills.installModal.selectAtLeastOne": "Please select at least one skill",

frontend/public/locales/zh/common.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1702,7 +1702,6 @@
17021702
"tenantResources.tenants.adminPasswordRequired": "请输入租户管理员密码",
17031703
"tenantResources.tenants.invalidEmailFormat": "邮箱格式不正确",
17041704
"tenantResources.tenants.emailAlreadyExists": "该邮箱已被使用",
1705-
"tenantResources.tenants.weakPassword": "密码强度不足,至少需要6位字符",
17061705
"tenantResources.tenants.passwordsDoNotMatch": "两次输入的密码不一致",
17071706
"tenantResources.tenants.confirmAdminPassword": "确认密码",
17081707
"tenantResources.tenants.adminAccountCreated": "租户管理员账户已创建",
@@ -1722,6 +1721,7 @@
17221721
"tenantResources.tenants.noSkillsAvailable": "暂无可安装的官方技能",
17231722
"tenantResources.tenants.skillsLoading": "加载技能中...",
17241723
"tenantResources.tenantDeleteFailed": "删除租户失败",
1724+
"tenantResources.tenantOperationFailed": "租户操作失败",
17251725
"tenantResources.skills.installOfficialSkills": "安装官方技能",
17261726
"tenantResources.skills.installModal.title": "安装官方技能",
17271727
"tenantResources.skills.installModal.selectAtLeastOne": "请至少选择一个技能",

0 commit comments

Comments
 (0)