Issues (1490)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Models/Code/WikiPage.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * This file is part of Fabrica.
5
 *
6
 * (c) Alexandre Salomé <[email protected]>
7
 * (c) Julien DIDIER <[email protected]>
8
 *
9
 * This source file is subject to the GPL license that is bundled
10
 * with this source code in the file LICENSE.
11
 */
12
13
namespace Fabrica\Models\Code;
14
15
use Pedreiro\Models\Base;
16
17 View Code Duplication
class WikiPage extends Base
0 ignored issues
show
This class seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
18
{
19
20
    protected $organizationPerspective = true;
21
22
    /**
23
     * The attributes that are mass assignable.
24
     *
25
     * @var array
26
     */
27
    protected $fillable = [
28
        'author_id',
29
        'committer_id',
30
        'token',
31
        'company_token',
32
        'is_active'
33
    ];
34
    /*# frozen_string_literal: true
35
36
    # rubocop:disable Rails/ActiveRecordAliases
37
    class WikiPage
38
    PageChangedError = Class.new(StandardError)
39
    PageRenameError = Class.new(StandardError)
40
41
    include ActiveModel::Validations
42
    include ActiveModel::Conversion
43
    include StaticModel
44
    extend ActiveModel::Naming
45
46
    def self.primary_key
47
    'slug'
48
    end
49
50
    def self.model_name
51
    ActiveModel::Name.new(self, nil, 'wiki')
52
    end
53
54
    # Sorts and groups pages by directory.
55
    #
56
    # pages - an array of WikiPage objects.
57
    #
58
    # Returns an array of WikiPage and WikiDirectory objects. The entries are
59
    # sorted by alphabetical order (directories and pages inside each directory).
60
    # Pages at the root level come before everything.
61
    def self.group_by_directory(pages)
62
    return [] if pages.blank?
63
64
    pages.sort_by { |page| [page.directory, page.slug] }
65
      .group_by(&:directory)
66
      .map do |dir, pages|
67
        if dir.present?
68
          WikiDirectory.new(dir, pages)
69
        else
70
          pages
71
        end
72
      end
73
      .flatten
74
    end
75
76
    def self.unhyphenize(name)
77
    name.gsub(/-+/, ' ')
78
    end
79
80
    def to_key
81
    [:slug]
82
    end
83
84
    validates :title, presence: true
85
    validates :content, presence: true
86
87
    # The GitLab ProjectWiki instance.
88
    attr_reader :wiki
89
90
    # The raw Gitlab::Git::WikiPage instance.
91
    attr_reader :page
92
93
    # The attributes Hash used for storing and validating
94
    # new Page values before writing to the raw repository.
95
    attr_accessor :attributes
96
97
    def hook_attrs
98
    Gitlab::HookData::WikiPageBuilder.new(self).build
99
    end
100
101
    def initialize(wiki, page = nil, persisted = false)
102
    @wiki       = wiki
103
    @page       = page
104
    @persisted  = persisted
105
    @attributes = {}.with_indifferent_access
106
107
    set_attributes if persisted?
108
    end
109
110
    # The escaped URL path of this page.
111
    def slug
112
    if @attributes[:slug].present?
113
      @attributes[:slug]
114
    else
115
      wiki.wiki.preview_slug(title, format)
116
    end
117
    end
118
119
    alias_method :to_param, :slug
120
121
    def human_title
122
    return 'Home' if title == 'home'
123
124
    title
125
    end
126
127
    # The formatted title of this page.
128
    def title
129
    if @attributes[:title]
130
      CGI.unescape_html(self.class.unhyphenize(@attributes[:title]))
131
    else
132
      ""
133
    end
134
    end
135
136
    # Sets the title of this page.
137
    def title=(new_title)
138
    @attributes[:title] = new_title
139
    end
140
141
    # The raw content of this page.
142
    def content
143
    @attributes[:content] ||= @page&.text_data
144
    end
145
146
    # The hierarchy of the directory this page is contained in.
147
    def directory
148
    wiki.page_title_and_dir(slug)&.last.to_s
149
    end
150
151
    # The processed/formatted content of this page.
152
    def formatted_content
153
    @attributes[:formatted_content] ||= @wiki.page_formatted_data(@page)
154
    end
155
156
    # The markup format for the page.
157
    def format
158
    @attributes[:format] || :markdown
159
    end
160
161
    # The commit message for this page version.
162
    def message
163
    version.try(:message)
164
    end
165
166
    # The GitLab Commit instance for this page.
167
    def version
168
    return unless persisted?
169
170
    @version ||= @page.version
171
    end
172
173
    def versions(options = {})
174
    return [] unless persisted?
175
176
    wiki.wiki.page_versions(@page.path, options)
177
    end
178
179
    def count_versions
180
    return [] unless persisted?
181
182
    wiki.wiki.count_page_versions(@page.path)
183
    end
184
185
    def last_version
186
    @last_version ||= versions(limit: 1).first
187
    end
188
189
    def last_commit_sha
190
    last_version&.sha
191
    end
192
193
    # Returns boolean True or False if this instance
194
    # is an old version of the page.
195
    def historical?
196
    return false unless last_commit_sha && version
197
198
    @page.historical? && last_commit_sha != version.sha
199
    end
200
201
    # Returns boolean True or False if this instance
202
    # is the latest commit version of the page.
203
    def latest?
204
    !historical?
205
    end
206
207
    # Returns boolean True or False if this instance
208
    # has been fully created on disk or not.
209
    def persisted?
210
    @persisted == true
211
    end
212
213
    # Creates a new Wiki Page.
214
    #
215
    # attr - Hash of attributes to set on the new page.
216
    #       :title   - The title (optionally including dir) for the new page.
217
    #       :content - The raw markup content.
218
    #       :format  - Optional symbol representing the
219
    #                  content format. Can be any type
220
    #                  listed in the ProjectWiki::MARKUPS
221
    #                  Hash.
222
    #       :message - Optional commit message to set on
223
    #                  the new page.
224
    #
225
    # Returns the String SHA1 of the newly created page
226
    # or False if the save was unsuccessful.
227
    def create(attrs = {})
228
    update_attributes(attrs)
229
230
    save(page_details: title) do
231
      wiki.create_page(title, content, format, attrs[:message])
232
    end
233
    end
234
235
    # Updates an existing Wiki Page, creating a new version.
236
    #
237
    # attrs - Hash of attributes to be updated on the page.
238
    #        :content         - The raw markup content to replace the existing.
239
    #        :format          - Optional symbol representing the content format.
240
    #                           See ProjectWiki::MARKUPS Hash for available formats.
241
    #        :message         - Optional commit message to set on the new version.
242
    #        :last_commit_sha - Optional last commit sha to validate the page unchanged.
243
    #        :title           - The Title (optionally including dir) to replace existing title
244
    #
245
    # Returns the String SHA1 of the newly created page
246
    # or False if the save was unsuccessful.
247
    def update(attrs = {})
248
    last_commit_sha = attrs.delete(:last_commit_sha)
249
250
    if last_commit_sha && last_commit_sha != self.last_commit_sha
251
      raise PageChangedError
252
    end
253
254
    update_attributes(attrs)
255
256
    if title_changed?
257
      page_details = title
258
259
      if wiki.find_page(page_details).present?
260
        @attributes[:title] = @page.url_path
261
        raise PageRenameError
262
      end
263
    else
264
      page_details = @page.url_path
265
    end
266
267
    save(page_details: page_details) do
268
      wiki.update_page(
269
        @page,
270
        content: content,
271
        format: format,
272
        message: attrs[:message],
273
        title: title
274
      )
275
    end
276
    end
277
278
    # Destroys the Wiki Page.
279
    #
280
    # Returns boolean True or False.
281
    def delete
282
    if wiki.delete_page(@page)
283
      true
284
    else
285
      false
286
    end
287
    end
288
289
    # Relative path to the partial to be used when rendering collections
290
    # of this object.
291
    def to_partial_path
292
    'projects/wikis/wiki_page'
293
    end
294
295
    def id
296
    page.version.to_s
297
    end
298
299
    def title_changed?
300
    title.present? && self.class.unhyphenize(@page.url_path) != title
301
    end
302
303
    # Updates the current @attributes hash by merging a hash of params
304
    def update_attributes(attrs)
305
    attrs[:title] = process_title(attrs[:title]) if attrs[:title].present?
306
307
    attrs.slice!(:content, :format, :message, :title)
308
309
    @attributes.merge!(attrs)
310
    end
311
312
    private
313
314
    # Process and format the title based on the user input.
315
    def process_title(title)
316
    return if title.blank?
317
318
    title = deep_title_squish(title)
319
    current_dirname = File.dirname(title)
320
321
    if @page.present?
322
      return title[1..-1] if current_dirname == '/'
323
      return File.join([directory.presence, title].compact) if current_dirname == '.'
324
    end
325
326
    title
327
    end
328
329
    # This method squishes all the filename
330
    # i.e: '   foo   /  bar  / page_name' => 'foo/bar/page_name'
331
    def deep_title_squish(title)
332
    components = title.split(File::SEPARATOR).map(&:squish)
333
334
    File.join(components)
335
    end
336
337
    def set_attributes
338
    attributes[:slug] = @page.url_path
339
    attributes[:title] = @page.title
340
    attributes[:format] = @page.format
341
    end
342
343
    def save(page_details:)
344
    return unless valid?
345
346
    unless yield
347
      errors.add(:base, wiki.error_message)
348
      return false
349
    end
350
351
    page_title, page_dir = wiki.page_title_and_dir(page_details)
352
    gitlab_git_wiki = wiki.wiki
353
    @page = gitlab_git_wiki.page(title: page_title, dir: page_dir)
354
355
    set_attributes
356
    @persisted = errors.blank?
357
    end
358
    end
359
360
    */
361
}
362