-
Notifications
You must be signed in to change notification settings - Fork 3.5k
[VPAT-55] chore(security): implement input validation across authentication and workspace forms #8528
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
[VPAT-55] chore(security): implement input validation across authentication and workspace forms #8528
Changes from all commits
863579b
9f4ce04
588779e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,7 @@ import { TOAST_TYPE, setToast } from "@plane/propel/toast"; | |
| import type { IUser, IWorkspace, TOnboardingSteps } from "@plane/types"; | ||
| // ui | ||
| import { CustomSelect, Input, Spinner } from "@plane/ui"; | ||
| import { validateWorkspaceName, validateSlug } from "@plane/utils"; | ||
| // hooks | ||
| import { useWorkspace } from "@/hooks/store/use-workspace"; | ||
| import { useUserProfile, useUserSettings } from "@/hooks/store/user"; | ||
|
|
@@ -138,8 +139,7 @@ export const CreateWorkspace = observer(function CreateWorkspace(props: Props) { | |
| name="name" | ||
| rules={{ | ||
| required: t("common.errors.required"), | ||
| validate: (value) => | ||
| /^[\w\s-]*$/.test(value) || t("workspace_creation.errors.validation.name_alphanumeric"), | ||
| validate: (value) => validateWorkspaceName(value, true), | ||
| maxLength: { | ||
| value: 80, | ||
| message: t("workspace_creation.errors.validation.name_length"), | ||
|
|
@@ -200,7 +200,8 @@ export const CreateWorkspace = observer(function CreateWorkspace(props: Props) { | |
| type="text" | ||
| value={value.toLocaleLowerCase().trim().replace(/ /g, "-")} | ||
| onChange={(e) => { | ||
| if (/^[a-zA-Z0-9_-]+$/.test(e.target.value)) setInvalidSlug(false); | ||
| const validation = validateSlug(e.target.value); | ||
| if (validation === true) setInvalidSlug(false); | ||
| else setInvalidSlug(true); | ||
| onChange(e.target.value.toLowerCase()); | ||
|
Comment on lines
202
to
206
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same slug validation issue as in The slug validation runs on the raw input ( onChange={(e) => {
- const validation = validateSlug(e.target.value);
+ const transformedSlug = e.target.value.toLowerCase().trim().replace(/ /g, "-");
+ const validation = validateSlug(transformedSlug);
if (validation === true) setInvalidSlug(false);
else setInvalidSlug(true);
onChange(e.target.value.toLowerCase());
}}🤖 Prompt for AI Agents |
||
| }} | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -15,7 +15,7 @@ import { Button } from "@plane/propel/button"; | |||||||||||||||||||||||||||
| import { TOAST_TYPE, setToast } from "@plane/propel/toast"; | ||||||||||||||||||||||||||||
| import type { IUser, IWorkspace } from "@plane/types"; | ||||||||||||||||||||||||||||
| import { Spinner } from "@plane/ui"; | ||||||||||||||||||||||||||||
| import { cn } from "@plane/utils"; | ||||||||||||||||||||||||||||
| import { cn, validateWorkspaceName, validateSlug } from "@plane/utils"; | ||||||||||||||||||||||||||||
| // hooks | ||||||||||||||||||||||||||||
| import { useInstance } from "@/hooks/store/use-instance"; | ||||||||||||||||||||||||||||
| import { useWorkspace } from "@/hooks/store/use-workspace"; | ||||||||||||||||||||||||||||
|
|
@@ -146,8 +146,7 @@ export const WorkspaceCreateStep = observer(function WorkspaceCreateStep({ | |||||||||||||||||||||||||||
| name="name" | ||||||||||||||||||||||||||||
| rules={{ | ||||||||||||||||||||||||||||
| required: t("common.errors.required"), | ||||||||||||||||||||||||||||
| validate: (value) => | ||||||||||||||||||||||||||||
| /^[\w\s-]*$/.test(value) || t("workspace_creation.errors.validation.name_alphanumeric"), | ||||||||||||||||||||||||||||
| validate: (value) => validateWorkspaceName(value, true), | ||||||||||||||||||||||||||||
| maxLength: { | ||||||||||||||||||||||||||||
| value: 80, | ||||||||||||||||||||||||||||
| message: t("workspace_creation.errors.validation.name_length"), | ||||||||||||||||||||||||||||
|
|
@@ -220,7 +219,8 @@ export const WorkspaceCreateStep = observer(function WorkspaceCreateStep({ | |||||||||||||||||||||||||||
| type="text" | ||||||||||||||||||||||||||||
| value={value.toLocaleLowerCase().trim().replace(/ /g, "-")} | ||||||||||||||||||||||||||||
| onChange={(e) => { | ||||||||||||||||||||||||||||
| if (/^[a-zA-Z0-9_-]+$/.test(e.target.value)) setInvalidSlug(false); | ||||||||||||||||||||||||||||
| const validation = validateSlug(e.target.value); | ||||||||||||||||||||||||||||
| if (validation === true) setInvalidSlug(false); | ||||||||||||||||||||||||||||
| else setInvalidSlug(true); | ||||||||||||||||||||||||||||
| onChange(e.target.value.toLowerCase()); | ||||||||||||||||||||||||||||
|
Comment on lines
221
to
225
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Slug validation runs on raw input before transformation. The displayed slug value applies transformations (lowercase, trim, replace spaces with hyphens on Line 213), but Consider validating the transformed value instead: onChange={(e) => {
- const validation = validateSlug(e.target.value);
+ const transformedSlug = e.target.value.toLowerCase().trim().replace(/ /g, "-");
+ const validation = validateSlug(transformedSlug);
if (validation === true) setInvalidSlug(false);
else setInvalidSlug(true);
onChange(e.target.value.toLowerCase());
}}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Company name
requiredparameter inconsistent with UI.The UI marks company name as required (Line 228 shows the asterisk), but
validateCompanyNameis called withrequired: false. If the field is truly required, passtrueto enforce validation:🤖 Prompt for AI Agents