From 04b752a99fce3ffa5d1cfa20253a9fef6882f9ba Mon Sep 17 00:00:00 2001
From: Nat
Date: Wed, 19 Feb 2025 17:31:04 +0800
Subject: [PATCH 1/3] FIX: Ensure translated content is safe for rendering
---
.../discourse_translator/translatable.rb | 6 ++++
.../translated_content_sanitizer.rb | 18 ++++++++++++
spec/lib/translated_content_sanitizer_spec.rb | 29 +++++++++++++++++++
3 files changed, 53 insertions(+)
create mode 100644 lib/discourse_translator/translated_content_sanitizer.rb
create mode 100644 spec/lib/translated_content_sanitizer_spec.rb
diff --git a/app/models/concerns/discourse_translator/translatable.rb b/app/models/concerns/discourse_translator/translatable.rb
index 9b451f8b..2866df77 100644
--- a/app/models/concerns/discourse_translator/translatable.rb
+++ b/app/models/concerns/discourse_translator/translatable.rb
@@ -17,8 +17,14 @@ def set_detected_locale(locale)
(content_locale || build_content_locale).update!(detected_locale: locale)
end
+ # This method is used to create a translation for a translatable (Post or Topic) and a specific locale.
+ # If a translation already exists for the locale, it will be updated.
+ # Texts are put through a Sanitizer to clean them up before saving.
+ # @param locale [String] the locale of the translation
+ # @param text [String] the translated text
def set_translation(locale, text)
locale = locale.to_s.gsub("_", "-")
+ text = DiscourseTranslator::TranslatedContentSanitizer.sanitize(self.class, text)
translations.find_or_initialize_by(locale: locale).update!(translation: text)
end
diff --git a/lib/discourse_translator/translated_content_sanitizer.rb b/lib/discourse_translator/translated_content_sanitizer.rb
new file mode 100644
index 00000000..c12e2217
--- /dev/null
+++ b/lib/discourse_translator/translated_content_sanitizer.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module DiscourseTranslator
+ class TranslatedContentSanitizer
+ def self.sanitize(model, content)
+ case model.to_s
+ when "Topic"
+ return ERB::Util.html_escape(content) unless SiteSetting.title_fancy_entities?
+ Topic.fancy_title(content)
+ when "Post"
+ PrettyText.cleanup(content, {})
+ else
+ # raise an error if the model is not supported
+ raise ArgumentError.new("Model not supported")
+ end
+ end
+ end
+end
diff --git a/spec/lib/translated_content_sanitizer_spec.rb b/spec/lib/translated_content_sanitizer_spec.rb
new file mode 100644
index 00000000..903ae6e9
--- /dev/null
+++ b/spec/lib/translated_content_sanitizer_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+describe DiscourseTranslator::TranslatedContentSanitizer do
+ describe "Posts" do
+ it "sanitizes the content" do
+ sanitized =
+ DiscourseTranslator::TranslatedContentSanitizer.sanitize(
+ Post,
+ "
Testing
This is a test post
",
+ )
+
+ expect(sanitized).to eq("
Testing
This is a test post")
+ end
+ end
+
+ describe "Topics" do
+ it "escapes and prettifies" do
+ sanitized =
+ DiscourseTranslator::TranslatedContentSanitizer.sanitize(
+ Topic,
+ "
Testing
This is a test post",
+ )
+
+ expect(sanitized).to eq(
+ "<script>alert(‘test’)</script><p> <h1>Testing</h1> This is a test post</p>",
+ )
+ end
+ end
+end
From 15c56350a3fde10da726270d78c84a7e5de09ff2 Mon Sep 17 00:00:00 2001
From: Nat
Date: Tue, 25 Feb 2025 11:25:08 +0800
Subject: [PATCH 2/3] Do not escape titles as we need to keep compatibility
with manual inline translations
---
.../discourse_translator/translatable.rb | 2 +-
.../translated_content_sanitizer.rb | 13 ++-------
spec/lib/translated_content_sanitizer_spec.rb | 29 ++++---------------
3 files changed, 9 insertions(+), 35 deletions(-)
diff --git a/app/models/concerns/discourse_translator/translatable.rb b/app/models/concerns/discourse_translator/translatable.rb
index 2866df77..ad8a202a 100644
--- a/app/models/concerns/discourse_translator/translatable.rb
+++ b/app/models/concerns/discourse_translator/translatable.rb
@@ -24,7 +24,7 @@ def set_detected_locale(locale)
# @param text [String] the translated text
def set_translation(locale, text)
locale = locale.to_s.gsub("_", "-")
- text = DiscourseTranslator::TranslatedContentSanitizer.sanitize(self.class, text)
+ text = DiscourseTranslator::TranslatedContentSanitizer.sanitize(text)
translations.find_or_initialize_by(locale: locale).update!(translation: text)
end
diff --git a/lib/discourse_translator/translated_content_sanitizer.rb b/lib/discourse_translator/translated_content_sanitizer.rb
index c12e2217..5e028697 100644
--- a/lib/discourse_translator/translated_content_sanitizer.rb
+++ b/lib/discourse_translator/translated_content_sanitizer.rb
@@ -2,17 +2,8 @@
module DiscourseTranslator
class TranslatedContentSanitizer
- def self.sanitize(model, content)
- case model.to_s
- when "Topic"
- return ERB::Util.html_escape(content) unless SiteSetting.title_fancy_entities?
- Topic.fancy_title(content)
- when "Post"
- PrettyText.cleanup(content, {})
- else
- # raise an error if the model is not supported
- raise ArgumentError.new("Model not supported")
- end
+ def self.sanitize(content)
+ PrettyText.cleanup(content, {})
end
end
end
diff --git a/spec/lib/translated_content_sanitizer_spec.rb b/spec/lib/translated_content_sanitizer_spec.rb
index 903ae6e9..8fb4e347 100644
--- a/spec/lib/translated_content_sanitizer_spec.rb
+++ b/spec/lib/translated_content_sanitizer_spec.rb
@@ -1,29 +1,12 @@
# frozen_string_literal: true
describe DiscourseTranslator::TranslatedContentSanitizer do
- describe "Posts" do
- it "sanitizes the content" do
- sanitized =
- DiscourseTranslator::TranslatedContentSanitizer.sanitize(
- Post,
- "
Testing
This is a test post",
- )
-
- expect(sanitized).to eq("
Testing
This is a test post")
- end
- end
-
- describe "Topics" do
- it "escapes and prettifies" do
- sanitized =
- DiscourseTranslator::TranslatedContentSanitizer.sanitize(
- Topic,
- "
Testing
This is a test post",
- )
-
- expect(sanitized).to eq(
- "<script>alert(‘test’)</script><p> <h1>Testing</h1> This is a test post</p>",
+ it "sanitizes the content" do
+ sanitized =
+ DiscourseTranslator::TranslatedContentSanitizer.sanitize(
+ "
Testing
This is a test post",
)
- end
+
+ expect(sanitized).to eq("
Testing
This is a test post")
end
end
From 0c49cfafd3b4a2e77d4e5e9e0c3a359704e72dad Mon Sep 17 00:00:00 2001
From: Nat
Date: Tue, 25 Feb 2025 11:32:46 +0800
Subject: [PATCH 3/3] compat to the previous working version without
prettytext.cleanup
---
.discourse-compatibility | 1 +
1 file changed, 1 insertion(+)
diff --git a/.discourse-compatibility b/.discourse-compatibility
index c89970d9..99519795 100644
--- a/.discourse-compatibility
+++ b/.discourse-compatibility
@@ -1,3 +1,4 @@
+< 3.5.0.beta2-dev: 5f24835801fdc7cb98e1bcf42d2ab2e49e609921
< 3.5.0.beta1-dev: 7d411e458bdd449f8aead2bc07cedeb00b856798
< 3.4.0.beta3-dev: b4cf3a065884816fa3f770248c2bf908ba65d8ac
< 3.4.0.beta1-dev: 5346b4bafba2c2fb817f030a473b7bbca97b909c