From 4a97d7c28c26b6bddc0ea2450d48d4ee3185008a Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Thu, 29 May 2025 17:53:48 +0530 Subject: [PATCH] fix: adding url validations for workspace name and user name --- apiserver/plane/app/serializers/user.py | 11 +++++++++++ apiserver/plane/app/serializers/workspace.py | 13 +++++++++++++ apiserver/plane/app/views/workspace/base.py | 7 +++++++ apiserver/plane/utils/url.py | 8 ++++++++ 4 files changed, 39 insertions(+) diff --git a/apiserver/plane/app/serializers/user.py b/apiserver/plane/app/serializers/user.py index ebc002c9c..c0e106178 100644 --- a/apiserver/plane/app/serializers/user.py +++ b/apiserver/plane/app/serializers/user.py @@ -3,11 +3,22 @@ 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 class UserSerializer(BaseSerializer): + def validate_first_name(self, value): + if contains_url(value): + raise serializers.ValidationError("First name cannot contain a URL.") + return value + + def validate_last_name(self, value): + if contains_url(value): + raise serializers.ValidationError("Last name cannot contain a URL.") + return value + class Meta: model = User # Exclude password field from the serializer diff --git a/apiserver/plane/app/serializers/workspace.py b/apiserver/plane/app/serializers/workspace.py index 9fba7256e..7a9289266 100644 --- a/apiserver/plane/app/serializers/workspace.py +++ b/apiserver/plane/app/serializers/workspace.py @@ -25,10 +25,12 @@ from plane.db.models import ( WorkspaceUserPreference, ) from plane.utils.constants import RESTRICTED_WORKSPACE_SLUGS +from plane.utils.url import contains_url # Django imports from django.core.validators import URLValidator from django.core.exceptions import ValidationError +import re class WorkSpaceSerializer(DynamicBaseSerializer): @@ -36,10 +38,21 @@ class WorkSpaceSerializer(DynamicBaseSerializer): logo_url = serializers.CharField(read_only=True) role = serializers.IntegerField(read_only=True) + def validate_name(self, value): + # Check if the name contains a URL + if contains_url(value): + raise serializers.ValidationError("Name must not contain URLs") + return value + def validate_slug(self, value): # Check if the slug is restricted if value in RESTRICTED_WORKSPACE_SLUGS: raise serializers.ValidationError("Slug is not valid") + # Slug should only contain alphanumeric characters, hyphens, and underscores + if not re.match(r"^[a-zA-Z0-9_-]+$", value): + raise serializers.ValidationError( + "Slug can only contain letters, numbers, hyphens (-), and underscores (_)" + ) return value class Meta: diff --git a/apiserver/plane/app/views/workspace/base.py b/apiserver/plane/app/views/workspace/base.py index e92e61e51..8ca29526d 100644 --- a/apiserver/plane/app/views/workspace/base.py +++ b/apiserver/plane/app/views/workspace/base.py @@ -43,6 +43,7 @@ from django.views.decorators.vary import vary_on_cookie from plane.utils.constants import RESTRICTED_WORKSPACE_SLUGS from plane.license.utils.instance_value import get_configuration_value from plane.bgtasks.workspace_seed_task import workspace_seed +from plane.utils.url import contains_url class WorkSpaceViewSet(BaseViewSet): @@ -109,6 +110,12 @@ class WorkSpaceViewSet(BaseViewSet): status=status.HTTP_400_BAD_REQUEST, ) + if contains_url(name): + return Response( + {"error": "Name cannot contain a URL"}, + status=status.HTTP_400_BAD_REQUEST, + ) + if serializer.is_valid(raise_exception=True): serializer.save(owner=request.user) # Create Workspace member diff --git a/apiserver/plane/utils/url.py b/apiserver/plane/utils/url.py index e485f93df..1b4a229a8 100644 --- a/apiserver/plane/utils/url.py +++ b/apiserver/plane/utils/url.py @@ -4,6 +4,14 @@ from typing import Optional from urllib.parse import urlparse, urlunparse +def contains_url(value: str) -> bool: + """ + Check if the value contains a URL. + """ + url_pattern = re.compile(r"https?://|www\\.") + return bool(url_pattern.search(value)) + + def is_valid_url(url: str) -> bool: """ Validates whether the given string is a well-formed URL.