Auth: Allow "@" in login username for feeds (bug 1521)
Thanks to Eric Smith for reporting this issue and providing a login to help test and debug this bug.
This commit is contained in:
parent
2417503478
commit
0df167ff3e
|
@ -2142,8 +2142,8 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
self.show_message(message, title, widget=self.treeChannels)
|
||||
|
||||
# Report subscriptions that require authentication
|
||||
retry_podcasts = {}
|
||||
if authreq:
|
||||
retry_podcasts = {}
|
||||
for url in authreq:
|
||||
title = _('Podcast requires authentication')
|
||||
message = _('Please login to %s:') % (cgi.escape(url),)
|
||||
|
@ -2158,10 +2158,6 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
failed.append(url)
|
||||
break
|
||||
|
||||
# If we have authentication data to retry, do so here
|
||||
if retry_podcasts:
|
||||
self.add_podcast_list(retry_podcasts.keys(), retry_podcasts)
|
||||
|
||||
# Report website redirections
|
||||
for url in redirections:
|
||||
title = _('Website redirection detected')
|
||||
|
@ -2196,6 +2192,14 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
# Update the list of subscribed podcasts
|
||||
self.update_podcast_list_model(select_url=url)
|
||||
|
||||
# If we have authentication data to retry, do so here
|
||||
if retry_podcasts:
|
||||
self.add_podcast_list(retry_podcasts.keys(), retry_podcasts)
|
||||
# This will NOT show new episodes for podcasts that have
|
||||
# been added ("worked"), but it will prevent problems with
|
||||
# multiple dialogs being open at the same time ;)
|
||||
return
|
||||
|
||||
# Offer to download new episodes
|
||||
episodes = []
|
||||
for podcast in self.channels:
|
||||
|
|
|
@ -131,7 +131,9 @@ class CoverDownloader(ObservableService):
|
|||
|
||||
if not os.path.exists(channel.cover_file):
|
||||
if url is None:
|
||||
url = channel.cover_url
|
||||
# We have to use authenticate_url, because password-protected
|
||||
# feeds might keep their cover art also protected (bug 1521)
|
||||
url = channel.authenticate_url(channel.cover_url)
|
||||
|
||||
new_url = youtube.get_real_cover(channel.url)
|
||||
if new_url is not None:
|
||||
|
|
|
@ -237,19 +237,17 @@ def username_password_from_url(url):
|
|||
...
|
||||
ValueError: URL has to be a string or unicode object.
|
||||
>>> username_password_from_url('http://a@b:c@host.com/')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: "@" must be encoded for username/password (RFC1738).
|
||||
('a@b', 'c')
|
||||
>>> username_password_from_url('ftp://a:b:c@host.com/')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: ":" must be encoded for username/password (RFC1738).
|
||||
('a', 'b:c')
|
||||
>>> username_password_from_url('http://i%2Fo:P%40ss%3A@host.com/')
|
||||
('i/o', 'P@ss:')
|
||||
>>> username_password_from_url('ftp://%C3%B6sterreich@host.com/')
|
||||
('\xc3\xb6sterreich', None)
|
||||
>>> username_password_from_url('http://w%20x:y%20z@example.org/')
|
||||
('w x', 'y z')
|
||||
>>> username_password_from_url('http://example.com/x@y:z@test.com/')
|
||||
(None, None)
|
||||
"""
|
||||
if type(url) not in (str, unicode):
|
||||
raise ValueError('URL has to be a string or unicode object.')
|
||||
|
@ -262,11 +260,20 @@ def username_password_from_url(url):
|
|||
(authentication, netloc) = netloc.rsplit('@', 1)
|
||||
if ':' in authentication:
|
||||
(username, password) = authentication.split(':', 1)
|
||||
# RFC1738 dictates that we should not allow these unquoted
|
||||
# characters in the username and password field (Section 3.1).
|
||||
for c in (':', '@', '/'):
|
||||
if c in username or c in password:
|
||||
raise ValueError('"%c" must be encoded for username/password (RFC1738).' % c)
|
||||
|
||||
# RFC1738 dictates that we should not allow ['/', '@', ':']
|
||||
# characters in the username and password field (Section 3.1):
|
||||
#
|
||||
# 1. The "/" can't be in there at this point because of the way
|
||||
# urlparse (which we use above) works.
|
||||
# 2. Due to gPodder bug 1521, we allow "@" in the username and
|
||||
# password field. We use netloc.rsplit('@', 1), which will
|
||||
# make sure that we split it at the last '@' in netloc.
|
||||
# 3. The colon must be excluded (RFC2617, Section 2) in the
|
||||
# username, but is apparently allowed in the password. This
|
||||
# is handled by the authentication.split(':', 1) above, and
|
||||
# will cause any extraneous ':'s to be part of the password.
|
||||
|
||||
username = urllib.unquote(username)
|
||||
password = urllib.unquote(password)
|
||||
else:
|
||||
|
@ -829,13 +836,15 @@ def url_strip_authentication(url):
|
|||
'http://x.org/'
|
||||
>>> url_strip_authentication('http://P%40%3A:i%2F@cx.lan')
|
||||
'http://cx.lan'
|
||||
>>> url_strip_authentication('http://x@x.com:s3cret@example.com/')
|
||||
'http://example.com/'
|
||||
"""
|
||||
url_parts = list(urlparse.urlsplit(url))
|
||||
# url_parts[1] is the HOST part of the URL
|
||||
|
||||
# Remove existing authentication data
|
||||
if '@' in url_parts[1]:
|
||||
url_parts[1] = url_parts[1].split('@', 2)[1]
|
||||
url_parts[1] = url_parts[1].rsplit('@', 1)[1]
|
||||
|
||||
return urlparse.urlunsplit(url_parts)
|
||||
|
||||
|
@ -858,21 +867,24 @@ def url_add_authentication(url, username, password):
|
|||
>>> url_add_authentication('http://localhost/x', 'aa', 'bc')
|
||||
'http://aa:bc@localhost/x'
|
||||
>>> url_add_authentication('http://blubb.lan/u.html', 'i/o', 'P@ss:')
|
||||
'http://i%2Fo:P%40ss%3A@blubb.lan/u.html'
|
||||
'http://i%2Fo:P@ss:@blubb.lan/u.html'
|
||||
>>> url_add_authentication('http://a:b@x.org/', 'c', 'd')
|
||||
'http://c:d@x.org/'
|
||||
>>> url_add_authentication('http://i%2F:P%40%3A@cx.lan', 'P@:', 'i/')
|
||||
'http://P%40%3A:i%2F@cx.lan'
|
||||
>>> url_add_authentication('http://i%2F:P%40%3A@cx.lan', 'P@x', 'i/')
|
||||
'http://P@x:i%2F@cx.lan'
|
||||
>>> url_add_authentication('http://x.org/', 'a b', 'c d')
|
||||
'http://a%20b:c%20d@x.org/'
|
||||
"""
|
||||
if username is None or username == '':
|
||||
return url
|
||||
|
||||
username = urllib.quote(username, safe='')
|
||||
# Relaxations of the strict quoting rules (bug 1521):
|
||||
# 1. Accept '@' in username and password
|
||||
# 2. Acecpt ':' in password only
|
||||
username = urllib.quote(username, safe='@')
|
||||
|
||||
if password is not None:
|
||||
password = urllib.quote(password, safe='')
|
||||
password = urllib.quote(password, safe='@:')
|
||||
auth_string = ':'.join((username, password))
|
||||
else:
|
||||
auth_string = username
|
||||
|
|
Loading…
Reference in New Issue