Issue #379: Cannot clone hg repos with web interface
Reported by: | rockin |
State: | new |
Created on: | 2020-07-07 19:32 |
Updated on: | 2020-07-13 14:31 |
Description
I cannot clone hg repos with the add repo feature in Kallithea. It fails with a 500 error. The bug seems to be an attempt match of a regex to a bytes object. Maybe it was introduced when Kallithea was ported to Python3
Attachments
Comments
Comment by Thomas De Schampheleire, on 2020-07-08 07:48
Thanks for reporting, it seems this issue occurs only when username/password auth is present in the URL.
Below patch should fix your problem, could you test in your context?
Thanks
# HG changeset patch # User Thomas De Schampheleire <thomas.de_schampheleire@nokia.com> # Date 1594192757 -7200 # Wed Jul 08 09:19:17 2020 +0200 # Branch stable # Node ID c56c87b03fdd4e6f5b59cd51792741a51d528f74 # Parent 0bca9e828db247730518cbb4fd9225ea42592faf vcs: fix cloning remote repository with HTTP authentication Using a remote clone URI of http://user:pass@host/... triggered an exception: ... E File ".../kallithea/lib/utils.py", line 256, in is_valid_repo_uri E GitRepository._check_url(url) E File ".../kallithea/lib/vcs/backends/git/repository.py", line 183, in _check_url E passmgr.add_password(*authinfo) E File "/usr/lib/python3.7/urllib/request.py", line 848, in add_password E self.reduce_uri(u, default_port) for u in uri) E File "/usr/lib/python3.7/urllib/request.py", line 848, in <genexpr> E self.reduce_uri(u, default_port) for u in uri) E File "/usr/lib/python3.7/urllib/request.py", line 875, in reduce_uri E host, port = splitport(authority) E File "/usr/lib/python3.7/urllib/parse.py", line 1022, in splitport E match = _portprog.fullmatch(host) E TypeError: cannot use a string pattern on a bytes-like object The authinfo tuple is obtained via mercurial.util.url, which unfortunately returns a tuple of bytes whereas urllib expects strings. It seems that mercurial internally has some more hacking around urllib as urllibcompat.py, which we don't use. Therefore, transform the bytes into strings before passing authinfo to urllib. diff --git a/kallithea/lib/vcs/backends/git/repository.py b/kallithea/lib/vcs/backends/git/repository.py --- a/kallithea/lib/vcs/backends/git/repository.py +++ b/kallithea/lib/vcs/backends/git/repository.py @@ -178,6 +178,16 @@ class GitRepository(BaseRepository): cleaned_uri = str(url_obj) if authinfo: + # mercurial.util.url returns authinfo as bytes, but urllib expects strings + #(realm, uris, user, password) + #(None, (b'http://127.0.0.1/repo', b'127.0.0.1'), b'user', b'pass') + authinfo = ( + safe_str(authinfo[0]), + tuple(safe_str(x) for x in authinfo[1]), + safe_str(authinfo[2]), + safe_str(authinfo[3]), + ) + # create a password manager passmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm() passmgr.add_password(*authinfo) diff --git a/kallithea/lib/vcs/backends/hg/repository.py b/kallithea/lib/vcs/backends/hg/repository.py --- a/kallithea/lib/vcs/backends/hg/repository.py +++ b/kallithea/lib/vcs/backends/hg/repository.py @@ -315,6 +315,16 @@ class MercurialRepository(BaseRepository cleaned_uri = str(url_obj) if authinfo: + # mercurial.util.url returns authinfo as bytes, but urllib expects strings + #(realm, uris, user, password) + #(None, (b'http://127.0.0.1/repo', b'127.0.0.1'), b'user', b'pass') + authinfo = ( + safe_str(authinfo[0]), + tuple(safe_str(x) for x in authinfo[1]), + safe_str(authinfo[2]), + safe_str(authinfo[3]), + ) + # create a password manager passmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm() passmgr.add_password(*authinfo) diff --git a/kallithea/tests/functional/test_admin_repos.py b/kallithea/tests/functional/test_admin_repos.py --- a/kallithea/tests/functional/test_admin_repos.py +++ b/kallithea/tests/functional/test_admin_repos.py @@ -344,6 +344,19 @@ class _BaseTestCase(base.TestController) _session_csrf_secret_token=self.session_csrf_secret_token())) response.mustcontain('Invalid repository URL') + def test_create_remote_repo_wrong_clone_uri_http_auth(self): + self.log_user() + repo_name = self.NEW_REPO + description = 'description for newly created repo' + response = self.app.post(base.url('repos'), + fixture._get_repo_create_params(repo_private=False, + repo_name=repo_name, + repo_type=self.REPO_TYPE, + repo_description=description, + clone_uri='http://user:pass@127.0.0.1/repo', + _session_csrf_secret_token=self.session_csrf_secret_token())) + response.mustcontain('Invalid repository URL') + def test_delete(self): self.log_user() repo_name = 'vcs_test_new_to_delete_%s' % self.REPO_TYPE
Comment by rockin, on 2020-07-09 14:36
It fixes the 500 error when I put auth informations in the clone_url. However, it seems Kallithea doesn’t validate correctly the clone_url. I had this problem before your patch.
Comment by Thomas De Schampheleire, on 2020-07-09 14:43
Can you give more details? Do you get an error? Which one? Please paste the relevant parts of the log.