Skip to content

Conversation

@sangeethailango
Copy link
Member

@sangeethailango sangeethailango commented Oct 13, 2025

Description

This PR will throw a validation error if the following special characters are given for the user's first name and last name

&+,:;$^}{*=?@#|'<>.()%!

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Summary by CodeRabbit

  • Bug Fixes
    • Strengthened validation for first and last names to reject URLs and disallowed special characters.
    • Added clearer, targeted error messages for invalid name characters shown inline on profile and onboarding forms.
    • Standardized name input rules across sign-up, onboarding, and profile edit flows to ensure consistent, valid profile data.

@makeplane
Copy link

makeplane bot commented Oct 13, 2025

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 13, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Added a module-level forbidden-character regex and checks to apps/api/plane/app/serializers/user.py. Added client-side regex pattern validation for first_name in apps/web/core/components/onboarding/steps/profile/root.tsx. Added client-side regex pattern validation for both first_name and last_name and visible last-name error feedback in apps/web/core/components/profile/form.tsx.

Changes

Cohort / File(s) Summary
Backend: serializer constant & validations
apps/api/plane/app/serializers/user.py
Added import re and public constant FORBIDDEN_NAME_CHARS_PATTERN. Extended UserSerializer.validate_first_name and validate_last_name to reject values matching the forbidden-character regex while retaining the existing URL containment checks and ValidationError responses.
Web: onboarding first-name pattern
apps/web/core/components/onboarding/steps/profile/root.tsx
Added regex pattern validation to first_name field (letters, spaces, hyphens, underscores) plus error message; left required and maxLength rules unchanged.
Web: profile form name patterns & UI feedback
apps/web/core/components/profile/form.tsx
Added client-side regex patterns for first_name and last_name ( /^[a-zA-Z\s-_]*$/ ) with error messages. Rendered visible error feedback for last_name when validation fails.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Client (submit / front-end)
  participant F as Front-end Validation
  participant S as Backend Serializer
  participant R as Regex (FORBIDDEN_NAME_CHARS_PATTERN)

  C->>F: input first_name / last_name
  F->>F: test against /^[a-zA-Z\s\-_]*$/
  alt front-end pattern fails
    F-->>C: show validation error (allowed characters)
  else passes
    F->>S: send payload
    S->>R: re.search(FORBIDDEN_NAME_CHARS_PATTERN, value)
    alt forbidden chars found
      R-->>S: match
      S-->>C: raise ValidationError("special characters not allowed")
    else no forbidden chars
      alt contains URL
        S-->>C: raise ValidationError("URLs are not allowed")
      else valid
        S-->>C: accept / return value
      end
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I twitch my whiskers, regex bright,
Banned symbols hidden from the light.
First and last both checked with care,
Front and back agree — no odd chars there.
A happy rabbit hops away. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description includes the Description and Type of Change sections but omits the required Test Scenarios and References headings from the repository template, which are needed to document how the changes were verified and to link related issues. Please add a Test Scenarios section detailing the tests performed to verify the validation logic and a References section linking the related issue or ticket.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and concisely summarizes the main change by indicating that special characters are now disallowed in user first and last names, and includes the relevant ticket number according to project conventions.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-special-characters-in-username

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sangeethailango sangeethailango changed the title [WEB-4434] fix: allowing special characters in username [WEB-4434] chore: disallowing special characters in username Oct 13, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/api/plane/app/serializers/user.py (1)

10-11: Improve import organization.

The re module is part of Python's standard library, not a Django import. Standard library imports should be placed at the top of the file, before third-party imports, according to PEP 8.

Apply this diff to reorganize the imports:

+# Python imports
+import re
+
 # Third party imports
 from rest_framework import serializers
 
 # Module import
 from plane.db.models import Account, Profile, User, Workspace, WorkspaceMemberInvite
 from plane.utils.url import contains_url
 
 from .base import BaseSerializer
-
-# Django imports
-import re
-
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3eecec5 and 24b9fbb.

📒 Files selected for processing (1)
  • apps/api/plane/app/serializers/user.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/api/plane/app/serializers/user.py (1)
apps/api/plane/utils/url.py (1)
  • contains_url (22-49)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Lint API
  • GitHub Check: Analyze (javascript)

@dheeru0198 dheeru0198 requested a review from Copilot October 13, 2025 09:51
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds validation to prevent special characters in user first names by implementing a regular expression check in the UserSerializer validation method.

  • Adds regex validation to reject first names containing special characters like &, +, :, ;, =, ?, @, #, |, ', <, >, ., (, ), %, !, -
  • Imports the re module to support regular expression operations
  • Maintains existing URL validation while adding the new character restriction

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/api/plane/app/serializers/user.py (1)

17-17: Simplify regex pattern for efficiency.

The pattern ^.*[...].*$ uses redundant anchors and wildcards. Since re.match() already matches from the start, the ^ is unnecessary. The pattern can be simplified.

Apply this diff:

-FORBIDDEN_NAME_CHARS_PATTERN = r"^.*[&+,:;$=?@#|'<>.()%!-].*$"
+FORBIDDEN_NAME_CHARS_PATTERN = r"[&+,:;$=?@#|'<>.()%!-]"

Then update the validation methods to use re.search() instead of re.match():

-        if re.match(FORBIDDEN_NAME_CHARS_PATTERN, value):
+        if re.search(FORBIDDEN_NAME_CHARS_PATTERN, value):

This achieves the same result with better performance.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 24b9fbb and 5b44aae.

📒 Files selected for processing (1)
  • apps/api/plane/app/serializers/user.py (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/api/plane/app/serializers/user.py (1)
apps/api/plane/utils/url.py (1)
  • contains_url (22-49)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/api/plane/app/serializers/user.py (1)

1-2: LGTM!

The re module import is now correctly placed with other Python standard library imports.

@sangeethailango sangeethailango changed the title [WEB-4434] chore: disallowing special characters in username [WEB-4434] chore: disallowing special characters in user first name and last name Oct 13, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/api/plane/app/serializers/user.py (2)

2-2: Move import to match the existing comment structure.

The re import is a standard Python library, not a Django import. It should be placed in the Python imports section (above line 4) instead of appearing after the "# Django imports" comment.

Apply this diff to correct the import placement:

 # Python imports
 import re
-
-
+
 # Third party imports

17-17: Simplify regex pattern for better readability.

The pattern ^.*[...].*$ is unnecessarily complex. The anchors ^.* and .*$ are redundant when using re.match(), which already matches from the start. The simpler pattern [...] achieves the same result and is more efficient.

Apply this diff (after adding the hyphen):

-FORBIDDEN_NAME_CHARS_PATTERN = r"^.*[&+,:;$^}{*=?@#|'<>.()%!\-].*$"
+FORBIDDEN_NAME_CHARS_PATTERN = r"[&+,:;$^}{*=?@#|'<>.()%!\-]"

Then update the validation to use re.search() instead of re.match():

-        if re.match(FORBIDDEN_NAME_CHARS_PATTERN, value):
+        if re.search(FORBIDDEN_NAME_CHARS_PATTERN, value):

This change makes the pattern clearer and more efficient while maintaining the same functionality.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1123f54 and 5439f47.

📒 Files selected for processing (1)
  • apps/api/plane/app/serializers/user.py (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/api/plane/app/serializers/user.py (2)
apps/api/plane/api/serializers/base.py (1)
  • BaseSerializer (5-114)
apps/api/plane/utils/url.py (1)
  • contains_url (22-49)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
apps/api/plane/app/serializers/user.py (3)

25-26: Good addition! Validation logic is correct.

The validation correctly checks for forbidden characters and provides a clear error message. The punctuation and capitalization are consistent with the URL validation error message.


34-35: Good addition! Consistent validation applied to last name.

The last name validation now mirrors the first name validation, ensuring consistency across both fields. The error message formatting is appropriate.


14-17: Include hyphen in forbidden-name regex and review apostrophe rule

Update the comment and pattern to block -:

-# & + , : ; $ ^ } { * = ? @ # | ' < > . ( ) % !
+# & + , : ; $ ^ } { * = ? @ # | ' < > . ( ) % ! -
 
-FORBIDDEN_NAME_CHARS_PATTERN = r"^.*[&+,:;$^}{*=?@#|'<>.()%!].*$"
+FORBIDDEN_NAME_CHARS_PATTERN = r"^.*[&+,:;$^}{*=?@#|'<>.()%!\-].*$"

If you intend to allow apostrophes (e.g. O’Brien), remove ' from the character class and manually verify no existing users rely on it.

dheeru0198
dheeru0198 previously approved these changes Oct 13, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/web/core/components/profile/form.tsx (1)

312-322: Consider applying consistent character validation to display_name.

The display_name field (lines 312-322) has length and whitespace validation but no character restrictions, while first_name and last_name now block special characters. If the goal is to prevent special characters in user-visible names, display_name should have similar validation.

If consistency is desired, add pattern validation to display_name:

                  rules={{
                    required: "Display name is required.",
+                    pattern: {
+                      value: /^[\p{L}\p{M} \-_]*$/u,
+                      message: "Display name can only contain letters, spaces, hyphens, and underscores",
+                    },
                    validate: (value) => {
                      if (value.trim().length < 1) return "Display name can't be empty.";
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5439f47 and 347cfad.

📒 Files selected for processing (2)
  • apps/web/core/components/onboarding/steps/profile/root.tsx (1 hunks)
  • apps/web/core/components/profile/form.tsx (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/web/core/components/profile/form.tsx (1)

302-302: Good addition of error feedback for last_name validation.

The error message display for last_name brings it into parity with first_name (line 273), ensuring consistent user experience when validation fails.

apps/web/core/components/onboarding/steps/profile/root.tsx (1)

217-220: Confirm alignment of client-side regex with server validation
Couldn’t locate FORBIDDEN_NAME_CHARS_PATTERN on the server—verify that the server’s name validation matches the client regex ^[a-zA-Z\s\-_]*$.

Comment on lines +217 to +220
pattern: {
value: /^[a-zA-Z\s\-_]*$/,
message: "Name can only contain letters, spaces, hyphens, and underscores",
},
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Regex pattern may be overly restrictive for international names and allows unwanted whitespace.

The pattern /^[a-zA-Z\s\-_]*$/ successfully blocks the listed special characters but has two concerns:

  1. International names: The whitelist approach blocks accented characters (é, ñ, ü), non-Latin scripts (Cyrillic, Arabic, Chinese), and apostrophes commonly found in names like "O'Brien" or "D'Angelo". This could create friction for international users.

  2. Whitespace matching: Using \s matches all whitespace characters including tabs (\t) and newlines (\n), not just regular spaces. Names like "John\t\tDoe" would be accepted.

Consider these improvements:

For international support, use Unicode letter categories:

-              pattern: {
-                value: /^[a-zA-Z\s\-_]*$/,
-                message: "Name can only contain letters, spaces, hyphens, and underscores",
-              },
+              pattern: {
+                value: /^[\p{L}\p{M} \-_]*$/u,
+                message: "Name can only contain letters, spaces, hyphens, and underscores",
+              },

For precise whitespace, replace \s with literal space:

-              pattern: {
-                value: /^[a-zA-Z\s\-_]*$/,
-                message: "Name can only contain letters, spaces, hyphens, and underscores",
-              },
+              pattern: {
+                value: /^[a-zA-Z \-_]*$/,
+                message: "Name can only contain letters, spaces, hyphens, and underscores",
+              },

Or combine both for international support with controlled whitespace:

-              pattern: {
-                value: /^[a-zA-Z\s\-_]*$/,
-                message: "Name can only contain letters, spaces, hyphens, and underscores",
-              },
+              pattern: {
+                value: /^[\p{L}\p{M} \-_]*$/u,
+                message: "Name can only contain letters, spaces, hyphens, and underscores",
+              },

Note: \p{L} matches Unicode letters, \p{M} matches combining marks (accents), and the u flag enables Unicode support.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pattern: {
value: /^[a-zA-Z\s\-_]*$/,
message: "Name can only contain letters, spaces, hyphens, and underscores",
},
pattern: {
value: /^[\p{L}\p{M} \-_]*$/u,
message: "Name can only contain letters, spaces, hyphens, and underscores",
},
🤖 Prompt for AI Agents
In apps/web/core/components/onboarding/steps/profile/root.tsx around lines 217
to 220, the current regex /^[a-zA-Z\s\-_]*$/ is too restrictive for
international names and allows tabs/newlines via \s; replace it with a
Unicode-aware pattern that permits Unicode letters and combining marks, explicit
spaces only, and common name punctuation (apostrophe, hyphen, underscore) and
ensure the regex uses the Unicode flag: use an anchored pattern like
^[\p{L}\p{M}\'\-\_ ]*$ with the u flag (or equivalent RegExp construction), and
update any validation messages accordingly so names with accented/non-Latin
letters and normal spaces are accepted while tabs/newlines remain rejected.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like these changes are valid make these changes. @sangeethailango

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +252 to +255
pattern: {
value: /^[a-zA-Z\s\-_]*$/,
message: "First name can only contain letters, spaces, hyphens, and underscores",
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Same pattern concerns: international names and whitespace handling.

Both first_name and last_name use the same regex /^[a-zA-Z\s\-_]*$/ which has the following concerns:

  1. International names: Blocks accented characters (é, ñ, ü), non-Latin scripts, and apostrophes in names like "O'Brien". This affects international users.

  2. Whitespace: Using \s allows tabs and newlines, not just spaces.

Apply the same improvements suggested for the onboarding component:

                  rules={{
                    required: "Please enter first name",
-                    pattern: {
-                      value: /^[a-zA-Z\s\-_]*$/,
-                      message: "First name can only contain letters, spaces, hyphens, and underscores",
-                    },
+                    pattern: {
+                      value: /^[\p{L}\p{M} \-_]*$/u,
+                      message: "First name can only contain letters, spaces, hyphens, and underscores",
+                    },
                  }}
                  rules={{
-                    pattern: {
-                      value: /^[a-zA-Z\s\-_]*$/,
-                      message: "Last name can only contain letters, spaces, hyphens, and underscores",
-                    },
+                    pattern: {
+                      value: /^[\p{L}\p{M} \-_]*$/u,
+                      message: "Last name can only contain letters, spaces, hyphens, and underscores",
+                    },
                  }}

Also applies to: 280-285

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants