Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dynamic_path_validator.rb « validators « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 18680b8975ffed1c93413b769f836d3ece4d94d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# DynamicPathValidator
#
# Custom validator for GitLab path values.
# These paths are assigned to `Namespace` (& `Group` as a subclass) & `Project`
#
# Values are checked for formatting and exclusion from a list of reserved path
# names.
class DynamicPathValidator < ActiveModel::EachValidator
  # All routes that appear on the top level must be listed here.
  # This will make sure that groups cannot be created with these names
  # as these routes would be masked by the paths already in place.
  #
  # Example:
  #   /api/api-project
  #
  #  the path `api` shouldn't be allowed because it would be masked by `api/*`
  #
  TOP_LEVEL_ROUTES = Set.new(%w[
    -
    .well-known
    abuse_reports
    admin
    all
    api
    assets
    autocomplete
    ci
    dashboard
    explore
    files
    groups
    health_check
    help
    hooks
    import
    invites
    issues
    jwt
    koding
    member
    merge_requests
    new
    notes
    notification_settings
    oauth
    profile
    projects
    public
    repository
    robots.txt
    s
    search
    sent_notifications
    services
    snippets
    teams
    u
    unsubscribes
    uploads
    users
  ]).freeze

  # All project routes with wildcard argument must be listed here.
  # Otherwise it can lead to routing issues when route considered as project name.
  #
  # Example:
  #  /group/project/tree/deploy_keys
  #
  #  without tree as reserved name routing can match 'group/project' as group name,
  #  'tree' as project name and 'deploy_keys' as route.
  #
  WILDCARD_ROUTES = Set.new(%w[
    artifacts
    badges
    blame
    blob
    commits
    create
    create_dir
    edit
    environments/folders
    files
    find_file
    gitlab-lfs/objects
    info/lfs/objects
    logs_tree
    new
    preview
    raw
    tree
    update
    wikis
  ]).freeze

  STRICT_RESERVED = (TOP_LEVEL_ROUTES | WILDCARD_ROUTES).freeze

  def self.valid?(path)
    path_segments = path.split('/')

    !reserved?(path) && path_segments.all? { |value| follow_format?(value) }
  end

  def self.reserved?(path)
    path = path.to_s.downcase
    top_level, wildcard_part = path.split('/', 2)

    includes_reserved_top_level?(top_level) || includes_reserved_wildcard?(wildcard_part)
  end

  def self.includes_reserved_wildcard?(path)
    WILDCARD_ROUTES.any? do |reserved_word|
      contains_path_part?(path, reserved_word)
    end
  end

  def self.includes_reserved_top_level?(path)
    TOP_LEVEL_ROUTES.any? do |reserved_route|
      contains_path_part?(path, reserved_route)
    end
  end

  def self.contains_path_part?(path, part)
    path =~ %r{(/|\A)#{Regexp.quote(part)}(/|\z)}
  end

  def self.follow_format?(value)
    value =~ Gitlab::Regex.namespace_regex
  end

  delegate :reserved?, :follow_format?, to: :class

  def validate_each(record, attribute, value)
    unless follow_format?(value)
      record.errors.add(attribute, Gitlab::Regex.namespace_regex_message)
    end

    full_path = record.respond_to?(:full_path) ? record.full_path : value

    if reserved?(full_path)
      record.errors.add(attribute, "#{value} is a reserved name")
    end
  end
end