diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-06 03:08:24 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-06 03:08:24 +0300 |
commit | bdad4dd5dabec7a0a611d5241fa2d56359884420 (patch) | |
tree | 333f5147c450cf0849823c7c42c7e52d70a0af74 /lib | |
parent | 96e23b2017cbe56969771960f6c274c5d3599397 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib')
19 files changed, 274 insertions, 77 deletions
diff --git a/lib/api/concerns/packages/npm_endpoints.rb b/lib/api/concerns/packages/npm_endpoints.rb index afbde296161..74ad3bb296f 100644 --- a/lib/api/concerns/packages/npm_endpoints.rb +++ b/lib/api/concerns/packages/npm_endpoints.rb @@ -27,6 +27,11 @@ module API end helpers do + params :package_name do + requires :package_name, type: String, file_path: true, desc: 'Package name', + documentation: { example: 'mypackage' } + end + def redirect_or_present_audit_report redirect_registry_request( forward_to_registry: true, @@ -172,7 +177,7 @@ module API tags %w[npm_packages] end params do - requires :package_name, type: String, desc: 'Package name' + use :package_name end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true get '*package_name', format: false, requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do diff --git a/lib/banzai/filter/dollar_math_post_filter.rb b/lib/banzai/filter/dollar_math_post_filter.rb index 94d1b4bcb48..b3c230131e4 100644 --- a/lib/banzai/filter/dollar_math_post_filter.rb +++ b/lib/banzai/filter/dollar_math_post_filter.rb @@ -17,19 +17,21 @@ module Banzai # encoded and will therefore not interfere with the detection of the dollar syntax. # Corresponds to the "$...$" syntax - DOLLAR_INLINE_PATTERN = %r{ - (?<matched>\$(?<math>(?:\S[^$\n]*?\S|[^$\s]))\$)(?:[^\d]|$) - }x.freeze + DOLLAR_INLINE_UNTRUSTED = + '(?P<matched>\$(?P<math>(?:\S[^$\n]*?\S|[^$\s]))\$)(?:[^\d]|$)' + DOLLAR_INLINE_UNTRUSTED_REGEX = + Gitlab::UntrustedRegexp.new(DOLLAR_INLINE_UNTRUSTED, multiline: false).freeze # Corresponds to the "$$...$$" syntax - DOLLAR_DISPLAY_INLINE_PATTERN = %r{ - (?<matched>\$\$\ *(?<math>[^$\n]+?)\ *\$\$) - }x.freeze + DOLLAR_DISPLAY_INLINE_UNTRUSTED = + '(?P<matched>\$\$\ *(?P<math>[^$\n]+?)\ *\$\$)' + DOLLAR_DISPLAY_INLINE_UNTRUSTED_REGEX = + Gitlab::UntrustedRegexp.new(DOLLAR_DISPLAY_INLINE_UNTRUSTED, multiline: false).freeze # Order dependent. Handle the `$$` syntax before the `$` syntax DOLLAR_MATH_PIPELINE = [ - { pattern: DOLLAR_DISPLAY_INLINE_PATTERN, style: :display }, - { pattern: DOLLAR_INLINE_PATTERN, style: :inline } + { pattern: DOLLAR_DISPLAY_INLINE_UNTRUSTED_REGEX, style: :display }, + { pattern: DOLLAR_INLINE_UNTRUSTED_REGEX, style: :inline } ].freeze # Do not recognize math inside these tags @@ -46,16 +48,18 @@ module Banzai next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS) node_html = node.to_html - next unless node_html.match?(DOLLAR_INLINE_PATTERN) || - node_html.match?(DOLLAR_DISPLAY_INLINE_PATTERN) + next unless DOLLAR_INLINE_UNTRUSTED_REGEX.match?(node_html) || + DOLLAR_DISPLAY_INLINE_UNTRUSTED_REGEX.match?(node_html) temp_doc = Nokogiri::HTML.fragment(node_html) DOLLAR_MATH_PIPELINE.each do |pipeline| temp_doc.xpath('child::text()').each do |temp_node| html = temp_node.to_html - temp_node.content.scan(pipeline[:pattern]).each do |matched, math| - html.sub!(matched, math_html(math: math, style: pipeline[:style])) + + pipeline[:pattern].scan(temp_node.content).each do |match| + math = pipeline[:pattern].extract_named_group(:math, match) + html.sub!(match.first, math_html(math: math, style: pipeline[:style])) end temp_node.replace(html) diff --git a/lib/banzai/filter/front_matter_filter.rb b/lib/banzai/filter/front_matter_filter.rb index c788137e122..53683ce07d9 100644 --- a/lib/banzai/filter/front_matter_filter.rb +++ b/lib/banzai/filter/front_matter_filter.rb @@ -6,13 +6,13 @@ module Banzai def call lang_mapping = Gitlab::FrontMatter::DELIM_LANG - html.sub(Gitlab::FrontMatter::PATTERN) do |_match| - lang = $~[:lang].presence || lang_mapping[$~[:delim]] + Gitlab::FrontMatter::PATTERN_UNTRUSTED_REGEX.replace_gsub(html) do |match| + lang = match[:lang].presence || lang_mapping[match[:delim]] - before = $~[:before] - before = "\n#{before}" if $~[:encoding].presence + before = match[:before] + before = "\n#{before}" if match[:encoding].presence - "#{before}```#{lang}:frontmatter\n#{$~[:front_matter]}```\n" + "#{before}```#{lang}:frontmatter\n#{match[:front_matter]}```\n" end end end diff --git a/lib/banzai/filter/inline_diff_filter.rb b/lib/banzai/filter/inline_diff_filter.rb index e47ff15e7b7..fc77984f135 100644 --- a/lib/banzai/filter/inline_diff_filter.rb +++ b/lib/banzai/filter/inline_diff_filter.rb @@ -6,6 +6,14 @@ module Banzai class InlineDiffFilter < HTML::Pipeline::Filter IGNORED_ANCESTOR_TAGS = %w(pre code tt).to_set + INLINE_DIFF_DELETION_UNTRUSTED = '(?:\[\-(.*?)\-\]|\{\-(.*?)\-\})' + INLINE_DIFF_DELETION_UNTRUSTED_REGEX = + Gitlab::UntrustedRegexp.new(INLINE_DIFF_DELETION_UNTRUSTED, multiline: false).freeze + + INLINE_DIFF_ADDITION_UNTRUSTED = '(?:\[\+(.*?)\+\]|\{\+(.*?)\+\})' + INLINE_DIFF_ADDITION_UNTRUSTED_REGEX = + Gitlab::UntrustedRegexp.new(INLINE_DIFF_ADDITION_UNTRUSTED, multiline: false).freeze + def call doc.xpath('descendant-or-self::text()').each do |node| next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS) @@ -21,8 +29,13 @@ module Banzai end def inline_diff_filter(text) - html_content = text.gsub(/(?:\[\-(.*?)\-\]|\{\-(.*?)\-\})/, '<span class="idiff left right deletion">\1\2</span>') - html_content.gsub(/(?:\[\+(.*?)\+\]|\{\+(.*?)\+\})/, '<span class="idiff left right addition">\1\2</span>') + html_content = INLINE_DIFF_DELETION_UNTRUSTED_REGEX.replace_gsub(text) do |match| + %(<span class="idiff left right deletion">#{match[1]}#{match[2]}</span>) + end + + INLINE_DIFF_ADDITION_UNTRUSTED_REGEX.replace_gsub(html_content) do |match| + %(<span class="idiff left right addition">#{match[1]}#{match[2]}</span>) + end end end end diff --git a/lib/extracts_ref.rb b/lib/extracts_ref.rb index 49c9772f760..5f73b474956 100644 --- a/lib/extracts_ref.rb +++ b/lib/extracts_ref.rb @@ -157,11 +157,11 @@ module ExtractsRef end def ambiguous_ref?(project, ref) + return false unless ref return true if project.repository.ambiguous_ref?(ref) + return false unless ref.starts_with?(%r{(refs|heads|tags)/}) - return false unless ref&.starts_with?('refs/') - - unprefixed_ref = ref.sub(%r{^refs/(heads|tags)/}, '') + unprefixed_ref = ref.sub(%r{^(refs/)?(heads|tags)/}, '') project.repository.commit(unprefixed_ref).present? end end diff --git a/lib/gitlab/background_migration/mailers/views/unconfirm_mailer/unconfirm_notification_email.html.haml b/lib/gitlab/background_migration/mailers/views/unconfirm_mailer/unconfirm_notification_email.html.haml index d8f7466a1ca..53d64fdf488 100644 --- a/lib/gitlab/background_migration/mailers/views/unconfirm_mailer/unconfirm_notification_email.html.haml +++ b/lib/gitlab/background_migration/mailers/views/unconfirm_mailer/unconfirm_notification_email.html.haml @@ -3,16 +3,16 @@ Dear GitLab user, %p - As part of our commitment to keeping GitLab secure, we have identified and addressed a vulnerability in GitLab that allowed some users to bypass the email verification process in a #{link_to("recent security release", "https://about.gitlab.com/releases/2020/05/27/security-release-13-0-1-released", target: '_blank')}. + As part of our commitment to keeping GitLab secure, we have identified and addressed a vulnerability in GitLab that allowed some users to bypass the email verification process in a #{link_to('recent security release', 'https://about.gitlab.com/releases/2020/05/27/security-release-13-0-1-released', target: '_blank')}. %p As a precautionary measure, you will need to re-verify some of your account's email addresses before continuing to use GitLab. Sorry for the inconvenience! %p - We have already sent the re-verification email with a subject line of "Confirmation instructions" from #{@verification_from_mail}. Please feel free to contribute any questions or comments to #{link_to("this issue", "https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/7942", target: '_blank')}. + We have already sent the re-verification email with a subject line of 'Confirmation instructions' from #{@verification_from_mail}. Please feel free to contribute any questions or comments to #{link_to('this issue', 'https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/7942', target: '_blank')}. %p - If you are not "#{@user.username}", please #{link_to 'report this to our administrator', new_abuse_report_url(user_id: @user.id)} + If you are not "#{@user.username}", please report abuse from the user's #{link_to('profile page', user_url(@user.id), target: '_blank', rel: 'noopener noreferrer')}. #{link_to('Learn more.', help_page_url('user/report_abuse', anchor: 'report-abuse-from-the-users-profile-page', target: '_blank', rel: 'noopener noreferrer'))} %p Thank you for being a GitLab user! diff --git a/lib/gitlab/background_migration/mailers/views/unconfirm_mailer/unconfirm_notification_email.text.erb b/lib/gitlab/background_migration/mailers/views/unconfirm_mailer/unconfirm_notification_email.text.erb index d20af9b9803..81ef68e99f0 100644 --- a/lib/gitlab/background_migration/mailers/views/unconfirm_mailer/unconfirm_notification_email.text.erb +++ b/lib/gitlab/background_migration/mailers/views/unconfirm_mailer/unconfirm_notification_email.text.erb @@ -9,6 +9,8 @@ As a precautionary measure, you will need to re-verify some of your account's em We have already sent the re-verification email with a subject line of "Confirmation instructions" from <%= @verification_from_mail %>. Please feel free to contribute any questions or comments to this issue: https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/7942 -If you are not "<%= @user.username %>", please report this to our administrator. Report link: <%= new_abuse_report_url(user_id: @user.id) %> +If you are not "<%= @user.username %>", please report abuse from the user's profile page: <%= user_url(@user.id) %>. + +Learn more: <%= help_page_url('user/report_abuse', anchor: 'report-abuse-from-the-users-profile-page') %> Thank you for being a GitLab user! diff --git a/lib/gitlab/checks/tag_check.rb b/lib/gitlab/checks/tag_check.rb index 007a775eaf5..5c43ca946b5 100644 --- a/lib/gitlab/checks/tag_check.rb +++ b/lib/gitlab/checks/tag_check.rb @@ -10,7 +10,8 @@ module Gitlab 'Only a project maintainer or owner can delete a protected tag.', delete_protected_tag_non_web: 'You can only delete protected tags using the web interface.', create_protected_tag: 'You are not allowed to create this tag as it is protected.', - default_branch_collision: 'You cannot use default branch name to create a tag' + default_branch_collision: 'You cannot use default branch name to create a tag', + prohibited_tag_name: 'You cannot create a tag with a prohibited pattern.' }.freeze LOG_MESSAGES = { @@ -29,11 +30,20 @@ module Gitlab end default_branch_collision_check + prohibited_tag_checks protected_tag_checks end private + def prohibited_tag_checks + return if deletion? + + if tag_name.start_with?("refs/tags/") # rubocop: disable Style/GuardClause + raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name] + end + end + def protected_tag_checks logger.log_timed(LOG_MESSAGES[__method__]) do return unless ProtectedTag.protected?(project, tag_name) # rubocop:disable Cop/AvoidReturnFromBlocks diff --git a/lib/gitlab/ci/artifacts/decompressed_artifact_size_validator.rb b/lib/gitlab/ci/artifacts/decompressed_artifact_size_validator.rb new file mode 100644 index 00000000000..04930da5e30 --- /dev/null +++ b/lib/gitlab/ci/artifacts/decompressed_artifact_size_validator.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Artifacts + class DecompressedArtifactSizeValidator + DEFAULT_MAX_BYTES = 4.gigabytes.freeze + + FILE_FORMAT_VALIDATORS = { + gzip: ::Gitlab::Ci::DecompressedGzipSizeValidator + }.freeze + + FileDecompressionError = Class.new(StandardError) + + def initialize(file:, file_format:, max_bytes: DEFAULT_MAX_BYTES) + @file = file + @file_path = file&.path + @file_format = file_format + @max_bytes = max_bytes + end + + def validate! + validator_class = FILE_FORMAT_VALIDATORS[file_format.to_sym] + + return if file_path.nil? + return if validator_class.nil? + + if file.respond_to?(:object_store) && file.object_store == ObjectStorage::Store::REMOTE + return if valid_on_storage?(validator_class) + elsif validator_class.new(archive_path: file_path, max_bytes: max_bytes).valid? + return + end + + raise(FileDecompressionError, 'File decompression error') + end + + private + + attr_reader :file_path, :file, :file_format, :max_bytes + + def valid_on_storage?(validator_class) + temp_filename = "#{SecureRandom.uuid}.gz" + + is_valid = false + Tempfile.open(temp_filename, '/tmp') do |tempfile| + tempfile.binmode + ::Faraday.get(file.url) do |req| + req.options.on_data = proc { |chunk, _| tempfile.write(chunk) } + end + + is_valid = validator_class.new(archive_path: tempfile.path, max_bytes: max_bytes).valid? + tempfile.unlink + end + + is_valid + end + end + end + end +end diff --git a/lib/gitlab/ci/config/yaml/loader.rb b/lib/gitlab/ci/config/yaml/loader.rb index 7277981f1e3..924a1f2e46b 100644 --- a/lib/gitlab/ci/config/yaml/loader.rb +++ b/lib/gitlab/ci/config/yaml/loader.rb @@ -34,18 +34,12 @@ module Gitlab def load! ensure_custom_tags - if project.present? && ::Feature.enabled?(:ci_multi_doc_yaml, project) - ::Gitlab::Config::Loader::MultiDocYaml.new( - content, - max_documents: MAX_DOCUMENTS, - additional_permitted_classes: AVAILABLE_TAGS, - reject_empty: true - ).load! - else - ::Gitlab::Config::Loader::Yaml - .new(content, additional_permitted_classes: AVAILABLE_TAGS) - .load! - end + ::Gitlab::Config::Loader::MultiDocYaml.new( + content, + max_documents: MAX_DOCUMENTS, + additional_permitted_classes: AVAILABLE_TAGS, + reject_empty: true + ).load! end end end diff --git a/lib/gitlab/ci/config/yaml/result.rb b/lib/gitlab/ci/config/yaml/result.rb index 33f9a454106..6b53adc3a57 100644 --- a/lib/gitlab/ci/config/yaml/result.rb +++ b/lib/gitlab/ci/config/yaml/result.rb @@ -31,7 +31,7 @@ module Gitlab def content return @config.last if has_header? - @config.first + @config.first || {} end end end diff --git a/lib/gitlab/ci/decompressed_gzip_size_validator.rb b/lib/gitlab/ci/decompressed_gzip_size_validator.rb new file mode 100644 index 00000000000..9b7b5f0dd66 --- /dev/null +++ b/lib/gitlab/ci/decompressed_gzip_size_validator.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + class DecompressedGzipSizeValidator + DEFAULT_MAX_BYTES = 4.gigabytes.freeze + TIMEOUT_LIMIT = 210.seconds + + ServiceError = Class.new(StandardError) + + def initialize(archive_path:, max_bytes: DEFAULT_MAX_BYTES) + @archive_path = archive_path + @max_bytes = max_bytes + end + + def valid? + validate + end + + private + + def validate + pgrps = nil + valid_archive = true + + validate_archive_path + + Timeout.timeout(TIMEOUT_LIMIT) do + stderr_r, stderr_w = IO.pipe + stdout, wait_threads = Open3.pipeline_r(*command, pgroup: true, err: stderr_w) + + # When validation is performed on a small archive (e.g. 100 bytes) + # `wait_thr` finishes before we can get process group id. Do not + # raise exception in this scenario. + pgrps = wait_threads.map do |wait_thr| + Process.getpgid(wait_thr[:pid]) + rescue Errno::ESRCH + nil + end + pgrps.compact! + + status = wait_threads.last.value + + if status.success? + result = stdout.readline + + valid_archive = false if result.to_i > max_bytes + else + valid_archive = false + end + + ensure + stdout.close + stderr_w.close + stderr_r.close + end + + valid_archive + rescue StandardError + pgrps.each { |pgrp| Process.kill(-1, pgrp) } if pgrps + + false + end + + def validate_archive_path + Gitlab::PathTraversal.check_path_traversal!(archive_path) + + raise(ServiceError, 'Archive path is a symlink') if File.lstat(archive_path).symlink? + raise(ServiceError, 'Archive path is not a file') unless File.file?(archive_path) + end + + def command + [['gzip', '-dc', archive_path], ['wc', '-c']] + end + + attr_reader :archive_path, :max_bytes + end + end +end diff --git a/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml index 792bd7f666b..f10011ab23b 100644 --- a/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml @@ -26,11 +26,12 @@ variables: # Setting this variable will affect all Security templates # (SAST, Dependency Scanning, ...) SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products" + DAST_IMAGE_SUFFIX: "" dast: stage: dast image: - name: "$SECURE_ANALYZERS_PREFIX/dast:$DAST_VERSION" + name: "$SECURE_ANALYZERS_PREFIX/dast:$DAST_VERSION$DAST_IMAGE_SUFFIX" variables: GIT_STRATEGY: none allow_failure: true @@ -57,6 +58,11 @@ dast: $REVIEW_DISABLED == '1' when: never - if: $CI_COMMIT_BRANCH && + $CI_GITLAB_FIPS_MODE == "true" && + $GITLAB_FEATURES =~ /\bdast\b/ + variables: + DAST_IMAGE_SUFFIX: "-fips" + - if: $CI_COMMIT_BRANCH && $GITLAB_FEATURES =~ /\bdast\b/ after_script: # Remove any debug.log files because they might contain secrets. diff --git a/lib/gitlab/ci/templates/Security/DAST.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/DAST.latest.gitlab-ci.yml index d1d1c4d7e52..989f9caf601 100644 --- a/lib/gitlab/ci/templates/Security/DAST.latest.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/DAST.latest.gitlab-ci.yml @@ -26,11 +26,12 @@ variables: # Setting this variable will affect all Security templates # (SAST, Dependency Scanning, ...) SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products" + DAST_IMAGE_SUFFIX: "" dast: stage: dast image: - name: "$SECURE_ANALYZERS_PREFIX/dast:$DAST_VERSION" + name: "$SECURE_ANALYZERS_PREFIX/dast:$DAST_VERSION$DAST_IMAGE_SUFFIX" variables: GIT_STRATEGY: none allow_failure: true @@ -59,6 +60,12 @@ dast: $REVIEW_DISABLED == '1' when: never + # Add the job to merge request pipelines if there's an open merge request. (FIPS) + - if: $CI_PIPELINE_SOURCE == "merge_request_event" && + $CI_GITLAB_FIPS_MODE == "true" && + $GITLAB_FEATURES =~ /\bdast\b/ + variables: + DAST_IMAGE_SUFFIX: "-fips" # Add the job to merge request pipelines if there's an open merge request. - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $GITLAB_FEATURES =~ /\bdast\b/ @@ -67,6 +74,12 @@ dast: - if: $CI_OPEN_MERGE_REQUESTS when: never + # Add the job to branch pipelines. (FIPS) + - if: $CI_COMMIT_BRANCH && + $CI_GITLAB_FIPS_MODE == "true" && + $GITLAB_FEATURES =~ /\bdast\b/ + variables: + DAST_IMAGE_SUFFIX: "-fips" # Add the job to branch pipelines. - if: $CI_COMMIT_BRANCH && $GITLAB_FEATURES =~ /\bdast\b/ diff --git a/lib/gitlab/front_matter.rb b/lib/gitlab/front_matter.rb index 093501e860b..d215a77f4d7 100644 --- a/lib/gitlab/front_matter.rb +++ b/lib/gitlab/front_matter.rb @@ -8,15 +8,35 @@ module Gitlab ';;;' => 'json' }.freeze - DELIM = Regexp.union(DELIM_LANG.keys) + DELIM_UNTRUSTED = "(?:#{Gitlab::FrontMatter::DELIM_LANG.keys.map { |x| RE2::Regexp.escape(x) }.join('|')})".freeze - PATTERN = %r{ - \A(?<encoding>[^\r\n]*coding:[^\r\n]*\R)? # optional encoding line - (?<before>\s*) - ^(?<delim>#{DELIM})[ \t]*(?<lang>\S*)\R # opening front matter marker (optional language specifier) - (?<front_matter>.*?) # front matter block content (not greedy) - ^(\k<delim> | \.{3}) # closing front matter marker - [^\S\r\n]*(\R|\z) - }mx.freeze + # Original pattern: + # \A(?<encoding>[^\r\n]*coding:[^\r\n]*\R)? # optional encoding line + # (?<before>\s*) + # ^(?<delim>#{DELIM})[ \t]*(?<lang>\S*)\R # opening front matter marker (optional language specifier) + # (?<front_matter>.*?) # front matter block content (not greedy) + # ^(\k<delim> | \.{3}) # closing front matter marker + # [^\S\r\n]*(\R|\z) + # rubocop:disable Style/StringConcatenation + # rubocop:disable Style/LineEndConcatenation + PATTERN_UNTRUSTED = + # optional encoding line + "\\A(?P<encoding>[^\\r\\n]*coding:[^\\r\\n]*#{::Gitlab::UntrustedRegexp::BACKSLASH_R})?" + + '(?P<before>\s*)' + + + # opening front matter marker (optional language specifier) + "^(?P<delim>#{DELIM_UNTRUSTED})[ \\t]*(?P<lang>\\S*)#{::Gitlab::UntrustedRegexp::BACKSLASH_R}" + + + # front matter block content (not greedy) + '(?P<front_matter>(?:\n|.)*?)' + + + # closing front matter marker + "^((?P<delim_closing>#{DELIM_UNTRUSTED})|\\.{3})" + + "[^\\S\\r\\n]*(#{::Gitlab::UntrustedRegexp::BACKSLASH_R}|\\z)" + # rubocop:enable Style/LineEndConcatenation + # rubocop:enable Style/StringConcatenation + + PATTERN_UNTRUSTED_REGEX = + Gitlab::UntrustedRegexp.new(PATTERN_UNTRUSTED, multiline: true).freeze end end diff --git a/lib/gitlab/import_export/json/streaming_serializer.rb b/lib/gitlab/import_export/json/streaming_serializer.rb index 9bb0770dc90..2c64ca53f76 100644 --- a/lib/gitlab/import_export/json/streaming_serializer.rb +++ b/lib/gitlab/import_export/json/streaming_serializer.rb @@ -133,29 +133,10 @@ module Gitlab def authorized_record_json(record, options) include_keys = options[:include].flat_map(&:keys) keys_to_authorize = record.try(:restricted_associations, include_keys) - return record.to_json(options) if keys_to_authorize.blank? - - record_hash = record.as_json(options).with_indifferent_access - filtered_record_hash(record, keys_to_authorize, record_hash).to_json(options) - end - - def filtered_record_hash(record, keys_to_authorize, record_hash) - keys_to_authorize.each do |key| - next unless record_hash[key].present? - - readable = record.try(:readable_records, key, current_user: current_user) - if record.has_many_association?(key) - readable_ids = readable.pluck(:id) - record_hash[key].keep_if do |association_record| - readable_ids.include?(association_record[:id]) - end - else - record_hash[key] = nil unless readable.present? - end - end + return record.to_json(options) if keys_to_authorize.blank? - record_hash + record.to_authorized_json(keys_to_authorize, current_user, options) end def batch(relation, key) diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb index 5d2dc2f7d19..16a03f2356c 100644 --- a/lib/gitlab/search_results.rb +++ b/lib/gitlab/search_results.rb @@ -175,7 +175,7 @@ module Gitlab def projects scope = limit_projects - scope = filters[:include_archived] ? scope : scope.non_archived + scope = scope.non_archived if Feature.enabled?(:search_projects_hide_archived) && !filters[:include_archived] scope.search(query) end diff --git a/lib/gitlab/untrusted_regexp.rb b/lib/gitlab/untrusted_regexp.rb index fe3377dae68..150f50e4da6 100644 --- a/lib/gitlab/untrusted_regexp.rb +++ b/lib/gitlab/untrusted_regexp.rb @@ -16,6 +16,10 @@ module Gitlab class UntrustedRegexp require_dependency 're2' + # recreate Ruby's \R metacharacter + # https://ruby-doc.org/3.2.2/Regexp.html#class-Regexp-label-Character+Classes + BACKSLASH_R = '(\n|\v|\f|\r|\x{0085}|\x{2028}|\x{2029}|\r\n)' + delegate :===, :source, to: :regexp def initialize(pattern, multiline: false) diff --git a/lib/gitlab/wiki_pages/front_matter_parser.rb b/lib/gitlab/wiki_pages/front_matter_parser.rb index 071b0dde619..dbe848f0acf 100644 --- a/lib/gitlab/wiki_pages/front_matter_parser.rb +++ b/lib/gitlab/wiki_pages/front_matter_parser.rb @@ -53,7 +53,7 @@ module Gitlab include Gitlab::Utils::StrongMemoize def initialize(delim = nil, lang = '', text = nil) - @lang = lang.downcase.presence || Gitlab::FrontMatter::DELIM_LANG[delim] + @lang = lang&.downcase.presence || Gitlab::FrontMatter::DELIM_LANG[delim] @text = text&.strip! end @@ -109,11 +109,17 @@ module Gitlab end def parse_front_matter_block - wiki_content.match(Gitlab::FrontMatter::PATTERN) { |m| Block.new(m[:delim], m[:lang], m[:front_matter]) } || Block.new + if match = Gitlab::FrontMatter::PATTERN_UNTRUSTED_REGEX.match(wiki_content) + Block.new(match[:delim], match[:lang], match[:front_matter]) + else + Block.new + end end def strip_front_matter_block - wiki_content.gsub(Gitlab::FrontMatter::PATTERN, '') + Gitlab::FrontMatter::PATTERN_UNTRUSTED_REGEX.replace_gsub(wiki_content) do + '' + end end end end |