Example #1
0
    def register_flute_room(self, channel, server, buf, i_am_captain=False):
        """
        Register flute room on this account. If a room under this channel name
        already exists, be careful about overwriting it.
        """
        old_room = None

        # If this room already exists and is active, don't register it again.
        if channel in self.active_flute_rooms:
            old_room = self.active_flute_rooms[channel]
            if old_room.is_active():
                util.flute_channel_msg(buf,
                                       "Channel %s is already a flute room" %
                                       channel)  # XXX fix!
                raise FluteCommandError

        # If there used to be a room with this name but we are not overwriting
        # it, remove the old one.
        if old_room:
            self.active_flute_rooms.pop(channel)  # XXX more cleanup?

        # Create the room
        flute_room = room.FluteRoom(channel, server, buf, i_am_captain)
        # and register it.
        self.active_flute_rooms[channel] = flute_room

        return flute_room
Example #2
0
def introduction_cmd(parsed_args, buf):
    account = accounts.get_my_account()

    # Prepare the metadata
    server = util.get_local_server(buf)

    # If a nick is provided, introduce to that nick. Otherwise, check if we are
    # currently having a private conversation with another nick, and if so
    # introduce to that nick.
    if len(parsed_args) >= 2:
        target_nick = parsed_args[1]
    else:
        if otrlib.buffer_is_private(buf):
            target_nick = util.get_local_channel(buf)
        else:
            util.control_msg(
                "Bad introduction command! Can't introduce yourself to a channel!"
            )
            raise flute.FluteCommandError

    introduction.send_introduction(account, target_nick, server, buf)

    util.flute_channel_msg(buf,
                           "[Introduced ourselves to %s.]" % target_nick,
                           color="green")
Example #3
0
    def decrypt_room_message(self, message_ciphertext):
        """
        Figure out the right "room message key" and try to decrypt the room message
        ciphertext.
        """
        plaintext = None

        # Dont even try decrypting if we don't know the current room message key...
        if self.key_cache.is_empty():
            util.debug("Received ROOM_MESSAGE in %s but no message key. Ignoring." % self.name)
            util.flute_channel_msg(self.buf,
                                   "[You hear a flute screeching... Please do '/flute join-room' to join the session.]",
                                   "grey")
            return ""

        # Loop over all keys and try to decrypt packet.
        for potential_room_message_key in self.key_cache.message_key_iterator():
            try:
                plaintext = crypto.decrypt_room_message(potential_room_message_key, message_ciphertext)
                break
            except crypto.DecryptFail:
                util.debug("Hm, that key did not work. Trying next one...")
                continue

        # Did we get a plaintext? If yes, return it!!
        if plaintext:
            return plaintext

        # If we are here, all keys failed to decrypt and we can't do anything else...
        util.debug("All keys failed to decrypt ROOM_MESSAGE packet...")
        raise MessageDecryptFail
Example #4
0
    def register_flute_room(self, channel, server, buf, i_am_captain=False):
        """
        Register flute room on this account. If a room under this channel name
        already exists, be careful about overwriting it.
        """
        old_room = None

        # If this room already exists and is active, don't register it again.
        if channel in self.active_flute_rooms:
            old_room = self.active_flute_rooms[channel]
            if old_room.is_active():
                util.flute_channel_msg(buf, "Channel %s is already a flute room" % channel) # XXX fix!
                raise FluteCommandError

        # If there used to be a room with this name but we are not overwriting
        # it, remove the old one.
        if old_room:
            self.active_flute_rooms.pop(channel) # XXX more cleanup?

        # Create the room
        flute_room = room.FluteRoom(channel, server, buf, i_am_captain)
        # and register it.
        self.active_flute_rooms[channel] = flute_room

        return flute_room
Example #5
0
    def key_transport_is_replay(self, new_key_counter):
        if new_key_counter <= self.key_transport_counter:
            util.flute_channel_msg(self.buf,
                                   "Received replayed KEY_TRANSPORT packet (%d / %d)" % \
                                   (new_key_counter, self.key_transport_counter),
                                   color="red")
            return True

        return False
Example #6
0
File: flute.py Project: h1r00/flute
def handle_room_message_packet(packet_payload, parsed, server):
    sender_host = parsed['from']
    sender_nick = parsed['from_nick']
    channel = parsed['to_channel']
    account = accounts.get_my_account()

    if not channel: # XXX functionify
        util.debug("Received ROOM_MESSAGE not in channel from %s. Ignoring." % sender_host)
        return ""

    # Is this channel a flute room for us?
    # XXX Code duplication
    try:
        flute_room = account.get_flute_room(channel, server)
    except accounts.NoSuchRoom:
        util.debug("Received ROOM_MESSAGE in a regular channel (%s). Ignoring." % channel)
        buf = util.get_current_buffer() # XXX weechat API shouldn't polute flute.py
        util.flute_channel_msg(buf,
                               "[Tootie-too! What an annoying sound! Do '/flute join-room' to join the flute session.]",
                               color="lightcyan")
        return ""


    payload = base64.b64decode(packet_payload)

    if len(payload) <= 64:
        raise IncompletePacket

    util.debug("Attempting to decrypt ROOM_MESSAGE in %s" % channel)

    # Get packet fields
    signature = payload[:SIG_LEN]
    message_ciphertext = payload[SIG_LEN:]

    # Decrypt ciphertext
    try:
        plaintext = flute_room.decrypt_room_message(message_ciphertext)
    except room.MessageDecryptFail:
        util.flute_channel_msg(flute_room.buf,
                               "Could not decrypt message sent in room. Maybe old key. Try rejoining the channel.",
                               color="red")
        return ""

    if not plaintext:
        return ""

    msg = "[ENCRYPTED] %s" % plaintext
    msg_in = otrlib.build_privmsg_in(sender_host, channel, msg)
    return msg_in
Example #7
0
File: flute.py Project: h1r00/flute
def send_room_join(channel, server, buf):
    """Send ROOM_JOIN message."""
    account = accounts.get_my_account()

    # Don't send ROOM_JOIN to empty channel. No one to handle it.
    if util.irc_channel_is_empty(channel, server):
        util.flute_channel_msg(buf, "Can't 'join-room' in an empty channel!", "red")
        util.flute_channel_msg(buf, "Do '/flute start-room' if you want to start a new flute room instead.", "red")
        return

    # First of all, register this new room.
    flute_room = account.register_flute_room(channel, server, buf)

    # Get the keys to be placed in the packet
    my_pub_key = account.get_identity_pubkey()
    my_room_key = flute_room.get_room_participant_pubkey()

    # Sign them
    packet_fields = my_pub_key + my_room_key
    packet_signed = account.sign_msg_with_identity_key(packet_fields)

    payload_b64 = base64.b64encode(packet_signed)

    msg = ROOM_JOIN_OPCODE + payload_b64
    transport.send_flute_privmsg(server, channel, msg)

    util.flute_channel_msg(buf, "Requested to join room %s..." % channel)
Example #8
0
def introduction_cmd(parsed_args, buf):
    account = accounts.get_my_account()

    # Prepare the metadata
    server = util.get_local_server(buf)

    # If a nick is provided, introduce to that nick. Otherwise, check if we are
    # currently having a private conversation with another nick, and if so
    # introduce to that nick.
    if len(parsed_args) >= 2:
        target_nick = parsed_args[1]
    else:
        if otrlib.buffer_is_private(buf):
            target_nick = util.get_local_channel(buf)
        else:
            util.control_msg("Bad introduction command! Can't introduce yourself to a channel!")
            raise flute.FluteCommandError

    introduction.send_introduction(account, target_nick, server, buf)

    util.flute_channel_msg(buf,
                           "[Introduced ourselves to %s.]" % target_nick,
                           color="green")
Example #9
0
File: flute.py Project: h1r00/flute
def start_flute_room(channel, server, buf):
    """Start a Flute room in 'channel'@'server' on weechat buffer 'buf'."""
    account = accounts.get_my_account()
    util.debug("Starting a flute session in %s." % channel)

    # Make sure we are the only nick in the channel otherwise someone else
    # might already be captaining.
    if not util.irc_channel_is_empty(channel, server):
        util.flute_channel_msg(buf, "Can only start flute session in empty channel!", "red")
        util.flute_channel_msg(buf, "Try '/flute join-room' in this channel instead.", "red")
        return

    account.register_flute_room(channel, server, buf, i_am_captain=True)

    util.flute_channel_msg(buf, "We are now the captain in room %s!" % channel)
Example #10
0
File: flute.py Project: h1r00/flute
def handle_key_transport_packet(packet_payload, parsed, server):
    sender = parsed['from_nick']
    channel = parsed['to_channel']
    account = accounts.get_my_account()

    if not channel: # XXX functionify
        util.debug("Received KEY_TRANSPORT not in channel from %s. Ignoring." % sender)
        return ""

    # Is this channel a flute room for us?
    # XXX Code duplication
    try:
        flute_room = account.get_flute_room(channel, server)
    except accounts.NoSuchRoom:
        util.debug("Received KEY_TRANSPORT in a regular channel (%s). Ignoring." % channel)
        return ""

    payload = base64.b64decode(packet_payload)

    if len(payload) < MINIMUM_KEY_TRANSPORT_PAYLOAD_LEN:
        raise IncompletePacket

    if flute_room.i_am_captain:
        util.debug("Received KEY_TRANSPORT in %s by %s but I am captain! Ignoring." % (channel, sender))
        return ""

    util.debug("Received KEY_TRANSPORT in %s! Handling it." % channel)

    # Start parsing the packet
    signature = payload[:SIG_LEN]

    captain_identity_pubkey = payload[SIG_LEN:SIG_LEN+PUBKEY_LEN]
    captain_identity_pubkey = crypto.parse_signing_pubkey(captain_identity_pubkey)

    captain_transport_pubkey = payload[SIG_LEN+PUBKEY_LEN : SIG_LEN+PUBKEY_LEN+PUBKEY_LEN]
    captain_transport_pubkey = crypto.parse_pub_key(captain_transport_pubkey)

    new_key_counter, = struct.unpack('>I',payload[SIG_LEN + PUBKEY_LEN + PUBKEY_LEN: SIG_LEN + PUBKEY_LEN + PUBKEY_LEN + KEY_ID_LEN])

    encrypted_message_key_array = payload[SIG_LEN+PUBKEY_LEN+PUBKEY_LEN + KEY_ID_LEN:]

    # Check if we trust the captain.
    try:
        captain_friend_name = account.get_friend_from_identity_key(captain_identity_pubkey)
    except accounts.IdentityKeyNotTrusted:
        hexed_captain_key = crypto.get_hexed_key(captain_identity_pubkey)
        buf = flute_room.buf
        util.flute_channel_msg(buf, "Untrusted nickname %s is the captain of this channel with key: %s" % (sender, hexed_captain_key),
                               color="red")
        util.flute_channel_msg(buf, "Ignoring KEY_TRANSPORT by untrusted captain. If you trust that key and "
                               "you want to join the channel, please issue the following command and rejoin:\n"
                               "\t /flute trust-key <name> %s\n"
                               "where <name> is the nickname you want to assign to the key."  % hexed_captain_key,
                               color="red")
        util.flute_channel_msg(buf, "Example: /flute trust-key alice %s" % hexed_captain_key,
                               color="red")
        return ""

    # Verify captain signature
    captain_identity_pubkey.verify(payload)    # XXX catch exception

    # Check for replays using KEY_TRANSPORT counter
    if new_key_counter < 1:
        util.debug("Corrupted key counter %d" % new_key_counter)
        return ""
    if flute_room.key_transport_is_replay(new_key_counter):
        return ""

    # Try to decrypt the message key array
    try:
        room_message_key = crypto.decrypt_room_message_key(encrypted_message_key_array,
                                                           captain_transport_pubkey,
                                                           flute_room.get_room_participant_privkey())
    except crypto.NoKeyFound:
        util.debug("Received KEY_TRANSPORT but did not find my key. F**k.")
        return ""

    # We got the room message key!
    flute_room.set_room_message_key(room_message_key, new_key_counter)
    flute_room.status = "done"

    # We found our captain. Add them to the room!
    # XXX careful not to double-add the captain in case of rekey
    flute_room.add_member(sender, captain_identity_pubkey, captain_transport_pubkey)

    # Print some messages to the user
    buf = util.flute_channel_msg(flute_room.buf,
                                 "Got room key for %s from captain %s (friend name: %s)!" % (channel, sender, captain_friend_name))
    util.debug("Got a new room message key from captain %s: %s" % \
               (sender, crypto.get_hexed_key(room_message_key)))

    return ""
Example #11
0
File: flute.py Project: h1r00/flute
def handle_room_join_packet(packet_payload, parsed, server):
    sender_nick = parsed['from_nick']
    channel = parsed['to_channel']
    account = accounts.get_my_account()

    if not parsed['to_channel']: # XXX functionify
        util.debug("Received ROOM_JOIN not in channel from %s. Ignoring." % sender_nick)
        return ""

    # Is this channel a flute room for us?
    try:
        flute_room = account.get_flute_room(channel, server)
    except accounts.NoSuchRoom:
        util.debug("Received ROOM_JOIN in a regular channel (%s). Ignoring." % channel)
        return ""

    payload = base64.b64decode(packet_payload)

    if len(payload) < ROOM_JOIN_PAYLOAD_LEN:
        raise IncompletePacket

    signature = payload[:SIG_LEN]
    identity_pubkey = crypto.parse_signing_pubkey(payload[SIG_LEN:SIG_LEN+PUBKEY_LEN])
    room_pubkey = crypto.parse_pub_key(payload[SIG_LEN+PUBKEY_LEN:SIG_LEN+PUBKEY_LEN+PUBKEY_LEN])

    # Verify signature
    # XXX is this the right logic for this particular packet?
    # XXX catch exception
    identity_pubkey.verify(payload)

    # XXX should we add all members even if we don't know them?
    flute_room.add_member(sender_nick, identity_pubkey, room_pubkey)

    # No need to do anything more if we are not captain in this channel.
    if not flute_room.i_am_captain:
        util.debug("Received ROOM_JOIN in %s but not captain. Ignoring." % channel)
        return ""

    util.debug("Received ROOM_JOIN in %s. Sending KEY_TRANSPORT (%d members)!" % (channel, len(flute_room.members)))

    # We are the captain. Check if we trust this key. Reject member otherwise.
    try:
        joining_friend_name = account.get_friend_from_identity_key(identity_pubkey)
    except accounts.IdentityKeyNotTrusted:
        buf = flute_room.buf
        util.flute_channel_msg(buf, "%s nickname %s is trying to join the channel with key %s." %
                               (otrlib.colorize("Untrusted", "red"), sender_nick,
                                crypto.get_hexed_key(identity_pubkey)), "red")
        util.flute_channel_msg(buf, "If you trust that key and you want them to join the channel, "
                               "please issue the following command and ask them to rejoin the channel:\n"
                               "\t /flute trust-key <name> %s\n"
                               "where <name> is the nickname you want to assign to the key."  %
                               crypto.get_hexed_key(identity_pubkey), "red")

        util.flute_channel_msg(buf, "Example: /flute trust-key alice %s" % crypto.get_hexed_key(identity_pubkey), "red")
        return ""

    # XXX Security: Maybe we should ask the captain before autoadding them!
    buf = flute_room.buf
    util.flute_channel_msg(buf, "User '%s' (friend name: %s) was added to the flute room!" % \
                           (sender_nick, joining_friend_name),
                           color="green")

    # We are captains in the channel. Act like it!
    # There is a new room member! Refresh and send new key!
    send_key_transport_packet(flute_room)
    return ""