From d09fa22226f3a00d7755072be349b0dddd1aece9 Mon Sep 17 00:00:00 2001 From: rulingcom Date: Wed, 21 Oct 2026 10:49:42 +0800 Subject: [PATCH] Block dangerous upload extensions and enforce owner-only edit/delete for seminar contributions --- app/controllers/seminars_controller.rb | 17 +++++++++++++++-- app/models/seminar_signup_contribute.rb | 4 ++-- app/uploaders/seminar_contribute_uploader.rb | 14 ++++++++++++++ app/views/seminars/_contribute_form.html.erb | 3 +-- app/views/seminars/con_upload.html.erb | 9 ++++++++- config/locales/en.yml | 3 ++- config/locales/zh_tw.yml | 3 ++- 7 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 app/uploaders/seminar_contribute_uploader.rb diff --git a/app/controllers/seminars_controller.rb b/app/controllers/seminars_controller.rb index dc35ed0..8f80aee 100644 --- a/app/controllers/seminars_controller.rb +++ b/app/controllers/seminars_controller.rb @@ -550,6 +550,10 @@ class SeminarsController < ApplicationController if flag update_params['seminar_submission_values']['0']['value']['en'] = ' ' end + if session[:seminar_signup_id].blank? + redirect_to "#{params[:referer_url].to_s.chomp('/')}/?method=con_upload" and return + end + update_params['seminar_signup_id'] = session[:seminar_signup_id].to_s @con = SeminarSignupContribute.new(update_params) if @con.save signup = SeminarSignup.where(id:update_params['seminar_signup_id']).first @@ -573,13 +577,17 @@ class SeminarsController < ApplicationController @seminar.save redirect_to "#{params[:referer_url].to_s.chomp('/')}/?method=con_upload" else - redirect_to "#{params[:referer_url]}", :notice => t('recaptcha.errors.verification_failed') + msg = @con.errors[:file].present? ? t('recaptcha.errors.file_type_not_allowed') : t('recaptcha.errors.verification_failed') + redirect_to "#{params[:referer_url].to_s.chomp('/')}/?method=con_upload¬ice=#{msg}", :notice => msg end end def update @con = SeminarSignupContribute.find(params[:seminar_signup_contribute][:id]) + if session[:seminar_signup_id].blank? || @con.seminar_signup_id.to_s != session[:seminar_signup_id].to_s + redirect_to "#{params[:referer_url].to_s.chomp('/')}/?method=con_upload" and return + end update_params = seminar_signup_contribute_params.merge('seminar_submission_values'=>params['seminar_submission_values'].to_h) update_params.permit! if update_params['seminar_submission_values'].present? @@ -627,7 +635,8 @@ class SeminarsController < ApplicationController @seminar.save redirect_to "#{params[:referer_url].to_s.chomp('/')}/?method=con_upload" else - redirect_to "#{params[:referer_url]}", :notice => t('recaptcha.errors.verification_failed') + msg = @con.errors[:file].present? ? t('recaptcha.errors.file_type_not_allowed') : t('recaptcha.errors.verification_failed') + redirect_to "#{params[:referer_url].to_s.chomp('/')}/?method=con_upload¬ice=#{msg}", :notice => msg end end @@ -636,6 +645,10 @@ class SeminarsController < ApplicationController con = SeminarSignupContribute.find(params[:con_no]) + if session[:seminar_signup_id].blank? || con.seminar_signup_id.to_s != session[:seminar_signup_id].to_s + redirect_to "#{params[:referer_url].to_s.chomp('/')}/?method=con_upload" and return + end + # seminar_signup = SeminarSignup.find_by(_id: con.seminar_signup_id ) # seminar = SeminarMain.find_by(_id: seminar_signup.seminar_main_id ) signup = con.seminar_signup diff --git a/app/models/seminar_signup_contribute.rb b/app/models/seminar_signup_contribute.rb index 0942997..e6e55e2 100644 --- a/app/models/seminar_signup_contribute.rb +++ b/app/models/seminar_signup_contribute.rb @@ -7,7 +7,7 @@ class SeminarSignupContribute field :abstract_number , type: String , default: "" field :presentation_type , type: String , default: "" field :sort_number , type: Integer, default: 10000 - mount_uploader :file, AssetUploader + mount_uploader :file, SeminarContributeUploader field :filename, type: String field :description field :preferred_session @@ -62,4 +62,4 @@ class SeminarSignupContribute end self.filename end -end \ No newline at end of file +end diff --git a/app/uploaders/seminar_contribute_uploader.rb b/app/uploaders/seminar_contribute_uploader.rb new file mode 100644 index 0000000..22b8065 --- /dev/null +++ b/app/uploaders/seminar_contribute_uploader.rb @@ -0,0 +1,14 @@ +# encoding: utf-8 + +# 研討會投稿是「外部訪客」上傳,與後台可信上傳不同。 +# 繼承核心 AssetUploader(沿用 store_dir、檔名截短),僅加上危險副檔名黑名單, +# 擋掉會在瀏覽器執行腳本、或可能被伺服器端執行的類型,防止 XSS。 +class SeminarContributeUploader < AssetUploader + def extension_blacklist + %w[ + html htm xhtml shtml mhtml svg xml js mjs + php php3 php4 php5 phtml pht cgi pl py rb asp aspx jsp jspx sh bash + htaccess swf jar hta vbs + ] + end +end diff --git a/app/views/seminars/_contribute_form.html.erb b/app/views/seminars/_contribute_form.html.erb index 83294ce..01007cf 100644 --- a/app/views/seminars/_contribute_form.html.erb +++ b/app/views/seminars/_contribute_form.html.erb @@ -94,7 +94,6 @@ "> <%= f.submit "Submit", class: 'btn btn-primary', :id => 'button-mail' %> - <%= f.button "Delete", type: 'reset', class: 'btn' %> @@ -136,4 +135,4 @@ float: left; cursor: pointer; } - \ No newline at end of file + diff --git a/app/views/seminars/con_upload.html.erb b/app/views/seminars/con_upload.html.erb index 8b7d1b6..5f6e0d1 100644 --- a/app/views/seminars/con_upload.html.erb +++ b/app/views/seminars/con_upload.html.erb @@ -22,6 +22,13 @@ prefix_url = OrbitHelper.url_to_show(@seminar.to_param) end %> +<% notice = (params[:notice] rescue nil) %> +<% if notice.present? %> + <%= content_tag :p, notice, :class => ["notice alert alert-error in fade"], :style => "color: red; font-weight: bold;" %> + +<% end %> <% if (@seminar.contribute_start_date.nil? || @seminar.contribute_start_date <= @time_now) && ( @seminar.contribute_end_date.nil? || @seminar.contribute_end_date+1 >= @time_now ) %> <% begin %> <% if !session[:seminar_signup_id].blank? %> @@ -109,4 +116,4 @@ end%> <% else %> <%= t("seminar.out_of_date") %> -<% end %> \ No newline at end of file +<% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 26c147b..4c340c2 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -23,6 +23,7 @@ en: recaptcha: errors: verification_failed: Verification Failed #驗證碼錯誤 + file_type_not_allowed: This file type is not allowed helpers: label: seminar_review_result: @@ -214,4 +215,4 @@ en: select: Select box checkbox: Multiple choice radio: Single choice - choices: Choices \ No newline at end of file + choices: Choices diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml index 72ddba8..5849f6c 100644 --- a/config/locales/zh_tw.yml +++ b/config/locales/zh_tw.yml @@ -23,6 +23,7 @@ zh_tw: recaptcha: errors: verification_failed: 驗證碼錯誤 + file_type_not_allowed: 檔案格式不允許上傳 helpers: label: seminar_review_result: @@ -214,4 +215,4 @@ zh_tw: select: 下拉選單 checkbox: 多選 radio: 單選 - choices: 選項 \ No newline at end of file + choices: 選項