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; }
/// <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 } }