Skip to content

Commit f351cc2

Browse files
committed
Merge branch 'sh-backport-10-3-4-security-fixes' into 'master'
Backport 10.3.4 security fixes into master See merge request gitlab-org/gitlab-ce!16509
2 parents 3b13159 + d1eb3ff commit f351cc2

File tree

86 files changed

+1183
-278
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+1183
-278
lines changed

app/assets/javascripts/deploy_keys/components/key.vue

+19-10
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
<script>
22
import actionBtn from './action_btn.vue';
33
import { getTimeago } from '../../lib/utils/datetime_utility';
4+
import tooltip from '../../vue_shared/directives/tooltip';
45
56
export default {
67
components: {
78
actionBtn,
89
},
10+
directives: {
11+
tooltip,
12+
},
913
props: {
1014
deployKey: {
1115
type: Object,
@@ -32,6 +36,9 @@
3236
isEnabled(id) {
3337
return this.store.findEnabledKey(id) !== undefined;
3438
},
39+
tooltipTitle(project) {
40+
return project.can_push ? 'Write access allowed' : 'Read access only';
41+
},
3542
},
3643
};
3744
</script>
@@ -52,21 +59,23 @@
5259
<div class="description">
5360
{{ deployKey.fingerprint }}
5461
</div>
55-
<div
56-
v-if="deployKey.can_push"
57-
class="write-access-allowed"
58-
>
59-
Write access allowed
60-
</div>
6162
</div>
6263
<div class="deploy-key-content prepend-left-default deploy-key-projects">
6364
<a
64-
v-for="(project, i) in deployKey.projects"
65-
class="label deploy-project-label"
66-
:href="project.full_path"
65+
v-for="(deployKeysProject, i) in deployKey.deploy_keys_projects"
6766
:key="i"
67+
class="label deploy-project-label"
68+
:href="deployKeysProject.project.full_path"
69+
:title="tooltipTitle(deployKeysProject)"
70+
v-tooltip
6871
>
69-
{{ project.full_name }}
72+
{{ deployKeysProject.project.full_name }}
73+
<i
74+
v-if="!deployKeysProject.can_push"
75+
aria-hidden="true"
76+
class="fa fa-lock"
77+
>
78+
</i>
7079
</a>
7180
</div>
7281
<div class="deploy-key-content">

app/assets/javascripts/labels_select.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ export default class LabelsSelect {
231231
selectedClass.push('label-item');
232232
$a.attr('data-label-id', label.id);
233233
}
234-
$a.addClass(selectedClass.join(' ')).html(colorEl + " " + label.title);
234+
$a.addClass(selectedClass.join(' ')).html(`${colorEl} ${_.escape(label.title)}`);
235235
// Return generated html
236236
return $li.html($a).prop('outerHTML');
237237
},

app/assets/javascripts/notebook/cells/markdown.vue

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script>
22
/* global katex */
33
import marked from 'marked';
4+
import sanitize from 'sanitize-html';
45
import Prompt from './prompt.vue';
56
67
const renderer = new marked.Renderer();
@@ -82,7 +83,12 @@
8283
},
8384
computed: {
8485
markdown() {
85-
return marked(this.cell.source.join('').replace(/\\/g, '\\\\'));
86+
return sanitize(marked(this.cell.source.join('').replace(/\\/g, '\\\\')), {
87+
allowedTags: false,
88+
allowedAttributes: {
89+
'*': ['class'],
90+
},
91+
});
8692
},
8793
},
8894
};

app/assets/javascripts/notebook/cells/output/html.vue

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script>
2+
import sanitize from 'sanitize-html';
23
import Prompt from '../prompt.vue';
34
45
export default {
@@ -11,12 +12,24 @@
1112
required: true,
1213
},
1314
},
15+
computed: {
16+
sanitizedOutput() {
17+
return sanitize(this.rawCode, {
18+
allowedTags: sanitize.defaults.allowedTags.concat([
19+
'img', 'svg',
20+
]),
21+
allowedAttributes: {
22+
img: ['src'],
23+
},
24+
});
25+
},
26+
},
1427
};
1528
</script>
1629

1730
<template>
1831
<div class="output">
1932
<prompt />
20-
<div v-html="rawCode"></div>
33+
<div v-html="sanitizedOutput"></div>
2134
</div>
2235
</template>

app/controllers/admin/deploy_keys_controller.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ def deploy_keys
5050
end
5151

5252
def create_params
53-
params.require(:deploy_key).permit(:key, :title, :can_push)
53+
params.require(:deploy_key).permit(:key, :title)
5454
end
5555

5656
def update_params
57-
params.require(:deploy_key).permit(:title, :can_push)
57+
params.require(:deploy_key).permit(:title)
5858
end
5959
end

app/controllers/groups/milestones_controller.rb

+4-2
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ def milestone_path
7575
end
7676

7777
def milestones
78-
search_params = params.merge(group_ids: group.id)
79-
8078
milestones = MilestonesFinder.new(search_params).execute
8179
legacy_milestones = GroupMilestone.build_collection(group, group_projects, params)
8280

@@ -94,4 +92,8 @@ def milestone
9492

9593
render_404 unless @milestone
9694
end
95+
96+
def search_params
97+
params.permit(:state).merge(group_ids: group.id)
98+
end
9799
end

app/controllers/omniauth_callbacks_controller.rb

+9
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ def handle_omniauth
112112

113113
continue_login_process
114114
end
115+
rescue Gitlab::OAuth::SigninDisabledForProviderError
116+
handle_disabled_provider
115117
rescue Gitlab::OAuth::SignupDisabledError
116118
handle_signup_error
117119
end
@@ -168,6 +170,13 @@ def fail_ldap_login
168170
redirect_to new_user_session_path
169171
end
170172

173+
def handle_disabled_provider
174+
label = Gitlab::OAuth::Provider.label_for(oauth['provider'])
175+
flash[:alert] = "Signing in using #{label} has been disabled"
176+
177+
redirect_to new_user_session_path
178+
end
179+
171180
def log_audit_event(user, options = {})
172181
AuditEventService.new(user, user, options)
173182
.for_authentication.security_event

app/controllers/projects/deploy_keys_controller.rb

+6-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def new
2424
def create
2525
@key = DeployKeys::CreateService.new(current_user, create_params).execute
2626

27-
unless @key.valid? && @project.deploy_keys << @key
27+
unless @key.valid?
2828
flash[:alert] = @key.errors.full_messages.join(', ').html_safe
2929
end
3030

@@ -71,11 +71,14 @@ def deploy_key
7171
end
7272

7373
def create_params
74-
params.require(:deploy_key).permit(:key, :title, :can_push)
74+
create_params = params.require(:deploy_key)
75+
.permit(:key, :title, deploy_keys_projects_attributes: [:can_push])
76+
create_params.dig(:deploy_keys_projects_attributes, '0')&.merge!(project_id: @project.id)
77+
create_params
7578
end
7679

7780
def update_params
78-
params.require(:deploy_key).permit(:title, :can_push)
81+
params.require(:deploy_key).permit(:title, deploy_keys_projects_attributes: [:id, :can_push])
7982
end
8083

8184
def authorize_update_deploy_key!

app/controllers/projects/milestones_controller.rb

+8-6
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,6 @@ def destroy
9292

9393
def milestones
9494
@milestones ||= begin
95-
if @project.group && can?(current_user, :read_group, @project.group)
96-
group = @project.group
97-
end
98-
99-
search_params = params.merge(project_ids: @project.id, group_ids: group&.id)
100-
10195
MilestonesFinder.new(search_params).execute
10296
end
10397
end
@@ -113,4 +107,12 @@ def authorize_admin_milestone!
113107
def milestone_params
114108
params.require(:milestone).permit(:title, :description, :start_date, :due_date, :state_event)
115109
end
110+
111+
def search_params
112+
if @project.group && can?(current_user, :read_group, @project.group)
113+
group = @project.group
114+
end
115+
116+
params.permit(:state).merge(project_ids: @project.id, group_ids: group&.id)
117+
end
116118
end

app/finders/milestones_finder.rb

+2-6
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,7 @@ def by_state(items)
4646
end
4747

4848
def order(items)
49-
if params.has_key?(:order)
50-
items.reorder(params[:order])
51-
else
52-
order_statement = Gitlab::Database.nulls_last_order('due_date', 'ASC')
53-
items.reorder(order_statement)
54-
end
49+
order_statement = Gitlab::Database.nulls_last_order('due_date', 'ASC')
50+
items.reorder(order_statement).order('title ASC')
5551
end
5652
end

app/models/deploy_key.rb

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
class DeployKey < Key
2-
has_many :deploy_keys_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
2+
include IgnorableColumn
3+
4+
has_many :deploy_keys_projects, inverse_of: :deploy_key, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
35
has_many :projects, through: :deploy_keys_projects
46

57
scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) }
68
scope :are_public, -> { where(public: true) }
79

10+
ignore_column :can_push
11+
12+
accepts_nested_attributes_for :deploy_keys_projects
13+
814
def private?
915
!public?
1016
end
@@ -22,10 +28,18 @@ def destroyed_when_orphaned?
2228
end
2329

2430
def has_access_to?(project)
25-
projects.include?(project)
31+
deploy_keys_project_for(project).present?
2632
end
2733

2834
def can_push_to?(project)
29-
can_push? && has_access_to?(project)
35+
!!deploy_keys_project_for(project)&.can_push?
36+
end
37+
38+
def deploy_keys_project_for(project)
39+
deploy_keys_projects.find_by(project: project)
40+
end
41+
42+
def projects_with_write_access
43+
Project.preload(:route).where(id: deploy_keys_projects.with_write_access.select(:project_id))
3044
end
3145
end

app/models/deploy_keys_project.rb

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
class DeployKeysProject < ActiveRecord::Base
22
belongs_to :project
3-
belongs_to :deploy_key
3+
belongs_to :deploy_key, inverse_of: :deploy_keys_projects
44

5-
validates :deploy_key_id, presence: true
5+
scope :without_project_deleted, -> { joins(:project).where(projects: { pending_delete: false }) }
6+
scope :in_project, ->(project) { where(project: project) }
7+
scope :with_write_access, -> { where(can_push: true) }
8+
9+
accepts_nested_attributes_for :deploy_key
10+
11+
validates :deploy_key, presence: true
612
validates :deploy_key_id, uniqueness: { scope: [:project_id], message: "already exists in project" }
713
validates :project_id, presence: true
814

app/models/global_milestone.rb

+4-4
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ def self.states_count(projects, group = nil)
4444
def self.group_milestones_states_count(group)
4545
return STATE_COUNT_HASH unless group
4646

47-
params = { group_ids: [group.id], state: 'all', order: nil }
47+
params = { group_ids: [group.id], state: 'all' }
4848

4949
relation = MilestonesFinder.new(params).execute
50-
grouped_by_state = relation.group(:state).count
50+
grouped_by_state = relation.reorder(nil).group(:state).count
5151

5252
{
5353
opened: grouped_by_state['active'] || 0,
@@ -60,10 +60,10 @@ def self.group_milestones_states_count(group)
6060
def self.legacy_group_milestone_states_count(projects)
6161
return STATE_COUNT_HASH unless projects
6262

63-
params = { project_ids: projects.map(&:id), state: 'all', order: nil }
63+
params = { project_ids: projects.map(&:id), state: 'all' }
6464

6565
relation = MilestonesFinder.new(params).execute
66-
project_milestones_by_state_and_title = relation.group(:state, :title).count
66+
project_milestones_by_state_and_title = relation.reorder(nil).group(:state, :title).count
6767

6868
opened = count_by_state(project_milestones_by_state_and_title, 'active')
6969
closed = count_by_state(project_milestones_by_state_and_title, 'closed')

app/models/hooks/web_hook.rb

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ class WebHook < ActiveRecord::Base
44
has_many :web_hook_logs, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
55

66
validates :url, presence: true, url: true
7+
validates :token, format: { without: /\n/ }
78

89
def execute(data, hook_name)
910
WebHookService.new(self, data, hook_name).execute

app/models/service.rb

+5
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ def event_field(event)
118118
nil
119119
end
120120

121+
def api_field_names
122+
fields.map { |field| field[:name] }
123+
.reject { |field_name| field_name =~ /(password|token|key)/ }
124+
end
125+
121126
def global_fields
122127
fields
123128
end

app/presenters/projects/settings/deploy_keys_presenter.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class DeployKeysPresenter < Gitlab::View::Presenter::Simple
77
delegate :size, to: :available_public_keys, prefix: true
88

99
def new_key
10-
@key ||= DeployKey.new
10+
@key ||= DeployKey.new.tap { |dk| dk.deploy_keys_projects.build }
1111
end
1212

1313
def enabled_keys

app/serializers/deploy_key_entity.rb

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,20 @@ class DeployKeyEntity < Grape::Entity
33
expose :user_id
44
expose :title
55
expose :fingerprint
6-
expose :can_push
76
expose :destroyed_when_orphaned?, as: :destroyed_when_orphaned
87
expose :almost_orphaned?, as: :almost_orphaned
98
expose :created_at
109
expose :updated_at
11-
expose :projects, using: ProjectEntity do |deploy_key|
12-
deploy_key.projects.without_deleted.select { |project| options[:user].can?(:read_project, project) }
10+
expose :deploy_keys_projects, using: DeployKeysProjectEntity do |deploy_key|
11+
deploy_key.deploy_keys_projects
12+
.without_project_deleted
13+
.select { |deploy_key_project| Ability.allowed?(options[:user], :read_project, deploy_key_project.project) }
1314
end
1415
expose :can_edit
1516

1617
private
1718

1819
def can_edit
19-
options[:user].can?(:update_deploy_key, object)
20+
Ability.allowed?(options[:user], :update_deploy_key, object)
2021
end
2122
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class DeployKeysProjectEntity < Grape::Entity
2+
expose :can_push
3+
expose :project, using: ProjectEntity
4+
end

0 commit comments

Comments
 (0)