This instance will be upgraded to Heptapod 0.31.0rc on 2022-05-19 at 11:00 UTC+2 (a few minutes of down time)

blob_helper.rb 6.77 KB
Newer Older
1
module BlobHelper
http://jneen.net/'s avatar
http://jneen.net/ committed
2
3
  def highlight(blob_name, blob_content, repository: nil, plain: false)
    highlighted = Gitlab::Highlight.highlight(blob_name, blob_content, plain: plain, repository: repository)
4
    raw %(<pre class="code highlight"><code>#{highlighted}</code></pre>)
5
6
7
  end

  def no_highlight_files
8
    %w(credits changelog news copying copyright license authors)
9
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
10

11
12
13
  def edit_blob_link(project = @project, ref = @ref, path = @path, options = {})
    return unless current_user

14
15
    blob = options.delete(:blob)
    blob ||= project.repository.blob_at(ref, path) rescue nil
16

17
    return unless blob
18
19
20

    edit_path = namespace_project_edit_blob_path(project.namespace, project,
                                     tree_join(ref, path),
21
                                     options[:link_opts])
22

Douwe Maan's avatar
Douwe Maan committed
23
    if !on_top_of_branch?(project, ref)
24
      button_tag "Edit", class: "btn disabled has-tooltip", title: "You can only edit files when you are on a branch", data: { container: 'body' }
Douwe Maan's avatar
Douwe Maan committed
25
    elsif can_edit_blob?(blob, project, ref)
26
      link_to "Edit", edit_path, class: 'btn btn-sm'
27
28
29
30
31
32
    elsif can?(current_user, :fork_project, project)
      continue_params = {
        to:     edit_path,
        notice: edit_in_new_fork_notice,
        notice_now: edit_in_new_fork_notice_now
      }
Rubén Dávila's avatar
Rubén Dávila committed
33
      fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params)
34

35
      link_to "Edit", fork_path, class: 'btn', method: :post
36
37
38
39
40
41
42
43
44
45
    end
  end

  def modify_file_link(project = @project, ref = @ref, path = @path, label:, action:, btn_class:, modal_type:)
    return unless current_user

    blob = project.repository.blob_at(ref, path) rescue nil

    return unless blob

Douwe Maan's avatar
Douwe Maan committed
46
    if !on_top_of_branch?(project, ref)
47
      button_tag label, class: "btn btn-#{btn_class} disabled has-tooltip", title: "You can only #{action} files when you are on a branch", data: { container: 'body' }
48
    elsif blob.lfs_pointer?
49
      button_tag label, class: "btn btn-#{btn_class} disabled has-tooltip", title: "It is not possible to #{action} files that are stored in LFS using the web interface", data: { container: 'body' }
Douwe Maan's avatar
Douwe Maan committed
50
    elsif can_edit_blob?(blob, project, ref)
51
52
53
54
55
56
57
      button_tag label, class: "btn btn-#{btn_class}", 'data-target' => "#modal-#{modal_type}-blob", 'data-toggle' => 'modal'
    elsif can?(current_user, :fork_project, project)
      continue_params = {
        to:     request.fullpath,
        notice: edit_in_new_fork_notice + " Try to #{action} this file again.",
        notice_now: edit_in_new_fork_notice_now
      }
Rubén Dávila's avatar
Rubén Dávila committed
58
      fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params)
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

      link_to label, fork_path, class: "btn btn-#{btn_class}", method: :post
    end
  end

  def replace_blob_link(project = @project, ref = @ref, path = @path)
    modify_file_link(
      project,
      ref,
      path,
      label:      "Replace",
      action:     "replace",
      btn_class:  "default",
      modal_type: "upload"
    )
  end

  def delete_blob_link(project = @project, ref = @ref, path = @path)
    modify_file_link(
      project,
      ref,
      path,
      label:      "Delete",
      action:     "delete",
      btn_class:  "remove",
      modal_type: "remove"
    )
  end

  def can_edit_blob?(blob, project = @project, ref = @ref)
    !blob.lfs_pointer? && can_edit_tree?(project, ref)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
90
91
92
93
94
95
96
  end

  def leave_edit_message
    "Leave edit mode?\nAll unsaved changes will be lost."
  end

  def editing_preview_title(filename)
97
    if Gitlab::MarkupHelper.previewable?(filename)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
98
99
      'Preview'
    else
Douwe Maan's avatar
Douwe Maan committed
100
      'Preview Changes'
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
101
102
    end
  end
103
104
105
106
107
108
109
110

  # Return an image icon depending on the file mode and extension
  #
  # mode - File unix mode
  # mode - File name
  def blob_icon(mode, name)
    icon("#{file_type_icon_class('file', mode, name)} fw")
  end
111

112
  def blob_text_viewable?(blob)
113
    blob && blob.text? && !blob.lfs_pointer? && !blob.only_display_raw?
114
115
116
117
118
119
120
121
122
  end

  def blob_size(blob)
    if blob.lfs_pointer?
      blob.lfs_size
    else
      blob.size
    end
  end
Stan Hu's avatar
Stan Hu committed
123
124
125
126
127

  # SVGs can contain malicious JavaScript; only include whitelisted
  # elements and attributes. Note that this whitelist is by no means complete
  # and may omit some elements.
  def sanitize_svg(blob)
128
    blob.data = Gitlab::Sanitizers::SVG.clean(blob.data)
Stan Hu's avatar
Stan Hu committed
129
130
    blob
  end
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

  # 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
149

Jacob Vosmaer's avatar
Jacob Vosmaer committed
150
151
152
153
  def cached_blob?
    stale = stale?(etag: @blob.id) # The #stale? method sets cache headers.

    # Because we are opionated we set the cache headers ourselves.
154
    response.cache_control[:public] = @project.public?
155

Douwe Maan's avatar
Douwe Maan committed
156
157
158
159
160
161
162
163
164
165
166
    response.cache_control[:max_age] =
      if @ref && @commit && @ref == @commit.id
        # This is a link to a commit by its commit SHA. That means that the blob
        # is immutable. The only reason to invalidate the cache is if the commit
        # was deleted or if the user lost access to the repository.
        Blob::CACHE_TIME_IMMUTABLE
      else
        # A branch or tag points at this blob. That means that the expected blob
        # value may change over time.
        Blob::CACHE_TIME
      end
167

168
    response.etag = @blob.id
Jacob Vosmaer's avatar
Jacob Vosmaer committed
169
    !stale
170
  end
171
172
173
174
175
176
177

  def licenses_for_select
    return @licenses_for_select if defined?(@licenses_for_select)

    licenses = Licensee::License.all

    @licenses_for_select = {
178
179
      Popular: licenses.select(&:featured).map { |license| { name: license.name, id: license.key } },
      Other: licenses.reject(&:featured).map { |license| { name: license.name, id: license.key } }
180
181
    }
  end
182

183
184
185
186
  def ref_project
    @ref_project ||= @target_project || @project
  end

Alfredo Sumaran's avatar
Alfredo Sumaran committed
187
  def gitignore_names
188
    @gitignore_names ||= Gitlab::Template::GitignoreTemplate.dropdown_names
189
  end
Alfredo Sumaran's avatar
Alfredo Sumaran committed
190

191
  def gitlab_ci_ymls
192
    @gitlab_ci_ymls ||= Gitlab::Template::GitlabCiYmlTemplate.dropdown_names(params[:context])
193
  end
Sean McGivern's avatar
Sean McGivern committed
194

195
196
197
198
  def dockerfile_names
    @dockerfile_names ||= Gitlab::Template::DockerfileTemplate.dropdown_names
  end

Sean McGivern's avatar
Sean McGivern committed
199
200
201
202
203
204
205
  def blob_editor_paths
    {
      'relative-url-root' => Rails.application.config.relative_url_root,
      'assets-prefix' => Gitlab::Application.config.assets.prefix,
      'blob-language' => @blob && @blob.language.try(:ace_mode)
    }
  end
206
end