application_setting.rb 22.8 KB
Newer Older
1 2
# frozen_string_literal: true

3
class ApplicationSetting < ApplicationRecord
4
  include CacheableAttributes
5
  include CacheMarkdownField
6
  include TokenAuthenticatable
7
  include ChronicDurationAttribute
Doug Stull's avatar
Doug Stull committed
8

9
  INSTANCE_REVIEW_MIN_USERS = 50
rpereira2's avatar
rpereira2 committed
10 11 12
  GRAFANA_URL_ERROR_MESSAGE = 'Please check your Grafana URL setting in ' \
    'Admin Area > Settings > Metrics and profiling > Metrics - Grafana'

Guillaume Grossetie's avatar
Guillaume Grossetie committed
13 14 15
  KROKI_URL_ERROR_MESSAGE = 'Please check your Kroki URL setting in ' \
    'Admin Area > Settings > General > Kroki'

16
  add_authentication_token_field :runners_registration_token, encrypted: -> { Feature.enabled?(:application_settings_tokens_optional_encryption) ? :optional : :required }
17
  add_authentication_token_field :health_check_access_token
18
  add_authentication_token_field :static_objects_external_storage_auth_token
19

20
  belongs_to :self_monitoring_project, class_name: "Project", foreign_key: 'instance_administration_project_id'
21
  belongs_to :push_rule
22 23
  alias_attribute :self_monitoring_project_id, :instance_administration_project_id

24 25 26
  belongs_to :instance_group, class_name: "Group", foreign_key: 'instance_administrators_group_id'
  alias_attribute :instance_group_id, :instance_administrators_group_id
  alias_attribute :instance_administrators_group, :instance_group
27

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
  def self.kroki_formats_attributes
    {
      blockdiag: {
        label: 'BlockDiag (includes BlockDiag, SeqDiag, ActDiag, NwDiag, PacketDiag and RackDiag)'
      },
      bpmn: {
        label: 'BPMN'
      },
      excalidraw: {
        label: 'Excalidraw'
      }
    }
  end

  store_accessor :kroki_formats, *ApplicationSetting.kroki_formats_attributes.keys, prefix: true
43

44 45 46 47 48 49
  # Include here so it can override methods from
  # `add_authentication_token_field`
  # We don't prepend for now because otherwise we'll need to
  # fix a lot of tests using allow_any_instance_of
  include ApplicationSettingImplementation

50 51 52
  serialize :restricted_visibility_levels # rubocop:disable Cop/ActiveRecordSerialize
  serialize :import_sources # rubocop:disable Cop/ActiveRecordSerialize
  serialize :disabled_oauth_sign_in_sources, Array # rubocop:disable Cop/ActiveRecordSerialize
53 54
  serialize :domain_allowlist, Array # rubocop:disable Cop/ActiveRecordSerialize
  serialize :domain_denylist, Array # rubocop:disable Cop/ActiveRecordSerialize
55
  serialize :repository_storages # rubocop:disable Cop/ActiveRecordSerialize
56
  serialize :asset_proxy_allowlist, Array # rubocop:disable Cop/ActiveRecordSerialize
57 58
  # See https://gitlab.com/gitlab-org/gitlab/-/issues/300916
  serialize :asset_proxy_whitelist, Array # rubocop:disable Cop/ActiveRecordSerialize
59

60 61 62 63 64
  cache_markdown_field :sign_in_text
  cache_markdown_field :help_page_text
  cache_markdown_field :shared_runners_text, pipeline: :plain_markdown
  cache_markdown_field :after_sign_up_text

65
  default_value_for :id, 1
66
  default_value_for :repository_storages_weighted, {}
67
  default_value_for :kroki_formats, {}
68

69 70
  chronic_duration_attr_writer :archive_builds_in_human_readable, :archive_builds_in_seconds

rpereira2's avatar
rpereira2 committed
71 72 73 74 75 76 77 78
  validates :grafana_url,
            system_hook_url: {
              blocked_message: "is blocked: %{exception_message}. " + GRAFANA_URL_ERROR_MESSAGE
            },
            if: :grafana_url_absolute?

  validate :validate_grafana_url

79 80
  validates :uuid, presence: true

81
  validates :outbound_local_requests_whitelist,
82 83 84
            length: { maximum: 1_000, message: N_('is too long (maximum is 1000 entries)') },
            allow_nil: false,
            qualified_domain_array: true
85

86
  validates :session_expire_delay,
87 88
            presence: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }
89

90 91 92 93 94 95
  validates :minimum_password_length,
            presence: true,
            numericality: { only_integer: true,
                            greater_than_or_equal_to: DEFAULT_MINIMUM_PASSWORD_LENGTH,
                            less_than_or_equal_to: Devise.password_length.max }

96
  validates :home_page_url,
97
            allow_blank: true,
98
            addressable_url: true,
99 100 101 102
            if: :home_page_url_column_exists?

  validates :help_page_support_url,
            allow_blank: true,
103
            addressable_url: true,
104
            if: :help_page_support_url_column_exists?
105

106 107 108 109 110
  validates :help_page_documentation_base_url,
            length: { maximum: 255, message: _("is too long (maximum is %{count} characters)") },
            allow_blank: true,
            addressable_url: true

111
  validates :after_sign_out_path,
112
            allow_blank: true,
113
            addressable_url: true
114

115
  validates :abuse_notification_email,
116
            devise_email: true,
117
            allow_blank: true
118

119
  validates :two_factor_grace_period,
120 121 122 123
            numericality: { greater_than_or_equal_to: 0 }

  validates :recaptcha_site_key,
            presence: true,
124
            if: :recaptcha_or_login_protection_enabled
125 126 127

  validates :recaptcha_private_key,
            presence: true,
128
            if: :recaptcha_or_login_protection_enabled
129

130 131 132 133
  validates :akismet_api_key,
            presence: true,
            if: :akismet_enabled

134 135 136 137 138 139 140 141 142 143
  validates :unique_ips_limit_per_user,
            numericality: { greater_than_or_equal_to: 1 },
            presence: true,
            if: :unique_ips_limit_enabled

  validates :unique_ips_limit_time_window,
            numericality: { greater_than_or_equal_to: 0 },
            presence: true,
            if: :unique_ips_limit_enabled

144
  validates :kroki_url,
145
            presence: { if: :kroki_enabled }
Guillaume Grossetie's avatar
Guillaume Grossetie committed
146

147
  validate :validate_kroki_url, if: :kroki_enabled
148

149 150
  validates :kroki_formats, json_schema: { filename: 'application_setting_kroki_formats' }

151 152 153 154
  validates :plantuml_url,
            presence: true,
            if: :plantuml_enabled

Felix Becker's avatar
Felix Becker committed
155 156 157 158
  validates :sourcegraph_url,
            presence: true,
            if: :sourcegraph_enabled

159 160 161 162 163
  validates :gitpod_url,
            presence: true,
            addressable_url: { enforce_sanitization: true },
            if: :gitpod_enabled

164 165 166 167 168
  validates :snowplow_collector_hostname,
            presence: true,
            hostname: true,
            if: :snowplow_enabled

169 170 171 172
  validates :max_attachment_size,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

173 174 175 176
  validates :max_artifacts_size,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

177 178 179 180
  validates :max_import_size,
            presence: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }

181 182
  validates :max_pages_size,
            presence: true,
183
            numericality: { only_integer: true, greater_than_or_equal_to: 0,
184 185
                            less_than: ::Gitlab::Pages::MAX_SIZE / 1.megabyte }

186
  validates :default_artifacts_expire_in, presence: true, duration: true
187

188
  validates :container_expiration_policies_enable_historic_entries,
189
            inclusion: { in: [true, false], message: _('must be a boolean value') }
190

191 192 193 194
  validates :container_registry_token_expire_delay,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

195 196
  validates :repository_storages, presence: true
  validate :check_repository_storages
197
  validate :check_repository_storages_weighted
198

199 200 201 202 203
  validates :auto_devops_domain,
            allow_blank: true,
            hostname: { allow_numeric_hostname: true, require_valid_tld: true },
            if: :auto_devops_enabled?

204
  validates :enabled_git_access_protocol,
205
            inclusion: { in: %w(ssh http), allow_blank: true }
206

207 208 209
  validates :domain_denylist,
            presence: { message: 'Domain denylist cannot be empty if denylist is enabled.' },
            if: :domain_denylist_enabled?
210

211 212 213 214 215 216
  validates :housekeeping_incremental_repack_period,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

  validates :housekeeping_full_repack_period,
            presence: true,
217
            numericality: { only_integer: true, greater_than_or_equal_to: :housekeeping_incremental_repack_period }
218 219 220

  validates :housekeeping_gc_period,
            presence: true,
221
            numericality: { only_integer: true, greater_than_or_equal_to: :housekeeping_full_repack_period }
222

223 224 225 226
  validates :terminal_max_session_time,
            presence: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }

227 228 229 230
  validates :polling_interval_multiplier,
            presence: true,
            numericality: { greater_than_or_equal_to: 0 }

231 232
  validates :gitaly_timeout_default,
            presence: true,
233
            if: :gitaly_timeout_default_changed?,
234 235 236 237 238
            numericality: {
              only_integer: true,
              greater_than_or_equal_to: 0,
              less_than_or_equal_to: Settings.gitlab.max_request_duration_seconds
            }
239 240 241

  validates :gitaly_timeout_medium,
            presence: true,
242
            if: :gitaly_timeout_medium_changed?,
243 244 245 246 247 248 249 250 251 252
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }
  validates :gitaly_timeout_medium,
            numericality: { less_than_or_equal_to: :gitaly_timeout_default },
            if: :gitaly_timeout_default
  validates :gitaly_timeout_medium,
            numericality: { greater_than_or_equal_to: :gitaly_timeout_fast },
            if: :gitaly_timeout_fast

  validates :gitaly_timeout_fast,
            presence: true,
253
            if: :gitaly_timeout_fast_changed?,
254 255 256 257 258
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }
  validates :gitaly_timeout_fast,
            numericality: { less_than_or_equal_to: :gitaly_timeout_default },
            if: :gitaly_timeout_default

259 260 261 262 263 264
  validates :diff_max_patch_bytes,
            presence: true,
            numericality: { only_integer: true,
                            greater_than_or_equal_to: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES,
                            less_than_or_equal_to: Gitlab::Git::Diff::MAX_PATCH_BYTES_UPPER_BOUND }

265 266
  validates :user_default_internal_regex, js_regex: true, allow_nil: true

267 268 269 270 271 272
  validates :personal_access_token_prefix,
            format: { with: /\A[a-zA-Z0-9_+=\/@:.-]+\z/,
                      message: _("can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'") },
            length: { maximum: 20, message: _('is too long (maximum is %{count} characters)') },
            allow_blank: true

273 274
  validates :commit_email_hostname, format: { with: /\A[^@]+\z/ }

275 276 277 278
  validates :archive_builds_in_seconds,
            allow_nil: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 1.day.seconds }

Jan Provaznik's avatar
Jan Provaznik committed
279 280 281 282
  validates :local_markdown_version,
            allow_nil: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than: 65536 }

283 284 285 286 287 288 289 290 291 292 293
  validates :asset_proxy_url,
            presence: true,
            allow_blank: false,
            url: true,
            if: :asset_proxy_enabled?

  validates :asset_proxy_secret_key,
            presence: true,
            allow_blank: false,
            if: :asset_proxy_enabled?

294 295 296 297 298 299 300
  validates :static_objects_external_storage_url,
            addressable_url: true, allow_blank: true

  validates :static_objects_external_storage_auth_token,
            presence: true,
            if: :static_objects_external_storage_url?

301 302 303 304
  validates :protected_paths,
            length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
            allow_nil: false

305 306 307
  validates :push_event_hooks_limit,
            numericality: { greater_than_or_equal_to: 0 }

308 309 310
  validates :push_event_activities_limit,
            numericality: { greater_than_or_equal_to: 0 }

311
  validates :snippet_size_limit, numericality: { only_integer: true, greater_than: 0 }
312
  validates :wiki_page_max_content_bytes, numericality: { only_integer: true, greater_than_or_equal_to: 1.kilobytes }
313

314
  validates :email_restrictions, untrusted_regexp: true
315

316 317
  validates :hashed_storage_enabled, inclusion: { in: [true], message: _("Hashed storage can't be disabled anymore for new projects") }

318 319 320
  validates :container_registry_delete_tags_service_timeout,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }

321 322 323
  validates :container_registry_cleanup_tags_service_max_list_size,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }

324 325 326
  validates :container_registry_expiration_policies_worker_capacity,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }

327 328 329
  validates :invisible_captcha_enabled,
            inclusion: { in: [true, false], message: _('must be a boolean value') }

330
  SUPPORTED_KEY_TYPES.each do |type|
Nick Thomas's avatar
Nick Thomas committed
331
    validates :"#{type}_key_restriction", presence: true, key_restriction: { type: type }
332 333
  end

Nick Thomas's avatar
Nick Thomas committed
334 335
  validates :allowed_key_types, presence: true

336
  validates_each :restricted_visibility_levels do |record, attr, value|
337
    value&.each do |level|
338
      unless Gitlab::VisibilityLevel.options.value?(level)
339
        record.errors.add(attr, _("'%{level}' is not a valid visibility level") % { level: level })
340 341 342 343
      end
    end
  end

344
  validates_each :import_sources do |record, attr, value|
345
    value&.each do |source|
346
      unless Gitlab::ImportSources.options.value?(source)
347
        record.errors.add(attr, _("'%{source}' is not a import source") % { source: source })
348 349 350 351
      end
    end
  end

352 353
  validate :terms_exist, if: :enforce_terms?

354 355 356 357 358
  validates :external_authorization_service_default_label,
            presence: true,
            if: :external_authorization_service_enabled

  validates :external_authorization_service_url,
359
            addressable_url: true, allow_blank: true,
360 361 362 363 364 365
            if: :external_authorization_service_enabled

  validates :external_authorization_service_timeout,
            numericality: { greater_than: 0, less_than_or_equal_to: 10 },
            if: :external_authorization_service_enabled

charlieablett's avatar
charlieablett committed
366 367 368 369 370 371 372
  validates :spam_check_endpoint_url,
            addressable_url: true, allow_blank: true

  validates :spam_check_endpoint_url,
            presence: true,
            if: :spam_check_endpoint_enabled

373 374 375 376
  validates :external_auth_client_key,
            presence: true,
            if: -> (setting) { setting.external_auth_client_cert.present? }

377 378 379 380 381 382 383 384 385 386
  validates :lets_encrypt_notification_email,
            devise_email: true,
            format: { without: /@example\.(com|org|net)\z/,
                      message: N_("Let's Encrypt does not accept emails on example.com") },
            allow_blank: true

  validates :lets_encrypt_notification_email,
            presence: true,
            if: :lets_encrypt_terms_of_service_accepted?

387 388 389 390 391 392
  validates :eks_integration_enabled,
            inclusion: { in: [true, false] }

  validates :eks_account_id,
            format: { with: Gitlab::Regex.aws_account_id_regex,
                      message: Gitlab::Regex.aws_account_id_message },
393
            if: :eks_integration_enabled?
394 395 396

  validates :eks_access_key_id,
            length: { in: 16..128 },
397
            if: -> (setting) { setting.eks_integration_enabled? && setting.eks_access_key_id.present? }
398 399 400

  validates :eks_secret_access_key,
            presence: true,
401
            if: -> (setting) { setting.eks_integration_enabled? && setting.eks_access_key_id.present? }
402

403 404 405 406 407 408
  validates_with X509CertificateCredentialsValidator,
                 certificate: :external_auth_client_cert,
                 pkey: :external_auth_client_key,
                 pass: :external_auth_client_key_pass,
                 if: -> (setting) { setting.external_auth_client_cert.present? }

409 410 411 412 413 414
  validates :default_ci_config_path,
    format: { without: %r{(\.{2}|\A/)},
              message: N_('cannot include leading slash or directory traversal.') },
    length: { maximum: 255 },
    allow_blank: true

415
  validates :issues_create_limit,
416 417 418 419
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }

  validates :raw_blob_request_limit,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }
420

421 422 423
  validates :ci_jwt_signing_key,
            rsa_key: true, allow_nil: true

424 425 426 427
  validates :rate_limiting_response_text,
            length: { maximum: 255, message: _('is too long (maximum is %{count} characters)') },
            allow_blank: true

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
  validates :throttle_unauthenticated_requests_per_period,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

  validates :throttle_unauthenticated_period_in_seconds,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

  validates :throttle_authenticated_api_requests_per_period,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

  validates :throttle_authenticated_api_period_in_seconds,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

  validates :throttle_authenticated_web_requests_per_period,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

  validates :throttle_authenticated_web_period_in_seconds,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

  validates :throttle_protected_paths_requests_per_period,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

  validates :throttle_protected_paths_period_in_seconds,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

460 461 462
  validates :notes_create_limit,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }

463 464 465 466
  validates :notes_create_limit_allowlist,
            length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
            allow_nil: false

467 468 469 470 471 472
  attr_encrypted :asset_proxy_secret_key,
                 mode: :per_attribute_iv,
                 key: Settings.attr_encrypted_db_key_base_truncated,
                 algorithm: 'aes-256-cbc',
                 insecure_mode: true

473 474 475 476 477 478 479 480
  private_class_method def self.encryption_options_base_truncated_aes_256_gcm
    {
      mode: :per_attribute_iv,
      key: Settings.attr_encrypted_db_key_base_truncated,
      algorithm: 'aes-256-gcm',
      encode: true
    }
  end
481

482 483 484 485 486 487 488 489 490 491
  attr_encrypted :external_auth_client_key, encryption_options_base_truncated_aes_256_gcm
  attr_encrypted :external_auth_client_key_pass, encryption_options_base_truncated_aes_256_gcm
  attr_encrypted :lets_encrypt_private_key, encryption_options_base_truncated_aes_256_gcm
  attr_encrypted :eks_secret_access_key, encryption_options_base_truncated_aes_256_gcm
  attr_encrypted :akismet_api_key, encryption_options_base_truncated_aes_256_gcm
  attr_encrypted :elasticsearch_aws_secret_access_key, encryption_options_base_truncated_aes_256_gcm
  attr_encrypted :recaptcha_private_key, encryption_options_base_truncated_aes_256_gcm
  attr_encrypted :recaptcha_site_key, encryption_options_base_truncated_aes_256_gcm
  attr_encrypted :slack_app_secret, encryption_options_base_truncated_aes_256_gcm
  attr_encrypted :slack_app_verification_token, encryption_options_base_truncated_aes_256_gcm
492
  attr_encrypted :ci_jwt_signing_key, encryption_options_base_truncated_aes_256_gcm
493
  attr_encrypted :secret_detection_token_revocation_token, encryption_options_base_truncated_aes_256_gcm
494
  attr_encrypted :cloud_license_auth_token, encryption_options_base_truncated_aes_256_gcm
495

496
  validates :disable_feed_token,
497
            inclusion: { in: [true, false], message: _('must be a boolean value') }
498

499
  before_validation :ensure_uuid!
500
  before_validation :coerce_repository_storages_weighted, if: :repository_storages_weighted_changed?
501

502
  before_save :ensure_runners_registration_token
503
  before_save :ensure_health_check_access_token
504

505
  after_commit do
506
    reset_memoized_terms
507
  end
508
  after_commit :expire_performance_bar_allowed_user_ids_cache, if: -> { previous_changes.key?('performance_bar_allowed_group_id') }
509

rpereira2's avatar
rpereira2 committed
510
  def validate_grafana_url
Guillaume Grossetie's avatar
Guillaume Grossetie committed
511
    validate_url(parsed_grafana_url, :grafana_url, GRAFANA_URL_ERROR_MESSAGE)
rpereira2's avatar
rpereira2 committed
512 513 514 515 516 517
  end

  def grafana_url_absolute?
    parsed_grafana_url&.absolute?
  end

Guillaume Grossetie's avatar
Guillaume Grossetie committed
518 519 520 521 522 523 524 525
  def validate_kroki_url
    validate_url(parsed_kroki_url, :kroki_url, KROKI_URL_ERROR_MESSAGE)
  end

  def kroki_url_absolute?
    parsed_kroki_url&.absolute?
  end

526 527
  def sourcegraph_url_is_com?
    !!(sourcegraph_url =~ /\Ahttps:\/\/(www\.)?sourcegraph\.com/)
528 529
  end

530 531 532 533 534 535 536 537
  def instance_review_permitted?
    users_count = Rails.cache.fetch('limited_users_count', expires_in: 1.day) do
      ::User.limit(INSTANCE_REVIEW_MIN_USERS + 1).count(:all)
    end

    users_count >= INSTANCE_REVIEW_MIN_USERS
  end

538
  def self.create_from_defaults
539 540
    check_schema!

541 542 543
    transaction(requires_new: true) do
      super
    end
544 545 546 547
  rescue ActiveRecord::RecordNotUnique
    # We already have an ApplicationSetting record, so just return it.
    current_without_cache
  end
548 549 550 551

  def self.find_or_create_without_cache
    current_without_cache || create_from_defaults
  end
552

553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
  # Due to the frequency with which settings are accessed, it is
  # likely that during a backup restore a running GitLab process
  # will insert a new `application_settings` row before the
  # constraints have been added to the table. This would add an
  # extra row with ID 1 and prevent the primary key constraint from
  # being added, which made ActiveRecord throw a
  # IrreversibleOrderError anytime the settings were accessed
  # (https://gitlab.com/gitlab-org/gitlab/-/issues/36405).  To
  # prevent this from happening, we do a sanity check that the
  # primary key constraint is present before inserting a new entry.
  def self.check_schema!
    return if ActiveRecord::Base.connection.primary_key(self.table_name).present?

    raise "The `#{self.table_name}` table is missing a primary key constraint in the database schema"
  end

569 570 571 572 573
  # By default, the backend is Rails.cache, which uses
  # ActiveSupport::Cache::RedisStore. Since loading ApplicationSetting
  # can cause a significant amount of load on Redis, let's cache it in
  # memory.
  def self.cache_backend
574
    Gitlab::ProcessMemoryCache.cache_backend
575
  end
576 577 578 579

  def recaptcha_or_login_protection_enabled
    recaptcha_enabled || login_recaptcha_protection_enabled
  end
580

581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
  kroki_formats_attributes.keys.each do |key|
    define_method :"kroki_formats_#{key}=" do |value|
      super(::Gitlab::Utils.to_boolean(value))
    end
  end

  def kroki_format_supported?(diagram_type)
    case diagram_type
    when 'excalidraw'
      return kroki_formats_excalidraw
    when 'bpmn'
      return kroki_formats_bpmn
    end

    return kroki_formats_blockdiag if ::Gitlab::Kroki::BLOCKDIAG_FORMATS.include?(diagram_type)

    ::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES.include?(diagram_type)
  end

rpereira2's avatar
rpereira2 committed
600 601 602 603 604
  private

  def parsed_grafana_url
    @parsed_grafana_url ||= Gitlab::Utils.parse_url(grafana_url)
  end
Guillaume Grossetie's avatar
Guillaume Grossetie committed
605 606

  def parsed_kroki_url
607 608 609 610 611 612
    @parsed_kroki_url ||= Gitlab::UrlBlocker.validate!(kroki_url, schemes: %w(http https), enforce_sanitization: true)[0]
  rescue Gitlab::UrlBlocker::BlockedUrlError => error
    self.errors.add(
      :kroki_url,
      "is not valid. #{error}"
    )
Guillaume Grossetie's avatar
Guillaume Grossetie committed
613 614 615 616 617
  end

  def validate_url(parsed_url, name, error_message)
    unless parsed_url
      self.errors.add(
Guillaume Grossetie's avatar
Guillaume Grossetie committed
618 619
        name,
        "must be a valid relative or absolute URL. #{error_message}"
Guillaume Grossetie's avatar
Guillaume Grossetie committed
620 621 622
      )
    end
  end
623
end
624

625
ApplicationSetting.prepend_if_ee('EE::ApplicationSetting')