Compare commits

...

1 Commits

Author SHA1 Message Date
Dheeraj Kumar Ketireddy 46d1d9f823 added PageBinaryUpdateSerializer for binary data validation and update 2025-07-29 11:26:02 +05:30
3 changed files with 105 additions and 16 deletions
+51
View File
@@ -1,8 +1,10 @@
# Third party imports
from rest_framework import serializers
import base64
# Module imports
from .base import BaseSerializer
from plane.utils.binary_validator import validate_binary_data
from plane.db.models import (
Page,
PageLog,
@@ -186,3 +188,52 @@ class PageVersionDetailSerializer(BaseSerializer):
"updated_by",
]
read_only_fields = ["workspace", "page"]
class PageBinaryUpdateSerializer(serializers.Serializer):
"""Serializer for updating page binary description with validation"""
description_binary = serializers.CharField(required=False, allow_blank=True)
description_html = serializers.CharField(required=False, allow_blank=True)
description = serializers.JSONField(required=False, allow_null=True)
def validate_description_binary(self, value):
"""Validate the base64-encoded binary data"""
if not value:
return value
try:
# Decode the base64 data
binary_data = base64.b64decode(value)
# Validate the binary data
is_valid, error_message = validate_binary_data(binary_data)
if not is_valid:
raise serializers.ValidationError(
f"Invalid binary data: {error_message}"
)
return value
except Exception as e:
if isinstance(e, serializers.ValidationError):
raise
raise serializers.ValidationError("Failed to decode base64 data")
def update(self, instance, validated_data):
"""Update the page instance with validated data"""
if "description_binary" in validated_data:
if validated_data["description_binary"]:
instance.description_binary = base64.b64decode(
validated_data["description_binary"]
)
else:
instance.description_binary = None
if "description_html" in validated_data:
instance.description_html = validated_data["description_html"]
if "description" in validated_data:
instance.description = validated_data["description"]
instance.save()
return instance
+12 -16
View File
@@ -25,6 +25,7 @@ from plane.app.serializers import (
PageSerializer,
SubPageSerializer,
PageDetailSerializer,
PageBinaryUpdateSerializer,
)
from plane.db.models import (
Page,
@@ -538,32 +539,27 @@ class PagesDescriptionViewSet(BaseViewSet):
{"description_html": page.description_html}, cls=DjangoJSONEncoder
)
# Get the base64 data from the request
base64_data = request.data.get("description_binary")
# If base64 data is provided
if base64_data:
# Decode the base64 data to bytes
new_binary_data = base64.b64decode(base64_data)
# capture the page transaction
# Use serializer for validation and update
serializer = PageBinaryUpdateSerializer(page, data=request.data, partial=True)
if serializer.is_valid():
# Capture the page transaction
if request.data.get("description_html"):
page_transaction.delay(
new_value=request.data, old_value=existing_instance, page_id=pk
)
# Store the updated binary data
page.description_binary = new_binary_data
page.description_html = request.data.get("description_html")
page.description = request.data.get("description")
page.save()
# Return a success response
# Update the page using serializer
updated_page = serializer.save()
# Run background tasks
page_version.delay(
page_id=page.id,
page_id=updated_page.id,
existing_instance=existing_instance,
user_id=request.user.id,
)
return Response({"message": "Updated successfully"})
else:
return Response({"error": "No binary data provided"})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class PageDuplicateEndpoint(BaseAPIView):
+42
View File
@@ -0,0 +1,42 @@
# Python imports
def validate_binary_data(binary_data):
"""
Validate that binary data appears to be valid document format and doesn't contain malicious content.
Args:
binary_data (bytes): The binary data to validate
Returns:
tuple: (is_valid: bool, error_message: str or None)
"""
if not binary_data:
return True, None # Empty is OK
# Size check - 10MB limit
MAX_SIZE = 10 * 1024 * 1024
if len(binary_data) > MAX_SIZE:
return False, "Binary data exceeds maximum size limit (10MB)"
# Basic format validation
if len(binary_data) < 4:
return False, "Binary data too short to be valid document format"
# Check for suspicious text patterns (HTML/JS)
try:
decoded_text = binary_data.decode("utf-8", errors="ignore")[:200]
suspicious_patterns = [
"<html",
"<!doctype",
"<script",
"javascript:",
"data:",
"<iframe",
]
if any(pattern in decoded_text.lower() for pattern in suspicious_patterns):
return False, "Binary data contains suspicious content patterns"
except:
pass # Binary data might not be decodable as text, which is fine
return True, None