From d5267dfd0dac8e4cab4919bf8aca611de3a5497b Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 24 Apr 2016 21:45:26 -0700 Subject: Prevent private snippets in public/internal projects from being leaked via API Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/15580 --- app/finders/snippets_finder.rb | 2 +- lib/api/project_snippets.rb | 15 ++++-- spec/requests/api/project_snippets_spec.rb | 87 ++++++++++++++++++++++++++++++ spec/requests/api/projects_spec.rb | 2 +- 4 files changed, 99 insertions(+), 7 deletions(-) diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb index a41172816b8..01cbf91c658 100644 --- a/app/finders/snippets_finder.rb +++ b/app/finders/snippets_finder.rb @@ -51,7 +51,7 @@ class SnippetsFinder snippets = project.snippets.fresh if current_user - if project.team.member?(current_user.id) + if project.team.member?(current_user.id) || current_user.admin? snippets else snippets.public_and_internal diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb index 22ce3c6a066..ce1bf0d26d2 100644 --- a/lib/api/project_snippets.rb +++ b/lib/api/project_snippets.rb @@ -11,6 +11,11 @@ module API end not_found! end + + def snippets_for_current_user + finder_params = { filter: :by_project, project: user_project } + SnippetsFinder.new.execute(current_user, finder_params) + end end # Get a project snippets @@ -20,7 +25,7 @@ module API # Example Request: # GET /projects/:id/snippets get ":id/snippets" do - present paginate(user_project.snippets), with: Entities::ProjectSnippet + present paginate(snippets_for_current_user), with: Entities::ProjectSnippet end # Get a project snippet @@ -31,7 +36,7 @@ module API # Example Request: # GET /projects/:id/snippets/:snippet_id get ":id/snippets/:snippet_id" do - @snippet = user_project.snippets.find(params[:snippet_id]) + @snippet = snippets_for_current_user.find(params[:snippet_id]) present @snippet, with: Entities::ProjectSnippet end @@ -73,7 +78,7 @@ module API # Example Request: # PUT /projects/:id/snippets/:snippet_id put ":id/snippets/:snippet_id" do - @snippet = user_project.snippets.find(params[:snippet_id]) + @snippet = snippets_for_current_user.find(params[:snippet_id]) authorize! :update_project_snippet, @snippet attrs = attributes_for_keys [:title, :file_name, :visibility_level] @@ -97,7 +102,7 @@ module API # DELETE /projects/:id/snippets/:snippet_id delete ":id/snippets/:snippet_id" do begin - @snippet = user_project.snippets.find(params[:snippet_id]) + @snippet = snippets_for_current_user.find(params[:snippet_id]) authorize! :update_project_snippet, @snippet @snippet.destroy rescue @@ -113,7 +118,7 @@ module API # Example Request: # GET /projects/:id/snippets/:snippet_id/raw get ":id/snippets/:snippet_id/raw" do - @snippet = user_project.snippets.find(params[:snippet_id]) + @snippet = snippets_for_current_user.find(params[:snippet_id]) env['api.format'] = :txt content_type 'text/plain' diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb index 3722ddf5a33..9706d060cfa 100644 --- a/spec/requests/api/project_snippets_spec.rb +++ b/spec/requests/api/project_snippets_spec.rb @@ -15,4 +15,91 @@ describe API::API, api: true do expect(json_response['expires_at']).to be_nil end end + + describe 'GET /projects/:project_id/snippets/' do + it 'all snippets available to team member' do + project = create(:project, :public) + user = create(:user) + project.team << [user, :developer] + public_snippet = create(:project_snippet, :public, project: project) + internal_snippet = create(:project_snippet, :internal, project: project) + private_snippet = create(:project_snippet, :private, project: project) + + get api("/projects/#{project.id}/snippets/", user) + + expect(response.status).to eq(200) + expect(json_response.size).to eq(3) + expect(json_response.map{ |snippet| snippet['id']} ).to include(public_snippet.id, internal_snippet.id, private_snippet.id) + end + + it 'hides private snippets from regular user' do + project = create(:project, :public) + user = create(:user) + create(:project_snippet, :private, project: project) + + get api("/projects/#{project.id}/snippets/", user) + expect(response.status).to eq(200) + expect(json_response.size).to eq(0) + end + end + + describe 'POST /projects/:project_id/snippets/' do + it 'creates a new snippet' do + admin = create(:admin) + project = create(:project) + params = { + title: 'Test Title', + file_name: 'test.rb', + code: 'puts "hello world"', + visibility_level: Gitlab::VisibilityLevel::PUBLIC + } + + post api("/projects/#{project.id}/snippets/", admin), params + + expect(response.status).to eq(201) + snippet = ProjectSnippet.find(json_response['id']) + expect(snippet.content).to eq(params[:code]) + expect(snippet.title).to eq(params[:title]) + expect(snippet.file_name).to eq(params[:file_name]) + expect(snippet.visibility_level).to eq(params[:visibility_level]) + end + end + + describe 'PUT /projects/:project_id/snippets/:id/' do + it 'updates snippet' do + admin = create(:admin) + snippet = create(:project_snippet, author: admin) + new_content = 'New content' + + put api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin), code: new_content + + expect(response.status).to eq(200) + snippet.reload + expect(snippet.content).to eq(new_content) + end + end + + describe 'DELETE /projects/:project_id/snippets/:id/' do + it 'deletes snippet' do + admin = create(:admin) + snippet = create(:project_snippet, author: admin) + + delete api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin) + + expect(response.status).to eq(200) + end + end + + describe 'GET /projects/:project_id/snippets/:id/raw' do + it 'returns raw text' do + admin = create(:admin) + snippet = create(:project_snippet, author: admin) + + get api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/raw", admin) + + expect(response.status).to eq(200) + expect(response.content_type).to eq 'text/plain' + expect(response.body).to eq(snippet.content) + end + end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index fccd08bd6da..66193eac051 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -11,7 +11,7 @@ describe API::API, api: true do let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } let(:project2) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace) } let(:project3) { create(:project, path: 'project3', creator_id: user.id, namespace: user.namespace) } - let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } + let(:snippet) { create(:project_snippet, :public, author: user, project: project, title: 'example') } let(:project_member) { create(:project_member, :master, user: user, project: project) } let(:project_member2) { create(:project_member, :developer, user: user3, project: project) } let(:user4) { create(:user) } -- cgit v1.2.1