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")
def user_got_kicked(irc_msg, server): """A user got kicked from a channel we are in. Remove them from the member list.""" account = accounts.get_my_account() parsed = util.parse_irc_quit_kick_part(irc_msg, server) nick = parsed['from_nick'] channel = parsed['channel'] command = parsed['command'] target = parsed['target'] assert(command.upper() == "KICK") util.debug("%s got kicked from %s by %s." % (target, channel, nick)) try: flute_room = account.get_flute_room(channel, server) except accounts.NoSuchRoom: util.debug("No flute room at %s. Sending plaintext." % channel) return try: flute_room.remove_member_and_rekey(target) except room.NoSuchMember: util.control_msg("A non-existent nick left the room. WTF.") # XXX i think this also catches ourselves
def send_key_transport_packet(flute_room): util.debug("I'm captain in %s: Membership changed. Refreshing message key." % flute_room.name) account = accounts.get_my_account() channel = flute_room.name server = flute_room.server assert(flute_room.i_am_captain) # Only captains should be here! # Prepare necessary packet fields. captain_identity_key = account.get_identity_pubkey() captain_transport_key = flute_room.get_room_participant_pubkey() # XXX maybe special func for captain's key? # XXX get_message_key_array also *generates* a new key. rename. message_key_array, key_transport_counter = flute_room.get_message_key_array_and_counter() # our array must be a multiple of 72 bytes assert(len(message_key_array) % MESSAGE_KEY_ARRAY_CELL_LEN == 0) # Encode new key id as big endian unsigned integer new_message_key_counter = struct.pack('>I', key_transport_counter) # Format the packet and sign it. packet_fields = captain_identity_key + captain_transport_key + new_message_key_counter + \ message_key_array packet_signed = account.sign_msg_with_identity_key(packet_fields) payload_b64 = base64.b64encode(packet_signed) flute_room.status = "bootstrapping" util.debug("Sending KEY_TRANSPORT in %s!" % channel) msg_type = KEY_TRANSPORT_OPCODE msg = msg_type + payload_b64 transport.send_flute_privmsg(server, channel, msg) flute_room.status = "done"
def user_left_channel(irc_msg, server): """A user left a channel we are in. Remove them from the channel if we are captain.""" account = accounts.get_my_account() parsed = util.parse_irc_quit_kick_part(irc_msg, server) nick = parsed['from_nick'] channel = parsed['channel'] command = parsed['command'] assert(command.upper() == "PART") util.debug("Received %s from %s in channel %s." % (command, nick, channel)) try: flute_room = account.get_flute_room(channel, server) except accounts.NoSuchRoom: util.debug("No flute room at %s. Sending plaintext." % channel) return try: flute_room.remove_member_and_rekey(nick) except room.NoSuchMember: util.control_msg("A non-existent nick left the room. WTF.") # XXX i think this also catches ourselves return
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)
def send_key_transport_packet(viola_room): util.debug("I'm captain in %s: Membership changed. Refreshing message key." % viola_room.name) account = accounts.get_my_account() channel = viola_room.name server = viola_room.server assert(viola_room.i_am_captain) # Only captains should be here! # Prepare necessary packet fields. captain_identity_key = account.get_identity_pubkey() captain_transport_key = viola_room.get_room_participant_pubkey() # XXX maybe special func for captain's key? message_key_array = viola_room.get_message_key_array() # XXX also generates key. rename. # our array must be a multiple of 72 bytes assert(len(message_key_array) % MESSAGE_KEY_ARRAY_CELL_LEN == 0) # Sign all previous fields. packet_fields = captain_identity_key + captain_transport_key + message_key_array packet_signed = account.sign_msg_with_identity_key(packet_fields) payload_b64 = base64.b64encode(packet_signed) viola_room.status = "bootstrapping" util.debug("Sending KEY_TRANSPORT in %s!" % channel) msg = KEY_TRANSPORT_OPCODE + payload_b64 transport.send_viola_privmsg(server, channel, msg) viola_room.status = "done"
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.viola_channel_msg(buf, "Can't 'join-room' in an empty channel!", "red") util.viola_channel_msg(buf, "Do '/viola start-room' if you want to start a new viola room instead.", "red") return # First of all, register this new room. viola_room = account.register_viola_room(channel, server, buf) # Get the keys to be placed in the packet my_pub_key = account.get_identity_pubkey() my_room_key = viola_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_viola_privmsg(server, channel, msg) util.viola_channel_msg(buf, "Requested to join room %s..." % channel)
def user_left_channel(irc_msg, server): """A user left a channel we are in. Remove them from the channel if we are captain.""" account = accounts.get_my_account() parsed = util.parse_irc_quit_kick_part(irc_msg, server) nick = parsed['from_nick'] channel = parsed['channel'] command = parsed['command'] assert(command.upper() == "PART") util.debug("Received %s from %s in channel %s." % (command, nick, channel)) try: viola_room = account.get_viola_room(channel, server) except accounts.NoSuchRoom: util.debug("No viola room at %s. Sending plaintext." % channel) return try: viola_room.remove_member_and_rekey(nick) except room.NoSuchMember: util.control_msg("A non-existent nick left the room. WTF.") # XXX i think this also catches ourselves return
def user_got_kicked(irc_msg, server): """A user got kicked from a channel we are in. Remove them from the member list.""" account = accounts.get_my_account() parsed = util.parse_irc_quit_kick_part(irc_msg, server) nick = parsed['from_nick'] channel = parsed['channel'] command = parsed['command'] target = parsed['target'] assert(command.upper() == "KICK") util.debug("%s got kicked from %s by %s." % (target, channel, nick)) try: viola_room = account.get_viola_room(channel, server) except accounts.NoSuchRoom: util.debug("No viola room at %s. Sending plaintext." % channel) return try: viola_room.remove_member_and_rekey(target) except room.NoSuchMember: util.control_msg("A non-existent nick left the room. WTF.") # XXX i think this also catches ourselves
def user_quit_irc(irc_msg, server): """A user quit IRC. Remove them form the member list of any channel they are in.""" account = accounts.get_my_account() parsed = util.parse_irc_quit_kick_part(irc_msg, server) nick = parsed['from_nick'] command = parsed['command'] assert(command.upper() == "QUIT") account.user_quit_irc(nick)
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 viola room for us? # XXX Code duplication try: viola_room = account.get_viola_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 viola.py util.viola_channel_msg(buf, "[You hear a viola screeching... Please do '/viola join-room' to join the session.]", "lightcyan") return "" try: room_message_key = viola_room.get_room_message_key() except room.NoMessageKey: util.debug("Received ROOM_MESSAGE in %s but no message key. Ignoring." % channel) # XXX ??? util.viola_channel_msg(viola_room.buf, "[You hear a viola screeching... Please do '/viola join-room' to join the session.]", "grey") 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:] # XXX catch decrypt exception try: plaintext = crypto.decrypt_room_message(room_message_key, message_ciphertext) except nacl.exceptions.CryptoError: util.viola_channel_msg(viola_room.buf, "Could not decrypt message sent in room. Maybe old key. Try rejoining the channel.", "red") # XXX this won't work return "" msg_in = otrlib.build_privmsg_in(sender_host, channel, plaintext) return msg_in[0] + '⚷' + msg_in[1:]
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
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)
def start_viola_room(channel, server, buf): """Start a Viola room in 'channel'@'server' on weechat buffer 'buf'.""" account = accounts.get_my_account() util.debug("Starting a viola 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.viola_channel_msg(buf, "Can only start viola session in empty channel!", "red") util.viola_channel_msg(buf, "Try '/viola join-room' in this channel instead.", "red") return account.register_viola_room(channel, server, buf, i_am_captain=True) util.viola_channel_msg(buf, "We are now the captain in room %s!" % channel)
def trust_key_cmd(parsed_args, buf): nickname = parsed_args[1] hexed_key = parsed_args[2] # Check for illegal nickname chars if not nickname.isalnum(): util.control_msg("Invalid nickname: %s" % nickname) raise flute.FluteCommandError if len(hexed_key) != 64 or not util.is_hex(hexed_key): util.control_msg("Invalid key value: %s" % hexed_key) raise flute.FluteCommandError account = accounts.get_my_account() account.trust_key(nickname, hexed_key)
def rekey_room(metadata): """Extract channel/server from metadata and rekey flute room.""" # Get channel/server from metadata splited_room_id = metadata.split(',') room = splited_room_id[0] server = splited_room_id[1] util.debug("Attempting to rekey room %s..." % room) # Find the right flute room account = accounts.get_my_account() try: flute_room = account.get_flute_room(room, server) except accounts.NoSuchRoom: util.debug("Tried to rekey unknown room %s..." % room) return # Rekey room! flute_room.rekey()
def handle_outgoing_irc_msg_to_channel(parsed, server): """We are about to send 'parsed' to a channel. If the channel is a flute room where the room message key is known, encrypt the message and send it directly. Otherwise if no Flute session is going on, return the plaintext string that should be output to the channel.""" channel = parsed['to_channel'] msg = parsed['text'] account = accounts.get_my_account() try: flute_room = account.get_flute_room(channel, server) except accounts.NoSuchRoom: util.debug("No flute room at %s. Sending plaintext." % channel) return msg try: room_message_key = flute_room.get_current_room_message_key() except room.NoMessageKey: util.debug("No message key at %s. Sending plaintext." % channel) # XXX ??? return msg if not flute_room.status == "done": util.debug("Room %s not setup yet. Sending plaintext." % channel) # XXX ??? return msg util.debug("Sending encrypted msg to %s" % channel) # OK we are in a flute room and we even know the key! # Send a ROOM_MESSAGE! # XXX functionify ciphertext = crypto.get_room_message_ciphertext(room_message_key, msg) packet_signed = account.sign_msg_with_identity_key(ciphertext) payload_b64 = base64.b64encode(packet_signed) msg = ROOM_MESSAGE_OPCODE + payload_b64 transport.send_flute_privmsg(server, channel, msg) return ""
def handle_outgoing_irc_msg_to_channel(parsed, server): """We are about to send 'parsed' to a channel. If the channel is a viola room where the room message key is known, encrypt the message and send it directly. Otherwise if no Viola session is going on, return the plaintext string that should be output to the channel.""" channel = parsed['to_channel'] msg = parsed['text'] account = accounts.get_my_account() try: viola_room = account.get_viola_room(channel, server) except accounts.NoSuchRoom: util.debug("No viola room at %s. Sending plaintext." % channel) return msg try: room_message_key = viola_room.get_room_message_key() except room.NoMessageKey: util.debug("No message key at %s. Sending plaintext." % channel) # XXX ??? return msg if not viola_room.status == "done": util.debug("Room %s not setup yet. Sending plaintext." % channel) # XXX ??? return msg util.debug("Sending encrypted msg to %s" % channel) # OK we are in a viola room and we even know the key! # Send a ROOM_MESSAGE! # XXX functionify ciphertext = crypto.get_room_message_ciphertext(room_message_key, msg) packet_signed = account.sign_msg_with_identity_key(ciphertext) payload_b64 = base64.b64encode(packet_signed) msg = ROOM_MESSAGE_OPCODE + payload_b64 transport.send_viola_privmsg(server, channel, msg) return ""
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")
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 ""
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 viola room for us? try: viola_room = account.get_viola_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? viola_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 viola_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(viola_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 = viola_room.buf util.viola_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.viola_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 /viola 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.viola_channel_msg(buf, "Example: /viola trust-key alice %s" % crypto.get_hexed_key(identity_pubkey), "red") return "" # XXX Security: Maybe we should ask the captain before autoadding them! buf = viola_room.buf util.viola_channel_msg(buf, "Friend '%s' was added to the viola room!" % joining_friend_name) # We are captains in the channel. Act like it! # There is a new room member! Refresh and send new key! send_key_transport_packet(viola_room) return ""
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 viola room for us? # XXX Code duplication try: viola_room = account.get_viola_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) < MINIMUM_KEY_TRANSPORT_PAYLOAD_LEN: raise IncompletePacket if viola_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) encrypted_message_key_array = payload[SIG_LEN+PUBKEY_LEN+PUBKEY_LEN:] # Check if we trust the captain. try: captain_friend_name = account.get_friend_from_identity_key(captain_identity_pubkey) except accounts.IdentityKeyNotTrusted: buf = viola_room.buf util.viola_channel_msg(buf, "Untrusted nickname %s is the captain of this channel with key: %s" % (sender, captain_identity_pubkey), "red") util.viola_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 /viola trust-key <name> %s\n" "where <name> is the nickname you want to assign to the key." % crypto.get_hexed_key(captain_identity_pubkey), "red") util.viola_channel_msg(buf, "Example: /viola trust-key alice %s" % crypto.get_hexed_key(captain_identity_pubkey), "red") return "" # Verify captain signature captain_identity_pubkey.verify(payload) # XXX catch exception # Try to decrypt the message key array try: room_message_key = crypto.decrypt_room_message_key(encrypted_message_key_array, captain_transport_pubkey, viola_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! viola_room.set_room_message_key(room_message_key) viola_room.status = "done" # We found our captain. Add them to the room! # XXX should we do this here or before the checks? viola_room.add_member(sender, captain_identity_pubkey, captain_transport_pubkey) # Print some messages to the user buf = util.viola_channel_msg(viola_room.buf, "Joined room %s with captain %s!" % (channel, sender)) util.debug("Got a new room message key from captain %s: %s" % \ (sender, crypto.get_hexed_key(room_message_key))) return ""
def list_fingerprint_cmd(): account = accounts.get_my_account() account.print_fingerprint()
def list_friends_cmd(): account = accounts.get_my_account() account.print_friend_list()
def user_changed_irc_nick(old_nick, new_nick): """User changed nickname. Track the change.""" account = accounts.get_my_account() # A user changed nick: we need to update the flute rooms. account.user_changed_nick(old_nick, new_nick)
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 ""
def user_changed_irc_nick(old_nick, new_nick): """User changed nickname. Track the change.""" account = accounts.get_my_account() # A user changed nick: we need to update the viola rooms. account.user_changed_nick(old_nick, new_nick)
def introduction_cmd(parsed_args, buf): account = accounts.get_my_account() introduction.send_introduction(account, parsed_args, buf)