mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
fix(ssh): accept full passwords in keyboard-interactive prompts (#1569)
This commit is contained in:
1 parent
f412a28bb8
commit
f4164a74b2
2 files changed
+74
-8
No files matched your search
@@ -44,6 +44,7 @@ export function TOTPDialog({
|
|||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
|
|
||||||
|
const isPassword = mode === "password";
|
||||||
const isPush = mode === "push";
|
const isPush = mode === "push";
|
||||||
const isMenu = mode === "menu";
|
const isMenu = mode === "menu";
|
||||||
const isTotp = !isPush && !isMenu && mode !== "password";
|
const isTotp = !isPush && !isMenu && mode !== "password";
|
||||||
@@ -62,16 +63,17 @@ export function TOTPDialog({
|
|||||||
const input = e.currentTarget.elements.namedItem(
|
const input = e.currentTarget.elements.namedItem(
|
||||||
"totpCode",
|
"totpCode",
|
||||||
) as HTMLInputElement;
|
) as HTMLInputElement;
|
||||||
if (input?.value.trim()) {
|
const value = isPassword ? input?.value : input?.value.trim();
|
||||||
onSubmit(input.value.trim());
|
if (value) onSubmit(value);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const title = isPush
|
const title = isPush
|
||||||
? t("sshAuth.mfaPushRequired")
|
? t("sshAuth.mfaPushRequired")
|
||||||
: isMenu
|
: isPassword
|
||||||
? t("sshAuth.mfaPromptRequired")
|
? t("common.password")
|
||||||
: t("sshAuth.totpRequired");
|
: isMenu
|
||||||
|
? t("sshAuth.mfaPromptRequired")
|
||||||
|
: t("sshAuth.totpRequired");
|
||||||
|
|
||||||
const label = prompt || (isTotp ? t("sshAuth.totpCodeLabel") : undefined);
|
const label = prompt || (isTotp ? t("sshAuth.totpCodeLabel") : undefined);
|
||||||
|
|
||||||
@@ -102,7 +104,17 @@ export function TOTPDialog({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<form onSubmit={handleSubmit} className="flex flex-col gap-3">
|
<form onSubmit={handleSubmit} className="flex flex-col gap-3">
|
||||||
{isPush ? null : isMenu ? (
|
{isPush ? null : isPassword ? (
|
||||||
|
<Input
|
||||||
|
id="totpCode"
|
||||||
|
name="totpCode"
|
||||||
|
type="password"
|
||||||
|
autoComplete="current-password"
|
||||||
|
autoFocus
|
||||||
|
placeholder={t("placeholders.enterPassword")}
|
||||||
|
className="rounded-none bg-muted/50 border-border text-sm"
|
||||||
|
/>
|
||||||
|
) : isMenu ? (
|
||||||
<Input
|
<Input
|
||||||
id="totpCode"
|
id="totpCode"
|
||||||
name="totpCode"
|
name="totpCode"
|
||||||
@@ -137,7 +149,11 @@ export function TOTPDialog({
|
|||||||
<div className="flex justify-end gap-2">
|
<div className="flex justify-end gap-2">
|
||||||
{cancel}
|
{cancel}
|
||||||
<button type="submit" className={PROMPT_PRIMARY_BUTTON}>
|
<button type="submit" className={PROMPT_PRIMARY_BUTTON}>
|
||||||
{isPush ? t("sshAuth.mfaSendRequest") : t("sshAuth.totpVerify")}
|
{isPush
|
||||||
|
? t("sshAuth.mfaSendRequest")
|
||||||
|
: isPassword
|
||||||
|
? t("common.connect")
|
||||||
|
: t("sshAuth.totpVerify")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import "@testing-library/jest-dom/vitest";
|
||||||
|
import React from "react";
|
||||||
|
import { fireEvent, render, screen } from "@testing-library/react";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
import { TOTPDialog } from "@/ssh/dialogs/TOTPDialog";
|
||||||
|
|
||||||
|
vi.mock("react-i18next", () => ({
|
||||||
|
useTranslation: () => ({ t: (key: string) => key }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("SSH password prompts", () => {
|
||||||
|
it("accepts a full password and preserves whitespace", () => {
|
||||||
|
const onSubmit = vi.fn();
|
||||||
|
const { container } = render(
|
||||||
|
<TOTPDialog
|
||||||
|
isOpen
|
||||||
|
prompt="Password:"
|
||||||
|
mode="password"
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
onCancel={vi.fn()}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
const input = container.querySelector("input")!;
|
||||||
|
expect(input.type).toBe("password");
|
||||||
|
expect(input).not.toHaveAttribute("maxLength");
|
||||||
|
expect(input).not.toHaveAttribute("pattern");
|
||||||
|
expect(input).not.toHaveAttribute("inputMode", "numeric");
|
||||||
|
fireEvent.change(input, { target: { value: " LongPassword!123 " } });
|
||||||
|
fireEvent.submit(container.querySelector("form")!);
|
||||||
|
expect(onSubmit).toHaveBeenCalledWith(" LongPassword!123 ");
|
||||||
|
expect(screen.queryByText("sshAuth.totpRequired")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still restricts verification codes to digits", () => {
|
||||||
|
const { container } = render(
|
||||||
|
<TOTPDialog
|
||||||
|
isOpen
|
||||||
|
prompt="Code:"
|
||||||
|
mode="totp"
|
||||||
|
onSubmit={vi.fn()}
|
||||||
|
onCancel={vi.fn()}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
expect(container.querySelector("input")).toHaveAttribute(
|
||||||
|
"pattern",
|
||||||
|
"[0-9]*",
|
||||||
|
);
|
||||||
|
expect(container.querySelector("input")).toHaveAttribute("maxLength", "8");
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user