예제 #1
0
class Client(Protocol):
    '''ssl client implementation.'''

    def __init__(self, uid, port):
        super(Client, self).__init__('client')
        
        self.uid = uid
        self.port = port
        
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.conn = SSLIOStream(self.sock, ssl_options={'ca_certs':SERVER_CRT_PATH, 'cert_reqs':ssl.CERT_REQUIRED})
        self.conn.connect(('127.0.0.1', self.port), self.on_connect)
    
    def on_connect(self):
        self.conn.set_close_callback(self.on_close)
        self.pubkey, self.privkey = None, None
        self.init_keys()
        self.write(OP_PUBKEY, self.pubkey)
        # this is hardcoded currently in absence of proper tests
        if self.uid == 2:
            self.send_message(1, 'hello world')
            logger.debug('Client %s: Sending message "Hello World" to user with uid 1' % self.uid)
        self.read_line()
    
    def read_line(self):
        self.conn.read_until(CRLF, self.handle_line)

    def on_close(self):
        self.conn = None
        self.sock = None

    def init_keys(self):
        if os.path.isfile(CLIENT_PUB_PATH % self.uid) and os.path.isfile(CLIENT_PRIV_PATH % self.uid):
            with open(CLIENT_PUB_PATH % self.uid, 'rb') as pubfile, open(CLIENT_PRIV_PATH % self.uid, 'rb') as privfile:
                self.pubkey = pubfile.read().strip()
                self.privkey = privfile.read().strip()
                logger.debug('read existing pub/priv key for uid %s' % self.uid)
        else:
            self.pubkey, self.privkey = self.generate_keys()
            with open(CLIENT_PUB_PATH % self.uid, 'wb') as pubfile, open(CLIENT_PRIV_PATH % self.uid, 'wb') as privfile:
                pubfile.write(self.pubkey)
                privfile.write(self.privkey)
                logger.debug('written pub/priv key for uid %s' % self.uid)

    def write(self, *messages):
        for message in messages:
            self.conn.write('%s%s' % (message, CRLF))

    def send_message(self, uid, message):
        with open(CLIENT_PUB_PATH % uid, 'rb') as pubfile:
            pubkey = pubfile.read()
            # encrypt message using receiver public key
            enc = self.encrypt_message(message, pubkey)
            # sign encrypted message for digital verification
            sig = self.generate_signature(enc[0])
            message = (OP_MESSAGE, pubkey, enc[0], sig[0],)
            self.write(*message)

    @staticmethod
    def generate_keys():
        random_generator = Random.new().read
        priv = RSA.generate(1024, random_generator)
        pub = priv.publickey()
        return (pub.exportKey().strip(), priv.exportKey().strip())

    def generate_signature(self, message):
        '''sign messaging using our priv key'''
        k = RSA.importKey(self.privkey)
        h = MD5.new(message).digest()
        return k.sign(h, '')

    @staticmethod
    def verify_signature(pubkey, signature, message):
        '''verify signature using signing user public key'''
        k = RSA.importKey(pubkey)
        h = MD5.new(message).digest()
        return k.verify(h, signature)

    @staticmethod
    def encrypt_message(message, pubkey):
        '''encrypt message using receiving user public key'''
        k = RSA.importKey(pubkey)
        return k.encrypt(message, 32)

    def decrypt_message(self, enc):
        '''decrypt message using our priv key'''
        k = RSA.importKey(self.privkey)
        return k.decrypt(enc)
예제 #2
0
파일: irc.py 프로젝트: ketralnis/iobot
class IrcConnection(object):
    def __init__(self, bot, server_name, address, port, nick, user,
            realname, owners, channels=None, password=None, ssl=None):
        self.bot = bot
        self.server_name = server_name
        self.owners = owners
        self.address = address
        self.port = port
        self.nick = nick
        self.user = user
        self.password = password
        self.ssl = ssl
        self.realname = realname
        self.initial_channels = set(channels) if channels else set()

        self.logger = getLogger(__name__)

        self._protocol_events = dict()
        self.channels = dict()
        self.users = dict()
        self.init_protocol_events()

    def init_protocol_events(self):
        self._protocol_events = {
            'PRIVMSG' : self.on_privmsg,
            'PING'    : self.on_ping,
            'JOIN'    : self.on_join,
            '401'     : self.on_nochan,
            '001'     : self.on_welcome,
            'KICK'    : self.on_kick,
            'PART'    : self.on_part,
            '353'     : self.on_names,
            'NICK'    : self.on_nick
        }

    def connect(self, reconnecting=False):
        self.logger.debug('CONNECTING...')
        _sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)

        if self.ssl is None:
            self._stream = IOStream(_sock)
        elif self.ssl is True:
            self._stream = SSLIOStream(_sock)
        else:
            self._stream = SSLIOStream(_sock, ssl_options=self.ssl)

        self._stream.connect((self.address, self.port), self._register)

    def _register(self):
        self.logger.debug('CONNECTED')

        if self.password:
            # TODO need to check for error responses
            self.authenticate()

        self.set_nick(self.nick)
        self.write_raw('USER %s 0 * :%s' % (self.user, self.realname))

        self._next()

    def add_channel(self, channel):
        self.channels[channel] = []

    def remove_channel(self, channel):
        del self.channels[channel]

    def add_user(self, channel, user):
        self.channels[channel].append(user)
        self.users[user.nick] = user

    def remove_user(self, channel, user):
        self.channels[channels].remove(user)
        del self.users[user.nick]

    def user_change_nick(self, old_nick, new_nick):
        user = self.users.pop(old_nick)
        user.nick = new_nick
        self.users[new_nick] = user

    def authenticate(self):
        self.logger.debug("Authenticating (%s)", self.password)
        self.write_raw('PASS %s' % self.password)

    def set_nick(self, nick):
        if not nick:
            raise IrcError('Cannot set empty nick')
        self.logger.debug('SETTING NICK {nick: %s}' % nick)
        self.write_raw('NICK %s' % nick)

    def join_channel(self, *channels):
        if not all([c for c in channels]):
            raise IrcError('Empty channel')
        self.logger.debug('JOINING CHANNEL(S): {channels: %s}' % repr(channels))
        chan_def = ','.join(channels)
        self.write_raw('JOIN %s' % chan_def)

    def part_channel(self, *channels):
        if not all([c for c in channels]):
            raise IrcError('Empty channel')
        self.logger.debug('PARTING CHANNEL: {channels: %s}' % repr(channels))
        chan_def = ','.join(channels)
        self.write_raw('PART :%s' % chan_def)

    def private_message(self, destination, message):
        if not message:
            raise IrcError('Cannot send empty message')
        if not destination:
            raise IrcError('Cannot send to empty destination')
        self.logger.debug('SENDING PRIVMSG: {destination: %s, message: %s}' % (destination, message))
        self.write_raw('PRIVMSG %s :%s' % (destination, message))

    def reply(self, event, message):
        if event.destination and event.destination != self.nick:
            destination = event.destination
        else:
            destination = event.nick
        self.private_message(destination, message)

    def reply_with_nick(self, event, message):
        if event.destination:
            message = '%s: %s' % (event.nick, message)
        self.reply(event, message)

    def kick(self, channel, user, comment=None):
        if not channel:
            raise IrcError('Cannot kick from empty channel')
        if not user:
            raise IrcError('Cannot kick empty player')
        self.logger.debug('KICKING {channel: %s, user: %s}' % (channel, user))
        kick_str = 'KICK %s %s' % (channel, user)
        if comment:
            kick_str += ' :%s' % comment
        self.write_raw(kick_str)

    def write_raw(self, line):
        line.replace(EOL, '')
        self.logger.debug('WRITE RAW: {line: %s}' % line)
        self._stream.write(line + EOL)

    def read_raw(self, line):
        self.logger.debug('READ RAW: {line: %s}' % line.replace(EOL, ''))
        event = IrcEvent(self.nick, line)
        self.handle(event)
        self.bot.process_hooks(self, event)
        self.bot.process_plugins(self, event)
        self._next()

    def handle(self, event):
        if event.type in self._protocol_events:
            self._protocol_events[event.type](event)

    def _next(self):
        self._stream.read_until(EOL, self.read_raw)

    def on_welcome(self, event):
        self.logger.debug('RECIEVED RPL_WELCOME')
        if self.initial_channels:
            self.join_channel(*self.initial_channels)

    def on_ping(self, event):
        # One ping only, please
        self.logger.debug('RECIEVED PING')
        self.write_raw("PONG %s\r\n" % event.text)

    def on_privmsg(self, event):
        # :[email protected] PRIVMSG #xx :hi
        self.logger.debug('RECIEVED PRIVMSG {destination: %s,'
                ' message: %s}' % (event.destination, event.text))
        pass

    def on_nick(self, event):
        old_nick = event.nick
        new_nick = event.text
        self.logger.debug('RECIEVED NICK {old_nick: %s, new_nick: %s}' %
                (old_nick, new_nick))
        if event.nick == self.nick:
            self.nick = new_nick
        else:
            self.user_change_nick(old_nick, new_nick)

    def on_join(self, event):
        channel = event.destination
        nick = event.nick
        self.logger.debug('RECIEVED JOIN {channel: %s, nick: %s}' % (channel, nick))
        if self.nick == nick:
            self.add_channel(channel)
        else:
            self.add_user(channel, IrcUser(nick))

    def on_names(self, event):
        nick_chan, nicks_raw = event.parameters_raw.split(':')
        nicks = nicks_raw.split()
        if '@' in nick_chan:
            channel = nick_chan.split('@')[-1].strip()
        elif '=' in nick_chan:
            channel = nick_chan.split('=')[-1].strip()
        else:
            raise Exception
        self.logger.debug('RECIEVED NAMES {channel: %s, nick_count: %d}' % (
            channel, len(nicks)))
        for nr in nicks:
            if nr[0] == '@':
                nick = nr[1:]
            elif nr[0] == '+':
                nick = nr[1:]
            else:
                nick = nr
            user = IrcUser(nick)
            self.add_user(channel, user)

    def on_nochan(self, event):
        channel = event.parameters[0]
        self.logger.debug('RECIEVED ERR_NOSUCHCHANNEL {channel: %s}' % channel)
        # :senor.crunchybueno.com 401 nodnc  #xx :No such nick/channel
        self.remove_channel(channel)

    def on_part(self, event):
        nick = event.nick
        channel = event.destination
        self.logger.debug('RECIEVED PART {channel: %s, nick: %s}' % (channel,
            nick))
        if event.nick == self.nick:
            self.logger.debug('IOBot parted from %s' % channel)
            self.remove_channel(channel)

    def on_kick(self, event):
        nick = event.parameters[0]
        channel = event.destination
        self.logger.debug('RECIEVED KICK {channel: %s, nick: %s}' % (channel,
            nick))
        if event.parameters[0] == self.nick:
            self.logger.warning('IOBot was KICKed from %s' % channel)
            self.remove_channel(channel)
예제 #3
0
class Client(Protocol):
    '''ssl client implementation.'''
    def __init__(self, uid, port):
        super(Client, self).__init__('client')

        self.uid = uid
        self.port = port

        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.conn = SSLIOStream(self.sock,
                                ssl_options={
                                    'ca_certs': SERVER_CRT_PATH,
                                    'cert_reqs': ssl.CERT_REQUIRED
                                })
        self.conn.connect(('127.0.0.1', self.port), self.on_connect)

    def on_connect(self):
        self.conn.set_close_callback(self.on_close)
        self.pubkey, self.privkey = None, None
        self.init_keys()
        self.write(OP_PUBKEY, self.pubkey)
        # this is hardcoded currently in absence of proper tests
        if self.uid == 2:
            self.send_message(1, 'hello world')
            logger.debug(
                'Client %s: Sending message "Hello World" to user with uid 1' %
                self.uid)
        self.read_line()

    def read_line(self):
        self.conn.read_until(CRLF, self.handle_line)

    def on_close(self):
        self.conn = None
        self.sock = None

    def init_keys(self):
        if os.path.isfile(CLIENT_PUB_PATH % self.uid) and os.path.isfile(
                CLIENT_PRIV_PATH % self.uid):
            with open(CLIENT_PUB_PATH % self.uid,
                      'rb') as pubfile, open(CLIENT_PRIV_PATH % self.uid,
                                             'rb') as privfile:
                self.pubkey = pubfile.read().strip()
                self.privkey = privfile.read().strip()
                logger.debug('read existing pub/priv key for uid %s' %
                             self.uid)
        else:
            self.pubkey, self.privkey = self.generate_keys()
            with open(CLIENT_PUB_PATH % self.uid,
                      'wb') as pubfile, open(CLIENT_PRIV_PATH % self.uid,
                                             'wb') as privfile:
                pubfile.write(self.pubkey)
                privfile.write(self.privkey)
                logger.debug('written pub/priv key for uid %s' % self.uid)

    def write(self, *messages):
        for message in messages:
            self.conn.write('%s%s' % (message, CRLF))

    def send_message(self, uid, message):
        with open(CLIENT_PUB_PATH % uid, 'rb') as pubfile:
            pubkey = pubfile.read()
            # encrypt message using receiver public key
            enc = self.encrypt_message(message, pubkey)
            # sign encrypted message for digital verification
            sig = self.generate_signature(enc[0])
            message = (
                OP_MESSAGE,
                pubkey,
                enc[0],
                sig[0],
            )
            self.write(*message)

    @staticmethod
    def generate_keys():
        random_generator = Random.new().read
        priv = RSA.generate(1024, random_generator)
        pub = priv.publickey()
        return (pub.exportKey().strip(), priv.exportKey().strip())

    def generate_signature(self, message):
        '''sign messaging using our priv key'''
        k = RSA.importKey(self.privkey)
        h = MD5.new(message).digest()
        return k.sign(h, '')

    @staticmethod
    def verify_signature(pubkey, signature, message):
        '''verify signature using signing user public key'''
        k = RSA.importKey(pubkey)
        h = MD5.new(message).digest()
        return k.verify(h, signature)

    @staticmethod
    def encrypt_message(message, pubkey):
        '''encrypt message using receiving user public key'''
        k = RSA.importKey(pubkey)
        return k.encrypt(message, 32)

    def decrypt_message(self, enc):
        '''decrypt message using our priv key'''
        k = RSA.importKey(self.privkey)
        return k.decrypt(enc)