Skip to content

Implement custom footer code option#385

Merged
freedit-dev merged 2 commits intofreedit-org:mainfrom
YGGverse:custom-footer
Dec 23, 2025
Merged

Implement custom footer code option#385
freedit-dev merged 2 commits intofreedit-org:mainfrom
YGGverse:custom-footer

Conversation

@oooo-ps
Copy link

@oooo-ps oooo-ps commented Dec 23, 2025

#383

Summary by CodeRabbit

  • New Features
    • Administrators can add custom footer HTML via a new textarea in admin settings (up to 2048 characters).
    • When configured, the site footer will render the custom code; otherwise the default footer remains.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 23, 2025

Walkthrough

Adds a configurable custom footer: new translation keys, a SiteConfig field, PageData exposure, an admin textarea to edit it, and conditional footer rendering that uses the custom code when present or falls back to the original footer.

Changes

Cohort / File(s) Summary
Translation Keys
i18n/en.toml, i18n/fr.toml, i18n/ja.toml, i18n/uk.toml, i18n/zh_cn.toml
Added custom_footer_code translation key in each language file (localized values; no other edits).
Configuration Struct
src/controller/mod.rs
Added custom_footer_code: Option<String> to SiteConfig with #[validate(skip)].
Default Implementation
src/controller/admin.rs
SiteConfig::default() updated to initialize custom_footer_code as None.
Page Data Structure
src/controller/meta_handler.rs
Added pub(super) custom_footer_code: Option<&'a str> to PageData and initialize it from site_config, filtering empty values.
Admin Template
templates/admin.html
Added a textarea input for custom_footer_code (pre-populated when present, 2048 char limit).
Footer Rendering
templates/layout.html
Footer now conditionally renders page_data.custom_footer_code if present; otherwise renders the original static footer (GitHub link, version, sha256, commit).

Sequence Diagram(s)

sequenceDiagram
    participant Admin as Admin User
    participant AdminForm as Admin Form (templates/admin.html)
    participant SiteConfig as SiteConfig (src/controller/mod.rs)
    participant Meta as Meta Handler / PageData (src/controller/meta_handler.rs)
    participant Template as Layout Template (templates/layout.html)

    Admin->>AdminForm: Edit & submit custom_footer_code
    AdminForm->>SiteConfig: Persist custom_footer_code
    Note over SiteConfig,Meta: On request rendering
    SiteConfig->>Meta: Provide site_config
    Meta->>Meta: Initialize PageData.custom_footer_code (None or &str)
    Template->>Meta: Check custom_footer_code
    alt custom_footer_code exists
        Template->>Template: Render custom footer code (unsafe HTML)
    else no custom_footer_code
        Template->>Template: Render default static footer
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: implementing a custom footer code feature across configuration, templates, and translation files.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3fffcd8 and e225b29.

📒 Files selected for processing (1)
  • templates/layout.html
🚧 Files skipped from review as they are similar to previous changes (1)
  • templates/layout.html
⏰ 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: Cargo test, clippy and doc (windows-latest, x86_64-pc-windows-gnu)
  • GitHub Check: Cargo test, clippy and doc (windows-latest, x86_64-pc-windows-msvc)

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.

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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/controller/admin.rs (1)

340-360: Critical: Missing sanitization for custom_footer_code.

The admin_post function sanitizes other user-controlled fields (lines 351-356) using clean_html(), but custom_footer_code is not sanitized. This creates an XSS vulnerability when the unsanitized content is rendered in templates/layout.html.

🔎 Proposed fix to add sanitization
     site_config.site_name = clean_html(&site_config.site_name);
     site_config.domain = clean_html(&site_config.domain);
     site_config.description = clean_html(&site_config.description);
     site_config.captcha_difficulty = clean_html(&site_config.captcha_difficulty);
     site_config.captcha_name = clean_html(&site_config.captcha_name);
     site_config.tos_link = clean_html(&site_config.tos_link);
+    site_config.custom_footer_code = site_config.custom_footer_code.map(|s| clean_html(&s));

     set_one_with_key(&DB, "default", "site_config", &site_config)?;
🧹 Nitpick comments (1)
src/controller/mod.rs (1)

530-531: Consider adding length validation for the custom footer code field.

While this field is admin-controlled and intentionally allows custom code injection, having no length validation could lead to storage, memory, or page load performance issues if excessively large content is provided. Other string fields in SiteConfig have maximum length constraints (e.g., description at 5120, article_max_length at 65535).

🔎 Suggested improvement
-    #[validate(skip)]
+    #[validate(length(max = 65535))]
     custom_footer_code: Option<String>,

Alternatively, choose a different limit based on expected use cases (analytics scripts, custom HTML, etc.).

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 936a20b and 3fffcd8.

📒 Files selected for processing (10)
  • i18n/en.toml
  • i18n/fr.toml
  • i18n/ja.toml
  • i18n/uk.toml
  • i18n/zh_cn.toml
  • src/controller/admin.rs
  • src/controller/meta_handler.rs
  • src/controller/mod.rs
  • templates/admin.html
  • templates/layout.html
🧰 Additional context used
🧬 Code graph analysis (1)
src/controller/mod.rs (2)
src/controller/inn.rs (1)
  • FormInn (124-139)
src/controller/feed.rs (1)
  • FormFeedAdd (533-542)
⏰ 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: Cargo test, clippy and doc (windows-latest, x86_64-pc-windows-msvc)
  • GitHub Check: Cargo test, clippy and doc (windows-latest, x86_64-pc-windows-gnu)
🔇 Additional comments (6)
i18n/en.toml (1)

22-22: LGTM!

English translation is appropriate and consistent with other translation keys.

i18n/uk.toml (1)

22-22: LGTM!

Ukrainian translation is properly localized and consistent with other translation keys.

templates/admin.html (1)

235-250: Template implementation looks consistent.

The conditional rendering pattern matches the existing spam_regex field implementation. However, ensure that server-side sanitization is properly implemented to prevent XSS vulnerabilities.

src/controller/admin.rs (1)

383-383: LGTM!

Default initialization to None is appropriate for the optional custom footer code field.

src/controller/meta_handler.rs (2)

170-170: LGTM!

The field declaration is correct with proper lifetime management and visibility.


186-197: LGTM! Clean implementation of the custom footer code feature.

The initialization logic correctly:

  • Converts Option<String> to Option<&'a str> using as_deref()
  • Filters out empty strings for better UX
  • Maintains proper lifetime relationships

The field reordering is a stylistic change with no functional impact.

comment_max_length = "Longueur maximale du commentaire"
comments = "Comments" # @TODO
created = "Créé"
custom_footer_code = "Custom footer code" # @TODO
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 | 🟡 Minor

Incomplete French translation.

The translation value is still in English rather than French. Consider translating to something like "Code de pied de page personnalisé".

🤖 Prompt for AI Agents
In i18n/fr.toml around line 22, the value for custom_footer_code is still in
English; replace the English string with the French translation (e.g., "Code de
pied de page personnalisé") so the key is fully localized.

comment_max_length = "コメントの最大長"
comments = "Comments" # @TODO
created = "作成日時"
custom_footer_code = "Custom footer code" # @TODO
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 | 🟡 Minor

Incomplete Japanese translation.

The translation value is still in English rather than Japanese. Consider translating to something like "カスタムフッターコード".

🤖 Prompt for AI Agents
In i18n/ja.toml around line 22, the value for custom_footer_code is still in
English; replace the English string "Custom footer code" with the appropriate
Japanese translation (e.g., "カスタムフッターコード") ensuring UTF-8 encoding and
preserving the TOML key/value format so localization loads correctly.

comment_max_length = "评论最大长度"
comments = "Comments" # @TODO
created = "创建时间"
custom_footer_code = "Custom footer code" # @TODO
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 | 🟡 Minor

Incomplete Chinese translation.

The translation value is still in English rather than Chinese. Consider translating to something like "自定义页脚代码".

🤖 Prompt for AI Agents
In i18n/zh_cn.toml around line 22, the value for custom_footer_code is still in
English; replace the English string with the appropriate Chinese translation
(e.g., "自定义页脚代码") so the key provides the correct Simplified Chinese
localization; ensure quotes and TOML syntax remain valid.

Comment on lines +147 to +154
{% if let Some(custom_footer_code) = page_data.custom_footer_code %}
{{custom_footer_code}}
{% else %}
<p><a href="https://github.com/freedit-org/freedit">GitHub</a></p>
<p><small>version: <a href="https://github.com/freedit-org/freedit/releases/tag/v{{ crate::VERSION }}">v{{ crate::VERSION }}</a></small></p>
<p><small>sha256: {{ crate::CURRENT_SHA256.as_str()|truncate(10) }}</small></p>
<p><small>commit: <a href="https://github.com/freedit-org/freedit/commit/{{ crate::GIT_COMMIT }}">{{ crate::GIT_COMMIT }}</a></small></p>
{% endif %}
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n templates/layout.html | sed -n '140,160p'

Repository: freedit-org/freedit

Length of output: 1026


🏁 Script executed:

rg -A 20 "custom_footer_code" src/controller/admin.rs

Repository: freedit-org/freedit

Length of output: 546


🏁 Script executed:

rg -B 5 -A 15 "pub.*async fn admin_post" src/controller/admin.rs | head -100

Repository: freedit-org/freedit

Length of output: 779


🏁 Script executed:

rg "clean_html" src/

Repository: freedit-org/freedit

Length of output: 2592


🏁 Script executed:

rg -A 50 "pub.*async fn admin_post" src/controller/admin.rs

Repository: freedit-org/freedit

Length of output: 1947


🏁 Script executed:

rg -B 5 -A 30 "struct SiteConfig" src/

Repository: freedit-org/freedit

Length of output: 1882


🏁 Script executed:

rg "custom_footer_code" src/ -B 3 -A 3

Repository: freedit-org/freedit

Length of output: 1561


Critical: Potential XSS vulnerability from unsanitized HTML rendering.

Line 148 renders custom_footer_code directly without escaping, allowing arbitrary HTML/JavaScript injection. While the CSP has script-src 'none' which mitigates inline scripts, this still enables:

  • HTML injection and page defacement
  • Malicious links and phishing attacks
  • Potential CSP bypasses through various techniques

The custom_footer_code field is accepted from admin input but notably excluded from sanitization in the admin_post handler—all other HTML-accepting fields (site_name, domain, description, etc.) are sanitized using clean_html(). Apply the same sanitization to custom_footer_code, or escape the output in the template.

🤖 Prompt for AI Agents
In templates/layout.html around lines 147 to 154, custom_footer_code is rendered
raw which permits stored XSS; ensure custom_footer_code is sanitized like other
admin HTML fields before storage or escaped at render time. Fix by applying the
same clean_html() sanitization in the admin_post handler when saving
custom_footer_code (so only safe HTML is stored) and then render the stored
value as safe HTML in the template, or alternately update the template to escape
output unless the value has been sanitized/stored as clean; make the change
consistent with how site_name/domain/description are handled.

@oooo-ps
Copy link
Author

oooo-ps commented Dec 23, 2025

Forgot to disable html entities, wait please.

@oooo-ps
Copy link
Author

oooo-ps commented Dec 23, 2025

Done.

@freedit-dev freedit-dev merged commit 5f86b3f into freedit-org:main Dec 23, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants