public async Task<SendMessageResult> SendMessageAsync(Message message)
        {
            try
            {
                Dictionary<string, byte[]> keys = null;
                string text = message.Text;

                await messageRepository.AddMessageAsync(message);

                if (EncryptionEnabled)
                {
                    var deviceIdAndPublicKeyMap = await deviceInfoProvider.GetUserDevicesAndPublicKeys((int) message.Recipient);
                    if (deviceIdAndPublicKeyMap.Count > 0)
                    {
                        //don't forget current user's other devices
                        var myDevices = await deviceInfoProvider.GetUserDevicesAndPublicKeys(Settings.MyId);
                        foreach (var myDevice in myDevices)
                        {
                            if (myDevice.Key != Settings.UserDeviceId && myDevice.Key != Settings.MyId.ToString())
                                deviceIdAndPublicKeyMap[myDevice.Key] = myDevice.Value;
                        }
                        text = cryptoService.Encrypt(message.Text, deviceIdAndPublicKeyMap, out keys);
                    }
                }

                var request = new SendMessageRequest
                    {
                        ReceiverUserId = message.Recipient,
                        SenderName = Settings.NickName,
                        MessageType = ServerClient.Entities.Ws.Requests.MessageType.Text,
                        MessageToken = message.MessageToken,
                        Thumbnail = message.Thumbnail,
                        GroupId = message.GroupId,
                        Message = text,
                        Keys = keys,
                    };

                var response = await messagingService.SendMessage(request);
                if (response.Error == Errors.SendMessage_ProvideKeysForTheseDevices)
                {
                    foreach (var item in response.MissedDevicesWithPublicKeysToReEncrypt)
                    {
                        await deviceInfoProvider.SavePublicKeyForDeviceId(item.DeviceId, item.UserId, Convert.ToBase64String(item.PublicKey));
                    }
                    //try again
                    return await SendMessageAsync(message);
                }
                if (response.Error == Errors.SendMessage_ReceiversNotFound)
                {
                    return SendMessageResult.ReceiverUnknown;
                }
                if (response.Error == Errors.SendMessage_ReceiverAndSenderAreSame)
                {
                    return SendMessageResult.ReceiverAndSenderAreSame;
                }

                OnMessageSent(message.MessageToken);
                return SendMessageResult.Ok;
            }
            catch (ConnectionException)
            {
                return SendMessageResult.ConnectionError;
            }
            catch (Exception ex)
            {
				App.Logger.Report (ex);
                return SendMessageResult.UnknownError;
            }
        }
        public SendMessageResponse SendMessage(ISession session, SendMessageRequest request)
        {
            var response = request.CreateResponse<SendMessageResponse>();
            Logger.Info("SendMessage from Id={0} (Device={1}) to Id={2} ({3} devices)",
                session.UserId, session.DeviceId.Cut(), request.ReceiverUserId, request.Keys != null ? request.Keys.Count : -1);

            Dictionary<string, long> actualMessageReceiversDevices = null;
            Dictionary<string, byte[]> keys = request.Keys;

            if (request.GroupId != Guid.Empty)// group conversation
            {
                var groupChat = _groupChatsRepository.GetChat(request.GroupId);

                //sender is in the group?
                if (groupChat.Participants.All(i => i.UserId != session.UserId))
                {
                    response.Success = false;
                    response.Error = Errors.YouAreNotParticipantOfThatGroup;
                    return response;
                }

                if (keys == null) //means not encrypted
                {
                    keys = groupChat.Participants
                        .SelectMany(p => p.Devices)
                        .Where(p => p != session.DeviceId)
                        .Distinct()
                        .ToDictionary<string, string, byte[]>(k => k, v => null); //null value means unencrypted
                }
                else
                {
                    //it means we will check all provided devices below (see if (actualMessageReceiversDevices != null)) -- just to avoid copy-paste

                    actualMessageReceiversDevices = new Dictionary<string, long>();
                    foreach (var groupChatParticipant in groupChat.Participants)
                    {
                        foreach (var device in groupChatParticipant.Devices)
                        {
                            actualMessageReceiversDevices[device] = groupChatParticipant.UserId;
                        }
                    }
                }
            }
            else // private conversation
            {
                if (request.ReceiverUserId == session.UserId)
                {
                    response.Success = false;
                    response.Error = Errors.SendMessage_ReceiverAndSenderAreSame;
                    return response;
                }

                if (keys == null)//means not encrypted
                {
                    keys = _devicesRepository.GetDevices(request.ReceiverUserId).ToDictionary<string, string, byte[]>(k => k, v => null);
                }
                else
                {
                    //it means we will check all provided devices below (see if (actualMessageReceiversDevices != null)) -- just to avoid copy-paste
                    actualMessageReceiversDevices = _devicesRepository.GetDevices(request.ReceiverUserId).ToDictionary(k => k, v => request.ReceiverUserId);
                }
            }

            if (actualMessageReceiversDevices != null) //TODO: uncoment later
            {
                var providedDevices = keys.Select(i => i.Key);

                List<string> union;
                List<string> notProvidedDevices; //conversation has more devices than user provided as targets
                List<string> wrongDevices; //some of the devices user provided are not members of that conversation
                actualMessageReceiversDevices.Select(i => i.Key)
                    .FindIntersectionAndDifference(providedDevices, out union, out notProvidedDevices, out wrongDevices);

                if (notProvidedDevices.Any())
                {
                    response.Success = false;
                    response.Error = Errors.SendMessage_ProvideKeysForTheseDevices;
                    //we will help the user - provide public keys as well
                    response.MissedDevicesWithPublicKeysToReEncrypt = notProvidedDevices
                       .Where(d => session.DeviceId != d)
                       .Select(d => new PublicKeyInfo
                       {
                           DeviceId = d, 
                           PublicKey = _devicesRepository.GetPublicKeyForDevice(d),
                           UserId = actualMessageReceiversDevices[d]
                       })
                       .ToList();
                    return response;
                }

                //cut receivers not in the conversation
                //TODO: uncomment it later
                /*foreach (var key in wrongDevices)
                {
                    keys.Remove(key);
                }*/
            }

            keys.Remove(session.DeviceId);

            if (keys.Count < 1)
            {
                response.Success = false;
                response.Error = Errors.SendMessage_ReceiversNotFound;
                return response;
            }

            foreach (var key in keys)
            {
                var innerMsg = new Message
                {
                    SenderAccessToken = session.AccessToken,
                    Text = request.Message,
                    GroupId = request.GroupId,
                    SenderId = session.UserId,
                    SenderDeviceId = session.DeviceId,
                    SenderName = request.SenderName,
                    ReceiverId = request.ReceiverUserId,
                    MessageTypeId = (int)request.MessageType,
                    Thumbnail = request.Thumbnail,
                    ReceiverDeviceId = key.Key,
                    EncryptionKey = key.Value,
                    MessageToken = request.MessageToken,
                };
                _messageEventManager.DeliverEventToDevice(innerMsg);
            }
            return response;
        }
Exemple #3
0
	    private static async void ProcessConsoleCommand(string line)
        {
	        var args = new List<string>();
            if (CommandParser.ParseCommand(line, "BeginTyping", 1, ref args))
            {
                var receiverId = long.Parse(args[0]);
                await messagingService.SendIsTyping(new SendIsTypingRequest { IsTyping = true, Devices = new List<string> { receiverId.ToString() }});
            }
            else if (CommandParser.ParseCommand(line, "EndTyping", 1, ref args))
            {
                var receiverId = long.Parse(args[0]);
                await messagingService.SendIsTyping(new SendIsTypingRequest { IsTyping = false, Devices = new List<string> { receiverId.ToString() }});
            }
            else if (CommandParser.ParseCommand(line, "CreateGroup", -1, ref args))
            {
                var participants = args
                    .Select(long.Parse)
                    .ToList();
                var createGroupChatResponse = await groupChatsService.CreateGroupChat(new CreateGroupChatRequest { GroupName = "Foo", Participants = participants});
                Out.WriteLine("Group is created: {0}", createGroupChatResponse.GroupId);
            }
            else if (CommandParser.ParseCommand(line, "AddParticipant", -1, ref args))
            {
                var groupId = Guid.Parse(args[0]);
                await groupChatsService.AddParticipants(new AddParticipantsRequest { GroupId = groupId, ParticipantIds = args.Skip(1).Select(long.Parse).ToList()});
            }
            else if (CommandParser.ParseCommand(line, "KickParticipant", -1, ref args))
            {
                var groupId = Guid.Parse(args[0]);
                await groupChatsService.KickParticipants(new KickParticipantsRequest { GroupId = groupId, ParticipantIds = args.Skip(1).Select(long.Parse).ToList() });
            }
            else if (CommandParser.ParseCommand(line, "LeaveGroup", 1, ref args))
            {
                var groupId = Guid.Parse(args[0]);
                await groupChatsService.LeaveGroup(new LeaveGroupRequest {GroupId = groupId});
            }
            else if (CommandParser.ParseCommand(line, "SetGroupName", 2, ref args))
            {
                var groupId = Guid.Parse(args[0]);
                await groupChatsService.ChangeGroup(new ChangeGroupRequest {GroupId = groupId, NewGroupName = args[1]});
            }
            else if (CommandParser.ParseCommand(line, "GetGroupInfo", 1, ref args))
            {
                var groupId = Guid.Parse(args[0]);
                var getGroupChatInfoResponse = await groupChatsService.GetGroupChatInfo(new GetGroupChatInfoRequest {GroupId = groupId});
                Out.WriteLine("GetGroupInfo: Name={0}, Participants.Count={1}", getGroupChatInfoResponse.GroupInfo.Name, getGroupChatInfoResponse.GroupInfo.Participants.Count);
            }
            else if (CommandParser.ParseCommand(line, "GetMyGroups", 0, ref args))
            {
                var getGroupsResponse = await groupChatsService.GetGroups(new GetGroupsRequest());
                Out.WriteLine("GetMyGroup: Groups.Count={0}", getGroupsResponse.Groups);
            }
            //private message
            else if (CommandParser.ParseCommand(line, "SendMessage", 2, ref args))
            {
                var receiverId = long.Parse(args[0]);
                string text = args[1];
                var sendMsgRequest = new SendMessageRequest
                    { 
                        ReceiverUserId = receiverId,
                        Message = text,
                        //Keys = new Dictionary<string, byte[]> { { receiverId.ToString(), new byte[1] } },
                        MessageToken = Guid.NewGuid(),
                        SenderName = "ConsoleAppFor_" + myUserId
                    };
                await messagingService.SendMessage(sendMsgRequest);
                Out.WriteLine("   server received your message");
            }
            //group message
            else if (CommandParser.ParseCommand(line, "SendGroupMessage", 2, ref args))
            {
                var groupId = Guid.Parse(args[0]);
                string text = args[1];
                var sendMsgRequest = new SendMessageRequest
                {
                    ReceiverUserId = 0,
                    GroupId = groupId,
                    Message = text,
                    //Keys = new Dictionary<string, byte[]> { { receiverId.ToString(), new byte[1] } },
                    MessageToken = Guid.NewGuid(),
                    SenderName = "ConsoleAppFor_" + myUserId
                };
                await messagingService.SendMessage(sendMsgRequest);
                Out.WriteLine("   server received your message");
            }
            else
            {
                Out.WriteLine("Command is not recognized");
            }
	    }
 public Task<SendMessageResponse> SendMessage(SendMessageRequest request)
 {
     return _connectionManager.SendRequestAndWaitResponse<SendMessageResponse>(request);
 }