diff options
author | Ash McKenzie <amckenzie@gitlab.com> | 2018-06-10 22:56:17 +1000 |
---|---|---|
committer | Ash McKenzie <amckenzie@gitlab.com> | 2018-06-13 12:11:38 +1000 |
commit | 2f297034036055aaf37f86ece22723aedf8741bf (patch) | |
tree | 731fab3c82dd23d63ba9b89ad101d11e409d2fe0 /app | |
parent | f646a8b9bc95fd6cecaa754f7dd0e8370c201502 (diff) | |
download | gitlab-ce-ash.mckenzie/secret-snippets.tar.gz |
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/concerns/snippets_url.rb | 39 | ||||
-rw-r--r-- | app/controllers/snippets_controller.rb | 10 | ||||
-rw-r--r-- | app/finders/snippets_finder.rb | 2 | ||||
-rw-r--r-- | app/helpers/icons_helper.rb | 2 | ||||
-rw-r--r-- | app/helpers/snippets_helper.rb | 19 | ||||
-rw-r--r-- | app/helpers/visibility_level_helper.rb | 6 | ||||
-rw-r--r-- | app/models/snippet.rb | 13 | ||||
-rw-r--r-- | app/views/dashboard/snippets/index.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/snippets/index.html.haml | 2 | ||||
-rw-r--r-- | app/views/shared/_visibility_radios.html.haml | 2 | ||||
-rw-r--r-- | app/views/shared/snippets/_header.html.haml | 4 | ||||
-rw-r--r-- | app/views/snippets/_snippets_scope_menu.html.haml | 7 |
12 files changed, 95 insertions, 13 deletions
diff --git a/app/controllers/concerns/snippets_url.rb b/app/controllers/concerns/snippets_url.rb new file mode 100644 index 00000000000..e79b7194b27 --- /dev/null +++ b/app/controllers/concerns/snippets_url.rb @@ -0,0 +1,39 @@ +module SnippetsUrl + extend ActiveSupport::Concern + + private + + attr_reader :snippet + + def authorize_secret_snippet! + if snippet.secret? + return if params[:secret] == snippet.secret_word + + return render_404 + end + + current_user ? render_404 : authenticate_user! + end + + def ensure_complete_url + redirect_to complete_url unless url_contains_secret? + end + + def url_contains_secret? + request.query_parameters['secret'] == snippet.secret_word + end + + def complete_url + @complete_url ||= begin + url = current_url + query_hash = Rack::Utils.parse_nested_query(url.query) + query_hash['secret'] = snippet.secret_word + url.query = query_hash.to_query + url.to_s + end + end + + def current_url + @current_url ||= URI.parse(request.original_url) + end +end diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index 3d51520ddf4..890614c0e28 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -3,6 +3,7 @@ class SnippetsController < ApplicationController include ToggleAwardEmoji include SpammableActions include SnippetsActions + include SnippetsUrl include RendersBlob include PreviewMarkdown @@ -13,6 +14,9 @@ class SnippetsController < ApplicationController # Allow read snippet before_action :authorize_read_snippet!, only: [:show, :raw] + # Ensure we're displaying the correct url, specifically for secret snippets + before_action :ensure_complete_url, only: [:show, :raw] + # Allow modify snippet before_action :authorize_update_snippet!, only: [:edit, :update] @@ -108,11 +112,7 @@ class SnippetsController < ApplicationController def authorize_read_snippet! return if can?(current_user, :read_personal_snippet, @snippet) - if current_user - render_404 - else - authenticate_user! - end + authorize_secret_snippet! end def authorize_update_snippet! diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb index d498a2d6d11..b678f481ca5 100644 --- a/app/finders/snippets_finder.rb +++ b/app/finders/snippets_finder.rb @@ -124,6 +124,8 @@ class SnippetsFinder < UnionFinder Snippet::PRIVATE when 'are_internal' Snippet::INTERNAL + when 'are_secret' + Snippet::SECRET when 'are_public' Snippet::PUBLIC else diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index 2f304b040c7..12406673836 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -82,6 +82,8 @@ module IconsHelper 'lock' when Gitlab::VisibilityLevel::INTERNAL 'shield' + when Gitlab::VisibilityLevel::SECRET + 'user-secret' else # Gitlab::VisibilityLevel::PUBLIC 'globe' end diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb index 733832c1bbb..f5db47cd6a3 100644 --- a/app/helpers/snippets_helper.rb +++ b/app/helpers/snippets_helper.rb @@ -1,5 +1,7 @@ module SnippetsHelper - def reliable_snippet_path(snippet, opts = nil) + def reliable_snippet_path(snippet, opts = {}) + opts[:secret] = snippet.secret_word if snippet.secret? + if snippet.project_id? project_snippet_path(snippet.project, snippet, opts) else @@ -7,6 +9,21 @@ module SnippetsHelper end end + def reliable_snippet_url(snippet, opts = {}) + opts[:secret] = snippet.secret_word if snippet.secret? + + if snippet.project_id? + project_snippet_url(snippet.project, snippet, opts) + else + snippet_url(snippet, opts) + end + end + + def shareable_snippets_link(snippet) + url = reliable_snippet_url(snippet) + link_to(url, url, id: 'shareable_link_url', title: 'Open') + end + def download_snippet_path(snippet) if snippet.project_id raw_project_snippet_path(@project, snippet, inline: false) diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb index e395cda03d3..f2c81c87f3b 100644 --- a/app/helpers/visibility_level_helper.rb +++ b/app/helpers/visibility_level_helper.rb @@ -60,6 +60,8 @@ module VisibilityLevelHelper "The snippet is visible to any logged in user." when Gitlab::VisibilityLevel::PUBLIC "The snippet can be accessed without any authentication." + when Gitlab::VisibilityLevel::SECRET + "The snippet can be accessed without any authentication, but is not searchable." end end @@ -143,9 +145,7 @@ module VisibilityLevelHelper end def visibility_level_label(level) - # The visibility level can be: - # 'VisibilityLevel|Private', 'VisibilityLevel|Internal', 'VisibilityLevel|Public' - s_(Project.visibility_levels.key(level)) + s_(::Gitlab::VisibilityLevel.all_options.key(level)) end def restricted_visibility_levels(show_all = false) diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 644120453cf..4ee229e3013 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -35,18 +35,21 @@ class Snippet < ActiveRecord::Base delegate :name, :email, to: :author, prefix: true, allow_nil: true + before_save :ensure_secret_word_added_if_needed + validates :author, presence: true validates :title, presence: true, length: { maximum: 255 } validates :file_name, length: { maximum: 255 } validates :content, presence: true - validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values } + validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.all_values } # Scopes scope :are_internal, -> { where(visibility_level: Snippet::INTERNAL) } scope :are_private, -> { where(visibility_level: Snippet::PRIVATE) } scope :are_public, -> { where(visibility_level: Snippet::PUBLIC) } + scope :are_secret, -> { where(visibility_level: Snippet::SECRET) } scope :public_and_internal, -> { where(visibility_level: [Snippet::PUBLIC, Snippet::INTERNAL]) } scope :fresh, -> { order("created_at DESC") } @@ -173,4 +176,12 @@ class Snippet < ActiveRecord::Base ::Project end end + + private + + def ensure_secret_word_added_if_needed + return if secret? && self.secret_word + + self.secret_word = secret? ? SecureRandom.hex : nil + end end diff --git a/app/views/dashboard/snippets/index.html.haml b/app/views/dashboard/snippets/index.html.haml index 4391624196b..7c2638baee2 100644 --- a/app/views/dashboard/snippets/index.html.haml +++ b/app/views/dashboard/snippets/index.html.haml @@ -3,7 +3,7 @@ - header_title "Snippets", dashboard_snippets_path = render 'dashboard/snippets_head' -= render partial: 'snippets/snippets_scope_menu', locals: { include_private: true } += render partial: 'snippets/snippets_scope_menu', locals: { include_private: true, include_secret: true } .d-block.d-sm-none diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml index 65efc083fdd..7a3a16ad44e 100644 --- a/app/views/projects/snippets/index.html.haml +++ b/app/views/projects/snippets/index.html.haml @@ -3,7 +3,7 @@ - if current_user .top-area - include_private = @project.team.member?(current_user) || current_user.admin? - = render partial: 'snippets/snippets_scope_menu', locals: { subject: @project, include_private: include_private } + = render partial: 'snippets/snippets_scope_menu', locals: { subject: @project, include_private: include_private, include_secret: false } .nav-controls - if can?(current_user, :create_project_snippet, @project) diff --git a/app/views/shared/_visibility_radios.html.haml b/app/views/shared/_visibility_radios.html.haml index dd6b9cce58e..8a95ab52f41 100644 --- a/app/views/shared/_visibility_radios.html.haml +++ b/app/views/shared/_visibility_radios.html.haml @@ -1,4 +1,4 @@ -- Gitlab::VisibilityLevel.values.each do |level| +- Gitlab::VisibilityLevel.values_for(form_model).each do |level| - disallowed = disallowed_visibility_level?(form_model, level) - restricted = restricted_visibility_levels.include?(level) - disabled = disallowed || restricted diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml index 828ec870dc0..f644d4ca871 100644 --- a/app/views/shared/snippets/_header.html.haml +++ b/app/views/shared/snippets/_header.html.haml @@ -26,6 +26,10 @@ %textarea.hidden.js-task-list-field = @snippet.description + .shareable_link + = shareable_snippets_link(@snippet) + = clipboard_button(title: s_('Copy to clipboard'), class: 'js-clipboard-btn snippet-clipboard-btn', target: '#shareable_link_url') + - if @snippet.updated_at != @snippet.created_at = edited_time_ago_with_tooltip(@snippet, placement: 'bottom', html_class: 'snippet-edited-ago', exclude_author: true) diff --git a/app/views/snippets/_snippets_scope_menu.html.haml b/app/views/snippets/_snippets_scope_menu.html.haml index dc4b0fd9ba0..6c1ed174bc0 100644 --- a/app/views/snippets/_snippets_scope_menu.html.haml +++ b/app/views/snippets/_snippets_scope_menu.html.haml @@ -24,6 +24,13 @@ %span.badge.badge-pill = subject.snippets.are_internal.count + - if include_secret + %li{ class: active_when(params[:scope] == "are_secret") } + = link_to subject_snippets_path(subject, scope: 'are_secret') do + Secret + %span.badge.badge-pill + = subject.snippets.are_secret.count + %li{ class: active_when(params[:scope] == "are_public") } = link_to subject_snippets_path(subject, scope: 'are_public') do Public |