public CryptedChatInviteReceivedEventArgs(ChatRoom room, ChatUser fromUser, int token, Action acceptInviteCallback)
 {
     Chat = room;
     FromUser = fromUser;
     Token = token;
     AcceptInviteCallback = acceptInviteCallback;
 }
 public CryptedChatPlainUserEventArgs(ChatUser user)
 {
     User = user;
 }
 public CryptedChatUserWantsToJoinEventArgs(ChatRoom room, ChatUser user, Action acceptJoinCallback)
 {
     Chat = room;
     User = user;
     AcceptJoinCallback = acceptJoinCallback;
 }
 public CryptedChatMessageReceivedEventArgs(ChatUser user, string message)
 {
     User = user;
     Message = message;
 }
Exemple #5
0
        /// <summary>
        /// Called by other code when a Crype packet has been received on the chat room bound to this chat session
        /// </summary>
        private void ChatRoomOnPacketReceived(object sender, ChatPacketReceivedEventArgs ea)
        {
            var packetInfo = PacketUtility.UnwrapPacket(ea.Packet.Body, _session.Identity.RsaCsp,
                                                    _masterKey);

            // get the underlying plain packet
            var packet = packetInfo.PlainPacket;

            // get information about the sender user
            var senderUser = new ChatUser(ea.Packet.Sender.Handle,  packetInfo.SignedByKey, ea.Packet.Sender);

            // update the user's last contact time if can (packet must be encrypted with the chat key, untargeted)
            if (IsEstablished && packetInfo.IsUntargeted)
            {
                var userInList = _otherUsers.SingleOrDefault(x => x.SkypeHandle == senderUser.SkypeHandle);
                if (userInList != default(ChatUser))
                {
                    userInList.LastMessageReceivedOn = DateTime.Now;
                }
            }

            // let the program know about the user's identity (to add it, to check if it has changed...)
            if (packetInfo.IsSigned && UserKeyReceived != null)
            {
                UserKeyReceived(this, new CryptedChatPlainUserEventArgs(senderUser));
            }

            // now a huge if-statement mess to process the packet ..
            var operation = PacketUtility.GetPacketOperation(packet);

            if (operation == "ChatJoinRequest")
            {
                // cant accept if we aren't in a session
                if (_localStatus != ChatLocalStatus.Established) return;
                // verify the security
                if (!packetInfo.IsSigned) throw new InvalidDataException("Packet must be signed");

                var token = ((DEncodeInt)PacketUtility.GetPacketParameter(packet, 0)).Value;

                if (UserWantsToJoin != null)
                {
                    // raise the event with the callback that will send an invite if accepted by the user
                    UserWantsToJoin(this, new CryptedChatUserWantsToJoinEventArgs(_chatRoom, senderUser, () =>
                        {
                            // accept the request: send a new master key to current users and THEN, send a invite

                            // new master key is created to prevent the joining client from reading old messages
                            var newMasterKey = new byte[32];
                            RngCsp.GetBytes(newMasterKey);
                            _masterKeyLastUpdatedOn = DateTime.Now;

                            var packetToSend = PacketUtility.CreatePacket("UpdateMasterKey",
                                                                      new DEncodeArray(newMasterKey));
                            packetToSend = PacketUtility.EncryptNonTargetedPacket(packetToSend, _masterKey);
                            _masterKey = newMasterKey;
                            _chatRoom.SendPacket(packetToSend);

                            // after updating the key, send an invite to the user with a new master key in it
                            // parameters: masterKey, parameters, userList, tokenFromChatJoinRequest
                            packetToSend = PacketUtility.CreatePacket("ChatInvite",
                                new DEncodeArray(_masterKey),
                                SerializeSessionParameters(_sessionParameters),
                                ConvertUserListToPacketFormat(_otherUsers),
                                new DEncodeInt(token));

                            packetToSend = PacketUtility.SignPacket(packetToSend, _session.Identity.RsaCsp);
                            packetToSend = PacketUtility.EncryptTargetedPacket(packetToSend, senderUser.IdentityPublicKey);
                            _chatRoom.SendPacket(packetToSend);

                            // let the GUI know
                            if (InternalMessageReceived != null)
                            {
                                var message = "Master key updated by self and invited: " + senderUser.SkypeHandle;
                                InternalMessageReceived(this, new CryptedChatInternalMessageEventArgs(message));
                            }
                        }));
                }
            }

            if (operation == "ChatInvite")
            {
                // verify the security
                if (!packetInfo.IsSigned || !packetInfo.IsTargeted) throw new InvalidDataException("Packet must be signed and targeted");

                var masterKeyReceived = ((DEncodeArray)PacketUtility.GetPacketParameter(packet, 0)).Value;
                var sessionParameters =
                    DeserializeSessionParameters((DEncodeList) PacketUtility.GetPacketParameter(packet, 1));
                var userList = ConvertUserListToNormalFormat((DEncodeList) PacketUtility.GetPacketParameter(packet, 2));
                var token = (int)((DEncodeInt)PacketUtility.GetPacketParameter(packet, 3)).Value;

                if (InviteReceived != null)
                {

                    // raise an event to ask the user if he/she wants to accept the invite
                    InviteReceived(this, new CryptedChatInviteReceivedEventArgs(_chatRoom, senderUser, token, () =>
                        {
                            SendLeavePacketIfEstablished();
                            // lets join the session (user accepted)
                            _localStatus = ChatLocalStatus.Established;
                            _masterKey = masterKeyReceived;
                            _masterKeyLastUpdatedOn = DateTime.Now;
                            _sessionParameters = sessionParameters;

                            // clear the old user list and replace it with the one we received from the inviting client, also add the inviting client
                            // to the list
                            _otherUsers.Clear();
                            _otherUsers.AddRange(userList);
                            _otherUsers.Add(senderUser);

                            // let other code know the state has been changed
                            if (StateChanged != null)
                            {
                                StateChanged(this, new CryptedChatStateChangedEventArgs(true, _sessionParameters));
                            }

                            // let other code know the user list was changed
                            if (UserListChanged != null)
                            {
                                UserListChanged(this, new CryptedChatUserListChangedEventArgs(_otherUsers));
                            }

                            // broadcast the information to other people in the chat
                            var packetToSend = PacketUtility.CreatePacket("ChatJoin");
                            packetToSend = PacketUtility.EncryptNonTargetedPacket(packetToSend, _masterKey);
                            _chatRoom.SendPacket(packetToSend);
                        }));
                }
            }

            if (operation == "UpdateMasterKey")
            {
                if (!packetInfo.IsUntargeted) throw new Exception("Packet must be untargeted");

                // update the master key replacing the old one with the received one
                _masterKey = ((DEncodeArray) PacketUtility.GetPacketParameter(packet, 0)).Value;
                _masterKeyLastUpdatedOn = DateTime.Now;

                if (InternalMessageReceived != null)
                {
                    var message = "Master key updated by: " + senderUser.SkypeHandle;
                    InternalMessageReceived(this, new CryptedChatInternalMessageEventArgs(message));
                }
            }

            if (operation == "ChatMessage")
            {
                if (!packetInfo.IsUntargeted) throw new Exception("Packet must be untargeted");

                // let the GUI know about the message
                var message = ((DEncodeString)PacketUtility.GetPacketParameter(packet, 0)).Value;
                if (MessageReceived != null)
                {
                    MessageReceived(this, new CryptedChatMessageReceivedEventArgs(senderUser, message));
                }
            }

            if (operation == "ChatJoin")
            {
                if (!packetInfo.IsUntargeted) throw new Exception("Packet must be untargeted");

                // add the joining user to the user list
                if (!_otherUsers.Contains(senderUser))
                {
                    _otherUsers.Add(senderUser);

                    if (UserListChanged != null)
                    {
                        UserListChanged(this, new CryptedChatUserListChangedEventArgs(_otherUsers));
                    }
                }

                // also raise the other event about this specific user joining
                if (UserJoined != null)
                {
                    UserJoined(this, new CryptedChatPlainUserEventArgs(senderUser));
                }
            }

            if (operation == "ChatLeave")
            {
                if (!packetInfo.IsUntargeted) throw new Exception("Packet must be untargeted");

                // remove the user
                if (_otherUsers.Any(x => x.SkypeHandle == senderUser.SkypeHandle))
                {
                    _otherUsers.Remove(_otherUsers.Single(x => x.SkypeHandle == senderUser.SkypeHandle));

                    if (UserListChanged != null)
                    {
                        UserListChanged(this, new CryptedChatUserListChangedEventArgs(_otherUsers));
                    }
                }

                // also raise the other event about this specific user leaving
                if (UserLeft != null)
                {
                    UserLeft(this, new CryptedChatPlainUserEventArgs(senderUser));
                }
            }

            if (operation == "Ping")
            {
                if (!packetInfo.IsUntargeted) throw new Exception("Packet must be untargeted");
                // do nothing
            }
        }