diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-26 14:36:54 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-26 14:36:54 +0000 |
commit | daf5ae5bd439f1f32363d410129d5b9e73fbb539 (patch) | |
tree | 6d670487dc3dccf1a0c3e6b8337e5b4ab9da4ee9 /app | |
parent | 6e8c2290dab8ae1612dff80e312911bc1147edaa (diff) | |
download | gitlab-ce-daf5ae5bd439f1f32363d410129d5b9e73fbb539.tar.gz |
Add latest changes from gitlab-org/security/gitlab@15-3-stable-ee
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/ide/components/preview/clientside.vue | 22 | ||||
-rw-r--r-- | app/assets/javascripts/ide/components/preview/navigator.vue | 6 | ||||
-rw-r--r-- | app/controllers/jwt_controller.rb | 45 | ||||
-rw-r--r-- | app/controllers/repositories/git_http_client_controller.rb | 23 | ||||
-rw-r--r-- | app/helpers/commits_helper.rb | 2 | ||||
-rw-r--r-- | app/models/snippet.rb | 15 | ||||
-rw-r--r-- | app/presenters/commit_presenter.rb | 10 | ||||
-rw-r--r-- | app/validators/bytesize_validator.rb | 30 | ||||
-rw-r--r-- | app/views/projects/commits/_commit.html.haml | 2 |
9 files changed, 100 insertions, 55 deletions
diff --git a/app/assets/javascripts/ide/components/preview/clientside.vue b/app/assets/javascripts/ide/components/preview/clientside.vue index b1f6f2c87b9..70b881b6ff6 100644 --- a/app/assets/javascripts/ide/components/preview/clientside.vue +++ b/app/assets/javascripts/ide/components/preview/clientside.vue @@ -2,7 +2,7 @@ import { GlLoadingIcon } from '@gitlab/ui'; import { listen } from 'codesandbox-api'; import { isEmpty, debounce } from 'lodash'; -import { Manager } from 'smooshpack'; +import { SandpackClient } from '@codesandbox/sandpack-client'; import { mapActions, mapGetters, mapState } from 'vuex'; import { packageJsonPath, @@ -21,7 +21,7 @@ export default { }, data() { return { - manager: {}, + client: {}, loading: false, sandpackReady: false, }; @@ -94,11 +94,11 @@ export default { this.sandpackReady = false; eventHub.$off('ide.files.change', this.onFilesChangeCallback); - if (!isEmpty(this.manager)) { - this.manager.listener(); + if (!isEmpty(this.client)) { + this.client.cleanup(); } - this.manager = {}; + this.client = {}; if (this.listener) { this.listener(); @@ -120,7 +120,7 @@ export default { return this.loadFileContent(this.mainEntry) .then(() => this.$nextTick()) .then(() => { - this.initManager(); + this.initClient(); this.listener = listen((e) => { switch (e.type) { @@ -136,15 +136,15 @@ export default { update() { if (!this.sandpackReady) return; - if (isEmpty(this.manager)) { + if (isEmpty(this.client)) { this.initPreview(); return; } - this.manager.updatePreview(this.sandboxOpts); + this.client.updatePreview(this.sandboxOpts); }, - initManager() { + initClient() { const { codesandboxBundlerUrl: bundlerURL } = this; const settings = { @@ -155,7 +155,7 @@ export default { ...(bundlerURL ? { bundlerURL } : {}), }; - this.manager = new Manager('#ide-preview', this.sandboxOpts, settings); + this.client = new SandpackClient('#ide-preview', this.sandboxOpts, settings); }, }, }; @@ -164,7 +164,7 @@ export default { <template> <div class="preview h-100 w-100 d-flex flex-column gl-bg-white"> <template v-if="showPreview"> - <navigator :manager="manager" /> + <navigator :client="client" /> <div id="ide-preview"></div> </template> <div diff --git a/app/assets/javascripts/ide/components/preview/navigator.vue b/app/assets/javascripts/ide/components/preview/navigator.vue index 96f9a85c23f..852de16d508 100644 --- a/app/assets/javascripts/ide/components/preview/navigator.vue +++ b/app/assets/javascripts/ide/components/preview/navigator.vue @@ -8,7 +8,7 @@ export default { GlLoadingIcon, }, props: { - manager: { + client: { type: Object, required: true, }, @@ -51,7 +51,7 @@ export default { onUrlChange(e) { const lastPath = this.path; - this.path = e.url.replace(this.manager.bundlerURL, '') || '/'; + this.path = e.url.replace(this.client.bundlerURL, '') || '/'; if (lastPath !== this.path) { this.currentBrowsingIndex = @@ -79,7 +79,7 @@ export default { }, visitPath(path) { // eslint-disable-next-line vue/no-mutating-props - this.manager.iframe.src = `${this.manager.bundlerURL}${path}`; + this.client.iframe.src = `${this.client.bundlerURL}${path}`; }, }, }; diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb index 8eebf9fbf6b..84f5632854b 100644 --- a/app/controllers/jwt_controller.rb +++ b/app/controllers/jwt_controller.rb @@ -36,31 +36,40 @@ class JwtController < ApplicationController @authentication_result = Gitlab::Auth.find_for_git_client(login, password, project: nil, ip: request.ip) if @authentication_result.failed? - render_unauthorized + log_authentication_failed(login, @authentication_result) + render_access_denied end end rescue Gitlab::Auth::MissingPersonalAccessTokenError - render_missing_personal_access_token + render_access_denied end - def render_missing_personal_access_token - render json: { - errors: [ - { code: 'UNAUTHORIZED', - message: _('HTTP Basic: Access denied\n' \ - 'You must use a personal access token with \'api\' scope for Git over HTTP.\n' \ - 'You can generate one at %{profile_personal_access_tokens_url}') % { profile_personal_access_tokens_url: profile_personal_access_tokens_url } } - ] - }, status: :unauthorized + def log_authentication_failed(login, result) + log_info = { + message: 'JWT authentication failed', + http_user: login, + remote_ip: request.ip, + auth_service: params[:service], + 'auth_result.type': result.type, + 'auth_result.actor_type': result.actor&.class + }.merge(::Gitlab::ApplicationContext.current) + + Gitlab::AuthLogger.warn(log_info) end - def render_unauthorized - render json: { - errors: [ - { code: 'UNAUTHORIZED', - message: 'HTTP Basic: Access denied' } - ] - }, status: :unauthorized + def render_access_denied + help_page = help_page_url( + 'user/profile/account/two_factor_authentication', + anchor: 'troubleshooting' + ) + + render( + json: { errors: [{ + code: 'UNAUTHORIZED', + message: format(_("HTTP Basic: Access denied. The provided password or token is incorrect or your account has 2FA enabled and you must use a personal access token instead of a password. See %{help_page_url}"), help_page_url: help_page) + }] }, + status: :unauthorized + ) end def auth_params diff --git a/app/controllers/repositories/git_http_client_controller.rb b/app/controllers/repositories/git_http_client_controller.rb index 8d7ba3e38c0..fbf5d82a45b 100644 --- a/app/controllers/repositories/git_http_client_controller.rb +++ b/app/controllers/repositories/git_http_client_controller.rb @@ -67,9 +67,21 @@ module Repositories end send_challenges - render plain: "HTTP Basic: Access denied\n", status: :unauthorized + render_access_denied rescue Gitlab::Auth::MissingPersonalAccessTokenError - render_missing_personal_access_token + render_access_denied + end + + def render_access_denied + help_page = help_page_url( + 'topics/git/troubleshooting_git', + anchor: 'error-on-git-fetch-http-basic-access-denied' + ) + + render( + plain: format(_("HTTP Basic: Access denied. The provided password or token is incorrect or your account has 2FA enabled and you must use a personal access token instead of a password. See %{help_page_url}"), help_page_url: help_page), + status: :unauthorized + ) end def basic_auth_provided? @@ -103,13 +115,6 @@ module Repositories @container, @project, @repo_type, @redirected_path = Gitlab::RepoPath.parse(repository_path) end - def render_missing_personal_access_token - render plain: "HTTP Basic: Access denied\n" \ - "You must use a personal access token with 'read_repository' or 'write_repository' scope for Git over HTTP.\n" \ - "You can generate one at #{profile_personal_access_tokens_url}", - status: :unauthorized - end - def repository strong_memoize(:repository) do repo_type.repository_for(container) diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 1920650bc93..4493bc2bc6d 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -171,7 +171,7 @@ module CommitsHelper ref, { merge_request: merge_request&.cache_key, - pipeline_status: commit.status_for(ref)&.cache_key, + pipeline_status: commit.detailed_status_for(ref)&.cache_key, xhr: request.xhr?, controller: controller.controller_path, path: @path # referred to in #link_to_browse_code diff --git a/app/models/snippet.rb b/app/models/snippet.rb index fd882633a44..943d09d983b 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -22,6 +22,8 @@ class Snippet < ApplicationRecord MAX_FILE_COUNT = 10 + DESCRIPTION_LENGTH_MAX = 1.megabyte + cache_markdown_field :title, pipeline: :single_line cache_markdown_field :description cache_markdown_field :content @@ -57,19 +59,10 @@ class Snippet < ApplicationRecord validates :title, presence: true, length: { maximum: 255 } validates :file_name, length: { maximum: 255 } + validates :description, bytesize: { maximum: -> { DESCRIPTION_LENGTH_MAX } }, if: :description_changed? validates :content, presence: true - validates :content, - length: { - maximum: ->(_) { Gitlab::CurrentSettings.snippet_size_limit }, - message: -> (_, data) do - current_value = ActiveSupport::NumberHelper.number_to_human_size(data[:value].size) - max_size = ActiveSupport::NumberHelper.number_to_human_size(Gitlab::CurrentSettings.snippet_size_limit) - - _("is too long (%{current_value}). The maximum size is %{max_size}.") % { current_value: current_value, max_size: max_size } - end - }, - if: :content_changed? + validates :content, bytesize: { maximum: -> { Gitlab::CurrentSettings.snippet_size_limit } }, if: :content_changed? after_create :create_statistics diff --git a/app/presenters/commit_presenter.rb b/app/presenters/commit_presenter.rb index 7df45ca03bb..2cb88179845 100644 --- a/app/presenters/commit_presenter.rb +++ b/app/presenters/commit_presenter.rb @@ -5,12 +5,20 @@ class CommitPresenter < Gitlab::View::Presenter::Delegated presents ::Commit, as: :commit - def status_for(ref) + def detailed_status_for(ref) + return unless can?(current_user, :read_pipeline, commit.latest_pipeline(ref)) return unless can?(current_user, :read_commit_status, commit.project) commit.latest_pipeline(ref)&.detailed_status(current_user) end + def status_for(ref = nil) + return unless can?(current_user, :read_pipeline, commit.latest_pipeline(ref)) + return unless can?(current_user, :read_commit_status, commit.project) + + commit.status(ref) + end + def any_pipelines? return false unless can?(current_user, :read_pipeline, commit.project) diff --git a/app/validators/bytesize_validator.rb b/app/validators/bytesize_validator.rb new file mode 100644 index 00000000000..adbdd81d5c4 --- /dev/null +++ b/app/validators/bytesize_validator.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +# BytesizeValidator +# +# Custom validator for verifying that bytesize of a field doesn't exceed the specified limit. +# It is different from Rails length validator because it takes .bytesize into account instead of .size/.length +# +# Example: +# +# class Snippet < ActiveRecord::Base +# validates :content, bytesize: { maximum: -> { Gitlab::CurrentSettings.snippet_size_limit } } +# end +# +# Configuration options: +# * <tt>maximum</tt> - Proc that evaluates the bytesize limit that cannot be exceeded +class BytesizeValidator < ActiveModel::EachValidator + def validate_each(record, attr, value) + size = value.to_s.bytesize + max_size = options[:maximum].call + + return if size <= max_size + + error_message = format(_('is too long (%{size}). The maximum size is %{max_size}.'), { + size: ActiveSupport::NumberHelper.number_to_human_size(size), + max_size: ActiveSupport::NumberHelper.number_to_human_size(max_size) + }) + + record.errors.add(attr, error_message) + end +end diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 71485e203db..6f44c130603 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -14,7 +14,7 @@ - project = local_assigns.fetch(:project) { merge_request&.project } - ref = local_assigns.fetch(:ref) { merge_request&.source_branch } - commit = commit.present(current_user: current_user) -- commit_status = commit.status_for(ref) +- commit_status = commit.detailed_status_for(ref) - collapsible = local_assigns.fetch(:collapsible, true) - link_data_attrs = local_assigns.fetch(:link_data_attrs, {}) - link = commit_path(project, commit, merge_request: merge_request) |