0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-08 17:53:55 +08:00
discourse/plugins/discourse-narrative-bot/app/controllers/discourse_narrative_bot/certificates_controller.rb
Alan Guo Xiang Tan 5daee2476d
DEV: Use render body instead of render inline in CertificatesController (#37915)
What is the problem?

- The `DiscourseNarrativeBot::CertificatesController#generate` action
  renders discobot certificate SVGs using `render inline: svg`.
- `render inline:` passes the string through Rails' ERB template engine,
  meaning any ERB tags in the content would be evaluated as Ruby code on
  the server.
- The SVG string is already fully rendered by `CertificateGenerator` —
the
  second ERB evaluation pass is redundant.

What is the solution?

- As a defence in depth measure, replace `render inline: svg` with
  `render body: svg, content_type: "image/svg+xml"` to send the
  pre-rendered SVG string verbatim as the response body with no template
  processing.
- The explicit `content_type` ensures browsers correctly interpret the
  response as SVG, matching the behavior of the `format.svg` block.
2026-02-19 16:41:13 +08:00

42 lines
1.2 KiB
Ruby
Vendored

# frozen_string_literal: true
module DiscourseNarrativeBot
class CertificatesController < ::ApplicationController
requires_plugin PLUGIN_NAME
layout false
skip_before_action :check_xhr
requires_login
def generate
immutable_for(24.hours)
%i[date user_id].each do |key|
raise Discourse::InvalidParameters.new("#{key} must be present") if params[key].blank?
end
if params[:user_id].to_i != current_user.id
rate_limiter = RateLimiter.new(current_user, "svg_certificate", 3, 1.minute)
else
rate_limiter = RateLimiter.new(current_user, "svg_certificate_self", 30, 10.minutes)
end
rate_limiter.performed! unless current_user.staff?
user = User.find_by(id: params[:user_id])
raise Discourse::NotFound if user.blank?
hijack do
generator = CertificateGenerator.new(user, params[:date], avatar_url(user))
svg = params[:type] == "advanced" ? generator.advanced_user_track : generator.new_user_track
respond_to { |format| format.svg { render body: svg, content_type: "image/svg+xml" } }
end
end
private
def avatar_url(user)
UrlHelper.absolute(Discourse.base_path + user.avatar_template.gsub("{size}", "250"))
end
end
end