mirror of
https://git.deluge-torrent.org/deluge
synced 2025-08-02 22:48:40 +00:00
Add basic authentication -- your connectionmanager config will be cleared and this will likely break other UIs
This commit is contained in:
parent
cc7a685397
commit
37c3b4334c
7 changed files with 291 additions and 53 deletions
|
@ -58,7 +58,6 @@ class _ConfigManager:
|
||||||
self.config_directory = directory
|
self.config_directory = directory
|
||||||
|
|
||||||
def get_config_dir(self):
|
def get_config_dir(self):
|
||||||
log.debug("get_config_dir: %s", self.config_directory)
|
|
||||||
return self.config_directory
|
return self.config_directory
|
||||||
|
|
||||||
def close(self, config):
|
def close(self, config):
|
||||||
|
|
85
deluge/core/authmanager.py
Normal file
85
deluge/core/authmanager.py
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
#
|
||||||
|
# authmanager.py
|
||||||
|
#
|
||||||
|
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
|
||||||
|
#
|
||||||
|
# Deluge is free software.
|
||||||
|
#
|
||||||
|
# You may redistribute it and/or modify it under the terms of the
|
||||||
|
# GNU General Public License, as published by the Free Software
|
||||||
|
# Foundation; either version 3 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# deluge is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
# See the GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with deluge. If not, write to:
|
||||||
|
# The Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import random
|
||||||
|
import stat
|
||||||
|
|
||||||
|
import deluge.component as component
|
||||||
|
import deluge.configmanager as configmanager
|
||||||
|
|
||||||
|
class AuthManager(component.Component):
|
||||||
|
def __init__(self):
|
||||||
|
component.Component.__init__(self, "AuthManager")
|
||||||
|
self.auth = {}
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.__load_auth_file()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.auth = {}
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def authorize(self, username, password):
|
||||||
|
"""
|
||||||
|
Authorizes users based on username and password
|
||||||
|
|
||||||
|
:param username: str, username
|
||||||
|
:param password: str, password
|
||||||
|
:returns: True or False
|
||||||
|
:rtype: bool
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if username not in self.auth:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.auth[username] == password:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __load_auth_file(self):
|
||||||
|
auth_file = configmanager.get_config_dir("auth")
|
||||||
|
# Check for auth file and create if necessary
|
||||||
|
if not os.path.exists(auth_file):
|
||||||
|
# We create a 'localclient' account with a random password
|
||||||
|
try:
|
||||||
|
from hashlib import sha1 as sha_hash
|
||||||
|
except ImportError:
|
||||||
|
from sha import new as sha_hash
|
||||||
|
open(auth_file, "w").write("localclient:" + sha_hash(str(random.random())).hexdigest())
|
||||||
|
# Change the permissions on the file so only this user can read/write it
|
||||||
|
os.chmod(auth_file, stat.S_IREAD | stat.S_IWRITE)
|
||||||
|
|
||||||
|
# Load the auth file into a dictionary: {username: password, ...}
|
||||||
|
f = open(auth_file, "r")
|
||||||
|
for line in f:
|
||||||
|
if line.startswith("#"):
|
||||||
|
# This is a comment line
|
||||||
|
continue
|
||||||
|
username, password = line.split(":")
|
||||||
|
self.auth[username] = password
|
|
@ -53,6 +53,9 @@ from deluge.core.signalmanager import SignalManager
|
||||||
from deluge.core.filtermanager import FilterManager
|
from deluge.core.filtermanager import FilterManager
|
||||||
from deluge.core.preferencesmanager import PreferencesManager
|
from deluge.core.preferencesmanager import PreferencesManager
|
||||||
from deluge.core.autoadd import AutoAdd
|
from deluge.core.autoadd import AutoAdd
|
||||||
|
from deluge.core.authmanager import AuthManager
|
||||||
|
from deluge.core.rpcserver import BasicAuthXMLRPCRequestHandler
|
||||||
|
|
||||||
from deluge.log import LOG as log
|
from deluge.log import LOG as log
|
||||||
|
|
||||||
STATUS_KEYS = ['active_time', 'compact', 'distributed_copies', 'download_payload_rate', 'eta',
|
STATUS_KEYS = ['active_time', 'compact', 'distributed_copies', 'download_payload_rate', 'eta',
|
||||||
|
@ -91,7 +94,9 @@ class Core(
|
||||||
try:
|
try:
|
||||||
log.info("Starting XMLRPC server on port %s", port)
|
log.info("Starting XMLRPC server on port %s", port)
|
||||||
SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(
|
SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(
|
||||||
self, (hostname, port), logRequests=False, allow_none=True)
|
self, (hostname, port),
|
||||||
|
requestHandler=BasicAuthXMLRPCRequestHandler,
|
||||||
|
logRequests=False, allow_none=True)
|
||||||
except:
|
except:
|
||||||
log.info("Daemon already running or port not available..")
|
log.info("Daemon already running or port not available..")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
@ -202,6 +207,9 @@ class Core(
|
||||||
# Create the AutoAdd component
|
# Create the AutoAdd component
|
||||||
self.autoadd = AutoAdd()
|
self.autoadd = AutoAdd()
|
||||||
|
|
||||||
|
# Start the AuthManager
|
||||||
|
self.authmanager = AuthManager()
|
||||||
|
|
||||||
# New release check information
|
# New release check information
|
||||||
self.new_release = None
|
self.new_release = None
|
||||||
|
|
||||||
|
@ -530,7 +538,7 @@ class Core(
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def export_get_config_values(self, keys):
|
def export_get_config_values(self, keys):
|
||||||
"""Get the config values for the entered keys"""
|
"""Get the config values for the entered keys"""
|
||||||
config = {}
|
config = {}
|
||||||
|
@ -540,7 +548,7 @@ class Core(
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
def export_set_config(self, config):
|
def export_set_config(self, config):
|
||||||
"""Set the config with values from dictionary"""
|
"""Set the config with values from dictionary"""
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
import gobject
|
import gobject
|
||||||
|
|
||||||
from deluge.SimpleXMLRPCServer import SimpleXMLRPCServer
|
from deluge.SimpleXMLRPCServer import SimpleXMLRPCServer
|
||||||
|
from deluge.SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
|
||||||
from SocketServer import ThreadingMixIn
|
from SocketServer import ThreadingMixIn
|
||||||
from base64 import decodestring, encodestring
|
from base64 import decodestring, encodestring
|
||||||
|
|
||||||
|
@ -99,10 +100,15 @@ class XMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
|
||||||
|
|
||||||
class BasicAuthXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
class BasicAuthXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
def do_POST(self):
|
def do_POST(self):
|
||||||
auth = self.headers['authorization']
|
if "authorization" in self.headers:
|
||||||
auth = auth.replace("Basic ","")
|
auth = self.headers['authorization']
|
||||||
decoded_auth = decodestring(auth)
|
auth = auth.replace("Basic ","")
|
||||||
# Check authentication here
|
decoded_auth = decodestring(auth)
|
||||||
# if cannot authenticate, end the connection or
|
# Check authentication here
|
||||||
# otherwise call original
|
if component.get("AuthManager").authorize(*decoded_auth.split(":")):
|
||||||
return SimpleXMLRPCRequestHandler.do_POST(self)
|
# User authorized, call the real do_POST now
|
||||||
|
return SimpleXMLRPCRequestHandler.do_POST(self)
|
||||||
|
|
||||||
|
# if cannot authenticate, end the connection
|
||||||
|
self.send_response(401)
|
||||||
|
self.end_headers()
|
||||||
|
|
|
@ -64,7 +64,7 @@ class Transport(xmlrpclib.Transport):
|
||||||
errcode, errmsg, headers = h.getreply()
|
errcode, errmsg, headers = h.getreply()
|
||||||
|
|
||||||
if errcode != 200:
|
if errcode != 200:
|
||||||
raise ProtocolError(
|
raise xmlrpclib.ProtocolError(
|
||||||
host + handler,
|
host + handler,
|
||||||
errcode, errmsg,
|
errcode, errmsg,
|
||||||
headers
|
headers
|
||||||
|
|
|
@ -31,6 +31,7 @@ import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
|
import urlparse
|
||||||
|
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
import deluge.xmlrpclib as xmlrpclib
|
import deluge.xmlrpclib as xmlrpclib
|
||||||
|
@ -45,7 +46,7 @@ DEFAULT_HOST = DEFAULT_URI.split(":")[1][2:]
|
||||||
DEFAULT_PORT = DEFAULT_URI.split(":")[-1]
|
DEFAULT_PORT = DEFAULT_URI.split(":")[-1]
|
||||||
|
|
||||||
DEFAULT_CONFIG = {
|
DEFAULT_CONFIG = {
|
||||||
"hosts": [DEFAULT_HOST + ":" + DEFAULT_PORT]
|
"hosts": [DEFAULT_URI]
|
||||||
}
|
}
|
||||||
|
|
||||||
HOSTLIST_COL_PIXBUF = 0
|
HOSTLIST_COL_PIXBUF = 0
|
||||||
|
@ -58,9 +59,31 @@ HOSTLIST_STATUS = [
|
||||||
"Connected"
|
"Connected"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
HOSTLIST_PIXBUFS = [
|
||||||
|
# This is populated in ConnectionManager.__init__
|
||||||
|
]
|
||||||
|
|
||||||
if deluge.common.windows_check():
|
if deluge.common.windows_check():
|
||||||
import win32api
|
import win32api
|
||||||
|
|
||||||
|
|
||||||
|
def cell_render_host(column, cell, model, row, data):
|
||||||
|
host = model[row][data]
|
||||||
|
u = urlparse.urlsplit(host)
|
||||||
|
if not u.hostname:
|
||||||
|
host = "http://" + host
|
||||||
|
u = urlparse.urlsplit(host)
|
||||||
|
if u.username:
|
||||||
|
text = u.username + ":*@" + u.hostname + ":" + str(u.port)
|
||||||
|
else:
|
||||||
|
text = u.hostname + ":" + str(u.port)
|
||||||
|
|
||||||
|
cell.set_property('text', text)
|
||||||
|
|
||||||
|
def cell_render_pixbuf(column, cell, model, row, data):
|
||||||
|
state = model[row][data]
|
||||||
|
cell.set_property('pixbuf', HOSTLIST_PIXBUFS[state])
|
||||||
|
|
||||||
class ConnectionManager(component.Component):
|
class ConnectionManager(component.Component):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
component.Component.__init__(self, "ConnectionManager")
|
component.Component.__init__(self, "ConnectionManager")
|
||||||
|
@ -71,15 +94,32 @@ class ConnectionManager(component.Component):
|
||||||
|
|
||||||
self.window = component.get("MainWindow")
|
self.window = component.get("MainWindow")
|
||||||
self.config = ConfigManager("hostlist.conf", DEFAULT_CONFIG)
|
self.config = ConfigManager("hostlist.conf", DEFAULT_CONFIG)
|
||||||
|
|
||||||
|
# Test to see if it's an old config
|
||||||
|
if DEFAULT_HOST + ":" + DEFAULT_PORT in self.config.config:
|
||||||
|
# This is likely an older 1.0 config, so lets mv it and start fresh
|
||||||
|
self.config = None
|
||||||
|
hostlist_conf = deluge.configmanager.get_config_dir("hostlist.conf")
|
||||||
|
shutil.move(hostlist_conf, hostlist_conf + ".1.0")
|
||||||
|
self.config = ConfigManager("hostlist.conf", DEFAULT_CONFIG)
|
||||||
|
# Change the permissions on the file so only this user can read/write it
|
||||||
|
os.chmod(hostlist_conf, stat.S_IREAD | stat.S_IWRITE)
|
||||||
|
|
||||||
self.gtkui_config = ConfigManager("gtkui.conf")
|
self.gtkui_config = ConfigManager("gtkui.conf")
|
||||||
self.connection_manager = self.glade.get_widget("connection_manager")
|
self.connection_manager = self.glade.get_widget("connection_manager")
|
||||||
# Make the Connection Manager window a transient for the main window.
|
# Make the Connection Manager window a transient for the main window.
|
||||||
self.connection_manager.set_transient_for(self.window.window)
|
self.connection_manager.set_transient_for(self.window.window)
|
||||||
|
|
||||||
|
# Create status pixbufs
|
||||||
|
for stock_id in (gtk.STOCK_NO, gtk.STOCK_YES, gtk.STOCK_CONNECT):
|
||||||
|
HOSTLIST_PIXBUFS.append(self.connection_manager.render_icon(stock_id, gtk.ICON_SIZE_MENU))
|
||||||
|
|
||||||
self.hostlist = self.glade.get_widget("hostlist")
|
self.hostlist = self.glade.get_widget("hostlist")
|
||||||
self.connection_manager.set_icon(common.get_logo(32))
|
self.connection_manager.set_icon(common.get_logo(32))
|
||||||
|
|
||||||
self.glade.get_widget("image1").set_from_pixbuf(common.get_logo(32))
|
self.glade.get_widget("image1").set_from_pixbuf(common.get_logo(32))
|
||||||
|
|
||||||
|
# connection status pixbuf, hostname:port, status
|
||||||
self.liststore = gtk.ListStore(gtk.gdk.Pixbuf, str, int)
|
self.liststore = gtk.ListStore(gtk.gdk.Pixbuf, str, int)
|
||||||
|
|
||||||
# Holds the online status of hosts
|
# Holds the online status of hosts
|
||||||
|
@ -95,9 +135,11 @@ class ConnectionManager(component.Component):
|
||||||
render = gtk.CellRendererPixbuf()
|
render = gtk.CellRendererPixbuf()
|
||||||
column = gtk.TreeViewColumn(
|
column = gtk.TreeViewColumn(
|
||||||
"Status", render, pixbuf=HOSTLIST_COL_PIXBUF)
|
"Status", render, pixbuf=HOSTLIST_COL_PIXBUF)
|
||||||
|
column.set_cell_data_func(render, cell_render_pixbuf, 2)
|
||||||
self.hostlist.append_column(column)
|
self.hostlist.append_column(column)
|
||||||
render = gtk.CellRendererText()
|
render = gtk.CellRendererText()
|
||||||
column = gtk.TreeViewColumn("Host", render, text=HOSTLIST_COL_URI)
|
column = gtk.TreeViewColumn("Host", render, text=HOSTLIST_COL_URI)
|
||||||
|
column.set_cell_data_func(render, cell_render_host, 1)
|
||||||
self.hostlist.append_column(column)
|
self.hostlist.append_column(column)
|
||||||
|
|
||||||
self.glade.signal_autoconnect({
|
self.glade.signal_autoconnect({
|
||||||
|
@ -138,28 +180,50 @@ class ConnectionManager(component.Component):
|
||||||
if self.gtkui_config["autoconnect"] and \
|
if self.gtkui_config["autoconnect"] and \
|
||||||
self.gtkui_config["autoconnect_host_uri"] != None:
|
self.gtkui_config["autoconnect_host_uri"] != None:
|
||||||
uri = self.gtkui_config["autoconnect_host_uri"]
|
uri = self.gtkui_config["autoconnect_host_uri"]
|
||||||
# Make sure the uri is proper
|
|
||||||
if uri[:7] != "http://":
|
|
||||||
uri = "http://" + uri
|
|
||||||
if self.test_online_status(uri):
|
if self.test_online_status(uri):
|
||||||
# Host is online, so lets connect
|
# Host is online, so lets connect
|
||||||
client.set_core_uri(uri)
|
client.set_core_uri(uri)
|
||||||
self.hide()
|
self.hide()
|
||||||
elif self.gtkui_config["autostart_localhost"]:
|
elif self.gtkui_config["autostart_localhost"]:
|
||||||
# Check to see if we are trying to connect to a localhost
|
# Check to see if we are trying to connect to a localhost
|
||||||
if uri[7:].split(":")[0] == "localhost" or \
|
u = urlparse.urlsplit(uri)
|
||||||
uri[7:].split(":")[0] == "127.0.0.1":
|
if u.hostname == "localhost" or u.hostname == "127.0.0.1":
|
||||||
# This is a localhost, so lets try to start it
|
# This is a localhost, so lets try to start it
|
||||||
port = uri[7:].split(":")[1]
|
|
||||||
# First add it to the list
|
# First add it to the list
|
||||||
self.add_host("localhost", port)
|
self.add_host("localhost", u.port)
|
||||||
self.start_localhost(port)
|
self.start_localhost(u.port)
|
||||||
# We need to wait for the host to start before connecting
|
# Get the localhost uri with authentication details
|
||||||
while not self.test_online_status(uri):
|
auth_uri = None
|
||||||
|
while not auth_uri:
|
||||||
|
# We need to keep trying because the daemon may not have been started yet
|
||||||
|
# and the 'auth' file may not have been created
|
||||||
|
auth_uri = self.get_localhost_auth_uri(uri)
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
client.set_core_uri(uri)
|
|
||||||
|
# We need to wait for the host to start before connecting
|
||||||
|
while not self.test_online_status(auth_uri):
|
||||||
|
time.sleep(0.01)
|
||||||
|
client.set_core_uri(auth_uri)
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
|
def get_localhost_auth_uri(self, uri):
|
||||||
|
"""
|
||||||
|
Grabs the localclient auth line from the 'auth' file and creates a localhost uri
|
||||||
|
|
||||||
|
:param uri: the uri to add the authentication info to
|
||||||
|
:returns: a localhost uri containing authentication information or None if the information is not available
|
||||||
|
"""
|
||||||
|
auth_file = deluge.configmanager.get_config_dir("auth")
|
||||||
|
if os.path.exists(auth_file):
|
||||||
|
u = urlparse.urlsplit(uri)
|
||||||
|
for line in open(auth_file):
|
||||||
|
username, password = line.split(":")
|
||||||
|
if username == "localclient":
|
||||||
|
# We use '127.0.0.1' in place of 'localhost' just incase this isn't defined properly
|
||||||
|
hostname = u.hostname.replace("localhost", "127.0.0.1")
|
||||||
|
return u.scheme + "://" + username + ":" + password + "@" + hostname + ":" + str(u.port)
|
||||||
|
return None
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
if self.gtkui_config["autoconnect"]:
|
if self.gtkui_config["autoconnect"]:
|
||||||
# We need to update the autoconnect_host_uri on connection to host
|
# We need to update the autoconnect_host_uri on connection to host
|
||||||
|
@ -195,30 +259,24 @@ class ConnectionManager(component.Component):
|
||||||
"""Updates the host status"""
|
"""Updates the host status"""
|
||||||
def update_row(model=None, path=None, row=None, columns=None):
|
def update_row(model=None, path=None, row=None, columns=None):
|
||||||
uri = model.get_value(row, HOSTLIST_COL_URI)
|
uri = model.get_value(row, HOSTLIST_COL_URI)
|
||||||
uri = "http://" + uri
|
|
||||||
threading.Thread(target=self.test_online_status, args=(uri,)).start()
|
threading.Thread(target=self.test_online_status, args=(uri,)).start()
|
||||||
try:
|
try:
|
||||||
online = self.online_status[uri]
|
online = self.online_status[uri]
|
||||||
except:
|
except:
|
||||||
online = False
|
online = False
|
||||||
|
|
||||||
|
# Update hosts status
|
||||||
if online:
|
if online:
|
||||||
image = gtk.STOCK_YES
|
|
||||||
online = HOSTLIST_STATUS.index("Online")
|
online = HOSTLIST_STATUS.index("Online")
|
||||||
else:
|
else:
|
||||||
image = gtk.STOCK_NO
|
|
||||||
online = HOSTLIST_STATUS.index("Offline")
|
online = HOSTLIST_STATUS.index("Offline")
|
||||||
|
|
||||||
|
if urlparse.urlsplit(uri).hostname == "localhost" or urlparse.urlsplit(uri).hostname == "127.0.0.1":
|
||||||
|
uri = self.get_localhost_auth_uri(uri)
|
||||||
|
|
||||||
if uri == current_uri:
|
if uri == current_uri:
|
||||||
# We are connected to this host, so lets display the connected
|
|
||||||
# icon.
|
|
||||||
image = gtk.STOCK_CONNECT
|
|
||||||
online = HOSTLIST_STATUS.index("Connected")
|
online = HOSTLIST_STATUS.index("Connected")
|
||||||
|
|
||||||
pixbuf = self.connection_manager.render_icon(
|
|
||||||
image, gtk.ICON_SIZE_MENU)
|
|
||||||
|
|
||||||
model.set_value(row, HOSTLIST_COL_PIXBUF, pixbuf)
|
|
||||||
model.set_value(row, HOSTLIST_COL_STATUS, online)
|
model.set_value(row, HOSTLIST_COL_STATUS, online)
|
||||||
|
|
||||||
current_uri = client.get_core_uri()
|
current_uri = client.get_core_uri()
|
||||||
|
@ -260,12 +318,10 @@ class ConnectionManager(component.Component):
|
||||||
|
|
||||||
# Check to see if a localhost is selected
|
# Check to see if a localhost is selected
|
||||||
localhost = False
|
localhost = False
|
||||||
if uri.split(":")[0] == "localhost" or uri.split(":")[0] == "127.0.0.1":
|
u = urlparse.urlsplit(uri)
|
||||||
|
if u.hostname == "localhost" or u.hostname == "127.0.0.1":
|
||||||
localhost = True
|
localhost = True
|
||||||
|
|
||||||
# Make actual URI string
|
|
||||||
uri = "http://" + uri
|
|
||||||
|
|
||||||
# Make sure buttons are sensitive at start
|
# Make sure buttons are sensitive at start
|
||||||
self.glade.get_widget("button_startdaemon").set_sensitive(True)
|
self.glade.get_widget("button_startdaemon").set_sensitive(True)
|
||||||
self.glade.get_widget("button_connect").set_sensitive(True)
|
self.glade.get_widget("button_connect").set_sensitive(True)
|
||||||
|
@ -321,7 +377,11 @@ class ConnectionManager(component.Component):
|
||||||
online = True
|
online = True
|
||||||
host = None
|
host = None
|
||||||
try:
|
try:
|
||||||
host = xmlrpclib.ServerProxy(uri.replace("localhost", "127.0.0.1"))
|
u = urlparse.urlsplit(uri)
|
||||||
|
if u.hostname == "localhost" or u.hostname == "127.0.0.1":
|
||||||
|
host = xmlrpclib.ServerProxy(self.get_localhost_auth_uri(uri))
|
||||||
|
else:
|
||||||
|
host = xmlrpclib.ServerProxy(uri)
|
||||||
host.ping()
|
host.ping()
|
||||||
except socket.error:
|
except socket.error:
|
||||||
online = False
|
online = False
|
||||||
|
@ -341,18 +401,32 @@ class ConnectionManager(component.Component):
|
||||||
dialog.set_icon(common.get_logo(16))
|
dialog.set_icon(common.get_logo(16))
|
||||||
hostname_entry = self.glade.get_widget("entry_hostname")
|
hostname_entry = self.glade.get_widget("entry_hostname")
|
||||||
port_spinbutton = self.glade.get_widget("spinbutton_port")
|
port_spinbutton = self.glade.get_widget("spinbutton_port")
|
||||||
|
username_entry = self.glade.get_widget("entry_username")
|
||||||
|
password_entry = self.glade.get_widget("entry_password")
|
||||||
response = dialog.run()
|
response = dialog.run()
|
||||||
if response == 1:
|
if response == 1:
|
||||||
|
username = username_entry.get_text()
|
||||||
|
password = password_entry.get_text()
|
||||||
|
hostname = hostname_entry.get_text()
|
||||||
|
if not urlparse.urlsplit(hostname).hostname:
|
||||||
|
# We need to add a http://
|
||||||
|
hostname = "http://" + hostname
|
||||||
|
u = urlparse.urlsplit(hostname)
|
||||||
|
if username and password:
|
||||||
|
host = u.scheme + "://" + username + ":" + password + "@" + u.hostname
|
||||||
|
else:
|
||||||
|
host = hostname
|
||||||
|
|
||||||
# We add the host
|
# We add the host
|
||||||
self.add_host(hostname_entry.get_text(),
|
self.add_host(host, port_spinbutton.get_value_as_int())
|
||||||
port_spinbutton.get_value_as_int())
|
|
||||||
|
|
||||||
dialog.hide()
|
dialog.hide()
|
||||||
|
|
||||||
def add_host(self, hostname, port):
|
def add_host(self, hostname, port):
|
||||||
"""Adds the host to the list"""
|
"""Adds the host to the list"""
|
||||||
if hostname.startswith("http://"):
|
if not urlparse.urlsplit(hostname).scheme:
|
||||||
hostname = hostname[7:]
|
# We need to add http:// to this
|
||||||
|
hostname = "http://" + hostname
|
||||||
|
|
||||||
# Check to make sure the hostname is at least 1 character long
|
# Check to make sure the hostname is at least 1 character long
|
||||||
if len(hostname) < 1:
|
if len(hostname) < 1:
|
||||||
|
@ -407,18 +481,17 @@ class ConnectionManager(component.Component):
|
||||||
row = self.liststore.get_iter(paths[0])
|
row = self.liststore.get_iter(paths[0])
|
||||||
status = self.liststore.get_value(row, HOSTLIST_COL_STATUS)
|
status = self.liststore.get_value(row, HOSTLIST_COL_STATUS)
|
||||||
uri = self.liststore.get_value(row, HOSTLIST_COL_URI)
|
uri = self.liststore.get_value(row, HOSTLIST_COL_URI)
|
||||||
port = uri.split(":")[1]
|
u = urlparse.urlsplit(uri)
|
||||||
if HOSTLIST_STATUS[status] == "Online" or\
|
if HOSTLIST_STATUS[status] == "Online" or\
|
||||||
HOSTLIST_STATUS[status] == "Connected":
|
HOSTLIST_STATUS[status] == "Connected":
|
||||||
# We need to stop this daemon
|
# We need to stop this daemon
|
||||||
uri = "http://" + uri
|
|
||||||
# Call the shutdown method on the daemon
|
# Call the shutdown method on the daemon
|
||||||
core = xmlrpclib.ServerProxy(uri)
|
core = xmlrpclib.ServerProxy(uri)
|
||||||
core.shutdown()
|
core.shutdown()
|
||||||
# Update display to show change
|
# Update display to show change
|
||||||
self.update()
|
self.update()
|
||||||
elif HOSTLIST_STATUS[status] == "Offline":
|
elif HOSTLIST_STATUS[status] == "Offline":
|
||||||
self.start_localhost(port)
|
self.start_localhost(u.port)
|
||||||
|
|
||||||
def start_localhost(self, port):
|
def start_localhost(self, port):
|
||||||
"""Starts a localhost daemon"""
|
"""Starts a localhost daemon"""
|
||||||
|
@ -444,11 +517,11 @@ class ConnectionManager(component.Component):
|
||||||
uri = self.liststore.get_value(row, HOSTLIST_COL_URI)
|
uri = self.liststore.get_value(row, HOSTLIST_COL_URI)
|
||||||
# Determine if this is a localhost
|
# Determine if this is a localhost
|
||||||
localhost = False
|
localhost = False
|
||||||
port = uri.split(":")[1]
|
u = urlparse.urlsplit(uri)
|
||||||
if uri.split(":")[0] == "localhost":
|
if u.hostname == "localhost" or u.hostname == "127.0.0.1":
|
||||||
localhost = True
|
localhost = True
|
||||||
|
|
||||||
uri = "http://" + uri
|
|
||||||
if status == HOSTLIST_STATUS.index("Connected"):
|
if status == HOSTLIST_STATUS.index("Connected"):
|
||||||
# Stop all the components first.
|
# Stop all the components first.
|
||||||
component.stop()
|
component.stop()
|
||||||
|
@ -465,9 +538,14 @@ class ConnectionManager(component.Component):
|
||||||
if localhost:
|
if localhost:
|
||||||
self.start_localhost(port)
|
self.start_localhost(port)
|
||||||
# We need to wait for the host to start before connecting
|
# We need to wait for the host to start before connecting
|
||||||
while not self.test_online_status(uri):
|
auth_uri = None
|
||||||
|
while not auth_uri:
|
||||||
|
auth_uri = self.get_localhost_auth_uri(uri)
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
client.set_core_uri(uri)
|
|
||||||
|
while not self.test_online_status(auth_uri):
|
||||||
|
time.sleep(0.01)
|
||||||
|
client.set_core_uri(auth_uri)
|
||||||
self._update_list()
|
self._update_list()
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
|
@ -477,7 +555,11 @@ class ConnectionManager(component.Component):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Status is OK, so lets change to this host
|
# Status is OK, so lets change to this host
|
||||||
client.set_core_uri(uri)
|
if localhost:
|
||||||
|
client.set_core_uri(self.get_localhost_auth_uri(uri))
|
||||||
|
else:
|
||||||
|
client.set_core_uri(uri)
|
||||||
|
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
def on_chk_autoconnect_toggled(self, widget):
|
def on_chk_autoconnect_toggled(self, widget):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||||
<!--Generated with glade3 3.4.5 on Fri Nov 7 23:39:07 2008 -->
|
<!--Generated with glade3 3.4.5 on Tue Dec 9 21:46:39 2008 -->
|
||||||
<glade-interface>
|
<glade-interface>
|
||||||
<widget class="GtkDialog" id="connection_manager">
|
<widget class="GtkDialog" id="connection_manager">
|
||||||
<property name="has_focus">True</property>
|
<property name="has_focus">True</property>
|
||||||
|
@ -378,6 +378,64 @@
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkHBox" id="hbox5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="spacing">5</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Username:</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkEntry" id="entry_username">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkHBox" id="hbox6">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="spacing">5</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label6">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Password:</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkEntry" id="entry_password">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child internal-child="action_area">
|
<child internal-child="action_area">
|
||||||
<widget class="GtkHButtonBox" id="dialog-action_area3">
|
<widget class="GtkHButtonBox" id="dialog-action_area3">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue