Commit 0a27fcc3 authored by Manoj M J's avatar Manoj M J

Do not expose starred projects of users with private profile via API

This change makes sure that starred projects
details of users with private profiles are not
exposed via the API, unless the accessing user
has ability to access private profiles of the user.
parent 2ae93baa
# frozen_string_literal: true # frozen_string_literal: true
class StarredProjectsFinder < ProjectsFinder class StarredProjectsFinder < ProjectsFinder
include Gitlab::Allowable
def initialize(user, params: {}, current_user: nil) def initialize(user, params: {}, current_user: nil)
@user = user
super( super(
params: params, params: params,
current_user: current_user, current_user: current_user,
project_ids_relation: user.starred_projects.select(:id) project_ids_relation: user.starred_projects.select(:id)
) )
end end
def execute
# Do not show starred projects if the user has a private profile.
return Project.none unless can?(current_user, :read_user_profile, @user)
super
end
end end
---
title: Do not expose starred projects of users with private profile via API
merge_request:
author:
type: security
...@@ -5,7 +5,7 @@ require 'spec_helper' ...@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe StarredProjectsFinder do RSpec.describe StarredProjectsFinder do
let(:project1) { create(:project, :public, :empty_repo) } let(:project1) { create(:project, :public, :empty_repo) }
let(:project2) { create(:project, :public, :empty_repo) } let(:project2) { create(:project, :public, :empty_repo) }
let(:other_project) { create(:project, :public, :empty_repo) } let(:private_project) { create(:project, :private, :empty_repo) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:other_user) { create(:user) } let(:other_user) { create(:user) }
...@@ -13,6 +13,9 @@ RSpec.describe StarredProjectsFinder do ...@@ -13,6 +13,9 @@ RSpec.describe StarredProjectsFinder do
before do before do
user.toggle_star(project1) user.toggle_star(project1)
user.toggle_star(project2) user.toggle_star(project2)
private_project.add_maintainer(user)
user.toggle_star(private_project)
end end
describe '#execute' do describe '#execute' do
...@@ -20,10 +23,11 @@ RSpec.describe StarredProjectsFinder do ...@@ -20,10 +23,11 @@ RSpec.describe StarredProjectsFinder do
subject { finder.execute } subject { finder.execute }
context 'user has a public profile' do
describe 'as same user' do describe 'as same user' do
let(:current_user) { user } let(:current_user) { user }
it { is_expected.to contain_exactly(project1, project2) } it { is_expected.to contain_exactly(project1, project2, private_project) }
end end
describe 'as other user' do describe 'as other user' do
...@@ -38,4 +42,37 @@ RSpec.describe StarredProjectsFinder do ...@@ -38,4 +42,37 @@ RSpec.describe StarredProjectsFinder do
it { is_expected.to contain_exactly(project1, project2) } it { is_expected.to contain_exactly(project1, project2) }
end end
end end
context 'user has a private profile' do
before do
user.update!(private_profile: true)
end
describe 'as same user' do
let(:current_user) { user }
it { is_expected.to contain_exactly(project1, project2, private_project) }
end
describe 'as other user' do
context 'user does not have access to view the private profile' do
let(:current_user) { other_user }
it { is_expected.to be_empty }
end
context 'user has access to view the private profile', :enable_admin_mode do
let(:current_user) { create(:admin) }
it { is_expected.to contain_exactly(project1, project2, private_project) }
end
end
describe 'as no user' do
let(:current_user) { nil }
it { is_expected.to be_empty }
end
end
end
end end
...@@ -70,4 +70,31 @@ RSpec.describe 'Getting starredProjects of the user' do ...@@ -70,4 +70,31 @@ RSpec.describe 'Getting starredProjects of the user' do
) )
end end
end end
context 'the user has a private profile' do
before do
user.update!(private_profile: true)
post_graphql(query, current_user: current_user)
end
context 'the current user does not have access to view the private profile of the user' do
let(:current_user) { create(:user) }
it 'finds no projects' do
expect(starred_projects).to be_empty
end
end
context 'the current user has access to view the private profile of the user' do
let(:current_user) { create(:admin) }
it 'finds all projects starred by the user, which the current user has access to' do
expect(starred_projects).to contain_exactly(
a_hash_including('id' => global_id_of(project_a)),
a_hash_including('id' => global_id_of(project_b)),
a_hash_including('id' => global_id_of(project_c))
)
end
end
end
end end
...@@ -1255,13 +1255,46 @@ RSpec.describe API::Projects do ...@@ -1255,13 +1255,46 @@ RSpec.describe API::Projects do
expect(json_response['message']).to eq('404 User Not Found') expect(json_response['message']).to eq('404 User Not Found')
end end
context 'with a public profile' do
it 'returns projects filtered by user' do it 'returns projects filtered by user' do
get api("/users/#{user3.id}/starred_projects/", user) get api("/users/#{user3.id}/starred_projects/", user)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] }).to contain_exactly(project.id, project2.id, project3.id) expect(json_response.map { |project| project['id'] })
.to contain_exactly(project.id, project2.id, project3.id)
end
end
context 'with a private profile' do
before do
user3.update!(private_profile: true)
user3.reload
end
context 'user does not have access to view the private profile' do
it 'returns no projects' do
get api("/users/#{user3.id}/starred_projects/", user)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response).to be_empty
end
end
context 'user has access to view the private profile' do
it 'returns projects filtered by user' do
get api("/users/#{user3.id}/starred_projects/", admin)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] })
.to contain_exactly(project.id, project2.id, project3.id)
end
end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment