3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-01 01:09:22 +01:00

Attempt to make sender validation in protocols a bit less repetitive

This commit is contained in:
James Lu 2016-04-29 23:30:49 -07:00
parent 05752d9f60
commit 7003ff848d
2 changed files with 43 additions and 17 deletions

View File

@ -907,6 +907,38 @@ class Protocol():
target = self.irc.nickToUid(target) or target target = self.irc.nickToUid(target) or target
return target return target
def checkSender(check):
"""
Helper function for protocols which validates that the sender given is
an internal client or server.
Check is given as a string, where 's' refers to server,
'c' refers to client, and 'cs' refers to either server or client."""
# We have to actually wrap this twice, to past checkSender('string')
# arguments to the actual function that performs checks. Gross.
def checkSender_get_check(func):
def checkSender_wrapper(self, sender, *args, **kwargs):
# 1) Perform checks.
isclient = self.irc.isInternalClient(sender)
isserver = self.irc.isInternalServer(sender)
log.debug('checkServer: query is %s, target is %s', check, sender)
log.debug('checkServer: isclient: %s, isserver: %s', isclient, isserver)
if check == 'cs':
if not (isclient or isserver):
raise LookupError('No such PyLink client/server exists.')
elif check == 'c':
if not isclient:
raise LookupError('No such PyLink client exists.')
elif check == 's':
if not isserver:
raise LookupError('No such PyLink server exists.')
# 2) Call and return the data of the original function.
return func(self, sender, *args, **kwargs)
return checkSender_wrapper
return checkSender_get_check
### FakeIRC classes, used for test cases ### FakeIRC classes, used for test cases
class FakeIRC(Irc): class FakeIRC(Irc):

View File

@ -71,16 +71,15 @@ class InspIRCdProtocol(TS6BaseProtocol):
self._operUp(uid, opertype) self._operUp(uid, opertype)
return u return u
@checkSender('c')
def join(self, client, channel): def join(self, client, channel):
"""Joins a PyLink client to a channel.""" """Joins a PyLink client to a channel."""
# InspIRCd doesn't distinguish between burst joins and regular joins, # InspIRCd doesn't distinguish between burst joins and regular joins,
# so what we're actually doing here is sending FJOIN from the server, # so what we're actually doing here is sending FJOIN from the server,
# on behalf of the clients that are joining. # on behalf of the clients that are joining.
channel = utils.toLower(self.irc, channel) channel = utils.toLower(self.irc, channel)
server = self.irc.isInternalClient(client) server = self.irc.getServer(client)
if not server:
log.error('(%s) Error trying to join %r to %r (no such client exists)', self.irc.name, client, channel)
raise LookupError('No such PyLink client exists.')
# Strip out list-modes, they shouldn't be ever sent in FJOIN. # Strip out list-modes, they shouldn't be ever sent in FJOIN.
modes = [m for m in self.irc.channels[channel].modes if m[0] not in self.irc.cmodes['*A']] modes = [m for m in self.irc.channels[channel].modes if m[0] not in self.irc.cmodes['*A']]
self._send(server, "FJOIN {channel} {ts} {modes} :,{uid}".format( self._send(server, "FJOIN {channel} {ts} {modes} :,{uid}".format(
@ -89,6 +88,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
self.irc.channels[channel].users.add(client) self.irc.channels[channel].users.add(client)
self.irc.users[client].channels.add(channel) self.irc.users[client].channels.add(channel)
@checkSender('s')
def sjoin(self, server, channel, users, ts=None): def sjoin(self, server, channel, users, ts=None):
"""Sends an SJOIN for a group of users to a channel. """Sends an SJOIN for a group of users to a channel.
@ -104,8 +104,6 @@ class InspIRCdProtocol(TS6BaseProtocol):
server = server or self.irc.sid server = server or self.irc.sid
assert users, "sjoin: No users sent?" assert users, "sjoin: No users sent?"
log.debug('(%s) sjoin: got %r for users', self.irc.name, users) log.debug('(%s) sjoin: got %r for users', self.irc.name, users)
if not server:
raise LookupError('No such PyLink client exists.')
orig_ts = self.irc.channels[channel].ts orig_ts = self.irc.channels[channel].ts
ts = ts or orig_ts ts = ts or orig_ts
@ -163,15 +161,12 @@ class InspIRCdProtocol(TS6BaseProtocol):
userobj.opertype = otype userobj.opertype = otype
self._send(target, 'OPERTYPE %s' % otype.replace(" ", "_")) self._send(target, 'OPERTYPE %s' % otype.replace(" ", "_"))
@checkSender('cs')
def mode(self, numeric, target, modes, ts=None): def mode(self, numeric, target, modes, ts=None):
"""Sends mode changes from a PyLink client/server.""" """Sends mode changes from a PyLink client/server."""
# -> :9PYAAAAAA FMODE #pylink 1433653951 +os 9PYAAAAAA # -> :9PYAAAAAA FMODE #pylink 1433653951 +os 9PYAAAAAA
# -> :9PYAAAAAA MODE 9PYAAAAAA -i+w # -> :9PYAAAAAA MODE 9PYAAAAAA -i+w
if (not self.irc.isInternalClient(numeric)) and \
(not self.irc.isInternalServer(numeric)):
raise LookupError('No such PyLink client/server exists.')
log.debug('(%s) inspircd._sendModes: received %r for mode list', self.irc.name, modes) log.debug('(%s) inspircd._sendModes: received %r for mode list', self.irc.name, modes)
if ('+o', None) in modes and not utils.isChannel(target): if ('+o', None) in modes and not utils.isChannel(target):
# https://github.com/inspircd/inspircd/blob/master/src/modules/m_spanningtree/opertype.cpp#L26-L28 # https://github.com/inspircd/inspircd/blob/master/src/modules/m_spanningtree/opertype.cpp#L26-L28
@ -185,12 +180,9 @@ class InspIRCdProtocol(TS6BaseProtocol):
else: else:
self._send(numeric, 'MODE %s %s' % (target, joinedmodes)) self._send(numeric, 'MODE %s %s' % (target, joinedmodes))
@checkSender('cs')
def kill(self, numeric, target, reason): def kill(self, numeric, target, reason):
"""Sends a kill from a PyLink client/server.""" """Sends a kill from a PyLink client/server."""
if (not self.irc.isInternalClient(numeric)) and \
(not self.irc.isInternalServer(numeric)):
raise LookupError('No such PyLink client/server exists.')
# InspIRCd will show the raw kill message sent from our server as the quit message. # InspIRCd will show the raw kill message sent from our server as the quit message.
# So, make the kill look actually like a kill instead of someone quitting with # So, make the kill look actually like a kill instead of someone quitting with
# an arbitrary message. # an arbitrary message.
@ -207,22 +199,23 @@ class InspIRCdProtocol(TS6BaseProtocol):
if self.irc.isInternalClient(target): if self.irc.isInternalClient(target):
self.removeClient(target) self.removeClient(target)
@checkSender('s')
def topicBurst(self, numeric, target, text): def topicBurst(self, numeric, target, text):
"""Sends a topic change from a PyLink server. This is usually used on burst.""" """Sends a topic change from a PyLink server. This is usually used on burst."""
if not self.irc.isInternalServer(numeric):
raise LookupError('No such PyLink server exists.')
ts = int(time.time()) ts = int(time.time())
servername = self.irc.servers[numeric].name servername = self.irc.servers[numeric].name
self._send(numeric, 'FTOPIC %s %s %s :%s' % (target, ts, servername, text)) self._send(numeric, 'FTOPIC %s %s %s :%s' % (target, ts, servername, text))
self.irc.channels[target].topic = text self.irc.channels[target].topic = text
self.irc.channels[target].topicset = True self.irc.channels[target].topicset = True
@checkSender('c')
def invite(self, numeric, target, channel): def invite(self, numeric, target, channel):
"""Sends an INVITE from a PyLink client..""" """Sends an INVITE from a PyLink client.."""
if not self.irc.isInternalClient(numeric): if not self.irc.isInternalClient(numeric):
raise LookupError('No such PyLink client exists.') raise LookupError('No such PyLink client exists.')
self._send(numeric, 'INVITE %s %s' % (target, channel)) self._send(numeric, 'INVITE %s %s' % (target, channel))
@checkSender('c')
def knock(self, numeric, target, text): def knock(self, numeric, target, text):
"""Sends a KNOCK from a PyLink client.""" """Sends a KNOCK from a PyLink client."""
if not self.irc.isInternalClient(numeric): if not self.irc.isInternalClient(numeric):
@ -284,7 +277,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
"protocol module. WHOIS requests are handled " "protocol module. WHOIS requests are handled "
"locally by InspIRCd servers, so there is no " "locally by InspIRCd servers, so there is no "
"need for PyLink to send numerics directly yet.") "need for PyLink to send numerics directly yet.")
@checkSender('c')
def away(self, source, text): def away(self, source, text):
"""Sends an AWAY message from a PyLink client. <text> can be an empty string """Sends an AWAY message from a PyLink client. <text> can be an empty string
to unset AWAY status.""" to unset AWAY status."""
@ -334,6 +327,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
endburstf() endburstf()
return sid return sid
@checkSender('cs')
def squit(self, source, target, text='No reason given'): def squit(self, source, target, text='No reason given'):
"""SQUITs a PyLink server.""" """SQUITs a PyLink server."""
# -> :9PY SQUIT 9PZ :blah, blah # -> :9PY SQUIT 9PZ :blah, blah