diff options
Diffstat (limited to 'lib/gitlab/middleware/multipart.rb')
-rw-r--r-- | lib/gitlab/middleware/multipart.rb | 124 |
1 files changed, 26 insertions, 98 deletions
diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb index a6d8a778e05..79f1abe820f 100644 --- a/lib/gitlab/middleware/multipart.rb +++ b/lib/gitlab/middleware/multipart.rb @@ -41,7 +41,7 @@ module Gitlab end def with_open_files - @rewritten_fields.each do |field, tmp_path| + @rewritten_fields.keys.each do |field| raise "invalid field: #{field.inspect}" unless valid_field_name?(field) parsed_field = Rack::Utils.parse_nested_query(field) @@ -51,10 +51,10 @@ module Gitlab if value.nil? # we have a top level param, eg. field = 'foo' and not 'foo[bar]' raise "invalid field: #{field.inspect}" if field != key - value = open_file(@request.params, key, tmp_path.presence) + value = open_file(extract_upload_params_from(@request.params, with_prefix: key)) @open_files << value else - value = decorate_params_value(value, @request.params[key], tmp_path.presence) + value = decorate_params_value(value, @request.params[key]) end update_param(key, value) @@ -67,12 +67,12 @@ module Gitlab end # This function calls itself recursively - def decorate_params_value(path_hash, value_hash, path_override = nil) - unless path_hash.is_a?(Hash) && path_hash.count == 1 - raise "invalid path: #{path_hash.inspect}" + def decorate_params_value(hash_path, value_hash) + unless hash_path.is_a?(Hash) && hash_path.count == 1 + raise "invalid path: #{hash_path.inspect}" end - path_key, path_value = path_hash.first + path_key, path_value = hash_path.first unless value_hash.is_a?(Hash) && value_hash[path_key] raise "invalid value hash: #{value_hash.inspect}" @@ -80,19 +80,19 @@ module Gitlab case path_value when nil - value_hash[path_key] = open_file(value_hash.dig(path_key), '', path_override) + value_hash[path_key] = open_file(extract_upload_params_from(value_hash[path_key])) @open_files << value_hash[path_key] value_hash when Hash - decorate_params_value(path_value, value_hash[path_key], path_override) + decorate_params_value(path_value, value_hash[path_key]) value_hash else raise "unexpected path value: #{path_value.inspect}" end end - def open_file(params, key, path_override = nil) - ::UploadedFile.from_params(params, key, allowed_paths, path_override) + def open_file(params) + ::UploadedFile.from_params(params, allowed_paths) end # update_params ensures that both rails controllers and rack middleware can find @@ -111,6 +111,20 @@ module Gitlab private + def extract_upload_params_from(params, with_prefix: '') + param_key = "#{with_prefix}#{JWT_PARAM_SUFFIX}" + jwt_token = params[param_key] + raise "Empty JWT param: #{param_key}" if jwt_token.blank? + + payload = Gitlab::Workhorse.decode_jwt(jwt_token).first + raise "Invalid JWT payload: not a Hash" unless payload.is_a?(Hash) + + upload_params = payload.fetch(JWT_PARAM_FIXED_KEY, {}) + raise "Empty params for: #{param_key}" if upload_params.empty? + + upload_params + end + def valid_field_name?(name) # length validation return false if name.size >= REWRITTEN_FIELD_NAME_MAX_LENGTH @@ -149,82 +163,6 @@ module Gitlab end end - # TODO this class is meant to replace Handler when the feature flag - # upload_middleware_jwt_params_handler is removed - # See https://gitlab.com/gitlab-org/gitlab/-/issues/233895#roll-out-steps - class HandlerForJWTParams < Handler - def with_open_files - @rewritten_fields.keys.each do |field| - raise "invalid field: #{field.inspect}" unless valid_field_name?(field) - - parsed_field = Rack::Utils.parse_nested_query(field) - raise "unexpected field: #{field.inspect}" unless parsed_field.count == 1 - - key, value = parsed_field.first - if value.nil? # we have a top level param, eg. field = 'foo' and not 'foo[bar]' - raise "invalid field: #{field.inspect}" if field != key - - value = open_file(extract_upload_params_from(@request.params, with_prefix: key)) - @open_files << value - else - value = decorate_params_value(value, @request.params[key]) - end - - update_param(key, value) - end - - yield - ensure - @open_files.compact - .each(&:close) - end - - # This function calls itself recursively - def decorate_params_value(hash_path, value_hash) - unless hash_path.is_a?(Hash) && hash_path.count == 1 - raise "invalid path: #{hash_path.inspect}" - end - - path_key, path_value = hash_path.first - - unless value_hash.is_a?(Hash) && value_hash[path_key] - raise "invalid value hash: #{value_hash.inspect}" - end - - case path_value - when nil - value_hash[path_key] = open_file(extract_upload_params_from(value_hash[path_key])) - @open_files << value_hash[path_key] - value_hash - when Hash - decorate_params_value(path_value, value_hash[path_key]) - value_hash - else - raise "unexpected path value: #{path_value.inspect}" - end - end - - def open_file(params) - ::UploadedFile.from_params_without_field(params, allowed_paths) - end - - private - - def extract_upload_params_from(params, with_prefix: '') - param_key = "#{with_prefix}#{JWT_PARAM_SUFFIX}" - jwt_token = params[param_key] - raise "Empty JWT param: #{param_key}" if jwt_token.blank? - - payload = Gitlab::Workhorse.decode_jwt(jwt_token).first - raise "Invalid JWT payload: not a Hash" unless payload.is_a?(Hash) - - upload_params = payload.fetch(JWT_PARAM_FIXED_KEY, {}) - raise "Empty params for: #{param_key}" if upload_params.empty? - - upload_params - end - end - def initialize(app) @app = app end @@ -235,22 +173,12 @@ module Gitlab message = ::Gitlab::Workhorse.decode_jwt(encoded_message)[0] - handler_class.new(env, message).with_open_files do + ::Gitlab::Middleware::Multipart::Handler.new(env, message).with_open_files do @app.call(env) end rescue UploadedFile::InvalidPathError => e [400, { 'Content-Type' => 'text/plain' }, e.message] end - - private - - def handler_class - if Feature.enabled?(:upload_middleware_jwt_params_handler, default_enabled: true) - ::Gitlab::Middleware::Multipart::HandlerForJWTParams - else - ::Gitlab::Middleware::Multipart::Handler - end - end end end end |