From e0ab280b774e34fcfd6fd031616247714230ca68 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 29 Sep 2021 12:57:02 +0000 Subject: Add latest changes from gitlab-org/security/gitlab@14-3-stable-ee --- app/assets/javascripts/gfm_auto_complete.js | 33 +++++++++++++++++------- app/controllers/admin/users_controller.rb | 6 +++-- app/controllers/concerns/impersonation.rb | 6 ++++- app/controllers/import/gitea_controller.rb | 6 +++-- app/controllers/profiles/passwords_controller.rb | 8 ++++++ app/models/user.rb | 3 ++- app/services/projects/destroy_service.rb | 11 ++++++++ app/views/projects/_export.html.haml | 1 + 8 files changed, 58 insertions(+), 16 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js index 470c785f7e4..cb63c86a4fa 100644 --- a/app/assets/javascripts/gfm_auto_complete.js +++ b/app/assets/javascripts/gfm_auto_complete.js @@ -1,6 +1,6 @@ import $ from 'jquery'; import '~/lib/utils/jquery_at_who'; -import { escape, sortBy, template } from 'lodash'; +import { escape as lodashEscape, sortBy, template } from 'lodash'; import * as Emoji from '~/emoji'; import axios from '~/lib/utils/axios_utils'; import { s__, __, sprintf } from '~/locale'; @@ -11,8 +11,21 @@ import { spriteIcon } from './lib/utils/common_utils'; import { parsePikadayDate } from './lib/utils/datetime_utility'; import glRegexp from './lib/utils/regexp'; -function sanitize(str) { - return str.replace(/<(?:.|\n)*?>/gm, ''); +/** + * Escapes user input before we pass it to at.js, which + * renders it as HTML in the autocomplete dropdown. + * + * at.js allows you to reference data using `${}` syntax + * (e.g. ${search}) which it replaces with the actual data + * before rendering it in the autocomplete dropdown. + * To prevent user input from executing this `${}` syntax, + * we also need to escape the $ character. + * + * @param string user input + * @return {string} escaped user input + */ +function escape(string) { + return lodashEscape(string).replace(/\$/g, '$'); } function createMemberSearchString(member) { @@ -44,8 +57,8 @@ export function membersBeforeSave(members) { return { username: member.username, avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar, - title: sanitize(title), - search: sanitize(createMemberSearchString(member)), + title, + search: createMemberSearchString(member), icon: avatarIcon, availability: member?.availability, }; @@ -366,7 +379,7 @@ class GfmAutoComplete { } return { id: i.iid, - title: sanitize(i.title), + title: i.title, reference: i.reference, search: `${i.iid} ${i.title}`, }; @@ -404,7 +417,7 @@ class GfmAutoComplete { return { id: m.iid, - title: sanitize(m.title), + title: m.title, search: m.title, expired, dueDate, @@ -456,7 +469,7 @@ class GfmAutoComplete { } return { id: m.iid, - title: sanitize(m.title), + title: m.title, reference: m.reference, search: `${m.iid} ${m.title}`, }; @@ -492,7 +505,7 @@ class GfmAutoComplete { beforeSave(merges) { if (GfmAutoComplete.isLoading(merges)) return merges; return $.map(merges, (m) => ({ - title: sanitize(m.title), + title: m.title, color: m.color, search: m.title, set: m.set, @@ -586,7 +599,7 @@ class GfmAutoComplete { } return { id: m.id, - title: sanitize(m.title), + title: m.title, search: `${m.id} ${m.title}`, }; }); diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 9c556d16913..55e03503ba9 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -45,7 +45,7 @@ class Admin::UsersController < Admin::ApplicationController end def impersonate - if can?(user, :log_in) + if can?(user, :log_in) && !impersonation_in_progress? session[:impersonator_id] = current_user.id warden.set_user(user, scope: :user) @@ -57,7 +57,9 @@ class Admin::UsersController < Admin::ApplicationController redirect_to root_path else flash[:alert] = - if user.blocked? + if impersonation_in_progress? + _("You are already impersonating another user") + elsif user.blocked? _("You cannot impersonate a blocked user") elsif user.internal? _("You cannot impersonate an internal user") diff --git a/app/controllers/concerns/impersonation.rb b/app/controllers/concerns/impersonation.rb index a4f2c263eb4..0764fbc8eb3 100644 --- a/app/controllers/concerns/impersonation.rb +++ b/app/controllers/concerns/impersonation.rb @@ -14,7 +14,7 @@ module Impersonation protected def check_impersonation_availability - return unless session[:impersonator_id] + return unless impersonation_in_progress? unless Gitlab.config.gitlab.impersonation_enabled stop_impersonation @@ -31,6 +31,10 @@ module Impersonation current_user end + def impersonation_in_progress? + session[:impersonator_id].present? + end + def log_impersonation_event Gitlab::AppLogger.info("User #{impersonator.username} has stopped impersonating #{current_user.username}") end diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb index 5a4eef352b8..32c9da67e90 100644 --- a/app/controllers/import/gitea_controller.rb +++ b/app/controllers/import/gitea_controller.rb @@ -66,11 +66,13 @@ class Import::GiteaController < Import::GithubController override :client_options def client_options - { host: provider_url, api_version: 'v1' } + verified_url, provider_hostname = verify_blocked_uri + + { host: verified_url.scheme == 'https' ? provider_url : verified_url.to_s, api_version: 'v1', hostname: provider_hostname } end def verify_blocked_uri - Gitlab::UrlBlocker.validate!( + @verified_url_and_hostname ||= Gitlab::UrlBlocker.validate!( provider_url, allow_localhost: allow_local_requests?, allow_local_network: allow_local_requests?, diff --git a/app/controllers/profiles/passwords_controller.rb b/app/controllers/profiles/passwords_controller.rb index 85e901eb3eb..c8c2dd1c7d6 100644 --- a/app/controllers/profiles/passwords_controller.rb +++ b/app/controllers/profiles/passwords_controller.rb @@ -47,6 +47,8 @@ class Profiles::PasswordsController < Profiles::ApplicationController password_attributes[:password_automatically_set] = false unless @user.password_automatically_set || @user.valid_password?(user_params[:current_password]) + handle_invalid_current_password_attempt! + redirect_to edit_profile_password_path, alert: _('You must provide a valid current password') return end @@ -85,6 +87,12 @@ class Profiles::PasswordsController < Profiles::ApplicationController render_404 unless @user.allow_password_authentication? end + def handle_invalid_current_password_attempt! + Gitlab::AppLogger.info(message: 'Invalid current password when attempting to update user password', username: @user.username, ip: request.remote_ip) + + @user.increment_failed_attempts! + end + def user_params params.require(:user).permit(:current_password, :password, :password_confirmation) end diff --git a/app/models/user.rb b/app/models/user.rb index b5f0251f639..a4c8d606911 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1883,7 +1883,8 @@ class User < ApplicationRecord def password_expired_if_applicable? return false if bot? - return false unless password_expired? && password_automatically_set? + return false unless password_expired? + return false if password_automatically_set? return false unless allow_password_authentication? true diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index e27ea7c07e5..afa8de04fca 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -117,6 +117,7 @@ module Projects trash_relation_repositories! trash_project_repositories! destroy_web_hooks! + destroy_project_bots! # Rails attempts to load all related records into memory before # destroying: https://github.com/rails/rails/issues/22510 @@ -149,6 +150,16 @@ module Projects end end + # The project can have multiple project bots with personal access tokens generated. + # We need to remove them when a project is deleted + # rubocop: disable CodeReuse/ActiveRecord + def destroy_project_bots! + project.members.includes(:user).references(:user).merge(User.project_bot).each do |member| + Users::DestroyService.new(current_user).execute(member.user, skip_authorization: true) + end + end + # rubocop: enable CodeReuse/ActiveRecord + def remove_registry_tags return true unless Gitlab.config.registry.enabled return false unless remove_legacy_registry_tags diff --git a/app/views/projects/_export.html.haml b/app/views/projects/_export.html.haml index eb4630b84d5..97f5cdb54e5 100644 --- a/app/views/projects/_export.html.haml +++ b/app/views/projects/_export.html.haml @@ -16,6 +16,7 @@ %li= _('Job logs and artifacts') %li= _('Container registry images') %li= _('CI variables') + %li= _('Pipeline triggers') %li= _('Webhooks') %li= _('Any encrypted tokens') - if project.export_status == :finished -- cgit v1.2.3