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 :user
|
||||||
belongs_to :color_scheme
|
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_settings, dependent: :destroy
|
||||||
has_many :theme_translation_overrides, dependent: :destroy
|
has_many :theme_translation_overrides, dependent: :destroy
|
||||||
has_many :child_theme_relation,
|
has_many :child_theme_relation,
|
||||||
|
@ -59,6 +59,7 @@ class Theme < ActiveRecord::Base
|
||||||
class_name: "ThemeField"
|
class_name: "ThemeField"
|
||||||
|
|
||||||
validate :component_validations
|
validate :component_validations
|
||||||
|
validate :validate_theme_fields
|
||||||
|
|
||||||
after_create :update_child_components
|
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?
|
errors.add(:base, I18n.t("themes.errors.component_no_default")) if default?
|
||||||
end
|
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!
|
def switch_to_component!
|
||||||
return if component
|
return if component
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ class ThemeField < ActiveRecord::Base
|
||||||
has_one :javascript_cache, dependent: :destroy
|
has_one :javascript_cache, dependent: :destroy
|
||||||
has_one :upload_reference, as: :target, dependent: :destroy
|
has_one :upload_reference, as: :target, dependent: :destroy
|
||||||
|
|
||||||
|
validates :value, { length: { maximum: 1024**2 } }
|
||||||
|
|
||||||
after_save do
|
after_save do
|
||||||
if self.type_id == ThemeField.types[:theme_upload_var] && saved_change_to_upload_id?
|
if self.type_id == ThemeField.types[:theme_upload_var] && saved_change_to_upload_id?
|
||||||
UploadReference.ensure_exist!(upload_ids: [self.upload_id], target: self)
|
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)
|
expect(response.status).to eq(403)
|
||||||
end
|
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
|
it "allows zip-imported theme fields to be locally edited" do
|
||||||
r = RemoteTheme.create!(remote_url: "")
|
r = RemoteTheme.create!(remote_url: "")
|
||||||
theme.update!(remote_theme_id: r.id)
|
theme.update!(remote_theme_id: r.id)
|
||||||
|
|
Loading…
Reference in New Issue