mirror of
https://git.deluge-torrent.org/deluge
synced 2025-08-03 23:18:40 +00:00
Test fixes and #1814 fix.
All test were adapted, and some more were added to comply with the new multiuser support in deluge. Regarding #1814, host entries in the Connection Manager UI are now migrated from the old format were automatic localhost logins were possible, which no longer is.
This commit is contained in:
parent
bb9a8509c8
commit
f41f6ad46a
11 changed files with 215 additions and 75 deletions
|
@ -3,6 +3,8 @@
|
||||||
* Removed the AutoAdd feature on the core. It's now handled with the AutoAdd
|
* Removed the AutoAdd feature on the core. It's now handled with the AutoAdd
|
||||||
plugin, which is also shipped with Deluge, and it does a better job and
|
plugin, which is also shipped with Deluge, and it does a better job and
|
||||||
now, it even supports multiple users perfectly.
|
now, it even supports multiple users perfectly.
|
||||||
|
* Authentication/Permission exceptions are now sent to clients and recreated
|
||||||
|
there to allow acting upon them.
|
||||||
|
|
||||||
==== Core ====
|
==== Core ====
|
||||||
* Implement #1063 option to delete torrent file copy on torrent removal - patch from Ghent
|
* Implement #1063 option to delete torrent file copy on torrent removal - patch from Ghent
|
||||||
|
@ -20,10 +22,16 @@
|
||||||
* File modifications on the auth file are now detected and when they happen,
|
* File modifications on the auth file are now detected and when they happen,
|
||||||
the file is reloaded. Upon finding an old auth file with an old format, an
|
the file is reloaded. Upon finding an old auth file with an old format, an
|
||||||
upgrade to the new format is made, file saved, and reloaded.
|
upgrade to the new format is made, file saved, and reloaded.
|
||||||
|
* Authentication no longer requires a username/password. If one or both of
|
||||||
|
these is missing, an authentication error will be sent to the client
|
||||||
|
which sould then ask the username/password to the user.
|
||||||
|
|
||||||
==== GtkUI ====
|
==== GtkUI ====
|
||||||
* Fix uncaught exception when closing deluge in classic mode
|
* Fix uncaught exception when closing deluge in classic mode
|
||||||
* Allow changing ownership of torrents
|
* Allow changing ownership of torrents
|
||||||
|
* Host entries in the Connection Manager UI are now editable. They're
|
||||||
|
now also migrated from the old format were automatic localhost logins were
|
||||||
|
possible, which no longer is, this fixes #1814.
|
||||||
|
|
||||||
==== WebUI ====
|
==== WebUI ====
|
||||||
* Migrate to ExtJS 3.1
|
* Migrate to ExtJS 3.1
|
||||||
|
|
|
@ -56,7 +56,7 @@ except ImportError:
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
import deluge.configmanager
|
import deluge.configmanager
|
||||||
from deluge.core.authmanager import AUTH_LEVEL_NONE, AUTH_LEVEL_DEFAULT, AUTH_LEVEL_ADMIN
|
from deluge.core.authmanager import AUTH_LEVEL_NONE, AUTH_LEVEL_DEFAULT, AUTH_LEVEL_ADMIN
|
||||||
from deluge.error import DelugeError, NotAuthorizedError, AuthenticationRequired
|
from deluge.error import DelugeError, NotAuthorizedError, __PassthroughError
|
||||||
|
|
||||||
RPC_RESPONSE = 1
|
RPC_RESPONSE = 1
|
||||||
RPC_ERROR = 2
|
RPC_ERROR = 2
|
||||||
|
@ -219,6 +219,9 @@ class DelugeRPCProtocol(Protocol):
|
||||||
|
|
||||||
log.info("Deluge client disconnected: %s", reason.value)
|
log.info("Deluge client disconnected: %s", reason.value)
|
||||||
|
|
||||||
|
def valid_session(self):
|
||||||
|
return self.transport.sessionno in self.factory.authorized_sessions
|
||||||
|
|
||||||
def dispatch(self, request_id, method, args, kwargs):
|
def dispatch(self, request_id, method, args, kwargs):
|
||||||
"""
|
"""
|
||||||
This method is run when a RPC Request is made. It will run the local method
|
This method is run when a RPC Request is made. It will run the local method
|
||||||
|
@ -262,9 +265,14 @@ class DelugeRPCProtocol(Protocol):
|
||||||
if ret:
|
if ret:
|
||||||
self.factory.authorized_sessions[self.transport.sessionno] = (ret, args[0])
|
self.factory.authorized_sessions[self.transport.sessionno] = (ret, args[0])
|
||||||
self.factory.session_protocols[self.transport.sessionno] = self
|
self.factory.session_protocols[self.transport.sessionno] = self
|
||||||
except AuthenticationRequired, err:
|
|
||||||
self.sendData((RPC_EVENT_AUTH, request_id, err.message, args[0]))
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
|
if isinstance(e, __PassthroughError):
|
||||||
|
self.sendData(
|
||||||
|
(RPC_EVENT_AUTH, request_id,
|
||||||
|
e.__class__.__name__,
|
||||||
|
e._args, e._kwargs, args[0])
|
||||||
|
)
|
||||||
|
else:
|
||||||
sendError()
|
sendError()
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
else:
|
else:
|
||||||
|
@ -273,7 +281,7 @@ class DelugeRPCProtocol(Protocol):
|
||||||
self.transport.loseConnection()
|
self.transport.loseConnection()
|
||||||
finally:
|
finally:
|
||||||
return
|
return
|
||||||
elif method == "daemon.set_event_interest" and self.transport.sessionno in self.factory.authorized_sessions:
|
elif method == "daemon.set_event_interest" and self.valid_session():
|
||||||
log.debug("RPC dispatch daemon.set_event_interest")
|
log.debug("RPC dispatch daemon.set_event_interest")
|
||||||
# This special case is to allow clients to set which events they are
|
# This special case is to allow clients to set which events they are
|
||||||
# interested in receiving.
|
# interested in receiving.
|
||||||
|
@ -289,22 +297,24 @@ class DelugeRPCProtocol(Protocol):
|
||||||
finally:
|
finally:
|
||||||
return
|
return
|
||||||
|
|
||||||
if method in self.factory.methods and self.transport.sessionno in self.factory.authorized_sessions:
|
if method in self.factory.methods and self.valid_session():
|
||||||
log.debug("RPC dispatch %s", method)
|
log.debug("RPC dispatch %s", method)
|
||||||
try:
|
try:
|
||||||
method_auth_requirement = self.factory.methods[method]._rpcserver_auth_level
|
method_auth_requirement = self.factory.methods[method]._rpcserver_auth_level
|
||||||
auth_level = self.factory.authorized_sessions[self.transport.sessionno][0]
|
auth_level = self.factory.authorized_sessions[self.transport.sessionno][0]
|
||||||
if auth_level < method_auth_requirement:
|
if auth_level < method_auth_requirement:
|
||||||
# This session is not allowed to call this method
|
# This session is not allowed to call this method
|
||||||
log.debug("Session %s is trying to call a method it is not authorized to call!", self.transport.sessionno)
|
log.debug("Session %s is trying to call a method it is not "
|
||||||
raise NotAuthorizedError("Auth level too low: %s < %s" % (auth_level, method_auth_requirement))
|
"authorized to call!", self.transport.sessionno)
|
||||||
|
raise NotAuthorizedError(auth_level, method_auth_requirement)
|
||||||
# Set the session_id in the factory so that methods can know
|
# Set the session_id in the factory so that methods can know
|
||||||
# which session is calling it.
|
# which session is calling it.
|
||||||
self.factory.session_id = self.transport.sessionno
|
self.factory.session_id = self.transport.sessionno
|
||||||
ret = self.factory.methods[method](*args, **kwargs)
|
ret = self.factory.methods[method](*args, **kwargs)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
sendError()
|
sendError()
|
||||||
# Don't bother printing out DelugeErrors, because they are just for the client
|
# Don't bother printing out DelugeErrors, because they are just
|
||||||
|
# for the client
|
||||||
if not isinstance(e, DelugeError):
|
if not isinstance(e, DelugeError):
|
||||||
log.exception("Exception calling RPC request: %s", e)
|
log.exception("Exception calling RPC request: %s", e)
|
||||||
else:
|
else:
|
||||||
|
@ -545,8 +555,12 @@ def generate_ssl_keys():
|
||||||
|
|
||||||
# Write out files
|
# Write out files
|
||||||
ssl_dir = deluge.configmanager.get_config_dir("ssl")
|
ssl_dir = deluge.configmanager.get_config_dir("ssl")
|
||||||
open(os.path.join(ssl_dir, "daemon.pkey"), "w").write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
|
open(os.path.join(ssl_dir, "daemon.pkey"), "w").write(
|
||||||
open(os.path.join(ssl_dir, "daemon.cert"), "w").write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
|
crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)
|
||||||
|
)
|
||||||
|
open(os.path.join(ssl_dir, "daemon.cert"), "w").write(
|
||||||
|
crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
|
||||||
|
)
|
||||||
# Make the files only readable by this user
|
# Make the files only readable by this user
|
||||||
for f in ("daemon.pkey", "daemon.cert"):
|
for f in ("daemon.pkey", "daemon.cert"):
|
||||||
os.chmod(os.path.join(ssl_dir, f), stat.S_IREAD | stat.S_IWRITE)
|
os.chmod(os.path.join(ssl_dir, f), stat.S_IREAD | stat.S_IWRITE)
|
||||||
|
|
|
@ -50,11 +50,24 @@ class InvalidTorrentError(DelugeError):
|
||||||
class InvalidPathError(DelugeError):
|
class InvalidPathError(DelugeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class NotAuthorizedError(DelugeError):
|
class __PassthroughError(DelugeError):
|
||||||
pass
|
def __new__(cls, *args, **kwargs):
|
||||||
|
inst = super(__PassthroughError, cls).__new__(cls, *args, **kwargs)
|
||||||
|
inst._args = args
|
||||||
|
inst._kwargs = kwargs
|
||||||
|
return inst
|
||||||
|
|
||||||
|
class NotAuthorizedError(__PassthroughError):
|
||||||
|
def __init__(self, current_level, required_level):
|
||||||
|
self.message = _(
|
||||||
|
"Auth level too low: %(current_level)s < %(required_level)s" %
|
||||||
|
dict(current_level=current_level, required_level=required_level)
|
||||||
|
)
|
||||||
|
self.current_level = current_level
|
||||||
|
self.required_level = required_level
|
||||||
|
|
||||||
|
|
||||||
class _UsernameBasedException(DelugeError):
|
class __UsernameBasedPasstroughError(__PassthroughError):
|
||||||
|
|
||||||
def _get_message(self):
|
def _get_message(self):
|
||||||
return self._message
|
return self._message
|
||||||
|
@ -71,16 +84,16 @@ class _UsernameBasedException(DelugeError):
|
||||||
del _get_username, _set_username
|
del _get_username, _set_username
|
||||||
|
|
||||||
def __init__(self, message, username):
|
def __init__(self, message, username):
|
||||||
super(_UsernameBasedException, self).__init__(message)
|
super(__UsernameBasedPasstroughError, self).__init__(message)
|
||||||
self.message = message
|
self.message = message
|
||||||
self.username = username
|
self.username = username
|
||||||
|
|
||||||
|
|
||||||
class BadLoginError(_UsernameBasedException):
|
class BadLoginError(__UsernameBasedPasstroughError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class AuthenticationRequired(BadLoginError):
|
class AuthenticationRequired(__UsernameBasedPasstroughError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class AuthManagerError(_UsernameBasedException):
|
class AuthManagerError(__UsernameBasedPasstroughError):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
import tempfile
|
import tempfile
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
import deluge.configmanager
|
import deluge.configmanager
|
||||||
import deluge.log
|
import deluge.log
|
||||||
|
@ -31,3 +33,37 @@ try:
|
||||||
gettext.install("deluge", pkg_resources.resource_filename("deluge", "i18n"))
|
gettext.install("deluge", pkg_resources.resource_filename("deluge", "i18n"))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print e
|
print e
|
||||||
|
|
||||||
|
def start_core():
|
||||||
|
CWD = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
DAEMON_SCRIPT = """
|
||||||
|
import sys
|
||||||
|
import deluge.main
|
||||||
|
|
||||||
|
sys.argv.extend(['-d', '-c', '%s', '-L', 'info'])
|
||||||
|
|
||||||
|
deluge.main.start_daemon()
|
||||||
|
"""
|
||||||
|
config_directory = set_tmp_config_dir()
|
||||||
|
fp = tempfile.TemporaryFile()
|
||||||
|
fp.write(DAEMON_SCRIPT % config_directory)
|
||||||
|
fp.seek(0)
|
||||||
|
|
||||||
|
core = Popen([sys.executable], cwd=CWD, stdin=fp, stdout=PIPE, stderr=PIPE)
|
||||||
|
while True:
|
||||||
|
line = core.stderr.readline()
|
||||||
|
if "Factory starting on 58846" in line:
|
||||||
|
time.sleep(0.3) # Slight pause just incase
|
||||||
|
break
|
||||||
|
elif 'Traceback' in line:
|
||||||
|
raise SystemExit(
|
||||||
|
"Failed to start core daemon. Do \"\"\"%s\"\"\" to see what's "
|
||||||
|
"happening" %
|
||||||
|
"python -c \"import sys; import tempfile; "
|
||||||
|
"config_directory = tempfile.mkdtemp(); "
|
||||||
|
"import deluge.main; import deluge.configmanager; "
|
||||||
|
"deluge.configmanager.set_config_dir(config_directory); "
|
||||||
|
"sys.argv.extend(['-d', '-c', config_directory, '-L', 'info']); "
|
||||||
|
"deluge.main.start_daemon()"
|
||||||
|
)
|
||||||
|
return core
|
||||||
|
|
|
@ -2,7 +2,7 @@ from twisted.trial import unittest
|
||||||
|
|
||||||
import common
|
import common
|
||||||
|
|
||||||
from deluge.core.authmanager import AuthManager
|
from deluge.core.authmanager import AuthManager, AUTH_LEVEL_ADMIN
|
||||||
|
|
||||||
class AuthManagerTestCase(unittest.TestCase):
|
class AuthManagerTestCase(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -11,4 +11,7 @@ class AuthManagerTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def test_authorize(self):
|
def test_authorize(self):
|
||||||
from deluge.ui import common
|
from deluge.ui import common
|
||||||
self.assertEquals(self.auth.authorize(*common.get_localhost_auth()), 10)
|
self.assertEquals(
|
||||||
|
self.auth.authorize(*common.get_localhost_auth()),
|
||||||
|
AUTH_LEVEL_ADMIN
|
||||||
|
)
|
||||||
|
|
|
@ -1,53 +1,80 @@
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import signal
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
from subprocess import Popen, PIPE
|
|
||||||
|
|
||||||
import common
|
import common
|
||||||
|
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
|
|
||||||
|
from deluge import error
|
||||||
|
from deluge.core.authmanager import AUTH_LEVEL_ADMIN, AUTH_LEVEL_DEFAULT
|
||||||
from deluge.ui.client import client
|
from deluge.ui.client import client
|
||||||
|
|
||||||
CWD = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
|
||||||
|
|
||||||
DAEMON_SCRIPT = """
|
|
||||||
import sys
|
|
||||||
import deluge.main
|
|
||||||
|
|
||||||
sys.argv.extend(['-d', '-c', '%s', '-Linfo'])
|
|
||||||
|
|
||||||
deluge.main.start_daemon()
|
|
||||||
"""
|
|
||||||
|
|
||||||
class ClientTestCase(unittest.TestCase):
|
class ClientTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
config_directory = common.set_tmp_config_dir()
|
self.core = common.start_core()
|
||||||
|
|
||||||
fp = tempfile.TemporaryFile()
|
|
||||||
fp.write(DAEMON_SCRIPT % config_directory)
|
|
||||||
fp.seek(0)
|
|
||||||
|
|
||||||
self.core = Popen([sys.executable], cwd=CWD,
|
|
||||||
stdin=fp, stdout=PIPE, stderr=PIPE)
|
|
||||||
|
|
||||||
time.sleep(2) # Slight pause just incase
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.core.terminate()
|
self.core.terminate()
|
||||||
|
|
||||||
def test_connect_no_credentials(self):
|
def test_connect_no_credentials(self):
|
||||||
return # hack whilst core is broken
|
|
||||||
d = client.connect("localhost", 58846)
|
d = client.connect("localhost", 58846)
|
||||||
d.addCallback(self.assertEquals, 10)
|
|
||||||
|
def on_failure(failure):
|
||||||
|
self.assertEqual(
|
||||||
|
failure.trap(error.AuthenticationRequired),
|
||||||
|
error.AuthenticationRequired
|
||||||
|
)
|
||||||
|
self.addCleanup(client.disconnect)
|
||||||
|
|
||||||
|
d.addErrback(on_failure)
|
||||||
|
return d
|
||||||
|
|
||||||
|
def test_connect_localclient(self):
|
||||||
|
from deluge.ui import common
|
||||||
|
username, password = common.get_localhost_auth()
|
||||||
|
d = client.connect(
|
||||||
|
"localhost", 58846, username=username, password=password
|
||||||
|
)
|
||||||
|
|
||||||
def on_connect(result):
|
def on_connect(result):
|
||||||
|
self.assertEqual(client.get_auth_level(), AUTH_LEVEL_ADMIN)
|
||||||
self.addCleanup(client.disconnect)
|
self.addCleanup(client.disconnect)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
d.addCallback(on_connect)
|
d.addCallback(on_connect)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def test_connect_bad_password(self):
|
||||||
|
from deluge.ui import common
|
||||||
|
username, password = common.get_localhost_auth()
|
||||||
|
d = client.connect(
|
||||||
|
"localhost", 58846, username=username, password=password+'1'
|
||||||
|
)
|
||||||
|
|
||||||
|
def on_failure(failure):
|
||||||
|
self.assertEqual(
|
||||||
|
failure.trap(error.BadLoginError),
|
||||||
|
error.BadLoginError
|
||||||
|
)
|
||||||
|
self.addCleanup(client.disconnect)
|
||||||
|
|
||||||
|
d.addErrback(on_failure)
|
||||||
|
return d
|
||||||
|
|
||||||
|
def test_connect_without_password(self):
|
||||||
|
from deluge.ui import common
|
||||||
|
username, password = common.get_localhost_auth()
|
||||||
|
d = client.connect(
|
||||||
|
"localhost", 58846, username=username
|
||||||
|
)
|
||||||
|
|
||||||
|
def on_failure(failure):
|
||||||
|
self.assertEqual(
|
||||||
|
failure.trap(error.AuthenticationRequired),
|
||||||
|
error.AuthenticationRequired
|
||||||
|
)
|
||||||
|
self.assertEqual(failure.value.username, username)
|
||||||
|
self.addCleanup(client.disconnect)
|
||||||
|
|
||||||
|
d.addErrback(on_failure)
|
||||||
|
return d
|
||||||
|
|
|
@ -13,11 +13,14 @@ except ImportError:
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import common
|
import common
|
||||||
|
import warnings
|
||||||
rpath = common.rpath
|
rpath = common.rpath
|
||||||
|
|
||||||
from deluge.core.rpcserver import RPCServer
|
from deluge.core.rpcserver import RPCServer
|
||||||
from deluge.core.core import Core
|
from deluge.core.core import Core
|
||||||
|
warnings.filterwarnings("ignore", category=RuntimeWarning)
|
||||||
from deluge.ui.web.common import compress
|
from deluge.ui.web.common import compress
|
||||||
|
warnings.resetwarnings()
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
import deluge.error
|
import deluge.error
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
import warnings
|
||||||
|
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
|
@ -9,7 +10,10 @@ from twisted.web.server import Site
|
||||||
|
|
||||||
from deluge.httpdownloader import download_file
|
from deluge.httpdownloader import download_file
|
||||||
from deluge.log import setupLogger
|
from deluge.log import setupLogger
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=RuntimeWarning)
|
||||||
from deluge.ui.web.common import compress
|
from deluge.ui.web.common import compress
|
||||||
|
warnings.resetwarnings()
|
||||||
|
|
||||||
from email.utils import formatdate
|
from email.utils import formatdate
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,8 @@ except ImportError:
|
||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
import deluge.common
|
import deluge.common
|
||||||
|
from deluge import error
|
||||||
from deluge.log import LOG as log
|
from deluge.log import LOG as log
|
||||||
from deluge.error import AuthenticationRequired
|
|
||||||
from deluge.event import known_events
|
from deluge.event import known_events
|
||||||
|
|
||||||
if deluge.common.windows_check():
|
if deluge.common.windows_check():
|
||||||
|
@ -206,7 +206,8 @@ class DelugeRPCProtocol(Protocol):
|
||||||
# Run the callbacks registered with this Deferred object
|
# Run the callbacks registered with this Deferred object
|
||||||
d.callback(request[2])
|
d.callback(request[2])
|
||||||
elif message_type == RPC_EVENT_AUTH:
|
elif message_type == RPC_EVENT_AUTH:
|
||||||
d.errback(AuthenticationRequired(request[2], request[3]))
|
# Recreate exception and errback'it
|
||||||
|
d.errback(getattr(error, request[2])(*request[3], **request[4]))
|
||||||
elif message_type == RPC_ERROR:
|
elif message_type == RPC_ERROR:
|
||||||
# Create the DelugeRPCError to pass to the errback
|
# Create the DelugeRPCError to pass to the errback
|
||||||
r = self.__rpc_requests[request_id]
|
r = self.__rpc_requests[request_id]
|
||||||
|
@ -416,12 +417,15 @@ class DaemonSSLProxy(DaemonProxy):
|
||||||
containing a `:class:DelugeRPCError` object.
|
containing a `:class:DelugeRPCError` object.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if error_data.check(AuthenticationRequired):
|
if isinstance(error_data.value, error.NotAuthorizedError):
|
||||||
|
# Still log these errors
|
||||||
|
log.error(error_data.value.logable())
|
||||||
|
return error_data
|
||||||
|
if isinstance(error_data.value, error.__PassthroughError):
|
||||||
return error_data
|
return error_data
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if error_data.value.exception_type != 'AuthManagerError':
|
|
||||||
log.error(error_data.value.logable())
|
log.error(error_data.value.logable())
|
||||||
return error_data
|
return error_data
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ from twisted.internet import reactor
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
import common
|
import common
|
||||||
import deluge.configmanager
|
import deluge.configmanager
|
||||||
|
from deluge.ui.common import get_localhost_auth
|
||||||
from deluge.ui.client import client
|
from deluge.ui.client import client
|
||||||
import deluge.ui.client
|
import deluge.ui.client
|
||||||
from deluge.configmanager import ConfigManager
|
from deluge.configmanager import ConfigManager
|
||||||
|
@ -100,6 +101,7 @@ class ConnectionManager(component.Component):
|
||||||
self.gtkui_config = ConfigManager("gtkui.conf")
|
self.gtkui_config = ConfigManager("gtkui.conf")
|
||||||
|
|
||||||
self.config = ConfigManager("hostlist.conf.1.2", DEFAULT_CONFIG)
|
self.config = ConfigManager("hostlist.conf.1.2", DEFAULT_CONFIG)
|
||||||
|
self.config.run_converter((0, 1), 2, self.__migrate_config_1_to_2)
|
||||||
|
|
||||||
self.running = False
|
self.running = False
|
||||||
|
|
||||||
|
@ -483,8 +485,9 @@ class ConnectionManager(component.Component):
|
||||||
dialog.get_password())
|
dialog.get_password())
|
||||||
d = dialog.run().addCallback(dialog_finished, host, port, user)
|
d = dialog.run().addCallback(dialog_finished, host, port, user)
|
||||||
return d
|
return d
|
||||||
dialogs.ErrorDialog(_("Failed To Authenticate"),
|
dialogs.ErrorDialog(
|
||||||
reason.value.exception_msg).run()
|
_("Failed To Authenticate"), reason.value.message
|
||||||
|
).run()
|
||||||
|
|
||||||
def on_button_connect_clicked(self, widget=None):
|
def on_button_connect_clicked(self, widget=None):
|
||||||
model, row = self.hostlist.get_selection().get_selected()
|
model, row = self.hostlist.get_selection().get_selected()
|
||||||
|
@ -683,3 +686,16 @@ class ConnectionManager(component.Component):
|
||||||
|
|
||||||
def on_askpassword_dialog_entry_activate(self, entry):
|
def on_askpassword_dialog_entry_activate(self, entry):
|
||||||
self.askpassword_dialog.response(gtk.RESPONSE_OK)
|
self.askpassword_dialog.response(gtk.RESPONSE_OK)
|
||||||
|
|
||||||
|
def __migrate_config_1_to_2(self, config):
|
||||||
|
localclient_username, localclient_password = get_localhost_auth()
|
||||||
|
if not localclient_username:
|
||||||
|
# Nothing to do here, there's no auth file
|
||||||
|
return
|
||||||
|
for idx, (_, host, _, username, _) in enumerate(config["hosts"][:]):
|
||||||
|
if host in ("127.0.0.1", "localhost"):
|
||||||
|
if not username:
|
||||||
|
config["hosts"][idx][3] = localclient_username
|
||||||
|
config["hosts"][idx][4] = localclient_password
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
|
|
||||||
import zlib
|
import zlib
|
||||||
import gettext
|
import gettext
|
||||||
from mako.template import Template as MakoTemplate
|
|
||||||
from deluge import common
|
from deluge import common
|
||||||
|
|
||||||
_ = lambda x: gettext.gettext(x).decode("utf-8")
|
_ = lambda x: gettext.gettext(x).decode("utf-8")
|
||||||
|
@ -59,7 +58,11 @@ def compress(contents, request):
|
||||||
contents += compress.flush()
|
contents += compress.flush()
|
||||||
return contents
|
return contents
|
||||||
|
|
||||||
class Template(MakoTemplate):
|
try:
|
||||||
|
# This is beeing done like this in order to allow tests to use the above
|
||||||
|
# `compress` without requiring Mako to be instaled
|
||||||
|
from mako.template import Template as MakoTemplate
|
||||||
|
class Template(MakoTemplate):
|
||||||
"""
|
"""
|
||||||
A template that adds some built-ins to the rendering
|
A template that adds some built-ins to the rendering
|
||||||
"""
|
"""
|
||||||
|
@ -74,3 +77,12 @@ class Template(MakoTemplate):
|
||||||
data.update(self.builtins)
|
data.update(self.builtins)
|
||||||
rendered = MakoTemplate.render_unicode(self, *args, **data)
|
rendered = MakoTemplate.render_unicode(self, *args, **data)
|
||||||
return rendered.encode('utf-8', 'replace')
|
return rendered.encode('utf-8', 'replace')
|
||||||
|
except ImportError:
|
||||||
|
import warnings
|
||||||
|
warnings.warn("The Mako library is required to run deluge.ui.web",
|
||||||
|
RuntimeWarning)
|
||||||
|
class Template(object):
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
raise RuntimeError(
|
||||||
|
"The Mako library is required to run deluge.ui.web"
|
||||||
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue