Skip to content
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

Support for Rich Text Input #630

Merged
merged 5 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/app/Http/Requests/AnswerFormRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Stevebauman\Purify\Facades\Purify;

class AnswerFormRequest extends FormRequest
{
Expand Down Expand Up @@ -175,6 +176,7 @@ private function getPropertyRules($property): array
{
switch ($property['type']) {
case 'text':
case 'rich_text':
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Rich text configuration needs to be documented and standardized

The codebase shows:

  1. Frontend uses Quill editor with basic formatting options (headers, toolbar)
  2. No explicit HTML sanitization rules found in the backend
  3. No shared configuration between frontend and backend

Consider:

  • Document allowed HTML tags and attributes in a central config file
  • Add HTML sanitization rules in the backend
  • Ensure frontend toolbar options match the allowed HTML tags
  • Add frontend validation to match backend rules

Locations needing attention:

  • client/components/forms/RichTextAreaInput.client.vue: Add documentation for Quill configuration
  • api/app/Http/Requests/AnswerFormRequest.php: Add HTML sanitization rules for rich text fields
🔗 Analysis chain

Document rich text validation rules for frontend components

Since this is part of a larger rich text feature implementation spanning multiple components (OpenFormField, OpenTable, OpenText), it's important to ensure consistent handling of rich text content.

Consider:

  1. Creating a shared configuration for allowed HTML tags/attributes that can be used by both frontend and backend validation
  2. Documenting the rich text validation rules in a central location
  3. Adding frontend validation that mirrors these backend rules to provide immediate feedback to users

Let's check for any existing rich text validation documentation or configuration:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Look for rich text related documentation or configuration
fd -e md -e json -e php -e js -e ts -e vue . | xargs rg -l "rich.?text"

Length of output: 848


Script:

#!/bin/bash
# Check content of relevant files for existing validation rules or configuration
echo "=== Checking block types configuration ==="
cat client/data/blocks_types.json

echo -e "\n=== Checking OpenFormField rich text validation ==="
rg -A 10 "rich.?text" client/components/open/forms/OpenFormField.vue

echo -e "\n=== Checking backend validation rules ==="
rg -A 10 "rich.?text" api/app/Http/Requests/AnswerFormRequest.php

Length of output: 6214


Script:

#!/bin/bash
# Check for rich text editor component and its configuration
echo "=== Checking RichTextAreaInput component ==="
fd -e vue -e js -e ts . | xargs rg -l "RichTextAreaInput"

echo -e "\n=== Checking for HTML sanitization or validation rules ==="
rg -i "sanitize|allowedTags|html.?tags" --type ts --type js --type vue --type php

Length of output: 540


Script:

#!/bin/bash
# Check the rich text editor component implementation
echo "=== Checking RichTextAreaInput implementation ==="
cat client/components/forms/RichTextAreaInput.client.vue

echo -e "\n=== Checking for HTML sanitization with correct file type ==="
rg -i "sanitize|allowedTags|html.?tags" 

Length of output: 144583


Script:

#!/bin/bash
# Check for rich text editor configuration in the frontend
echo "=== Checking rich text editor configuration ==="
rg -A 5 "quillOptions" client/components/forms/RichTextAreaInput.client.vue

echo -e "\n=== Checking for HTML sanitization in backend ==="
rg -A 5 "rich_text.*sanitize" api/app/Http/Requests/AnswerFormRequest.php

Length of output: 678


💡 Codebase verification

⚠️ Potential issue

Based on the findings from our searches, I can now provide a final response:

Rich text input requires HTML purification

The codebase has HTML purification capabilities through a configured HTML Purifier (api/config/purify.php), but it's not being applied to rich text input. The current validation rule of ['string'] for rich text is insufficient.

 case 'rich_text':
-    return ['string'];
+    return [
+        'string',
+        function ($attribute, $value, $fail) {
+            $purified = clean($value); // Uses the configured HTML Purifier
+            if ($purified !== $value) {
+                $fail('The '.$attribute.' contains disallowed HTML content.');
+            }
+        }
+    ];

The HTML Purifier is already configured with safe defaults in config/purify.php:

  • Allowed HTML tags and attributes are restricted
  • Nofollow links are enforced
  • Target blank/noreferrer/noopener security attributes are enabled
  • Custom HTML5 definitions are supported
🔗 Analysis chain

Add security measures for rich text input validation

The current validation rule of ['string'] for rich text input may be insufficient to prevent security vulnerabilities like XSS attacks. Rich text input typically contains HTML markup that requires careful sanitization.

Consider implementing these security measures:

 case 'rich_text':
-    return ['string'];
+    return [
+        'string',
+        'max:10000', // Adjust max length as needed
+        function ($attribute, $value, $fail) {
+            // Use HTML Purifier or similar library
+            $clean = clean($value, [
+                'allowed_tags' => ['p', 'br', 'strong', 'em', 'u', 'ul', 'ol', 'li'],
+                'allowed_attributes' => ['href', 'title', 'target']
+            ]);
+            if ($clean !== $value) {
+                $fail('The '.$attribute.' contains disallowed HTML tags or attributes.');
+            }
+        }
+    ];

Let's check if HTML purifier or similar sanitization libraries are already available in the project:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for HTML sanitization libraries in composer.json
rg -A 5 "purifier|sanitize|clean" composer.json

# Check for any existing HTML sanitization usage
rg -A 5 "purifier|sanitize|clean|xss" app/

Length of output: 193


Script:

#!/bin/bash
# Let's first locate the composer.json file and the app directory
fd composer.json

# Find the Laravel app directory which might be in different locations
fd -t d "^app$"

# Let's also check for any sanitization-related code in the entire codebase
rg -i "sanitize|purify|clean|xss" 

# Check for HTML-related validation rules
rg -i "html|allowedTags|strip_tags" 

Length of output: 131154


Script:

#!/bin/bash
# Let's check for any HTML/rich text validation or sanitization in Laravel validation rules
rg -i "sanitize|purify|clean|html|allowedTags|strip_tags" api/app/Http/Requests/

# Check for any HTML sanitization packages in composer.json
rg -i "purifier|sanitize|clean|html" api/composer.json

# Check for any rich text validation or sanitization in the codebase
rg -i "rich_text.*validation|rich_text.*sanitize" api/

Length of output: 400


Script:

#!/bin/bash
# Let's check the context around rich_text case in AnswerFormRequest.php
rg -B 5 -A 5 "case 'rich_text'" api/app/Http/Requests/AnswerFormRequest.php

# Check if there are any other rich text related validations or configurations
rg -i "rich.?text" api/

# Check for any HTML validation rules in Laravel config
rg -i "html|validation" api/config/

Length of output: 2820


Script:

#!/bin/bash
# Let's check the HTML purifier service implementation
rg -A 10 "class OpenFormsHtmlDefinition" api/app/Service/HtmlPurifier/OpenFormsHtmlDefinition.php

# Check if there's any global middleware that handles HTML purification
rg -l "purify|sanitize|clean" api/app/Http/Middleware/

# Check if the purifier is used in form submission processing
rg -B 5 -A 5 "purify|sanitize|clean" api/app/Jobs/Form/StoreFormSubmissionJob.php

Length of output: 767

case 'signature':
return ['string'];
case 'number':
Expand Down Expand Up @@ -282,6 +284,10 @@ protected function prepareForValidation()
if ($property['type'] === 'phone_number' && (!isset($property['use_simple_text_input']) || !$property['use_simple_text_input']) && $receivedValue && in_array($receivedValue, $countryCodeMapper)) {
$mergeData[$property['id']] = null;
}

if ($property['type'] === 'rich_text' && $receivedValue) {
$mergeData[$property['id']] = Purify::clean($receivedValue);
}
});

$this->merge($mergeData);
Expand Down
1 change: 1 addition & 0 deletions client/components/open/forms/OpenFormField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ export default {
}
return {
text: 'TextInput',
rich_text: 'RichTextAreaInput',
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Missing import and component registration for RichTextAreaInput

The RichTextAreaInput component exists in the codebase but is not properly imported or registered in OpenFormField.vue. Please add:

  • Import statement for RichTextAreaInput from '../forms/RichTextAreaInput.client.vue'
  • Register it in the components section
🔗 Analysis chain

Verify RichTextAreaInput component availability

While the mapping is correct, we should ensure the RichTextAreaInput component is properly imported and registered.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for RichTextAreaInput component definition and imports
rg -l "RichTextAreaInput"

Length of output: 164


Script:

#!/bin/bash
# Check if RichTextAreaInput is properly imported in OpenFormField.vue
rg -A 5 "import.*RichTextAreaInput" client/components/open/forms/OpenFormField.vue

# Also check component registration in OpenFormField.vue
rg "components:\s*{[^}]*RichTextAreaInput[^}]*}" client/components/open/forms/OpenFormField.vue

Length of output: 323


Script:

#!/bin/bash
# Check for imports and component registration with simpler patterns
rg "import.*RichTextAreaInput" client/components/open/forms/OpenFormField.vue

# Look for components section
rg -A 10 "components:" client/components/open/forms/OpenFormField.vue

# Also check the actual RichTextAreaInput component file
head -n 20 client/components/forms/RichTextAreaInput.client.vue

Length of output: 928


💡 Codebase verification

Rich text input requires XSS protection implementation

The codebase analysis reveals that the RichTextAreaInput component uses Quill.js editor without explicit HTML sanitization. While Quill provides some built-in security features, additional sanitization measures are recommended:

  • Add HTML sanitization library (like DOMPurify) in client/components/forms/RichTextAreaInput.client.vue
  • Sanitize HTML content before emitting the update:modelValue event in client/components/forms/components/QuillyEditor.vue
🔗 Analysis chain

Verify XSS protection for rich text input

Rich text input can be vulnerable to XSS attacks. Ensure proper HTML sanitization is implemented in the RichTextAreaInput component.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for HTML sanitization implementation
rg -A 5 "sanitize|xss|dompurify|sanitization" --type vue

Length of output: 86


Script:

#!/bin/bash
# Search for RichTextAreaInput component and its implementation
fd -e js -e vue RichTextAreaInput

# Search for sanitization patterns in all files
rg -l "sanitize|xss|dompurify|sanitization"

# Get content of RichTextAreaInput component if found
fd -e js -e vue RichTextAreaInput -x cat {}

Length of output: 4875


Script:

#!/bin/bash
# Search for QuillyEditor component implementation
cat client/components/forms/components/QuillyEditor.vue

# Search for any HTML sanitization in dependencies or configuration
rg -l "quill.*sanitize" 

# Check package.json for sanitization-related dependencies
cat package.json

Length of output: 2463

number: 'TextInput',
rating: 'RatingInput',
scale: 'ScaleInput',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,15 @@
:multiple="field.multiple === true"
:move-to-form-assets="true"
/>
<rich-text-area-input
v-else-if="field.type === 'rich_text'"
name="prefill"
class="mt-3"
:form="field"
label="Pre-filled value"
/>
<text-input
v-else-if="!['files', 'signature'].includes(field.type)"
v-else-if="!['files', 'signature', 'rich_text'].includes(field.type)"
name="prefill"
class="mt-3"
:form="field"
Expand Down
1 change: 1 addition & 0 deletions client/components/open/tables/OpenTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ export default {
rafId: null,
fieldComponents: {
text: shallowRef(OpenText),
rich_text: shallowRef(OpenText),
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

HTML content is rendered without sanitization - Security Risk

The OpenText component directly renders HTML content using v-html without any sanitization, which poses a significant XSS security risk. The raw HTML content from the value prop is rendered directly into the DOM.

Required changes:

  • Implement HTML sanitization using a library like DOMPurify or sanitize-html before rendering content
  • Add the sanitization step in the component's computed property or method

Example implementation:

<template>
  <div v-html="sanitizedValue" />
</template>

<script>
import DOMPurify from 'dompurify'

export default {
  computed: {
    sanitizedValue() {
      return DOMPurify.sanitize(this.value)
    }
  }
}
</script>
🔗 Analysis chain

Verify HTML sanitization for rich text content

Since the OpenText component now renders HTML content (as per the AI summary), ensure that proper HTML sanitization is implemented to prevent XSS attacks.

Let's verify the sanitization implementation:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for sanitization implementation in OpenText component
ast-grep --pattern 'v-html="$_"' 

# Search for any HTML sanitization libraries
rg -l "sanitize|DOMPurify|xss|sanitizeHtml" --type vue

Length of output: 119


Script:

#!/bin/bash
# Search for OpenText component implementation
fd OpenText --type f --exec cat {}

# Search for sanitization patterns with ripgrep
rg -i "sanitize|DOMPurify|xss|sanitizeHtml|v-html"

# Search for v-html directive usage in vue files
fd "\.vue$" --exec cat {} | rg -i "v-html"

Length of output: 140064


Script:

#!/bin/bash
# Search for OpenText component implementation and any sanitization
fd OpenText --type f --exec grep -l "sanitize\|DOMPurify\|xss\|sanitizeHtml\|v-html" {} \;

# Search for any HTML sanitization libraries in package.json
fd "package.json" --type f --exec cat {} \;

Length of output: 3210


Script:

#!/bin/bash
# Let's examine the content of OpenText.vue to check for any sanitization implementation
cat ./client/components/open/tables/components/OpenText.vue

Length of output: 244

number: shallowRef(OpenText),
rating: shallowRef(OpenText),
scale: shallowRef(OpenText),
Expand Down
4 changes: 1 addition & 3 deletions client/components/open/tables/components/OpenText.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<template>
<span>
{{ value }}
</span>
<div v-html="value" />
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

Security Risk: Potential XSS Vulnerability

Using v-html without sanitization exposes the application to Cross-Site Scripting (XSS) attacks. Malicious users could inject harmful scripts through the value prop.

Consider these solutions:

  1. Implement HTML sanitization using a library like DOMPurify:
<template>
-  <div v-html="value" />
+  <div v-html="sanitizedValue" />
</template>

<script>
+ import DOMPurify from 'dompurify'

export default {
  components: {},
  props: {
    value: {
      type: String,
      required: true,
    },
  },
+  computed: {
+    sanitizedValue() {
+      return DOMPurify.sanitize(this.value)
+    }
+  }
}
</script>
  1. Or if rich text is not needed, continue using text interpolation:
- <div v-html="value" />
+ <div>{{ value }}</div>

Committable suggestion skipped: line range outside the PR's diff.


💡 Codebase verification

Security concern: Unsanitized v-html usage detected

The codebase shows multiple instances of v-html directive usage without any visible HTML sanitization implementation. This includes user-generated content in forms, notifications, and templates, which could pose XSS security risks. Specific instances that need attention:

  • client/components/open/tables/components/OpenText.vue: Direct v-html binding of value
  • client/components/open/forms/OpenFormField.vue: Direct v-html binding of field.content
  • client/components/forms/validation/AlertError.vue: Direct v-html binding of error messages
  • client/pages/templates/[slug].vue: Direct v-html binding of template descriptions and answers

Recommendation: Implement HTML sanitization using a library like DOMPurify before rendering HTML content to prevent XSS attacks.

🔗 Analysis chain

Verify HTML sanitization implementation

Let's verify if HTML sanitization is implemented elsewhere in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for HTML sanitization implementation
# Expected results: Find any existing sanitization logic or DOMPurify usage

# Check for DOMPurify or other sanitization libraries
rg -l "DOMPurify|sanitize|xss|dompurify" --type vue --type js

# Check for rich text related sanitization
ast-grep --pattern 'sanitize($$$)'

# Look for rich text processing logic
rg -A 5 "rich_text" --type vue --type js

Length of output: 197


Script:

#!/bin/bash
# Let's try a different approach to search for sanitization implementations

# Search for sanitization-related terms without file type restrictions
rg -l "DOMPurify|sanitize|xss|dompurify"

# Look for v-html directives to understand the pattern
rg "v-html"

# Search for any security-related utilities or helpers
rg -l "sanitizeHTML|escapeHTML|purifyHTML"

# Check package.json for any sanitization-related dependencies
cat package.json 2>/dev/null || true

Length of output: 1910

</template>

<script>
Expand Down
9 changes: 9 additions & 0 deletions client/data/blocks_types.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
"text_class": "text-blue-900",
"is_input": true
},
"rich_text": {
"name": "rich_text",
"title": "Rich Text Input",
"icon": "i-heroicons-bars-3-20-solid",
"default_block_name": "Description",
"bg_class": "bg-blue-100",
"text_class": "text-blue-900",
"is_input": true
},
Comment on lines +11 to +19
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Rich text implementation requires additional security measures

The codebase review reveals potential security concerns:

  1. The OpenText component uses v-html directly without sanitization:
<div v-html="value" />
  1. While Quill.js is used for rich text editing, there's no visible sanitization of content before storage or display.

Required actions:

  • Implement HTML sanitization before storing rich text content
  • Add sanitization when displaying content via v-html
  • Consider using DOMPurify or a similar library for sanitization

Recommended implementation:

  1. Add a sanitization library to package.json (e.g., DOMPurify)
  2. Sanitize content in OpenText component before rendering
  3. Add sanitization step in RichTextAreaInput before emitting values
🔗 Analysis chain

Verify security measures for rich text handling.

Since rich text content typically contains HTML and the OpenText component uses v-html (as mentioned in the summary), ensure that:

  1. Proper input sanitization is implemented
  2. HTML content is escaped appropriately
  3. XSS prevention measures are in place

Let's check for sanitization implementation:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for HTML sanitization implementation

# Look for sanitization libraries or implementations
echo "Checking for HTML sanitization..."
rg -l "sanitize|DOMPurify|xss|escapeHTML" --type js --type vue

# Check for security-related comments or documentation
echo "Checking for security documentation..."
rg "XSS|sanitization|security" --type js --type vue

Length of output: 338


Script:

#!/bin/bash
# Description: Check for HTML sanitization implementation with correct file types

# Look for sanitization libraries or implementations
echo "Checking for HTML sanitization..."
rg -l "sanitize|DOMPurify|xss|escapeHTML"

# Search for rich text related components and their implementations
echo -e "\nChecking rich text components..."
fd -e vue -e js . | xargs rg -l "v-html|rich.*text|RichText"

# Check package.json for security-related dependencies
echo -e "\nChecking package dependencies..."
find . -name "package.json" -exec cat {} \;

Length of output: 5129


Script:

#!/bin/bash
# Let's examine the rich text implementation specifically

# Check OpenText component implementation
echo "Checking OpenText component implementation..."
cat client/components/open/tables/components/OpenText.vue

# Check RichTextAreaInput implementation
echo -e "\nChecking RichTextAreaInput implementation..."
cat client/components/forms/RichTextAreaInput.client.vue

# Look for Quill.js configuration (since it's in dependencies)
echo -e "\nChecking for Quill.js configuration..."
rg "Quill|quill" --type vue --type js

Length of output: 5068

"date": {
"name": "date",
"title": "Date Input",
Expand Down
Loading