From a360142bb99b37e48051c2455246f0fd4e6cd542 Mon Sep 17 00:00:00 2001 From: Alex Kalderimis <akalderimis@gitlab.com> Date: Thu, 5 Aug 2021 13:29:18 +0100 Subject: [PATCH] Update apollo_upload_server dependency This enables us to make use of `strict_mode`, preventing denial of service attacks. Changelog: security --- Gemfile | 2 +- Gemfile.lock | 6 ++--- config/initializers/apollo_upload_server.rb | 5 ++++ lib/gitlab/middleware/multipart.rb | 2 +- .../file_uploads/graphql_add_design_spec.rb | 12 +++++++++- .../design_management/upload_spec.rb | 23 +++++++++++++++++-- 6 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 config/initializers/apollo_upload_server.rb diff --git a/Gemfile b/Gemfile index df805a6bcf91..ecb1e526e4d3 100644 --- a/Gemfile +++ b/Gemfile @@ -101,7 +101,7 @@ gem 'graphql', '~> 1.11.8' # TODO: remove app/views/graphiql/rails/editors/show.html.erb when https://github.com/rmosolgo/graphiql-rails/pull/71 is released: # https://gitlab.com/gitlab-org/gitlab/issues/31747 gem 'graphiql-rails', '~> 1.4.10' -gem 'apollo_upload_server', '~> 2.0.2' +gem 'apollo_upload_server', '~> 2.1.0' gem 'graphql-docs', '~> 1.6.0', group: [:development, :test] gem 'graphlient', '~> 0.4.0' # Used by BulkImport feature (group::import) diff --git a/Gemfile.lock b/Gemfile.lock index 658a7c68fa3a..3ff3f6ca76f8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -80,9 +80,9 @@ GEM aes_key_wrap (1.1.0) akismet (3.0.0) android_key_attestation (0.3.0) - apollo_upload_server (2.0.2) + apollo_upload_server (2.1.0) + actionpack (>= 4.2) graphql (>= 1.8) - rails (>= 4.2) asana (0.10.3) faraday (~> 1.0) faraday_middleware (~> 1.0) @@ -1391,7 +1391,7 @@ DEPENDENCIES acts-as-taggable-on (~> 7.0) addressable (~> 2.8) akismet (~> 3.0) - apollo_upload_server (~> 2.0.2) + apollo_upload_server (~> 2.1.0) asana (~> 0.10.3) asciidoctor (~> 2.0.10) asciidoctor-include-ext (~> 0.3.1) diff --git a/config/initializers/apollo_upload_server.rb b/config/initializers/apollo_upload_server.rb new file mode 100644 index 000000000000..295cb5d8ce88 --- /dev/null +++ b/config/initializers/apollo_upload_server.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +require 'apollo_upload_server' + +ApolloUploadServer::Middleware.strict_mode = true diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb index 30b3fe3d8931..49be3ffc8394 100644 --- a/lib/gitlab/middleware/multipart.rb +++ b/lib/gitlab/middleware/multipart.rb @@ -176,7 +176,7 @@ def call(env) ::Gitlab::Middleware::Multipart::Handler.new(env, message).with_open_files do @app.call(env) end - rescue UploadedFile::InvalidPathError => e + rescue UploadedFile::InvalidPathError, ApolloUploadServer::GraphQLDataBuilder::OutOfBounds => e [400, { 'Content-Type' => 'text/plain' }, [e.message]] end end diff --git a/spec/features/file_uploads/graphql_add_design_spec.rb b/spec/features/file_uploads/graphql_add_design_spec.rb index f805ea86b4c9..17fbf5f6838d 100644 --- a/spec/features/file_uploads/graphql_add_design_spec.rb +++ b/spec/features/file_uploads/graphql_add_design_spec.rb @@ -19,8 +19,18 @@ let_it_be(:user) { create(:user, :admin) } let_it_be(:personal_access_token) { create(:personal_access_token, user: user) } let_it_be(:design) { create(:design) } - let_it_be(:operations) { { "operationName": "uploadDesign", "variables": { "files": [], "projectPath": design.project.full_path, "iid": design.issue.iid }, "query": query }.to_json } let_it_be(:map) { { "1": ["variables.files.0"] }.to_json } + let_it_be(:operations) do + { + "operationName": "uploadDesign", + "variables": { + "files": [nil], + "projectPath": design.project.full_path, + "iid": design.issue.iid + }, + "query": query + }.to_json + end let(:url) { capybara_url("/api/graphql?private_token=#{personal_access_token.token}") } let(:file) { fixture_file_upload('spec/fixtures/dk.png') } diff --git a/spec/requests/api/graphql/mutations/design_management/upload_spec.rb b/spec/requests/api/graphql/mutations/design_management/upload_spec.rb index 2189ae3c5199..d3e6c689a59e 100644 --- a/spec/requests/api/graphql/mutations/design_management/upload_spec.rb +++ b/spec/requests/api/graphql/mutations/design_management/upload_spec.rb @@ -11,6 +11,7 @@ let(:project) { issue.project } let(:files) { [fixture_file_upload("spec/fixtures/dk.png")] } let(:variables) { {} } + let(:mutation_response) { graphql_mutation_response(:design_management_upload) } def mutation input = { @@ -21,14 +22,32 @@ def mutation graphql_mutation(:design_management_upload, input) end - let(:mutation_response) { graphql_mutation_response(:design_management_upload) } - before do enable_design_management project.add_developer(current_user) end + context 'when the input does not include a null value for each mapped file' do + let(:operations) { { query: mutation.query, variables: mutation.variables.merge(files: []) } } + let(:mapping) { { '1' => ['variables.files.0'] } } + let(:params) do + { '1' => files.first, operations: operations.to_json, map: mapping.to_json } + end + + it 'returns an error' do + workhorse_post_with_file(api('/', current_user, version: 'graphql'), + params: params, + file_key: '1' + ) + + expect(response).to have_attributes( + code: eq('400'), + body: include('out-of-bounds') + ) + end + end + it "returns an error if the user is not allowed to upload designs" do post_graphql_mutation_with_uploads(mutation, current_user: create(:user)) -- GitLab