mirror of
https://github.com/discourse/discourse.git
synced 2025-01-31 13:41:03 +08:00
8cf4ed5f88
This commit introduces a hidden `s3_inventory_bucket` site setting which replaces the `enable_s3_inventory` and `s3_configure_inventory_policy` site setting. The reason `enable_s3_inventory` and `s3_configure_inventory_policy` site settings are removed is because this feature has technically been broken since it was introduced. When the `enable_s3_inventory` feature is turned on, the app will because configure a daily inventory policy for the `s3_upload_bucket` bucket and store the inventories under a prefix in the bucket. The problem here is that once the inventories are created, there is nothing cleaning up all these inventories so whoever that has enabled this feature would have been paying the cost of storing a whole bunch of inventory files which are never used. Given that we have not received any complains about inventory files inflating S3 storage costs, we think that it is very likely that this feature is no longer being used and we are looking to drop support for this feature in the not too distance future. For now, we will still support a hidden `s3_inventory_bucket` site setting which site administrators can configure via the `DISCOURSE_S3_INVENTORY_BUCKET` env.
301 lines
9.6 KiB
Ruby
301 lines
9.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module SiteSettings
|
|
end
|
|
|
|
module SiteSettings::Validations
|
|
PROHIBITED_USER_AGENT_STRINGS = %w[
|
|
apple
|
|
windows
|
|
linux
|
|
ubuntu
|
|
gecko
|
|
firefox
|
|
chrome
|
|
safari
|
|
applewebkit
|
|
webkit
|
|
mozilla
|
|
macintosh
|
|
khtml
|
|
intel
|
|
osx
|
|
os\ x
|
|
iphone
|
|
ipad
|
|
mac
|
|
]
|
|
|
|
def validate_error(key, opts = {})
|
|
raise Discourse::InvalidParameters.new(I18n.t("errors.site_settings.#{key}", opts))
|
|
end
|
|
|
|
def validate_category_ids(category_ids)
|
|
category_ids = category_ids.split("|").map(&:to_i).to_set
|
|
if Category.where(id: category_ids).count != category_ids.size
|
|
validate_error :invalid_category_id
|
|
end
|
|
category_ids
|
|
end
|
|
|
|
def validate_default_categories(category_ids, default_categories_selected)
|
|
if (category_ids & default_categories_selected).size > 0
|
|
validate_error :default_categories_already_selected
|
|
end
|
|
end
|
|
|
|
def validate_default_categories_watching(new_val)
|
|
category_ids = validate_category_ids(new_val)
|
|
|
|
default_categories_selected = [
|
|
SiteSetting.default_categories_tracking.split("|"),
|
|
SiteSetting.default_categories_muted.split("|"),
|
|
SiteSetting.default_categories_watching_first_post.split("|"),
|
|
SiteSetting.default_categories_normal.split("|"),
|
|
].flatten.map(&:to_i).to_set
|
|
|
|
validate_default_categories(category_ids, default_categories_selected)
|
|
end
|
|
|
|
def validate_default_categories_tracking(new_val)
|
|
category_ids = validate_category_ids(new_val)
|
|
|
|
default_categories_selected = [
|
|
SiteSetting.default_categories_watching.split("|"),
|
|
SiteSetting.default_categories_muted.split("|"),
|
|
SiteSetting.default_categories_watching_first_post.split("|"),
|
|
SiteSetting.default_categories_normal.split("|"),
|
|
].flatten.map(&:to_i).to_set
|
|
|
|
validate_default_categories(category_ids, default_categories_selected)
|
|
end
|
|
|
|
def validate_default_categories_muted(new_val)
|
|
category_ids = validate_category_ids(new_val)
|
|
|
|
default_categories_selected = [
|
|
SiteSetting.default_categories_watching.split("|"),
|
|
SiteSetting.default_categories_tracking.split("|"),
|
|
SiteSetting.default_categories_watching_first_post.split("|"),
|
|
SiteSetting.default_categories_normal.split("|"),
|
|
].flatten.map(&:to_i).to_set
|
|
|
|
validate_default_categories(category_ids, default_categories_selected)
|
|
end
|
|
|
|
def validate_default_categories_watching_first_post(new_val)
|
|
category_ids = validate_category_ids(new_val)
|
|
|
|
default_categories_selected = [
|
|
SiteSetting.default_categories_watching.split("|"),
|
|
SiteSetting.default_categories_tracking.split("|"),
|
|
SiteSetting.default_categories_muted.split("|"),
|
|
SiteSetting.default_categories_normal.split("|"),
|
|
].flatten.map(&:to_i).to_set
|
|
|
|
validate_default_categories(category_ids, default_categories_selected)
|
|
end
|
|
|
|
def validate_default_categories_normal(new_val)
|
|
category_ids = validate_category_ids(new_val)
|
|
|
|
default_categories_selected = [
|
|
SiteSetting.default_categories_watching.split("|"),
|
|
SiteSetting.default_categories_tracking.split("|"),
|
|
SiteSetting.default_categories_muted.split("|"),
|
|
SiteSetting.default_categories_watching_first_post.split("|"),
|
|
].flatten.map(&:to_i).to_set
|
|
|
|
validate_default_categories(category_ids, default_categories_selected)
|
|
end
|
|
|
|
def validate_default_tags(tag_names, default_tags_selected)
|
|
validate_error :default_tags_already_selected if (tag_names & default_tags_selected).size > 0
|
|
end
|
|
|
|
def validate_default_tags_watching(new_val)
|
|
tag_names = new_val.split("|").to_set
|
|
|
|
default_tags_selected = [
|
|
SiteSetting.default_tags_tracking.split("|"),
|
|
SiteSetting.default_tags_muted.split("|"),
|
|
SiteSetting.default_tags_watching_first_post.split("|"),
|
|
].flatten.to_set
|
|
|
|
validate_default_tags(tag_names, default_tags_selected)
|
|
end
|
|
|
|
def validate_default_tags_tracking(new_val)
|
|
tag_names = new_val.split("|").to_set
|
|
|
|
default_tags_selected = [
|
|
SiteSetting.default_tags_watching.split("|"),
|
|
SiteSetting.default_tags_muted.split("|"),
|
|
SiteSetting.default_tags_watching_first_post.split("|"),
|
|
].flatten.to_set
|
|
|
|
validate_default_tags(tag_names, default_tags_selected)
|
|
end
|
|
|
|
def validate_default_tags_muted(new_val)
|
|
tag_names = new_val.split("|").to_set
|
|
|
|
default_tags_selected = [
|
|
SiteSetting.default_tags_watching.split("|"),
|
|
SiteSetting.default_tags_tracking.split("|"),
|
|
SiteSetting.default_tags_watching_first_post.split("|"),
|
|
].flatten.to_set
|
|
|
|
validate_default_tags(tag_names, default_tags_selected)
|
|
end
|
|
|
|
def validate_default_tags_watching_first_post(new_val)
|
|
tag_names = new_val.split("|").to_set
|
|
|
|
default_tags_selected = [
|
|
SiteSetting.default_tags_watching.split("|"),
|
|
SiteSetting.default_tags_tracking.split("|"),
|
|
SiteSetting.default_tags_muted.split("|"),
|
|
].flatten.to_set
|
|
|
|
validate_default_tags(tag_names, default_tags_selected)
|
|
end
|
|
|
|
def validate_enable_s3_uploads(new_val)
|
|
return if new_val == "f"
|
|
validate_error :cannot_enable_s3_uploads_when_s3_enabled_globally if GlobalSetting.use_s3?
|
|
validate_error :s3_upload_bucket_is_required if SiteSetting.s3_upload_bucket.blank?
|
|
end
|
|
|
|
def validate_secure_uploads(new_val)
|
|
if new_val == "t" && (!SiteSetting.Upload.enable_s3_uploads || !SiteSetting.s3_use_acls)
|
|
validate_error :secure_uploads_requirements
|
|
end
|
|
end
|
|
|
|
def validate_s3_use_acls(new_val)
|
|
validate_error :s3_use_acls_requirements if new_val == "f" && SiteSetting.secure_uploads
|
|
end
|
|
|
|
def validate_enable_page_publishing(new_val)
|
|
validate_error :page_publishing_requirements if new_val == "t" && SiteSetting.secure_uploads?
|
|
end
|
|
|
|
def validate_share_quote_buttons(new_val)
|
|
if new_val.include?("facebook") && SiteSetting.facebook_app_id.blank?
|
|
validate_error :share_quote_facebook_requirements
|
|
end
|
|
end
|
|
|
|
def validate_backup_location(new_val)
|
|
return unless new_val == BackupLocationSiteSetting::S3
|
|
if SiteSetting.s3_backup_bucket.blank?
|
|
validate_error(:s3_backup_requires_s3_settings, setting_name: "s3_backup_bucket")
|
|
end
|
|
|
|
unless SiteSetting.s3_use_iam_profile
|
|
if SiteSetting.s3_access_key_id.blank?
|
|
validate_error(:s3_backup_requires_s3_settings, setting_name: "s3_access_key_id")
|
|
end
|
|
if SiteSetting.s3_secret_access_key.blank?
|
|
validate_error(:s3_backup_requires_s3_settings, setting_name: "s3_secret_access_key")
|
|
end
|
|
end
|
|
end
|
|
|
|
def validate_s3_upload_bucket(new_val)
|
|
validate_bucket_setting("s3_upload_bucket", new_val, SiteSetting.s3_backup_bucket)
|
|
|
|
if new_val.blank? && SiteSetting.enable_s3_uploads?
|
|
validate_error(:s3_upload_bucket_is_required, setting_name: "s3_upload_bucket")
|
|
end
|
|
end
|
|
|
|
def validate_s3_backup_bucket(new_val)
|
|
validate_bucket_setting("s3_backup_bucket", SiteSetting.s3_upload_bucket, new_val)
|
|
end
|
|
|
|
def validate_enforce_second_factor(new_val)
|
|
if new_val != "no" && SiteSetting.enable_discourse_connect?
|
|
return validate_error :second_factor_cannot_be_enforced_with_discourse_connect_enabled
|
|
end
|
|
if new_val == "all" && Discourse.enabled_auth_providers.count > 0
|
|
auth_provider_names = Discourse.enabled_auth_providers.map(&:name).join(", ")
|
|
return(
|
|
validate_error(
|
|
:second_factor_cannot_enforce_with_socials,
|
|
auth_provider_names: auth_provider_names,
|
|
)
|
|
)
|
|
end
|
|
return if SiteSetting.enable_local_logins
|
|
return if new_val == "no"
|
|
validate_error :second_factor_cannot_be_enforced_with_disabled_local_login
|
|
end
|
|
|
|
def validate_enable_local_logins(new_val)
|
|
return if new_val == "t"
|
|
return if SiteSetting.enforce_second_factor == "no"
|
|
validate_error :local_login_cannot_be_disabled_if_second_factor_enforced
|
|
end
|
|
|
|
def validate_cors_origins(new_val)
|
|
return if new_val.blank?
|
|
return if new_val.split("|").none?(%r{/\z})
|
|
validate_error :cors_origins_should_not_have_trailing_slash
|
|
end
|
|
|
|
def validate_slow_down_crawler_user_agents(new_val)
|
|
return if new_val.blank?
|
|
|
|
new_val
|
|
.downcase
|
|
.split("|")
|
|
.each do |crawler|
|
|
if crawler.size < 3
|
|
validate_error(:slow_down_crawler_user_agent_must_be_at_least_3_characters)
|
|
end
|
|
if PROHIBITED_USER_AGENT_STRINGS.any? { |c| c.include?(crawler) }
|
|
validate_error(
|
|
:slow_down_crawler_user_agent_cannot_be_popular_browsers,
|
|
values: PROHIBITED_USER_AGENT_STRINGS.join(I18n.t("word_connector.comma")),
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
def validate_strip_image_metadata(new_val)
|
|
return if new_val == "t"
|
|
return if SiteSetting.composer_media_optimization_image_enabled == false
|
|
validate_error :strip_image_metadata_cannot_be_disabled_if_composer_media_optimization_image_enabled
|
|
end
|
|
|
|
def validate_twitter_summary_large_image(new_val)
|
|
return if new_val.blank?
|
|
return if !Upload.exists?(id: new_val, extension: "svg")
|
|
validate_error :twitter_summary_large_image_no_svg
|
|
end
|
|
|
|
private
|
|
|
|
def validate_bucket_setting(setting_name, upload_bucket, backup_bucket)
|
|
return if upload_bucket.blank? || backup_bucket.blank?
|
|
|
|
backup_bucket_name, backup_prefix = split_s3_bucket(backup_bucket)
|
|
upload_bucket_name, upload_prefix = split_s3_bucket(upload_bucket)
|
|
|
|
return if backup_bucket_name != upload_bucket_name
|
|
|
|
if backup_prefix == upload_prefix || backup_prefix.blank? ||
|
|
upload_prefix&.start_with?(backup_prefix)
|
|
validate_error(:s3_bucket_reused, setting_name: setting_name)
|
|
end
|
|
end
|
|
|
|
def split_s3_bucket(s3_bucket)
|
|
bucket_name, prefix = s3_bucket.downcase.split("/", 2)
|
|
prefix&.chomp!("/")
|
|
[bucket_name, prefix]
|
|
end
|
|
end
|