SECURITY: Limit ThemeField value length to prevent DoS (#22087)
Co-authored-by: Daniel Waterworth <me@danielwaterworth.com>
This commit is contained in:
parent
e576fdbe3a
commit
56b74e6042
|
@ -14,7 +14,7 @@ class Theme < ActiveRecord::Base
|
|||
|
||||
belongs_to :user
|
||||
belongs_to :color_scheme
|
||||
has_many :theme_fields, dependent: :destroy
|
||||
has_many :theme_fields, dependent: :destroy, validate: false
|
||||
has_many :theme_settings, dependent: :destroy
|
||||
has_many :theme_translation_overrides, dependent: :destroy
|
||||
has_many :child_theme_relation,
|
||||
|
@ -59,6 +59,7 @@ class Theme < ActiveRecord::Base
|
|||
class_name: "ThemeField"
|
||||
|
||||
validate :component_validations
|
||||
validate :validate_theme_fields
|
||||
|
||||
after_create :update_child_components
|
||||
|
||||
|
@ -300,6 +301,12 @@ class Theme < ActiveRecord::Base
|
|||
errors.add(:base, I18n.t("themes.errors.component_no_default")) if default?
|
||||
end
|
||||
|
||||
def validate_theme_fields
|
||||
theme_fields.each do |field|
|
||||
field.errors.full_messages.each { |message| errors.add(:base, message) } unless field.valid?
|
||||
end
|
||||
end
|
||||
|
||||
def switch_to_component!
|
||||
return if component
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ class ThemeField < ActiveRecord::Base
|
|||
has_one :javascript_cache, dependent: :destroy
|
||||
has_one :upload_reference, as: :target, dependent: :destroy
|
||||
|
||||
validates :value, { length: { maximum: 1024**2 } }
|
||||
|
||||
after_save do
|
||||
if self.type_id == ThemeField.types[:theme_upload_var] && saved_change_to_upload_id?
|
||||
UploadReference.ensure_exist!(upload_ids: [self.upload_id], target: self)
|
||||
|
|
|
@ -668,6 +668,42 @@ RSpec.describe Admin::ThemesController do
|
|||
expect(response.status).to eq(403)
|
||||
end
|
||||
|
||||
it "creates new theme fields" do
|
||||
expect(theme.theme_fields.count).to eq(0)
|
||||
|
||||
put "/admin/themes/#{theme.id}.json",
|
||||
params: {
|
||||
theme: {
|
||||
theme_fields: [{ name: "scss", target: "common", value: "test" }],
|
||||
},
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
theme.reload
|
||||
expect(theme.theme_fields.count).to eq(1)
|
||||
theme_field = theme.theme_fields.first
|
||||
expect(theme_field.name).to eq("scss")
|
||||
expect(theme_field.target_id).to eq(Theme.targets[:common])
|
||||
expect(theme_field.value).to eq("test")
|
||||
end
|
||||
|
||||
it "doesn't create theme fields when they don't pass validation" do
|
||||
expect(theme.theme_fields.count).to eq(0)
|
||||
|
||||
put "/admin/themes/#{theme.id}.json",
|
||||
params: {
|
||||
theme: {
|
||||
theme_fields: [
|
||||
{ name: "scss", target: "common", value: "Na " * 1024**2 + "Batman!" },
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
expect(response.status).to eq(422)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json["errors"].first).to include("Value is too long")
|
||||
end
|
||||
|
||||
it "allows zip-imported theme fields to be locally edited" do
|
||||
r = RemoteTheme.create!(remote_url: "")
|
||||
theme.update!(remote_theme_id: r.id)
|
||||
|
|
Loading…
Reference in New Issue