summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorAsh McKenzie <amckenzie@gitlab.com>2018-06-10 22:56:17 +1000
committerAsh McKenzie <amckenzie@gitlab.com>2018-06-13 12:11:38 +1000
commit2f297034036055aaf37f86ece22723aedf8741bf (patch)
tree731fab3c82dd23d63ba9b89ad101d11e409d2fe0 /app
parentf646a8b9bc95fd6cecaa754f7dd0e8370c201502 (diff)
downloadgitlab-ce-ash.mckenzie/secret-snippets.tar.gz
Diffstat (limited to 'app')
-rw-r--r--app/controllers/concerns/snippets_url.rb39
-rw-r--r--app/controllers/snippets_controller.rb10
-rw-r--r--app/finders/snippets_finder.rb2
-rw-r--r--app/helpers/icons_helper.rb2
-rw-r--r--app/helpers/snippets_helper.rb19
-rw-r--r--app/helpers/visibility_level_helper.rb6
-rw-r--r--app/models/snippet.rb13
-rw-r--r--app/views/dashboard/snippets/index.html.haml2
-rw-r--r--app/views/projects/snippets/index.html.haml2
-rw-r--r--app/views/shared/_visibility_radios.html.haml2
-rw-r--r--app/views/shared/snippets/_header.html.haml4
-rw-r--r--app/views/snippets/_snippets_scope_menu.html.haml7
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
&nbsp;
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