diff options
Diffstat (limited to 'app')
29 files changed, 122 insertions, 100 deletions
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index 5463397f475..c17d2186e29 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -31,8 +31,6 @@ #= require ace/ace #= require ace/ext-searchbox #= require underscore -#= require nprogress -#= require nprogress-turbolinks #= require dropzone #= require mousetrap #= require mousetrap/pause diff --git a/app/assets/javascripts/logo.js.coffee b/app/assets/javascripts/logo.js.coffee index 35b2fbbba07..d14b7139237 100644 --- a/app/assets/javascripts/logo.js.coffee +++ b/app/assets/javascripts/logo.js.coffee @@ -1,4 +1,4 @@ -NProgress.configure(showSpinner: false) +Turbolinks.enableProgressBar(); defaultClass = 'tanuki-shape' pieces = [ diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee index 40cfa59a229..23a218b4c7d 100644 --- a/app/assets/javascripts/merge_request_tabs.js.coffee +++ b/app/assets/javascripts/merge_request_tabs.js.coffee @@ -146,6 +146,7 @@ class @MergeRequestTabs url: "#{source}.json" + @_location.search success: (data) => document.querySelector("div#diffs").innerHTML = data.html + $('.js-timeago').timeago() $('div#diffs .js-syntax-highlight').syntaxHighlight() @expandViewContainer() if @diffViewType() is 'parallel' @diffsLoaded = true diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index f51054f13dc..e2d590f4df4 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -26,12 +26,6 @@ @import "framework"; /* - * NProgress load bar css - */ -@import 'nprogress'; -@import 'nprogress-bootstrap'; - -/* * Font icons */ @import "font-awesome"; diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index fa7641b1676..e2a30f5ed34 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -26,6 +26,7 @@ @import "framework/mobile.scss"; @import "framework/nav.scss"; @import "framework/pagination.scss"; +@import "framework/progress.scss"; @import "framework/panels.scss"; @import "framework/selects.scss"; @import "framework/sidebar.scss"; diff --git a/app/assets/stylesheets/framework/progress.scss b/app/assets/stylesheets/framework/progress.scss new file mode 100644 index 00000000000..e9800bd24b5 --- /dev/null +++ b/app/assets/stylesheets/framework/progress.scss @@ -0,0 +1,5 @@ +html.turbolinks-progress-bar::before { + background-color: $progress-color!important; + height: 2px!important; + box-shadow: 0 0 10px $progress-color, 0 0 5px $progress-color; +} diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index e0ccd6f100f..de947c89c19 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -13,6 +13,19 @@ transition-duration: .3s; } + .gitlab-text-container-link { + z-index: 1; + position: absolute; + left: 0px; + } + + #logo { + z-index: 2; + position: absolute; + width: 58px; + cursor: pointer; + } + &.right-sidebar-expanded { padding-right: $gutter_width; } @@ -74,7 +87,7 @@ width: 158px; float: left; margin: 0; - margin-left: 14px; + margin-left: 50px; font-size: 19px; line-height: 41px; font-weight: normal; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 2706d031d7b..7834cb0bfa5 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -7,7 +7,7 @@ $gl-header-color: #323232; $gl-link-color: #333c48; $md-text-color: #444; $md-link-color: #3084bb; -$nprogress-color: #c0392b; +$progress-color: #c0392b; $gl-font-size: 15px; $list-font-size: 15px; $sidebar_collapsed_width: 62px; diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss index f9c6f1b39f9..61bec02f6c5 100644 --- a/app/assets/stylesheets/pages/login.scss +++ b/app/assets/stylesheets/pages/login.scss @@ -8,6 +8,10 @@ max-width: none; } + .flash-container { + margin-bottom: $gl-padding; + } + .brand-holder { font-size: 18px; line-height: 1.5; diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 19ead07c06a..d5f9852ebed 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -14,6 +14,18 @@ ul.notes { margin: 0px; padding: 0px; + .timeline-icon { + float: left; + } + + .timeline-content { + margin-left: 55px; + } + + .note_created_ago, .note-updated-at { + white-space: nowrap; + } + .system-note { font-size: 14px; padding-top: 10px; @@ -151,6 +163,7 @@ ul.notes { border-left: none; &.notes_line { + vertical-align: middle; text-align: center; padding: 10px 0; background: #FFF; diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss index 2f57f21963d..0dc5a905f99 100644 --- a/app/assets/stylesheets/pages/todos.scss +++ b/app/assets/stylesheets/pages/todos.scss @@ -12,29 +12,10 @@ } } -.todos { - .panel { - border-top: none; - margin-bottom: 0; - } -} - .todo-item { font-size: $gl-font-size; - padding: $gl-padding-top 0 $gl-padding-top ($gl-avatar-size + $gl-padding-top); - border-bottom: 1px solid $table-border-color; - color: #7f8fa4; - - &.todo-inline { - .avatar { - position: relative; - top: -2px; - } - - .todo-title { - line-height: 40px; - } - } + padding-left: $gl-avatar-size + $gl-padding-top; + color: $secondary-text; a { color: #4c4e54; @@ -48,7 +29,7 @@ @include str-truncated(calc(100% - 174px)); font-weight: 600; - .author_name { + .author-name { color: #333; } } @@ -88,17 +69,7 @@ margin-bottom: 0; } } - - .todo-note-icon { - color: #777; - float: left; - font-size: $gl-font-size; - line-height: 16px; - margin-right: 5px; - } } - - &:last-child { border:none } } @media (max-width: $screen-xs-max) { diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb index f3bfede4354..8f83fdd02bc 100644 --- a/app/controllers/profiles/two_factor_auths_controller.rb +++ b/app/controllers/profiles/two_factor_auths_controller.rb @@ -12,11 +12,13 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController current_user.save! if current_user.changed? - if two_factor_grace_period_expired? - flash.now[:alert] = 'You must enable Two-factor Authentication for your account.' - else - grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours - flash.now[:alert] = "You must enable Two-factor Authentication for your account before #{l(grace_period_deadline)}." + if two_factor_authentication_required? + if two_factor_grace_period_expired? + flash.now[:alert] = 'You must enable Two-factor Authentication for your account.' + else + grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours + flash.now[:alert] = "You must enable Two-factor Authentication for your account before #{l(grace_period_deadline)}." + end end @qr_code = build_qr_code diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb index f7e6bb34443..b64dbbd89ce 100644 --- a/app/controllers/projects/avatars_controller.rb +++ b/app/controllers/projects/avatars_controller.rb @@ -1,4 +1,6 @@ class Projects::AvatarsController < Projects::ApplicationController + include BlobHelper + before_action :project def show @@ -7,7 +9,7 @@ class Projects::AvatarsController < Projects::ApplicationController headers['X-Content-Type-Options'] = 'nosniff' headers.store(*Gitlab::Workhorse.send_git_blob(@repository, @blob)) headers['Content-Disposition'] = 'inline' - headers['Content-Type'] = @blob.content_type + headers['Content-Type'] = safe_content_type(@blob) head :ok # 'render nothing: true' messes up the Content-Type else render_404 diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb index 0c551501ca4..a0835c9aad0 100644 --- a/app/controllers/projects/forks_controller.rb +++ b/app/controllers/projects/forks_controller.rb @@ -4,12 +4,22 @@ class Projects::ForksController < Projects::ApplicationController before_action :authorize_download_code! def index - @sort = params[:sort] || 'id_desc' - @all_forks = project.forks.includes(:creator).order_by(@sort) - - @public_forks, @protected_forks = @all_forks.partition do |project| - can?(current_user, :read_project, project) - end + base_query = project.forks.includes(:creator) + + @forks = if current_user + base_query.where('projects.visibility_level IN (?) OR projects.id IN (?)', + Project.public_and_internal_levels, + current_user.authorized_projects.pluck(:id)) + else + base_query.where('projects.visibility_level = ?', Project::PUBLIC) + end + + @total_forks_count = base_query.size + @private_forks_count = @total_forks_count - @forks.size + @public_forks_count = @total_forks_count - @private_forks_count + + @sort = params[:sort] || 'id_desc' + @forks = @forks.order_by(@sort).page(params[:page]).per(PER_PAGE) end def new diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index 87b4d08da0e..d9723acb1d9 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -1,6 +1,7 @@ # Controller for viewing a file's raw class Projects::RawController < Projects::ApplicationController include ExtractsPath + include BlobHelper before_action :require_non_empty_project before_action :assign_ref_vars @@ -17,7 +18,7 @@ class Projects::RawController < Projects::ApplicationController else headers.store(*Gitlab::Workhorse.send_git_blob(@repository, @blob)) headers['Content-Disposition'] = 'inline' - headers['Content-Type'] = get_blob_type + headers['Content-Type'] = safe_content_type(@blob) head :ok # 'render nothing: true' messes up the Content-Type end else @@ -27,16 +28,6 @@ class Projects::RawController < Projects::ApplicationController private - def get_blob_type - if @blob.text? - 'text/plain; charset=utf-8' - elsif @blob.image? - @blob.content_type - else - 'application/octet-stream' - end - end - def send_lfs_object lfs_object = find_lfs_object diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index eae19214bf5..4b1cf242885 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -89,7 +89,7 @@ class UsersController < ApplicationController def contributions_calendar @contributions_calendar ||= Gitlab::ContributionsCalendar. - new(contributed_projects.reject(&:forked?), @user) + new(contributed_projects, @user) end def load_events diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 7143a744869..7f63a2e2cb4 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -134,4 +134,22 @@ module BlobHelper blob.data = Loofah.scrub_fragment(blob.data, :strip).to_xml blob end + + # If we blindly set the 'real' content type when serving a Git blob we + # are enabling XSS attacks. An attacker could upload e.g. a Javascript + # file to a Git repository, trick the browser of a victim into + # downloading the blob, and then the 'application/javascript' content + # type would tell the browser to execute the attacker's Javascript. By + # overriding the content type and setting it to 'text/plain' (in the + # example of Javascript) we tell the browser of the victim not to + # execute untrusted data. + def safe_content_type(blob) + if blob.text? + 'text/plain; charset=utf-8' + elsif blob.image? + blob.content_type + else + 'application/octet-stream' + end + end end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 31bf45baeb7..e5fcaab9551 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -168,11 +168,11 @@ module EventsHelper link_to(namespace_project_snippet_path(event.project.namespace, event.project, event.note_target)) do - "#{event.note_target_type} ##{truncate event.note_target_id}" + "#{event.note_target_type} #{truncate event.note_target.to_reference}" end else link_to event_note_target_path(event) do - "#{event.note_target_type} ##{truncate event.note_target_iid}" + "#{event.note_target_type} #{truncate event.note_target.to_reference}" end end else diff --git a/app/models/user.rb b/app/models/user.rb index 6baf2468ade..3098d49d58a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -169,7 +169,7 @@ class User < ActiveRecord::Base validates :avatar_crop_x, :avatar_crop_y, :avatar_crop_size, numericality: { only_integer: true }, presence: true, - if: ->(user) { user.avatar? } + if: ->(user) { user.avatar? && user.avatar_changed? } before_validation :generate_password, on: :create before_validation :restricted_signup_domains, on: :create @@ -362,17 +362,19 @@ class User < ActiveRecord::Base def disable_two_factor! update_attributes( - two_factor_enabled: false, - encrypted_otp_secret: nil, - encrypted_otp_secret_iv: nil, - encrypted_otp_secret_salt: nil, - otp_backup_codes: nil + two_factor_enabled: false, + encrypted_otp_secret: nil, + encrypted_otp_secret_iv: nil, + encrypted_otp_secret_salt: nil, + otp_grace_period_started_at: nil, + otp_backup_codes: nil ) end def namespace_uniq # Return early if username already failed the first uniqueness validation - return if self.errors[:username].include?('has already been taken') + return if self.errors.key?(:username) && + self.errors[:username].include?('has already been taken') namespace_name = self.username existing_namespace = Namespace.by_path(namespace_name) diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml index 6975f6ed0db..f878d36e739 100644 --- a/app/views/dashboard/todos/_todo.html.haml +++ b/app/views/dashboard/todos/_todo.html.haml @@ -1,11 +1,11 @@ %li{class: "todo todo-#{todo.done? ? 'done' : 'pending'}", id: dom_id(todo) } - .todo-item{class: 'todo-block'} + .todo-item.todo-block = image_tag avatar_icon(todo.author_email, 40), class: 'avatar s40', alt:'' .todo-title - %span.author_name + %span.author-name = link_to_author todo - %span.todo_label + %span.todo-label = todo_action_name(todo) = todo_target_link(todo) diff --git a/app/views/events/event/_common.html.haml b/app/views/events/event/_common.html.haml index 4ecf1c33d2a..e9e16a7646f 100644 --- a/app/views/events/event/_common.html.haml +++ b/app/views/events/event/_common.html.haml @@ -4,7 +4,7 @@ = event_action_name(event) - if event.target - %strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target] + %strong= link_to event.target.to_reference, [event.project.namespace.becomes(Namespace), event.project, event.target] = event_preposition(event) diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index e53d5b07801..c799e9c588d 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -4,7 +4,7 @@ .header-logo %a#logo = brand_header_logo - = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home' do + = link_to root_path, class: 'gitlab-text-container-link', title: 'Dashboard', id: 'js-shortcuts-home' do .gitlab-text-container %h3 GitLab diff --git a/app/views/layouts/ci/_page.html.haml b/app/views/layouts/ci/_page.html.haml index 3cfd36720f0..a13241bebee 100644 --- a/app/views/layouts/ci/_page.html.haml +++ b/app/views/layouts/ci/_page.html.haml @@ -4,7 +4,7 @@ .header-logo %a#logo = brand_header_logo - = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home' do + = link_to root_path, class: 'gitlab-text-container-link', title: 'Dashboard', id: 'js-shortcuts-home' do .gitlab-text-container %h3 GitLab diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml index f99bc9a85eb..63ede71e6f1 100644 --- a/app/views/projects/diffs/_warning.html.haml +++ b/app/views/projects/diffs/_warning.html.haml @@ -3,17 +3,16 @@ Too many changes to show. .pull-right - unless diff_hard_limit_enabled? - = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: nil)), class: "btn btn-sm btn-warning" + = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: nil)), class: "btn btn-sm" - if current_controller?(:commit) or current_controller?(:merge_requests) - if current_controller?(:commit) - = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-warning btn-sm" - = link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-warning btn-sm" + = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-sm" + = link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-sm" - elsif @merge_request && @merge_request.persisted? - = link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-warning btn-sm" - = link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-warning btn-sm" + = link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-sm" + = link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-sm" %p To preserve performance only %strong #{shown_files_count} of #{diffs.size} files are displayed. - diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml index 42fa6fdb782..ace22625d1d 100644 --- a/app/views/projects/forks/index.html.haml +++ b/app/views/projects/forks/index.html.haml @@ -1,9 +1,7 @@ .top-area .nav-text - - public_count = @public_forks.size - - protected_count = @protected_forks.size - - full_count_title = "#{public_count} public and #{protected_count} private" - == #{pluralize(@all_forks.size, 'fork')}: #{full_count_title} + - full_count_title = "#{@public_forks_count} public and #{@private_forks_count} private" + == #{pluralize(@total_forks_count, 'fork')}: #{full_count_title} .nav-controls = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter project-filter-form-field form-control input-short', @@ -41,17 +39,17 @@ .projects-list-holder - - if @public_forks.blank? + - if @forks.blank? %ul.content-list %li .nothing-here-block No forks to show - else - = render 'shared/projects/list', projects: @public_forks, use_creator_avatar: true, + = render 'shared/projects/list', projects: @forks, use_creator_avatar: true, forks: true, show_last_commit_as_description: true - - if protected_count > 0 + - if @private_forks_count > 0 %ul.projects-list.private-forks-notice %li.project-row = icon('lock fw', base: 'circle', class: 'fa-lg private-fork-icon') - %strong= pluralize(protected_count, 'private fork') + %strong= pluralize(@private_forks_count, 'private fork') %span you have no access to. diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml index b9d5982a56f..18cf3f14f0b 100644 --- a/app/views/projects/merge_requests/_merge_request.html.haml +++ b/app/views/projects/merge_requests/_merge_request.html.haml @@ -48,7 +48,7 @@ = note_count .merge-request-info - \##{merge_request.iid} · + #{merge_request.to_reference} · opened #{time_ago_with_tooltip(merge_request.created_at, placement: 'bottom')} by #{link_to_member(@project, merge_request.author, avatar: false)} - if merge_request.target_project.default_branch != merge_request.target_branch diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 648512e5379..d7bc26e24b9 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -1,4 +1,4 @@ -- page_title "#{@merge_request.title} (##{@merge_request.iid})", "Merge Requests" +- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", "Merge Requests" - page_description @merge_request.description - page_card_attributes @merge_request.card_attributes diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index 14ea7b17786..b634a4af8d2 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -2,7 +2,7 @@ .status-box{ class: status_box_class(@merge_request) } = @merge_request.state_human_name %span.identifier - Merge Request ##{@merge_request.iid} + Merge Request #{@merge_request.to_reference} %span.creator · by #{link_to_member(@project, @merge_request.author, size: 24)} diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index e858c412836..52972576aff 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -28,7 +28,7 @@ %a{name: dom_id(note), href: "##{dom_id(note)}", title: 'Link here'} = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note_created_ago') - if note.updated_at != note.created_at - %span + %span.note-updated-at · = icon('edit', title: 'edited') = time_ago_with_tooltip(note.updated_at, placement: 'bottom', html_class: 'note_edited_ago') |