[VPAT-53] chore: disable autocomplete on sensitive input fields #5389
This commit is contained in:
@@ -153,7 +153,7 @@ export function InstanceSignInForm() {
|
||||
placeholder="[email protected]"
|
||||
value={formData.email}
|
||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
@@ -172,7 +172,7 @@ export function InstanceSignInForm() {
|
||||
placeholder="Enter your password"
|
||||
value={formData.password}
|
||||
onChange={(e) => handleFormChange("password", e.target.value)}
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
/>
|
||||
{showPassword ? (
|
||||
<button
|
||||
|
||||
@@ -229,7 +229,7 @@ export function InstanceSetupForm() {
|
||||
value={formData.email}
|
||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||
hasError={errorData.type && errorData.type === EErrorCodes.INVALID_EMAIL ? true : false}
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
/>
|
||||
{errorData.type && errorData.type === EErrorCodes.INVALID_EMAIL && errorData.message && (
|
||||
<p className="px-1 text-11 text-danger-primary">{errorData.message}</p>
|
||||
@@ -275,7 +275,7 @@ export function InstanceSetupForm() {
|
||||
hasError={errorData.type && errorData.type === EErrorCodes.INVALID_PASSWORD ? true : false}
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="on"
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{showPassword.password ? (
|
||||
<button
|
||||
@@ -319,6 +319,7 @@ export function InstanceSetupForm() {
|
||||
className="w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{showPassword.retypePassword ? (
|
||||
<button
|
||||
|
||||
@@ -82,7 +82,7 @@ export const AuthEmailForm = observer(function AuthEmailForm(props: TAuthEmailFo
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="[email protected]"
|
||||
className={`disable-autofill-style h-10 w-full placeholder:text-placeholder autofill:bg-danger-subtle border-0 focus:bg-none active:bg-transparent`}
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
ref={inputRef}
|
||||
/>
|
||||
|
||||
@@ -166,7 +166,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||
className="disable-autofill-style h-10 w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
{showPassword?.password ? (
|
||||
@@ -199,6 +199,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||
className="disable-autofill-style h-10 w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="off"
|
||||
/>
|
||||
{showPassword?.retypePassword ? (
|
||||
<EyeOff
|
||||
|
||||
@@ -105,6 +105,7 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||
placeholder="[email protected]"
|
||||
className={`disable-autofill-style h-10 w-full placeholder:text-placeholder border-0`}
|
||||
autoComplete="off"
|
||||
disabled
|
||||
/>
|
||||
{uniqueCodeFormData.email.length > 0 && (
|
||||
@@ -126,6 +127,7 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||
onChange={(e) => handleFormChange("code", e.target.value)}
|
||||
placeholder="123456"
|
||||
className="disable-autofill-style h-10 w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
<div className="flex w-full items-center justify-between px-1 text-11 pt-1">
|
||||
|
||||
@@ -157,6 +157,7 @@ function SecurityPage() {
|
||||
placeholder={t("old_password")}
|
||||
className="w-full"
|
||||
hasError={Boolean(errors.old_password)}
|
||||
autoComplete="current-password"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -197,6 +198,7 @@ function SecurityPage() {
|
||||
hasError={Boolean(errors.new_password)}
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -239,6 +241,7 @@ function SecurityPage() {
|
||||
hasError={Boolean(errors.confirm_password)}
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -155,6 +155,7 @@ function SecurityPage() {
|
||||
placeholder={t("old_password")}
|
||||
className="w-full"
|
||||
hasError={Boolean(errors.old_password)}
|
||||
autoComplete="current-password"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -195,6 +196,7 @@ function SecurityPage() {
|
||||
hasError={Boolean(errors.new_password)}
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -237,6 +239,7 @@ function SecurityPage() {
|
||||
hasError={Boolean(errors.confirm_password)}
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -81,7 +81,7 @@ export const AuthEmailForm = observer(function AuthEmailForm(props: TAuthEmailFo
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className={`disable-autofill-style h-10 w-full placeholder:text-placeholder autofill:bg-danger-primary border-0 focus:bg-none active:bg-transparent`}
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
ref={inputRef}
|
||||
/>
|
||||
|
||||
@@ -114,7 +114,7 @@ export const ForgotPasswordForm = observer(function ForgotPasswordForm() {
|
||||
hasError={Boolean(errors.email)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
disabled={resendTimerCode > 0}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -220,7 +220,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||
className="disable-autofill-style h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
<button
|
||||
@@ -257,6 +257,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||
className="disable-autofill-style h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="off"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -129,7 +129,7 @@ export const ResetPasswordForm = observer(function ResetPasswordForm() {
|
||||
minLength={8}
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="on"
|
||||
autoComplete="new-password"
|
||||
autoFocus
|
||||
/>
|
||||
{showPassword.password ? (
|
||||
@@ -160,6 +160,7 @@ export const ResetPasswordForm = observer(function ResetPasswordForm() {
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{showPassword.retypePassword ? (
|
||||
<EyeOff
|
||||
|
||||
@@ -133,7 +133,7 @@ export const SetPasswordForm = observer(function SetPasswordForm() {
|
||||
//hasError={Boolean(errors.email)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 text-placeholder cursor-not-allowed"
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
@@ -154,7 +154,7 @@ export const SetPasswordForm = observer(function SetPasswordForm() {
|
||||
minLength={8}
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="on"
|
||||
autoComplete="new-password"
|
||||
autoFocus
|
||||
/>
|
||||
{showPassword.password ? (
|
||||
@@ -185,6 +185,7 @@ export const SetPasswordForm = observer(function SetPasswordForm() {
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{showPassword.retypePassword ? (
|
||||
<EyeOff
|
||||
|
||||
@@ -114,7 +114,7 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className="disable-autofill-style h-10 w-full placeholder:text-placeholder border-0"
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
disabled
|
||||
/>
|
||||
{uniqueCodeFormData.email.length > 0 && (
|
||||
@@ -141,6 +141,7 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||
onChange={(e) => handleFormChange("code", e.target.value)}
|
||||
placeholder={t("auth.common.unique_code.placeholder")}
|
||||
className="disable-autofill-style h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
<div className="flex w-full items-center justify-between px-1 text-11 pt-1">
|
||||
|
||||
@@ -171,6 +171,7 @@ export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props)
|
||||
{ "border-danger-strong": errors.email },
|
||||
{ "cursor-not-allowed !bg-surface-2": secondStep }
|
||||
)}
|
||||
autoComplete="off"
|
||||
disabled={secondStep}
|
||||
/>
|
||||
)}
|
||||
@@ -194,6 +195,7 @@ export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props)
|
||||
ref={ref}
|
||||
placeholder={changeEmailT("form.code.placeholder")}
|
||||
className={cn({ "border-danger-strong": errors.code })}
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -399,7 +399,7 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||
className="w-full border-[0.5px] border-subtle pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="on"
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{showPassword.password ? (
|
||||
<EyeOff
|
||||
@@ -440,6 +440,7 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||
hasError={Boolean(errors.confirm_password)}
|
||||
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
||||
className="w-full border-subtle pr-12 placeholder:text-placeholder"
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{showPassword.retypePassword ? (
|
||||
<EyeOff
|
||||
|
||||
@@ -2,10 +2,7 @@ import React, { useState } from "react";
|
||||
import { cn } from "@plane/utils";
|
||||
import { AuthInput } from "./auth-input";
|
||||
|
||||
export interface AuthConfirmPasswordInputProps extends Omit<
|
||||
React.InputHTMLAttributes<HTMLInputElement>,
|
||||
"autoComplete"
|
||||
> {
|
||||
export type TAuthConfirmPasswordInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
|
||||
password: string;
|
||||
label?: string;
|
||||
error?: string;
|
||||
@@ -13,9 +10,8 @@ export interface AuthConfirmPasswordInputProps extends Omit<
|
||||
containerClassName?: string;
|
||||
labelClassName?: string;
|
||||
errorClassName?: string;
|
||||
autoComplete?: "on" | "off";
|
||||
onPasswordMatchChange?: (matches: boolean) => void;
|
||||
}
|
||||
};
|
||||
|
||||
export function AuthConfirmPasswordInput({
|
||||
password,
|
||||
@@ -29,7 +25,7 @@ export function AuthConfirmPasswordInput({
|
||||
onChange,
|
||||
onPasswordMatchChange,
|
||||
...props
|
||||
}: AuthConfirmPasswordInputProps) {
|
||||
}: TAuthConfirmPasswordInputProps) {
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
const confirmPassword = value as string;
|
||||
@@ -71,7 +67,7 @@ export function AuthConfirmPasswordInput({
|
||||
onChange={handleChange}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
/>
|
||||
{confirmPassword && passwordsMatch && <p className="text-13 text-success-primary">Passwords match</p>}
|
||||
</div>
|
||||
|
||||
@@ -3,13 +3,12 @@ import React, { useState } from "react";
|
||||
import { Input } from "../form-fields/input";
|
||||
import { cn } from "../utils";
|
||||
|
||||
export interface AuthInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "autoComplete"> {
|
||||
export type TAuthInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
|
||||
label?: string;
|
||||
error?: string;
|
||||
showPasswordToggle?: boolean;
|
||||
errorClassName?: string;
|
||||
autoComplete?: "on" | "off";
|
||||
}
|
||||
};
|
||||
|
||||
const baseContainerClassName = "flex flex-col gap-1.5";
|
||||
|
||||
@@ -20,8 +19,9 @@ export function AuthInput({
|
||||
errorClassName = "",
|
||||
className = "",
|
||||
type = "text",
|
||||
autoComplete = "off",
|
||||
...props
|
||||
}: AuthInputProps) {
|
||||
}: TAuthInputProps) {
|
||||
const { id } = props;
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const isPasswordType = type === "password";
|
||||
@@ -39,6 +39,7 @@ export function AuthInput({
|
||||
<Input
|
||||
{...props}
|
||||
type={inputType}
|
||||
autoComplete={autoComplete}
|
||||
className={cn(
|
||||
"rounded-md disable-autofill-style h-6 w-full placeholder:text-14 placeholder:text-placeholder p-0 border-none",
|
||||
{
|
||||
|
||||
@@ -4,17 +4,16 @@ import { cn, getPasswordStrength } from "@plane/utils";
|
||||
import { PasswordStrengthIndicator } from "../form-fields/password/indicator";
|
||||
import { AuthInput } from "./auth-input";
|
||||
|
||||
export interface AuthPasswordInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "autoComplete"> {
|
||||
export type TAuthPasswordInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
|
||||
label?: string;
|
||||
error?: string;
|
||||
showPasswordStrength?: boolean;
|
||||
showPasswordToggle?: boolean;
|
||||
containerClassName?: string;
|
||||
errorClassName?: string;
|
||||
autoComplete?: "on" | "off";
|
||||
onPasswordChange?: (password: string) => void;
|
||||
onPasswordStrengthChange?: (strength: E_PASSWORD_STRENGTH) => void;
|
||||
}
|
||||
};
|
||||
|
||||
export function AuthPasswordInput({
|
||||
label = "Password",
|
||||
@@ -29,7 +28,7 @@ export function AuthPasswordInput({
|
||||
onPasswordChange,
|
||||
onPasswordStrengthChange,
|
||||
...props
|
||||
}: AuthPasswordInputProps) {
|
||||
}: TAuthPasswordInputProps) {
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -67,7 +66,7 @@ export function AuthPasswordInput({
|
||||
onChange={handleChange}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
autoComplete="on"
|
||||
autoComplete="off"
|
||||
/>
|
||||
{showPasswordStrength && value && isFocused && (
|
||||
<PasswordStrengthIndicator password={value as string} showCriteria />
|
||||
|
||||
@@ -18,7 +18,7 @@ export { AuthConfirmPasswordInput } from "./auth-confirm-password-input";
|
||||
export { AuthForgotPassword } from "./auth-forgot-password";
|
||||
|
||||
export type { AuthFormProps, AuthFormData, AuthMode } from "./auth-form";
|
||||
export type { AuthInputProps } from "./auth-input";
|
||||
export type { AuthPasswordInputProps } from "./auth-password-input";
|
||||
export type { AuthConfirmPasswordInputProps } from "./auth-confirm-password-input";
|
||||
export type { TAuthInputProps } from "./auth-input";
|
||||
export type { TAuthPasswordInputProps } from "./auth-password-input";
|
||||
export type { TAuthConfirmPasswordInputProps } from "./auth-confirm-password-input";
|
||||
export type { AuthForgotPasswordProps } from "./auth-forgot-password";
|
||||
|
||||
@@ -7,7 +7,6 @@ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement>
|
||||
inputSize?: "xs" | "sm" | "md";
|
||||
hasError?: boolean;
|
||||
className?: string;
|
||||
autoComplete?: "on" | "off";
|
||||
}
|
||||
|
||||
const Input = React.forwardRef(function Input(props: InputProps, ref: React.ForwardedRef<HTMLInputElement>) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Eye, EyeClosed } from "lucide-react";
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { Tooltip } from "@plane/propel/tooltip";
|
||||
import { cn } from "@plane/utils";
|
||||
|
||||
interface PasswordInputProps {
|
||||
type TPasswordInputProps = {
|
||||
id: string;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
@@ -11,7 +11,8 @@ interface PasswordInputProps {
|
||||
className?: string;
|
||||
showToggle?: boolean;
|
||||
error?: boolean;
|
||||
}
|
||||
autoComplete?: React.HTMLInputAutoCompleteAttribute;
|
||||
};
|
||||
|
||||
export function PasswordInput({
|
||||
id,
|
||||
@@ -21,7 +22,8 @@ export function PasswordInput({
|
||||
className,
|
||||
showToggle = true,
|
||||
error = false,
|
||||
}: PasswordInputProps) {
|
||||
autoComplete = "off",
|
||||
}: TPasswordInputProps) {
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
return (
|
||||
<div className="relative">
|
||||
@@ -39,6 +41,7 @@ export function PasswordInput({
|
||||
className
|
||||
)}
|
||||
placeholder={placeholder}
|
||||
autoComplete={autoComplete}
|
||||
/>
|
||||
{showToggle && (
|
||||
<Tooltip tooltipContent={showPassword ? "Hide password" : "Show password"} position="top">
|
||||
|
||||
@@ -8,7 +8,6 @@ export interface PillInputProps extends Omit<React.InputHTMLAttributes<HTMLInput
|
||||
inputSize?: "xs" | "sm" | "md";
|
||||
hasError?: boolean;
|
||||
className?: string;
|
||||
autoComplete?: "on" | "off";
|
||||
value: string[];
|
||||
onChange: (value: string[]) => void;
|
||||
pillClassName?: string;
|
||||
|
||||
Reference in New Issue
Block a user