Importing repo by url fails with `?` at the end of the password, and other character combinations.
What
Urls such as https://abc:123!?@gitlab.example.com/engine/engine.git
fail to import because Addressable::URI.parse
raises an error when the url is passed in with symbols in the password segment.
According to a user, encoding the ?
as %3F
works, but encoding !
as %21
doesn't, which means the password can't be url-encoded automatically as a workaround.
When attempting with url "https://abc:%3F%21%23%2F%5C@gitlab.example.com/engine/engine.git" the credentials will be returned unchanged as {:user=>"abc", :password=>"%3F%21%23%2F%5C"}
from Gitlab::UrlSanitizer#credentials
, which I'm unsure if is intended.
Steps to reproduce
- Visit https://gitlab.com/projects/new
- Click
Repo by URL
and fill inhttps://abc:123!?@gitlab.example.com/path/to/repo.git
- Submitting will result in
Import url must be a valid URL
and Unable to save project. Error: Import url must be a valid URL`
Screenshots
Details
The import_url
is validated with AddressableUrlValidator
which gets passed the url in full. This in turn calls Gitlab::UrlSanitizer.valid?(url)
, which hands the input to Addressable::URI.parse
. This method is fine with !?!?!?
at the end of a normal URL but errors out when certain combinations are passed to it in the password segment. Its documentation suggests that the regex used is /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/
, which made me try combinations of \
, /
, ?
, and #
.
pry(main)> Addressable::URI.parse('https://abc:123!?@gitlab.example.com/path/to/repo.git')
Addressable::URI::InvalidURIError: Invalid port number: "123!"
Addressable::URI::InvalidURIError: Invalid port number: "123!"
# from /Users/myuser/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/addressable-2.3.8/lib/addressable/uri.rb:1283:in `port='
pry(main)> Addressable::URI.parse('https://abc:123!@gitlab.example.com/path/to/repo.git')
=> #<Addressable::URI:0x3fc61cff06c8 URI:https://abc:123!@gitlab.example.com/path/to/repo.git>
pry(main)> Addressable::URI.parse('https://abc:123!\@gitlab.example.com/path/to/repo.git')
=> #<Addressable::URI:0x3fc61d3a393c URI:https://abc:123!\@gitlab.example.com/path/to/repo.git>
pry(main)> Addressable::URI.parse('https://abc:123!/\@gitlab.example.com/path/to/repo.git')
Addressable::URI::InvalidURIError: Invalid port number: "123!"
# from /Users/myuser/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/addressable-2.3.8/lib/addressable/uri.rb:1283:in `port='
pry(main)> Addressable::URI.parse('https://abc:123!/@gitlab.example.com/path/to/repo.git')
Addressable::URI::InvalidURIError: Invalid port number: "123!"
# from /Users/myuser/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/addressable-2.3.8/lib/addressable/uri.rb:1283:in `port='
pry(main)> Addressable::URI.parse('https://abc:12/3!@gitlab.example.com/path/to/repo.git')
=> #<Addressable::URI:0x3fc61d325fa0 URI:https://abc:12/3!@gitlab.example.com/path/to/repo.git>
pry(main)> Addressable::URI.parse('https://abc:12/?3!@gitlab.example.com/path/to/repo.git')
=> #<Addressable::URI:0x3fc61a2edab8 URI:https://abc:12/?3!@gitlab.example.com/path/to/repo.git>
pry(main)> Addressable::URI.parse('https://abc:12/?3!\@gitlab.example.com/path/to/repo.git')
=> #<Addressable::URI:0x3fc61a2c2110 URI:https://abc:12/?3!\@gitlab.example.com/path/to/repo.git>
pry(main)> Addressable::URI.parse('https://abc:12/?3!/@gitlab.example.com/path/to/repo.git')
=> #<Addressable::URI:0x3fc61cefe738 URI:https://abc:12/?3!/@gitlab.example.com/path/to/repo.git>
pry(main)> Addressable::URI.parse('https://abc:12/3!/@gitlab.example.com/path/to/repo.git')
=> #<Addressable::URI:0x3fc61d2b1e84 URI:https://abc:12/3!/@gitlab.example.com/path/to/repo.git>
pry(main)> Addressable::URI.parse('https://abc:123!/@gitlab.example.com/path/to/repo.git')
Addressable::URI::InvalidURIError: Invalid port number: "123!"
# from /Users/myuser/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/addressable-2.3.8/lib/addressable/uri.rb:1283:in `port='
pry(main)> Addressable::URI.parse('https://abc:123@gitlab.example.com/path/to/repo.git')
=> #<Addressable::URI:0x3fc61d24ccc8 URI:https://abc:123@gitlab.example.com/path/to/repo.git>
pry(main)> Addressable::URI.parse('https://abc:123#@gitlab.example.com/path/to/repo.git')
=> #<Addressable::URI:0x3fc61d221f8c URI:https://abc:123#@gitlab.example.com/path/to/repo.git>