Server: Add ACL support
This commit is contained in:
parent
0ce6e39b10
commit
a7b1e6ab25
|
@ -5,6 +5,7 @@
|
|||
|
||||
import shelve
|
||||
from twisted.python import log
|
||||
from frn.user import FRNUser
|
||||
|
||||
CLIENTS_ORDER = ['Crosslink', 'Parrot', 'Gateway', 'PC Only']
|
||||
|
||||
|
@ -39,6 +40,7 @@ class ClientTracker(object):
|
|||
self._mute = {}
|
||||
self._block = {}
|
||||
self._admin = {}
|
||||
self._acl = {}
|
||||
self.cbClient = cbClient
|
||||
self.cbNet = cbNet
|
||||
self.cbMute = cbMute
|
||||
|
@ -53,6 +55,7 @@ class ClientTracker(object):
|
|||
self._mute = s['mute']
|
||||
self._block = s['block']
|
||||
self._admin = s['admin']
|
||||
self._acl = s['acl']
|
||||
except KeyError: pass
|
||||
s.close()
|
||||
|
||||
|
@ -61,6 +64,7 @@ class ClientTracker(object):
|
|||
s['mute'] = self._mute
|
||||
s['block'] = self._block
|
||||
s['admin'] = self._admin
|
||||
s['acl'] = self._acl
|
||||
s.close()
|
||||
|
||||
def isLoggedIn(self, clientId):
|
||||
|
@ -78,7 +82,7 @@ class ClientTracker(object):
|
|||
return l.index(clientId)+1
|
||||
|
||||
def getNetworkList(self):
|
||||
return self._net.keys()
|
||||
return sorted(set(self._net.keys())|set(self._acl.keys()))
|
||||
|
||||
def getClientList(self, network=[]):
|
||||
if network:
|
||||
|
@ -113,6 +117,9 @@ class ClientTracker(object):
|
|||
def login(self, client, status=0):
|
||||
clientId = client.user.ID
|
||||
if clientId not in self._clientData:
|
||||
if not self.aclTalkOk(client.user.NT, client.user.EA) and status < 1:
|
||||
client.user.S = 1
|
||||
else:
|
||||
client.user.S = status
|
||||
self._clientData[clientId] = client
|
||||
net = client.user.NT
|
||||
|
@ -133,7 +140,7 @@ class ClientTracker(object):
|
|||
self._mute[clientId].AI = a
|
||||
else:
|
||||
client.user.M = 0
|
||||
if clientId in self._block:
|
||||
if not self.canLogin(client.user):
|
||||
client.role = "BLOCK"
|
||||
if client.user.EA in self._admin:
|
||||
client.role = "ADMIN"
|
||||
|
@ -159,11 +166,13 @@ class ClientTracker(object):
|
|||
self.cbClient(net, self.getClientList(net))
|
||||
|
||||
def setStatus(self, clientId, status):
|
||||
oldStatus = self._clientData[clientId].user.S
|
||||
user = self.getClient(clientId)
|
||||
oldStatus = user.S
|
||||
if not self.aclTalkOk(user.NT, user.EA) and status < 1:
|
||||
status = 1
|
||||
if oldStatus != str(status):
|
||||
net = self._clientData[clientId].user.NT
|
||||
self._clientData[clientId].user.S = status
|
||||
self.cbClient(net, self.getClientList(net))
|
||||
self.cbClient(user.NT, self.getClientList(user.NT))
|
||||
|
||||
def mute(self, admin, clientId):
|
||||
if clientId not in self._mute:
|
||||
|
@ -210,5 +219,81 @@ class ClientTracker(object):
|
|||
self.save()
|
||||
self.cbAdmin(self.getAdminList())
|
||||
|
||||
def _getAcl(self, network):
|
||||
return self._acl.get(network, (False, False, {}))
|
||||
|
||||
def _setAcl(self, network, ac, tx, l):
|
||||
log.msg("Changing ACL for %s" % network)
|
||||
if ac == tx == False and len(l) == 0:
|
||||
log.msg("Default settings detected")
|
||||
if network in self._acl:
|
||||
log.msg("Deleting")
|
||||
del self._acl[network]
|
||||
else:
|
||||
log.msg("Setting ACL for %s to %s" % (network, str((ac,tx,l))))
|
||||
self._acl[network] = (ac, tx, l)
|
||||
self.save()
|
||||
|
||||
def getAcl(self, network):
|
||||
ac, tx, l = self._getAcl(network)
|
||||
return l.values()
|
||||
|
||||
def getAclFlags(self, network):
|
||||
ac, tx, l = self._getAcl(network)
|
||||
return (ac, tx)
|
||||
|
||||
def setAclFlags(self, network, ac, tx):
|
||||
oac, otx, l = self._getAcl(network)
|
||||
self._setAcl(network, ac, tx, l)
|
||||
|
||||
def addAcl(self, network, email):
|
||||
log.msg("Adding %s to ACL for %s" % (email, network))
|
||||
ac, tx, l = self._getAcl(network)
|
||||
if email not in l:
|
||||
knownUsers = dict([(x.user.EA, x.user) for x in self._clientData.values() + self._mute.values() + self._block.values()])
|
||||
user = knownUsers.get(email, FRNUser(EA=email)).copy(ID=email, AI=1)
|
||||
l[email] = user
|
||||
self._setAcl(network, ac, tx, l)
|
||||
|
||||
def delAcl(self, network, email):
|
||||
log.msg("Removing %s from ACL for %s" % (email, network))
|
||||
ac, tx, l = self._getAcl(network)
|
||||
if email in l:
|
||||
del l[email]
|
||||
self._setAcl(network, ac, tx, l)
|
||||
|
||||
def setAclTx(self, network, email, tx):
|
||||
oac, otx, l = self._getAcl(network)
|
||||
if email in l:
|
||||
if tx:
|
||||
l[email].AI = 0
|
||||
else:
|
||||
l[email].AI = 1
|
||||
self._setAcl(network, oac, otx, l)
|
||||
|
||||
def aclLoginOk(self, network, email):
|
||||
ac, tx, l = self._getAcl(network)
|
||||
if not ac:
|
||||
return True
|
||||
return email in l
|
||||
|
||||
def aclTalkOk(self, network, email):
|
||||
ac, tx, l = self._getAcl(network)
|
||||
if not tx:
|
||||
return True
|
||||
if email not in l:
|
||||
return False
|
||||
return l[email].AI == '0'
|
||||
|
||||
def canLogin(self, user):
|
||||
if self.isBlocked(user.ID):
|
||||
return False
|
||||
return self.aclLoginOk(user.NT, user.EA)
|
||||
|
||||
def canTalk(self, clientId):
|
||||
if self.isMute(clientId):
|
||||
return False
|
||||
u = self.getClient(clientId)
|
||||
return self.aclTalkOk(u.NT, u.EA)
|
||||
|
||||
# vim: set et ai sw=4 ts=4 sts=4:
|
||||
|
|
|
@ -55,8 +55,12 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
|||
self.sendBlockList(self.factory.tracker.getBlockList())
|
||||
if self.role == 'OWNER':
|
||||
self.sendAdminList(self.factory.tracker.getAdminList())
|
||||
self.sendAccessFlags(None)
|
||||
self.sendAccessList([])
|
||||
ac, tx = self.factory.tracker.getAclFlags(self.user.NT)
|
||||
self.sendAccessFlags(ac,tx)
|
||||
self.sendAccessList(self.factory.tracker.getAcl(self.user.NT))
|
||||
if self.role not in ['OK', 'ADMIN', 'OWNER']:
|
||||
self.transport.loseConnection()
|
||||
return
|
||||
self.startPinging()
|
||||
self.setTimeout(10.0)
|
||||
return
|
||||
|
@ -113,8 +117,10 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
|||
if self.role == 'OK':
|
||||
if self.user.EA == self.factory.serverAuth.OW:
|
||||
self.role = 'OWNER'
|
||||
log.msg("%s promoted to OWNER" % clientId)
|
||||
elif self.factory.tracker.isAdmin(self.user.ID):
|
||||
self.role = 'ADMIN'
|
||||
log.msg("%s promoted to ADMIN" % clientId)
|
||||
if versions.server > 2009004:
|
||||
self.waitingKey = True
|
||||
self.sendLine(str(versions.client))
|
||||
|
@ -201,9 +207,53 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
|||
if self.role == "OWNER":
|
||||
self.factory.tracker.unAdmin(body['ip'])
|
||||
|
||||
def decodeETX(self, body):
|
||||
log.msg("decodeETX(%s)" % str(body))
|
||||
if self.role == "OWNER":
|
||||
self.factory.tracker.setAclTx(self.user.NT, body['ea'], True)
|
||||
self.sendAccessList(self.factory.tracker.getAcl(self.user.NT))
|
||||
|
||||
def decodeRTX(self, body):
|
||||
log.msg("decodeRTX(%s)" % str(body))
|
||||
if self.role == "OWNER":
|
||||
self.factory.tracker.setAclTx(self.user.NT, body['ea'], False)
|
||||
self.sendAccessList(self.factory.tracker.getAcl(self.user.NT))
|
||||
|
||||
def decodeDT(self, body):
|
||||
log.msg("decodeDT(%s)" % str(body))
|
||||
if self.role == "OWNER":
|
||||
self.factory.tracker.delAcl(self.user.NT, body['ea'])
|
||||
self.sendAccessList(self.factory.tracker.getAcl(self.user.NT))
|
||||
|
||||
def decodeAT(self, body):
|
||||
log.msg("decodeAT(%s)" % str(body))
|
||||
if self.role == "OWNER":
|
||||
self.factory.tracker.addAcl(self.user.NT, body['ea'])
|
||||
self.sendAccessList(self.factory.tracker.getAcl(self.user.NT))
|
||||
|
||||
def decodeTXR(self, body):
|
||||
log.msg("decodeTXR(%s)" % str(body))
|
||||
if self.role == "OWNER":
|
||||
en, _ = self.factory.tracker.getAclFlags(self.user.NT)
|
||||
tx = body == '1'
|
||||
self.factory.tracker.setAclFlags(self.user.NT, en, tx)
|
||||
en,tx = self.factory.tracker.getAclFlags(self.user.NT)
|
||||
self.sendAccessFlags(en, tx)
|
||||
self.sendAccessList(self.factory.tracker.getAcl(self.user.NT))
|
||||
|
||||
def decodeENA(self, body):
|
||||
log.msg("decodeENA(%s)" % str(body))
|
||||
if self.role == "OWNER":
|
||||
_, tx = self.factory.tracker.getAclFlags(self.user.NT)
|
||||
en = body == '1'
|
||||
self.factory.tracker.setAclFlags(self.user.NT, en, tx)
|
||||
en,tx = self.factory.tracker.getAclFlags(self.user.NT)
|
||||
self.sendAccessFlags(en, tx)
|
||||
self.sendAccessList(self.factory.tracker.getAcl(self.user.NT))
|
||||
|
||||
def audioFrameReceived(self, frame):
|
||||
#log.msg("audioFrameReceived")
|
||||
if not self.factory.tracker.isMute(self.user.ID):
|
||||
if self.factory.tracker.canTalk(self.user.ID):
|
||||
clientIdx = self.getIndex()
|
||||
for c in self.factory.tracker.getClientList(self.user.NT):
|
||||
if int(c.S) < 2 and c.ID != self.user.ID:
|
||||
|
@ -250,16 +300,19 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
|||
self.sendLine(c.asXML('NN','CT','BC','ON','ID'))
|
||||
|
||||
def sendAccessList(self, clients):
|
||||
log.msg("Sending ACL to %s: %s" % (self.user.ON, str(clients)))
|
||||
self.transport.write(chr(7))
|
||||
self.sendLine(str(len(clients)))
|
||||
for c in clients: # FIXME
|
||||
self.sendLine(c.asXML('AI','NN','CT','BC','ON','ID'))
|
||||
|
||||
def sendAccessFlags(self, flags):
|
||||
def sendAccessFlags(self, access, talk):
|
||||
log.msg("Sending ACL flags to %s: %s" % (self.user.ON, str((access, talk))))
|
||||
FV = {True: '1', False: 'o'}
|
||||
self.transport.write(chr(10))
|
||||
self.sendLine('2') # TODO
|
||||
self.sendLine('o')
|
||||
self.sendLine('o')
|
||||
self.sendLine(FV[access])
|
||||
self.sendLine(FV[talk])
|
||||
|
||||
def sendTextMessage(self, clientId, message, target):
|
||||
self.transport.write(chr(4))
|
||||
|
|
|
@ -35,7 +35,7 @@ class FRNUser(object):
|
|||
self._fields[field.lower()] = str(value)
|
||||
|
||||
def get(self, field, default=''):
|
||||
return self._fields[field.lower()]
|
||||
return self._fields.get(field.lower(),'')
|
||||
|
||||
def items(self, *fields):
|
||||
if len(fields) == 0:
|
||||
|
|
Loading…
Reference in New Issue