gitlab-org--gitlab-foss/app/validators/dynamic_path_validator.rb

144 lines
3.1 KiB
Ruby
Raw Normal View History

# DynamicPathValidator
2015-12-07 21:17:12 +00:00
#
# Custom validator for GitLab path values.
# These paths are assigned to `Namespace` (& `Group` as a subclass) & `Project`
2015-12-07 21:17:12 +00:00
#
# 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[
2017-04-24 10:38:09 +00:00
-
.well-known
2017-04-24 10:38:09 +00:00
abuse_reports
admin
all
2017-04-24 10:38:09 +00:00
api
assets
2017-04-24 10:38:09 +00:00
autocomplete
ci
dashboard
2017-04-24 10:38:09 +00:00
explore
files
groups
2017-04-24 10:38:09 +00:00
health_check
help
hooks
2017-04-24 10:38:09 +00:00
import
invites
issues
2017-04-24 10:38:09 +00:00
jwt
koding
member
merge_requests
2016-01-08 09:19:22 +00:00
new
notes
2017-04-24 10:38:09 +00:00
notification_settings
oauth
profile
projects
public
repository
robots.txt
s
search
2017-04-24 10:38:09 +00:00
sent_notifications
services
snippets
teams
u
unsubscribes
uploads
2017-04-24 10:38:09 +00:00
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.
#
2017-04-24 10:38:09 +00:00
WILDCARD_ROUTES = Set.new(%w[
badges
blame
blob
builds
2017-04-24 10:38:09 +00:00
commits
create
create_dir
edit
environments/folders
files
find_file
gitlab-lfs/objects
info/lfs/objects
new
preview
raw
refs
2017-04-24 10:38:09 +00:00
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
2015-12-07 21:17:12 +00:00
def validate_each(record, attribute, value)
unless follow_format?(value)
2015-12-07 21:17:12 +00:00
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
2015-12-07 21:17:12 +00:00
end