mirror of
https://github.com/discourse/discourse.git
synced 2024-12-12 16:03:49 +08:00
3e331b1725
Why this change? Firstly, note that this is not a security commit because this feature is still in development and should not be used anywhere. The reason we want to set a limit here is to greatly reduce the possibility of a DoS attack in the future via `ThemeSetting` where someone would set an arbituary large json string in `ThemeSetting#json_value` and causing the server to run out of resources trying to serialize/deserialize the value. What does this change do? Adds an ActiveRecord validation to ensure that the bytesize of the json string being stored is smaller than or equal to 0.5mb. We believe 0.5mb is a decent limit for now but we can review the limit in the future if we believe it is too small.
85 lines
2.1 KiB
Ruby
85 lines
2.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class ThemeSetting < ActiveRecord::Base
|
|
belongs_to :theme
|
|
|
|
has_many :upload_references, as: :target, dependent: :destroy
|
|
|
|
TYPES_ENUM =
|
|
Enum.new(integer: 0, float: 1, string: 2, bool: 3, list: 4, enum: 5, upload: 6, objects: 7)
|
|
|
|
MAXIMUM_JSON_VALUE_SIZE_BYTES = 0.5 * 1024 * 1024 # 0.5 MB
|
|
|
|
validates_presence_of :name, :theme
|
|
before_validation :objects_type_enabled
|
|
validates :data_type, inclusion: { in: TYPES_ENUM.values }
|
|
validate :json_value_size, if: -> { self.data_type == TYPES_ENUM[:objects] }
|
|
validates :name, length: { maximum: 255 }
|
|
|
|
after_save :clear_settings_cache
|
|
after_destroy :clear_settings_cache
|
|
|
|
after_save do
|
|
if self.data_type == ThemeSetting.types[:upload] && saved_change_to_value?
|
|
UploadReference.ensure_exist!(upload_ids: [self.value], target: self)
|
|
end
|
|
end
|
|
|
|
def clear_settings_cache
|
|
# All necessary caches will be cleared on next ensure_baked!
|
|
theme.settings_field&.invalidate_baked!
|
|
end
|
|
|
|
def self.types
|
|
TYPES_ENUM
|
|
end
|
|
|
|
def self.guess_type(value)
|
|
case value
|
|
when Integer
|
|
types[:integer]
|
|
when Float
|
|
types[:float]
|
|
when String
|
|
types[:string]
|
|
when TrueClass, FalseClass
|
|
types[:bool]
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def objects_type_enabled
|
|
if self.data_type == ThemeSetting.types[:objects] &&
|
|
!SiteSetting.experimental_objects_type_for_theme_settings
|
|
self.data_type = nil
|
|
end
|
|
end
|
|
|
|
def json_value_size
|
|
if json_value.to_json.size > MAXIMUM_JSON_VALUE_SIZE_BYTES
|
|
errors.add(
|
|
:json_value,
|
|
I18n.t(
|
|
"theme_settings.errors.json_value.too_large",
|
|
max_size_megabytes: MAXIMUM_JSON_VALUE_SIZE_BYTES / 1024 / 1024,
|
|
),
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
# == Schema Information
|
|
#
|
|
# Table name: theme_settings
|
|
#
|
|
# id :bigint not null, primary key
|
|
# name :string(255) not null
|
|
# data_type :integer not null
|
|
# value :text
|
|
# theme_id :integer not null
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# json_value :jsonb
|
|
#
|