Add DB-based system manager server. New simple XML parser.
This commit is contained in:
parent
02b1c0209c
commit
214cb07962
|
@ -8,16 +8,16 @@ from zope.interface import Interface
|
||||||
|
|
||||||
class IManager(Interface):
|
class IManager(Interface):
|
||||||
|
|
||||||
def serverLogin(user):
|
def serverLogin(server):
|
||||||
"""Logs server on"""
|
"""Logs server on"""
|
||||||
|
|
||||||
def serverLogout(user):
|
def serverLogout(server):
|
||||||
"""Logs server out"""
|
"""Logs server out"""
|
||||||
|
|
||||||
def clientLogin(user):
|
def clientLogin(server, user):
|
||||||
"""Logs client in"""
|
"""Logs client in"""
|
||||||
|
|
||||||
def clientLogout(user):
|
def clientLogout(server, user):
|
||||||
"""Logs client out"""
|
"""Logs client out"""
|
||||||
|
|
||||||
def getClientList():
|
def getClientList():
|
||||||
|
|
|
@ -5,33 +5,146 @@
|
||||||
|
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from frn.manager import IManager
|
from frn.manager import IManager
|
||||||
from frn.userstore.database import DatabaseUserStore
|
from twisted.python import log
|
||||||
|
from twisted.python.failure import Failure
|
||||||
|
from twisted.mail.smtp import sendmail
|
||||||
|
import random, string, uuid
|
||||||
|
from frn.user import FRNUser
|
||||||
|
|
||||||
|
def rndpasswd():
|
||||||
|
return ''.join([random.choice(string.ascii_uppercase) for i in range(8)])
|
||||||
|
|
||||||
class DatabaseManager(object):
|
class DatabaseManager(object):
|
||||||
|
|
||||||
implements(IManager)
|
implements(IManager)
|
||||||
|
|
||||||
def __init__(self, store):
|
def __init__(self, pool):
|
||||||
self._store = store
|
self._pool = pool
|
||||||
|
self._pool.runOperation("""
|
||||||
|
CREATE TABLE IF NOT EXISTS frn_users (
|
||||||
|
_id VARCHAR(32) NOT NULL PRIMARY KEY,
|
||||||
|
_ea VARCHAR(30) UNIQUE NOT NULL,
|
||||||
|
_pw VARCHAR(20) NOT NULL,
|
||||||
|
_on VARCHAR(20) NOT NULL,
|
||||||
|
_bc VARCHAR(20) NOT NULL,
|
||||||
|
_nn VARCHAR(20) NOT NULL,
|
||||||
|
_ct VARCHAR(20) NOT NULL,
|
||||||
|
_nt VARCHAR(20),
|
||||||
|
_ds VARCHAR(20) NOT NULL,
|
||||||
|
_ip VARCHAR(20),
|
||||||
|
registration TIMESTAMP NOT NULL DEFAULT current_timestamp,
|
||||||
|
lastlogin TIMESTAMP,
|
||||||
|
server VARCHAR(20),
|
||||||
|
port INTEGER
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
self._pool.runOperation("""
|
||||||
|
CREATE TABLE IF NOT EXISTS frn_servers (
|
||||||
|
_vx VARCHAR(7) NOT NULL,
|
||||||
|
_sn VARCHAR(20) NOT NULL,
|
||||||
|
_pt INTEGER NOT NULL,
|
||||||
|
_bn VARCHAR(20),
|
||||||
|
_bp integer,
|
||||||
|
_ow VARCHAR(30) NOT NULL,
|
||||||
|
registration TIMESTAMP NOT NULL DEFAULT current_timestamp,
|
||||||
|
PRIMARY KEY(_sn, _pt)
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
|
||||||
def serverLogin(self, user):
|
def serverLogin(self, server):
|
||||||
pass
|
def checkauth(res):
|
||||||
|
if not isinstance(res, Failure):
|
||||||
|
if res[0] > 0:
|
||||||
|
return self._pool.runOperation("""
|
||||||
|
INSERT INTO frn_servers
|
||||||
|
(_vx, _sn, _pt, _bn, _bp, _ow) VALUES
|
||||||
|
(?,?,?,?,?,?)
|
||||||
|
""", (server.VX, server.SN, server.PT,
|
||||||
|
server.BN, server.BP, server.OW)).addCallbacks(
|
||||||
|
lambda x: 0, lambda x: -1)
|
||||||
|
else:
|
||||||
|
return -1
|
||||||
|
return self._pool.runQuery("SELECT count(*) FROM frn_users WHERE _ea=? AND _pw=?",
|
||||||
|
(server.OW, server.PW)).addBoth(checkauth)
|
||||||
|
|
||||||
def serverLogout(self, user):
|
def serverLogout(self, server):
|
||||||
pass
|
self._pool.runOperation("UPDATE frn_users SET server=NULL, port=NULL, _nt=NULL WHERE server=? AND port=?",
|
||||||
|
(server.SN, server.PT))
|
||||||
|
self._pool.runOperation("DELETE FROM frn_servers WHERE _sn=? AND _pt=?",
|
||||||
|
(server.SN, server.PT))
|
||||||
|
|
||||||
def clientLogin(self, user):
|
def clientLogin(self, server, user):
|
||||||
pass
|
def userfound(data):
|
||||||
|
log.msg("Client login: %s" % repr(data))
|
||||||
|
if data:
|
||||||
|
u = dict(zip(
|
||||||
|
('ID', 'EA', 'PW', 'ON', 'BC', 'NN', 'CT', 'NT', 'DS', 'IP', 'registration', 'lastlogin', 'server', 'port'),
|
||||||
|
data[0]))
|
||||||
|
if u['server']:
|
||||||
|
log.msg("Duplicate client %s" % repr(user))
|
||||||
|
return "DUPL"
|
||||||
|
self._pool.runQuery("""
|
||||||
|
UPDATE frn_users SET
|
||||||
|
_bc=?, _nn=?, _ct=?, _nt=?, _ds=?, _ip=?, server=?, port=?,
|
||||||
|
lastlogin=current_timestamp
|
||||||
|
WHERE _id=?
|
||||||
|
""", (user.BC, user.NN, user.CT, user.NT, user.DS, user.IP, server.SN, server.PT, u['ID']))
|
||||||
|
log.msg("Authenticated client %s" % repr(user))
|
||||||
|
return str(u['ID'])
|
||||||
|
else:
|
||||||
|
log.msg("Wrong client %s" % repr(user))
|
||||||
|
return "WRONG"
|
||||||
|
return self._pool.runQuery("SELECT * FROM frn_users WHERE _ea=? AND _on=? AND _pw=?",
|
||||||
|
(user.EA, user.ON, user.PW)).addCallbacks(userfound, lambda x: "WRONG")
|
||||||
|
|
||||||
def clientLogout(self, user):
|
def clientLogout(self, server, user):
|
||||||
pass
|
log.msg("Logging out client %s" % repr(user))
|
||||||
|
return self._pool.runOperation("UPDATE frn_users SET server=NULL, port=NULL, _nt=NULL WHERE _id=?",
|
||||||
|
(user.ID,)).addBoth(lambda x: "OK")
|
||||||
|
|
||||||
def getClientList(self):
|
def getClientList(self):
|
||||||
pass
|
def buildlist(tr):
|
||||||
|
tr.execute("SELECT _sn, _pt FROM frn_servers")
|
||||||
|
servers = tr.fetchall()
|
||||||
|
r = {}
|
||||||
|
for sn, sp in servers:
|
||||||
|
r[(sn,sp)] = {}
|
||||||
|
tr.execute("SELECT DISTINCT _nt FROM frn_users WHERE server=? AND port=?", (sn,sp))
|
||||||
|
networks = tr.fetchall()
|
||||||
|
for (n,) in networks:
|
||||||
|
r[(sn,sp)][n] = []
|
||||||
|
tr.execute("SELECT _id, _on, _bc, _ds, _nn, _ct FROM frn_users WHERE server=? AND port=? AND _nt=?",
|
||||||
|
(sn, sp, n))
|
||||||
|
clients = tr.fetchall()
|
||||||
|
for c in clients:
|
||||||
|
cu = FRNUser(**dict(zip(['EA','ON','BC','DS','NN','CT'],c)))
|
||||||
|
r[(sn,sp)][n].append(cu)
|
||||||
|
return r
|
||||||
|
return self._pool.runInteraction(buildlist)
|
||||||
|
|
||||||
def registerUser(self, user):
|
def registerUser(self, user):
|
||||||
pass
|
def fetchdata(is_new):
|
||||||
|
def maildata(data):
|
||||||
|
u = dict(zip(
|
||||||
|
('ID', 'EA', 'PW', 'ON', 'BC', 'NN', 'CT', 'NT', 'DS', 'IP', 'registration', 'lastlogin', 'server', 'port'),
|
||||||
|
data[0]))
|
||||||
|
log.msg("Mailing password to user %s" % str(u))
|
||||||
|
with open('mailtemplate.txt','r') as tplfile:
|
||||||
|
tpl = tplfile.read()
|
||||||
|
mailbody = string.Template(tpl).safe_substitute(u)
|
||||||
|
sendmail('127.0.0.1',
|
||||||
|
'admin@gnuradionetwork.org',
|
||||||
|
[u['EA']],
|
||||||
|
mailbody, port=2525)
|
||||||
|
return "OK"
|
||||||
|
return self._pool.runQuery(
|
||||||
|
"SELECT * FROM frn_users WHERE _ea=?", (user.EA,)
|
||||||
|
).addCallback(maildata).addErrback(lambda x: "ERROR")
|
||||||
|
return self._pool.runOperation("""
|
||||||
|
INSERT INTO frn_users (_id, _ea, _pw, _on, _bc, _ds, _nn, _ct)
|
||||||
|
VALUES (?,?,?,?,?,?,?,?)
|
||||||
|
""", (uuid.uuid4().get_hex()[:20], user.EA, rndpasswd(),
|
||||||
|
user.ON, user.BC, user.DS, user.NN, user.CT)
|
||||||
|
).addBoth(fetchdata)
|
||||||
|
|
||||||
# vim: set et ai sw=4 ts=4 sts=4:
|
# vim: set et ai sw=4 ts=4 sts=4:
|
||||||
|
|
|
@ -16,20 +16,20 @@ class DummyManager(object):
|
||||||
def _randId(self):
|
def _randId(self):
|
||||||
return '.'.join([str(randint(1,254)) for i in range(4)])
|
return '.'.join([str(randint(1,254)) for i in range(4)])
|
||||||
|
|
||||||
def serverLogin(self, user):
|
def serverLogin(self, server):
|
||||||
return defer.succeed(0)
|
return defer.succeed(0)
|
||||||
|
|
||||||
def serverLogout(self, user):
|
def serverLogout(self, server):
|
||||||
return defer.succeed(None)
|
return defer.succeed(None)
|
||||||
|
|
||||||
def clientLogin(self, user):
|
def clientLogin(self, server, user):
|
||||||
return defer.succeed(self._randId())
|
return defer.succeed(self._randId())
|
||||||
|
|
||||||
def clientLogout(self, user):
|
def clientLogout(self, server, user):
|
||||||
return defer.succeed('OK')
|
return defer.succeed('OK')
|
||||||
|
|
||||||
def getClientList(self):
|
def getClientList(self):
|
||||||
return defer.succeed([])
|
return defer.succeed({})
|
||||||
|
|
||||||
def registerUser(self, user):
|
def registerUser(self, user):
|
||||||
return defer.succeed('OK')
|
return defer.succeed('OK')
|
||||||
|
|
|
@ -55,23 +55,23 @@ class RemoteManager(object):
|
||||||
def doConnect(self):
|
def doConnect(self):
|
||||||
self.reactor.connectTCP(self.server, self.port, self.factory)
|
self.reactor.connectTCP(self.server, self.port, self.factory)
|
||||||
|
|
||||||
def serverLogin(self, user):
|
def serverLogin(self, server):
|
||||||
self.factory = CustomManagerClientFactory(user)
|
self.factory = CustomManagerClientFactory(server)
|
||||||
self.doConnect()
|
self.doConnect()
|
||||||
return self.factory.deferred
|
return self.factory.deferred
|
||||||
|
|
||||||
def serverLogout(self, user):
|
def serverLogout(self, server):
|
||||||
if self.factory.client is not None:
|
if self.factory.client is not None:
|
||||||
return self.factory.client.sendServerLogout(user)
|
return self.factory.client.sendServerLogout(server)
|
||||||
|
|
||||||
def clientLogin(self, user):
|
def clientLogin(self, server, user):
|
||||||
if self.maskParrot and user.BC == 'Parrot':
|
if self.maskParrot and user.BC == 'Parrot':
|
||||||
u = user.copy(BC='PC Only')
|
u = user.copy(BC='PC Only')
|
||||||
else:
|
else:
|
||||||
u = user.copy()
|
u = user.copy()
|
||||||
return self.factory.client.sendClientLogin(u)
|
return self.factory.client.sendClientLogin(u)
|
||||||
|
|
||||||
def clientLogout(self, user):
|
def clientLogout(self, server, user):
|
||||||
if self.maskParrot and user.BC == 'Parrot':
|
if self.maskParrot and user.BC == 'Parrot':
|
||||||
u = user.copy(BC='PC Only')
|
u = user.copy(BC='PC Only')
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -112,12 +112,16 @@ class FRNManagerServer(LineOnlyReceiver):
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
log.msg("Manager client connected from %s" % self.transport.getPeer().host)
|
log.msg("Manager client connected from %s" % self.transport.getPeer().host)
|
||||||
self._phase = "CONNECTED"
|
self._phase = "CONNECTED"
|
||||||
|
self.serverInfo = None
|
||||||
self.kp = makeRandomChallange()
|
self.kp = makeRandomChallange()
|
||||||
|
|
||||||
def connectionLost(self, reason):
|
def connectionLost(self, reason):
|
||||||
log.msg("Manager client disconnected from %s: %s" %
|
log.msg("Manager client disconnected from %s: %s" %
|
||||||
(self.transport.getPeer().host, reason))
|
(self.transport.getPeer().host, reason))
|
||||||
self.manager.serverLogout(None) # FIXME
|
if self.serverInfo:
|
||||||
|
self.manager.serverLogout(self.serverInfo)
|
||||||
|
self.serverInfo = None
|
||||||
|
self._phase = "DISCONNECTED"
|
||||||
|
|
||||||
def _authOnly(self):
|
def _authOnly(self):
|
||||||
if self._phase != "AUTHENTICATED":
|
if self._phase != "AUTHENTICATED":
|
||||||
|
@ -129,6 +133,8 @@ class FRNManagerServer(LineOnlyReceiver):
|
||||||
if self._phase == "CHALLANGE":
|
if self._phase == "CHALLANGE":
|
||||||
if sline == responseToChallange(self.kp):
|
if sline == responseToChallange(self.kp):
|
||||||
self._phase = "AUTHENTICATED"
|
self._phase = "AUTHENTICATED"
|
||||||
|
self.serverInfo = self.tmpServerInfo
|
||||||
|
log.msg("Auth success: %s" % repr(self.serverInfo))
|
||||||
else:
|
else:
|
||||||
self.transport.loseConnection()
|
self.transport.loseConnection()
|
||||||
else:
|
else:
|
||||||
|
@ -146,8 +152,19 @@ class FRNManagerServer(LineOnlyReceiver):
|
||||||
handler(xbody)
|
handler(xbody)
|
||||||
|
|
||||||
def sendClientList(self):
|
def sendClientList(self):
|
||||||
|
def gotClientList(cl):
|
||||||
|
self.sendLine(str(len(cl)))
|
||||||
|
for sn, sp in cl:
|
||||||
|
self.sendLine("%s - Port: %d" % (sn, sp))
|
||||||
|
self.sendLine(str(len(cl[(sn,sp)])))
|
||||||
|
for nt in cl[(sn,sp)]:
|
||||||
|
self.sendLine(nt)
|
||||||
|
self.sendLine(str(len(cl[(sn,sp)][nt])))
|
||||||
|
for u in cl[(sn,sp)][nt]:
|
||||||
|
self.sendLine(u.asXML('EA','ON','BC','DS','NN','CT'))
|
||||||
log.msg("SM")
|
log.msg("SM")
|
||||||
self.sendLine('0') # TODO
|
return self.manager.getClientList().addCallback(gotClientList)
|
||||||
|
|
||||||
|
|
||||||
def unimplemented(self, cmd, body):
|
def unimplemented(self, cmd, body):
|
||||||
log.err("Unimplemented command %s: %s" % (cmd, str(body)))
|
log.err("Unimplemented command %s: %s" % (cmd, str(body)))
|
||||||
|
@ -156,13 +173,17 @@ class FRNManagerServer(LineOnlyReceiver):
|
||||||
def sendManagerInfo(res):
|
def sendManagerInfo(res):
|
||||||
if versions.manager > 2009004:
|
if versions.manager > 2009004:
|
||||||
self._phase = "CHALLANGE"
|
self._phase = "CHALLANGE"
|
||||||
|
self.tmpServerInfo = FRNUser(**body)
|
||||||
else:
|
else:
|
||||||
self._phase = "AUTHENTICATED"
|
self._phase = "AUTHENTICATED"
|
||||||
|
self.serverInfo = FRNUser(**body)
|
||||||
|
log.msg("Auth success: %s" % repr(self.serverInfo))
|
||||||
self.sendLine(formatSimpleXML([
|
self.sendLine(formatSimpleXML([
|
||||||
('SV', versions.server),
|
('SV', versions.server),
|
||||||
('CV', versions.client),
|
('CV', versions.client),
|
||||||
('MC', versions.manager),
|
('MC', versions.manager),
|
||||||
('AL', res['al']),
|
# ('AL', res['al']),
|
||||||
|
('AL', res),
|
||||||
('KP', self.kp)
|
('KP', self.kp)
|
||||||
]))
|
]))
|
||||||
log.msg("SC: %s" % str(body))
|
log.msg("SC: %s" % str(body))
|
||||||
|
@ -172,13 +193,13 @@ class FRNManagerServer(LineOnlyReceiver):
|
||||||
def decodeCC(self, body): # Client login
|
def decodeCC(self, body): # Client login
|
||||||
log.msg("CC: %s" % str(body))
|
log.msg("CC: %s" % str(body))
|
||||||
self._authOnly()
|
self._authOnly()
|
||||||
self.manager.clientLogin(FRNUser(**body)).addCallback(
|
self.manager.clientLogin(self.serverInfo, FRNUser(**body)).addCallback(
|
||||||
self.sendLine)
|
self.sendLine)
|
||||||
|
|
||||||
def decodeCD(self, body): # Client logout
|
def decodeCD(self, body): # Client logout
|
||||||
log.msg("CD: %s" % str(body))
|
log.msg("CD: %s" % str(body))
|
||||||
self._authOnly()
|
self._authOnly()
|
||||||
self.manager.clientLogout(FRNUser(**body)).addCallback(
|
self.manager.clientLogout(self.serverInfo, FRNUser(**body)).addCallback(
|
||||||
self.sendLine)
|
self.sendLine)
|
||||||
|
|
||||||
def decodeIG(self, body): # Account creation
|
def decodeIG(self, body): # Account creation
|
||||||
|
|
|
@ -32,20 +32,19 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
|
|
||||||
def connectionLost(self, reason):
|
def connectionLost(self, reason):
|
||||||
log.msg("Client disconnected: %s" % self.clientAddress.host)
|
log.msg("Client disconnected: %s" % self.clientAddress.host)
|
||||||
self.stopPinging()
|
self.disconnect()
|
||||||
if self.user is not None:
|
|
||||||
if self.user.ID:
|
|
||||||
log.msg("Logging out client %s" % self.user.ID)
|
|
||||||
self.factory.manager.clientLogout(self.user)
|
|
||||||
self.factory.tracker.logout(self)
|
|
||||||
BufferingLineReceiver.connectionLost(self, reason)
|
BufferingLineReceiver.connectionLost(self, reason)
|
||||||
|
|
||||||
|
def timeoutConnection(self):
|
||||||
|
log.msg("Client dead: disconnecting %s" % self.user)
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
def lineReceived(self, line):
|
def lineReceived(self, line):
|
||||||
self.resetTimeout()
|
self.resetTimeout()
|
||||||
sline = line.strip()
|
sline = line.strip()
|
||||||
if self.waitingKey:
|
if self.waitingKey:
|
||||||
if responseToChallange(self.kp) != sline:
|
if responseToChallange(self.kp) != sline:
|
||||||
self.transport.loseConnection()
|
self.disconnect()
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.waitingKey = False
|
self.waitingKey = False
|
||||||
|
@ -59,7 +58,7 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
self.sendAccessFlags(ac,tx)
|
self.sendAccessFlags(ac,tx)
|
||||||
self.sendAccessList(self.factory.tracker.getAcl(self.user.NT))
|
self.sendAccessList(self.factory.tracker.getAcl(self.user.NT))
|
||||||
if self.role not in ['OK', 'ADMIN', 'OWNER']:
|
if self.role not in ['OK', 'ADMIN', 'OWNER']:
|
||||||
self.transport.loseConnection()
|
self.disconnect()
|
||||||
return
|
return
|
||||||
self.startPinging()
|
self.startPinging()
|
||||||
self.setTimeout(10.0)
|
self.setTimeout(10.0)
|
||||||
|
@ -72,7 +71,7 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
else:
|
else:
|
||||||
command, body = sline.split(':', 1)
|
command, body = sline.split(':', 1)
|
||||||
if command != 'CT' and self.user is None:
|
if command != 'CT' and self.user is None:
|
||||||
self.transport.loseConnection()
|
self.disconnect()
|
||||||
return
|
return
|
||||||
handler = getattr(self, 'decode'+command, None)
|
handler = getattr(self, 'decode'+command, None)
|
||||||
if body[0] == '<' and body[-1] == '>':
|
if body[0] == '<' and body[-1] == '>':
|
||||||
|
@ -110,6 +109,11 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
return succeed(("BLOCK", ""))
|
return succeed(("BLOCK", ""))
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
|
self.stopPinging()
|
||||||
|
if self.user is not None:
|
||||||
|
log.msg("Logging out client %s" % self.user)
|
||||||
|
self.factory.manager.clientLogout(self.user)
|
||||||
|
self.factory.tracker.logout(self)
|
||||||
self.transport.loseConnection()
|
self.transport.loseConnection()
|
||||||
|
|
||||||
def decodeCT(self, body):
|
def decodeCT(self, body):
|
||||||
|
@ -135,7 +139,7 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
self.sendLine(
|
self.sendLine(
|
||||||
self.factory.serverAuth.asXML('MT','SV','AL','BN','BP','KP'))
|
self.factory.serverAuth.asXML('MT','SV','AL','BN','BP','KP'))
|
||||||
if self.role not in ['OK', 'OWNER', 'ADMIN']:
|
if self.role not in ['OK', 'OWNER', 'ADMIN']:
|
||||||
self.transport.loseConnection()
|
self.disconnect()
|
||||||
else:
|
else:
|
||||||
self.sendNetworkList(self.factory.tracker.getNetworkList())
|
self.sendNetworkList(self.factory.tracker.getNetworkList())
|
||||||
self.transport.setTcpNoDelay(True)
|
self.transport.setTcpNoDelay(True)
|
||||||
|
@ -307,14 +311,14 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
log.msg("Sending ACL to %s: %s" % (self.user.ON, str(clients)))
|
log.msg("Sending ACL to %s: %s" % (self.user.ON, str(clients)))
|
||||||
self.transport.write(chr(7))
|
self.transport.write(chr(7))
|
||||||
self.sendLine(str(len(clients)))
|
self.sendLine(str(len(clients)))
|
||||||
for c in clients: # FIXME
|
for c in clients:
|
||||||
self.sendLine(c.asXML('AI','NN','CT','BC','ON','ID'))
|
self.sendLine(c.asXML('AI','NN','CT','BC','ON','ID'))
|
||||||
|
|
||||||
def sendAccessFlags(self, access, talk):
|
def sendAccessFlags(self, access, talk):
|
||||||
log.msg("Sending ACL flags to %s: %s" % (self.user.ON, str((access, talk))))
|
log.msg("Sending ACL flags to %s: %s" % (self.user.ON, str((access, talk))))
|
||||||
FV = {True: '1', False: 'o'}
|
FV = {True: '1', False: 'o'}
|
||||||
self.transport.write(chr(10))
|
self.transport.write(chr(10))
|
||||||
self.sendLine('2') # TODO
|
self.sendLine('2')
|
||||||
self.sendLine(FV[access])
|
self.sendLine(FV[access])
|
||||||
self.sendLine(FV[talk])
|
self.sendLine(FV[talk])
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
|
||||||
# See LICENSE.txt for copyright info
|
|
||||||
|
|
||||||
class FRNUserNotFound(StandardError): pass
|
|
||||||
|
|
||||||
|
|
||||||
# vim: set et ai sw=4 ts=4 sts=4:
|
|
|
@ -1,84 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
|
||||||
# See LICENSE.txt for copyright info
|
|
||||||
|
|
||||||
from twisted.python import log
|
|
||||||
from twisted.enterprise.adbapi import safe
|
|
||||||
from frn.userstore import FRNUserNotFound
|
|
||||||
from frn.user import FRNUser
|
|
||||||
|
|
||||||
|
|
||||||
def _asDict(curs, *args, **kw):
|
|
||||||
log.msg("Running query %s %s" % (str(args), str(kw)))
|
|
||||||
curs.execute(*args, **kw)
|
|
||||||
result = curs.fetchall()
|
|
||||||
columns = [d[0] for d in curs.description]
|
|
||||||
d = [dict(zip(columns, r)) for r in result]
|
|
||||||
log.msg("Query returned: %s" % str(d))
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
def _returnId(curs, *args, **kw):
|
|
||||||
log.msg("Running query %s %s" % (str(args), str(kw)))
|
|
||||||
curs.execute(*args, **kw)
|
|
||||||
rowId = curs.lastrowid
|
|
||||||
log.msg("Query returned: %s" % str(rowId))
|
|
||||||
return rowId
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseUserStore(object):
|
|
||||||
|
|
||||||
def __init__(self, pool):
|
|
||||||
self._pool = pool
|
|
||||||
|
|
||||||
def _query(self, *args, **kw):
|
|
||||||
return self._pool.runInteraction(_asDict, *args, **kw)
|
|
||||||
|
|
||||||
def getByName(self, name, email):
|
|
||||||
try:
|
|
||||||
return self._query("""
|
|
||||||
SELECT * FROM frn_users
|
|
||||||
WHERE "on"=? AND "ea"=?""",
|
|
||||||
(name, email)).addCallback(
|
|
||||||
lambda x: FRNUser(**x[0]))
|
|
||||||
except IndexError:
|
|
||||||
raise FRNUserNotFound
|
|
||||||
|
|
||||||
def getById(self, userId):
|
|
||||||
return self._query("""
|
|
||||||
SELECT * FROM frn_users
|
|
||||||
WHERE "id"=?""",
|
|
||||||
(int(userId), )).addCallback(
|
|
||||||
lambda x: FRNUser(x[0]))
|
|
||||||
|
|
||||||
def update(self, userId, **kw):
|
|
||||||
assignments = ','.join(["\"%s\"='%s'" % (k,safe(v))
|
|
||||||
for k,v in kw.items()])
|
|
||||||
op = "UPDATE frn_users SET "+assignments+" WHERE \"id\"=?"
|
|
||||||
self._pool.runOperation(op, (int(userId),))
|
|
||||||
|
|
||||||
def create(self, user):
|
|
||||||
return self._query(
|
|
||||||
"""INSERT INTO frn_users ("on","ea") VALUES (?,?)""",
|
|
||||||
(user.ON, user.EA)).addCallback(lambda x: "%015s" % x)
|
|
||||||
|
|
||||||
def list(self):
|
|
||||||
return self._query("SELECT * FROM frn_users").addCallback(
|
|
||||||
lambda x: [FRNUser(y) for y in x])
|
|
||||||
|
|
||||||
def login(self, user):
|
|
||||||
def gotUser(u):
|
|
||||||
log.msg("Got user %s" % u.ID)
|
|
||||||
if u.PW == user.PW:
|
|
||||||
return u.ID
|
|
||||||
return "WRONG"
|
|
||||||
log.msg("Authenticating %s (%s)" % (user.ON, user.EA))
|
|
||||||
return self.getByName(user.ON, user.EA).addCallbacks(
|
|
||||||
gotUser, lambda x: "WRONG")
|
|
||||||
|
|
||||||
def logout(self, userId):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# vim: set et ai sw=4 ts=4 sts=4:
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
||||||
# See LICENSE.txt for copyright info
|
# See LICENSE.txt for copyright info
|
||||||
|
|
||||||
from HTMLParser import HTMLParser
|
import re
|
||||||
from random import choice
|
from random import choice
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,45 +19,10 @@ def makeRandomChallange():
|
||||||
return ''.join([choice('0123456789') for i in range(6)])
|
return ''.join([choice('0123456789') for i in range(6)])
|
||||||
|
|
||||||
|
|
||||||
class SimpleXMLParser(HTMLParser):
|
re_tag = re.compile(r"<([A-Z]{2})>(.*)</\1>")
|
||||||
"""Dirty FRN-specific hack to handle bogus one-level nesting only
|
|
||||||
XML-like syntax"""
|
|
||||||
|
|
||||||
def handle_starttag(self, tag, attrs):
|
|
||||||
if not hasattr(self, 'fields'):
|
|
||||||
self.fields = {}
|
|
||||||
self.next_field = None
|
|
||||||
self.next_data = ''
|
|
||||||
if self.next_field is None:
|
|
||||||
self.next_field = tag
|
|
||||||
self.next_data = ''
|
|
||||||
else:
|
|
||||||
if attrs:
|
|
||||||
a = ' '+' '.join(['%s="%s"' % (k,v) for k,v in attrs])
|
|
||||||
else:
|
|
||||||
a = ''
|
|
||||||
self.next_data += "<%s%s>" % (tag,a)
|
|
||||||
|
|
||||||
def handle_data(self, data):
|
|
||||||
if self.next_field is not None:
|
|
||||||
self.next_data += data
|
|
||||||
|
|
||||||
def handle_endtag(self, tag):
|
|
||||||
if tag == self.next_field:
|
|
||||||
self.fields[self.next_field] = self.next_data
|
|
||||||
self.next_field = None
|
|
||||||
self.next_data = ''
|
|
||||||
else:
|
|
||||||
self.next_data += "</%s>" % tag
|
|
||||||
|
|
||||||
def get_fields(self):
|
|
||||||
return self.fields
|
|
||||||
|
|
||||||
|
|
||||||
def parseSimpleXML(xml):
|
def parseSimpleXML(xml):
|
||||||
p = SimpleXMLParser()
|
return dict(re_tag.findall(xml))
|
||||||
p.feed(xml)
|
|
||||||
return p.get_fields()
|
|
||||||
|
|
||||||
|
|
||||||
def formatSimpleXML(elements):
|
def formatSimpleXML(elements):
|
||||||
|
|
20
manager.py
20
manager.py
|
@ -9,6 +9,7 @@ from frn.protocol.manager import FRNManagerServer, FRNManagerServerFactory
|
||||||
from twisted.enterprise.adbapi import ConnectionPool
|
from twisted.enterprise.adbapi import ConnectionPool
|
||||||
from frn.manager.dummy import DummyManager
|
from frn.manager.dummy import DummyManager
|
||||||
from frn.manager.remote import RemoteManager
|
from frn.manager.remote import RemoteManager
|
||||||
|
from frn.manager.database import DatabaseManager
|
||||||
from frn.user import FRNUser
|
from frn.user import FRNUser
|
||||||
from twisted.python import log
|
from twisted.python import log
|
||||||
|
|
||||||
|
@ -17,16 +18,21 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
log.startLogging(sys.stderr)
|
log.startLogging(sys.stderr)
|
||||||
|
|
||||||
def standardManagerFactory():
|
def dummyManagerFactory():
|
||||||
log.msg("Building Manager")
|
log.msg("Building DummyManager")
|
||||||
|
return DummyManager()
|
||||||
|
|
||||||
|
def remoteManagerFactory():
|
||||||
|
log.msg("Building RemoteManager")
|
||||||
return RemoteManager(reactor)
|
return RemoteManager(reactor)
|
||||||
|
|
||||||
|
def databaseManagerFactory():
|
||||||
|
log.msg("Building DatabaseManager")
|
||||||
|
return DatabaseManager(
|
||||||
|
ConnectionPool("sqlite3", "/tmp/frnmanager.sqlite3", cp_noisy=True))
|
||||||
|
|
||||||
reactor.listenTCP(10025, FRNManagerServerFactory(
|
reactor.listenTCP(10025, FRNManagerServerFactory(
|
||||||
# DatabaseUserStore(
|
databaseManagerFactory
|
||||||
# ConnectionPool("sqlite3", "frn_users.sqlite3",
|
|
||||||
# check_same_thread=False)),
|
|
||||||
# DummyManager()
|
|
||||||
standardManagerFactory
|
|
||||||
))
|
))
|
||||||
reactor.run()
|
reactor.run()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue