discourse/lib/site_settings/validations.rb
Matt Palmer a98d2a8086
FEATURE: allow S3 ACLs to be disabled (#21769)
AWS recommends running buckets without ACLs, and to use resource policies to manage access control instead.
This is not a bad idea, because S3 ACLs are whack, and while resource policies are also whack, they're a more constrained form of whack.
Further, some compliance regimes get antsy if you don't go with the vendor's recommended settings, and arguing that you need to enable ACLs on a bucket just to store images in there is more hassle than it's worth.
The new site setting (s3_use_acls) cannot be disabled when secure
uploads is enabled -- the latter relies on private ACLs for security
at this point in time. We may want to reexamine this in future.
2023-06-06 15:47:40 +10:00

307 lines
9.8 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_enable_s3_inventory(new_val)
if new_val == "t" && !SiteSetting.Upload.enable_s3_uploads
validate_error :enable_s3_uploads_is_required
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