@@ -52,6 +52,11 @@ def __call__(self, value):
52
52
@deconstructible
53
53
class RepositoryURLValidator (object ):
54
54
55
+ disallow_relative_url = True
56
+
57
+ # Pattern for ``[email protected] :user/repo`` pattern
58
+ re_git_user = re .compile (r'^[\w]+@.+' )
59
+
55
60
def __call__ (self , value ):
56
61
allow_private_repos = getattr (settings , 'ALLOW_PRIVATE_REPOS' , False )
57
62
public_schemes = ['https' , 'http' , 'git' , 'ftps' , 'ftp' ]
@@ -60,28 +65,51 @@ def __call__(self, value):
60
65
if allow_private_repos :
61
66
valid_schemes += private_schemes
62
67
url = urlparse (value )
63
- if (
64
- ( # pylint: disable=too-many-boolean-expressions
65
- url .scheme not in valid_schemes and
66
- '@' not in value and
67
- not value .startswith ('lp:' )
68
- ) or
69
- (
70
- value .startswith ('/' ) or
71
- value .startswith ('file://' ) or
72
- value .startswith ('.' )
73
- )
74
- ):
75
- # Avoid ``/path/to/local/file`` and ``file://`` scheme but allow
76
- # ``[email protected] :user/project.git`` and ``lp:bazaar``
77
- raise ValidationError (_ ('Invalid scheme for URL' ))
78
- elif '&&' in value or '|' in value :
68
+
69
+ # Malicious characters go first
70
+ if '&&' in value or '|' in value :
79
71
raise ValidationError (_ ('Invalid character in the URL' ))
80
- elif (
81
- ('@' in value or url .scheme in private_schemes ) and
82
- not allow_private_repos
83
- ):
84
- raise ValidationError ('Clonning via SSH is not supported' )
85
- return value
72
+ elif url .scheme in valid_schemes :
73
+ return value
74
+
75
+ # Repo URL is not a supported scheme at this point, but there are
76
+ # several cases where we might support it
77
+ # Launchpad
78
+ elif value .startswith ('lp:' ):
79
+ return value
80
+ # Relative paths are conditionally supported
81
+ elif value .startswith ('.' ) and not self .disallow_relative_url :
82
+ return value
83
+ # SSH cloning and ``[email protected] :user/project.git``
84
+ elif self .re_git_user .search (value ) or url .scheme in private_schemes :
85
+ if allow_private_repos :
86
+ return value
87
+ else :
88
+ # Throw a more helpful error message
89
+ raise ValidationError ('Manual cloning via SSH is not supported' )
90
+
91
+ # No more valid URLs without supported URL schemes
92
+ raise ValidationError (_ ('Invalid scheme for URL' ))
93
+
94
+
95
+ class SubmoduleURLValidator (RepositoryURLValidator ):
96
+
97
+ """
98
+ A URL validator for repository submodules
99
+
100
+ If a repository has a relative submodule, the URL path is effectively the
101
+ supermodule's remote ``origin`` URL with the relative path applied.
102
+
103
+ From the git docs::
104
+
105
+ ``<repository>`` is the URL of the new submodule's origin repository.
106
+ This may be either an absolute URL, or (if it begins with ``./`` or
107
+ ``../``), the location relative to the superproject's default remote
108
+ repository
109
+ """
110
+
111
+ disallow_relative_url = False
112
+
86
113
87
114
validate_repository_url = RepositoryURLValidator ()
115
+ validate_submodule_url = SubmoduleURLValidator ()
0 commit comments