diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/api/group_import.rb | 17 | ||||
-rw-r--r-- | lib/api/projects.rb | 2 | ||||
-rw-r--r-- | lib/api/repositories.rb | 4 | ||||
-rw-r--r-- | lib/gitlab/bitbucket_import/importer.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/gl_repository.rb | 17 | ||||
-rw-r--r-- | lib/gitlab/gl_repository/identifier.rb | 74 | ||||
-rw-r--r-- | lib/gitlab/gl_repository/repo_type.rb | 27 | ||||
-rw-r--r-- | lib/gitlab/static_site_editor/config.rb | 6 | ||||
-rw-r--r-- | lib/gitlab/url_sanitizer.rb | 9 |
9 files changed, 114 insertions, 44 deletions
diff --git a/lib/api/group_import.rb b/lib/api/group_import.rb index a88a94c2c3d..01697e8adee 100644 --- a/lib/api/group_import.rb +++ b/lib/api/group_import.rb @@ -2,6 +2,8 @@ module API class GroupImport < Grape::API + helpers Helpers::FileUploadHelpers + helpers do def parent_group find_group!(params[:parent_id]) if params[:parent_id].present? @@ -49,29 +51,20 @@ module API params do requires :path, type: String, desc: 'Group path' requires :name, type: String, desc: 'Group name' + requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The group export file to be imported' optional :parent_id, type: Integer, desc: "The ID of the parent group that the group will be imported into. Defaults to the current user's namespace." - optional 'file.path', type: String, desc: 'Path to locally stored body (generated by Workhorse)' - optional 'file.name', type: String, desc: 'Real filename as send in Content-Disposition (generated by Workhorse)' - optional 'file.type', type: String, desc: 'Real content type as send in Content-Type (generated by Workhorse)' - optional 'file.size', type: Integer, desc: 'Real size of file (generated by Workhorse)' - optional 'file.md5', type: String, desc: 'MD5 checksum of the file (generated by Workhorse)' - optional 'file.sha1', type: String, desc: 'SHA1 checksum of the file (generated by Workhorse)' - optional 'file.sha256', type: String, desc: 'SHA256 checksum of the file (generated by Workhorse)' end post 'import' do authorize_create_group! require_gitlab_workhorse! - - uploaded_file = UploadedFile.from_params(params, :file, ImportExportUploader.workhorse_local_upload_path) - - bad_request!('Unable to process group import file') unless uploaded_file + validate_file! group_params = { path: params[:path], name: params[:name], parent_id: params[:parent_id], visibility_level: closest_allowed_visibility_level, - import_export_upload: ImportExportUpload.new(import_file: uploaded_file) + import_export_upload: ImportExportUpload.new(import_file: params[:file]) } group = ::Groups::CreateService.new(current_user, group_params).execute diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 732453cf1c4..f305da681c4 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -444,6 +444,8 @@ module API not_found!("Source Project") unless fork_from_project + authorize! :fork_project, fork_from_project + result = ::Projects::ForkService.new(fork_from_project, current_user).execute(user_project) if result diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index 0b2df85f61f..bf4f08ce390 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -6,6 +6,8 @@ module API class Repositories < Grape::API include PaginationParams + helpers ::API::Helpers::HeadersHelpers + before { authorize! :download_code, user_project } params do @@ -67,6 +69,8 @@ module API get ':id/repository/blobs/:sha/raw' do assign_blob_vars! + no_cache_headers + send_git_blob @repo, @blob end diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb index d8f9105d66d..5a9fad3be56 100644 --- a/lib/gitlab/bitbucket_import/importer.rb +++ b/lib/gitlab/bitbucket_import/importer.rb @@ -43,7 +43,7 @@ module Gitlab def store_pull_request_error(pull_request, ex) backtrace = Gitlab::BacktraceCleaner.clean_backtrace(ex.backtrace) - error = { type: :pull_request, iid: pull_request.iid, errors: ex.message, trace: backtrace, raw_response: pull_request.raw } + error = { type: :pull_request, iid: pull_request.iid, errors: ex.message, trace: backtrace, raw_response: pull_request.raw&.to_json } Gitlab::ErrorTracking.log_exception(ex, error) diff --git a/lib/gitlab/gl_repository.rb b/lib/gitlab/gl_repository.rb index 8abefad1ef3..b75b4be9a4e 100644 --- a/lib/gitlab/gl_repository.rb +++ b/lib/gitlab/gl_repository.rb @@ -12,14 +12,15 @@ module Gitlab WIKI = RepoType.new( name: :wiki, access_checker_class: Gitlab::GitAccessWiki, - repository_resolver: -> (project) { project&.wiki&.repository }, + repository_resolver: -> (container) { container&.wiki&.repository }, + project_resolver: -> (container) { container.is_a?(Project) ? container : nil }, suffix: :wiki ).freeze SNIPPET = RepoType.new( name: :snippet, access_checker_class: Gitlab::GitAccessSnippet, repository_resolver: -> (snippet) { snippet&.repository }, - container_resolver: -> (id) { Snippet.find_by_id(id) }, + container_class: Snippet, project_resolver: -> (snippet) { snippet&.project }, guest_read_ability: :read_snippet ).freeze @@ -42,16 +43,12 @@ module Gitlab end def self.parse(gl_repository) - type_name, _id = gl_repository.split('-').first - type = types[type_name] + result = ::Gitlab::GlRepository::Identifier.new(gl_repository) - unless type - raise ArgumentError, "Invalid GL Repository \"#{gl_repository}\"" - end + repo_type = result.repo_type + container = result.fetch_container! - container = type.fetch_container!(gl_repository) - - [container, type.project_for(container), type] + [container, repo_type.project_for(container), repo_type] end def self.default_type diff --git a/lib/gitlab/gl_repository/identifier.rb b/lib/gitlab/gl_repository/identifier.rb new file mode 100644 index 00000000000..dc3e7931696 --- /dev/null +++ b/lib/gitlab/gl_repository/identifier.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module Gitlab + class GlRepository + class Identifier + attr_reader :gl_repository, :repo_type + + def initialize(gl_repository) + @gl_repository = gl_repository + @segments = gl_repository.split('-') + + raise_error if segments.size > 3 + + @repo_type = find_repo_type + @container_id = find_container_id + @container_class = find_container_class + end + + def fetch_container! + container_class.find_by_id(container_id) + end + + private + + attr_reader :segments, :container_class, :container_id + + def find_repo_type + type_name = three_segments_format? ? segments.last : segments.first + type = Gitlab::GlRepository.types[type_name] + + raise_error unless type + + type + end + + def find_container_class + if three_segments_format? + case segments[0] + when 'project' + Project + when 'group' + Group + else + raise_error + end + else + repo_type.container_class + end + end + + def find_container_id + id = Integer(segments[1], 10, exception: false) + + raise_error unless id + + id + end + + # gl_repository can either have 2 or 3 segments: + # "wiki-1" is the older 2-segment format, where container is implied. + # "group-1-wiki" is the newer 3-segment format, including container information. + # + # TODO: convert all 2-segment format to 3-segment: + # https://gitlab.com/gitlab-org/gitlab/-/issues/219192 + def three_segments_format? + segments.size == 3 + end + + def raise_error + raise ArgumentError, "Invalid GL Repository \"#{gl_repository}\"" + end + end + end +end diff --git a/lib/gitlab/gl_repository/repo_type.rb b/lib/gitlab/gl_repository/repo_type.rb index 64c329b15ae..2b482ee3d2d 100644 --- a/lib/gitlab/gl_repository/repo_type.rb +++ b/lib/gitlab/gl_repository/repo_type.rb @@ -6,7 +6,7 @@ module Gitlab attr_reader :name, :access_checker_class, :repository_resolver, - :container_resolver, + :container_class, :project_resolver, :guest_read_ability, :suffix @@ -15,34 +15,25 @@ module Gitlab name:, access_checker_class:, repository_resolver:, - container_resolver: default_container_resolver, + container_class: default_container_class, project_resolver: nil, guest_read_ability: :download_code, suffix: nil) @name = name @access_checker_class = access_checker_class @repository_resolver = repository_resolver - @container_resolver = container_resolver + @container_class = container_class @project_resolver = project_resolver @guest_read_ability = guest_read_ability @suffix = suffix end def identifier_for_container(container) - "#{name}-#{container.id}" - end - - def fetch_id(identifier) - match = /\A#{name}-(?<id>\d+)\z/.match(identifier) - match[:id] if match - end + if container.is_a?(Group) + return "#{container.class.name.underscore}-#{container.id}-#{name}" + end - def fetch_container!(identifier) - id = fetch_id(identifier) - - raise ArgumentError, "Invalid GL Repository \"#{identifier}\"" unless id - - container_resolver.call(id) + "#{name}-#{container.id}" end def wiki? @@ -85,8 +76,8 @@ module Gitlab private - def default_container_resolver - -> (id) { Project.find_by_id(id) } + def default_container_class + Project end end end diff --git a/lib/gitlab/static_site_editor/config.rb b/lib/gitlab/static_site_editor/config.rb index c931cdecbeb..65c567ec2a6 100644 --- a/lib/gitlab/static_site_editor/config.rb +++ b/lib/gitlab/static_site_editor/config.rb @@ -21,7 +21,7 @@ module Gitlab project_id: project.id, project: project.path, namespace: project.namespace.path, - return_url: return_url, + return_url: sanitize_url(return_url), is_supported_content: supported_content?.to_s, base_url: Gitlab::Routing.url_helpers.project_show_sse_path(project, full_path) } @@ -52,6 +52,10 @@ module Gitlab def full_path "#{ref}/#{file_path}" end + + def sanitize_url(url) + url if Gitlab::UrlSanitizer.valid_web?(url) + end end end end diff --git a/lib/gitlab/url_sanitizer.rb b/lib/gitlab/url_sanitizer.rb index 215454fe63c..fa40a8b678b 100644 --- a/lib/gitlab/url_sanitizer.rb +++ b/lib/gitlab/url_sanitizer.rb @@ -3,6 +3,7 @@ module Gitlab class UrlSanitizer ALLOWED_SCHEMES = %w[http https ssh git].freeze + ALLOWED_WEB_SCHEMES = %w[http https].freeze def self.sanitize(content) regexp = URI::DEFAULT_PARSER.make_regexp(ALLOWED_SCHEMES) @@ -12,17 +13,21 @@ module Gitlab content.gsub(regexp, '') end - def self.valid?(url) + def self.valid?(url, allowed_schemes: ALLOWED_SCHEMES) return false unless url.present? return false unless url.is_a?(String) uri = Addressable::URI.parse(url.strip) - ALLOWED_SCHEMES.include?(uri.scheme) + allowed_schemes.include?(uri.scheme) rescue Addressable::URI::InvalidURIError false end + def self.valid_web?(url) + valid?(url, allowed_schemes: ALLOWED_WEB_SCHEMES) + end + def initialize(url, credentials: nil) %i[user password].each do |symbol| credentials[symbol] = credentials[symbol].presence if credentials&.key?(symbol) |