public StatusResponse CancelChat(string sessionID, string recipientMSISDN)
        {
            ExecuteAndHandleExceptions(() =>
            {
                User senderUser = CheckUserSession(sessionID);

                CheckMSISDN(recipientMSISDN);
                User recipientUser = CheckIfUserIsOnline(recipientMSISDN);

                CryptoChatEntities context = new CryptoChatEntities();

                // Find the existing chat session between the users
                var existingChatSession =
                    (from s in context.ChatSessions
                     where (s.FromUserId == senderUser.UserId && s.ToUserId == recipientUser.UserId) ||
                        (s.FromUserId == recipientUser.UserId && s.ToUserId == senderUser.UserId)
                     select s).FirstOrDefault();

                if (existingChatSession == null)
                {
                    throw new ErrorResponseException(HttpStatusCode.NotFound,
                        "ERR_INVALID_STATE", "No active chat session exists between " +
                        senderUser.MSISDN + " and " + recipientUser.MSISDN + ".");
                }

                // Delete the chat session
                DeleteChatSession(senderUser, recipientUser);

                // Send a notification to the recipient user (through a message)
                SendMessage(senderUser, recipientUser, MessageType.MSG_CANCEL_CHAT, "Chat canceled");
            });
            return new StatusResponse();
        }
Esempio n. 2
0
        private void DeleteAllExpiredSessionsAndMessages()
        {
            CryptoChatEntities context = new CryptoChatEntities();

            DateTime minAllowedLastActivityTime =
                DateTime.Now.AddSeconds(-Settings.Default.HttpSessionTimeoutSeconds);

            // Delete any expired chat sessions in the DB
            string deleteChatSessionsSQL =
                "DELETE FROM ChatSessions " +
                "FROM Users u JOIN ChatSessions s " +
                "  ON (u.UserId = s.FromUserId or u.UserId = s.ToUserId) " +
                "WHERE LastActivity < {0}";
            context.ExecuteStoreCommand(deleteChatSessionsSQL,
                new object[] { minAllowedLastActivityTime });

            // Delete any expired messages in the DB
            string deleteMessagesSQL =
                "DELETE FROM Messages " +
                "FROM Users u JOIN Messages m ON (u.UserId = m.ToUserId) " +
                "WHERE LastActivity < {0}";
            context.ExecuteStoreCommand(deleteMessagesSQL,
                new object[] { minAllowedLastActivityTime });

            // Send notifications about all users whose sessions were expired
            var usersWithExpiredSession =
                from u in context.Users
                where u.LastActivity < minAllowedLastActivityTime &&
                    u.SessionKey != null
                select u;
            foreach (var user in usersWithExpiredSession)
            {
                user.SessionKey = null;
                MobileCryptoChatService.SendMessageToAllOnlineUsers(user,
                    MessageType.MSG_USER_OFFLINE, "User lost connection with the server.");
            }
            context.SaveChanges();
        }
        public MessageResponse GetNextMessage(string sessionID)
        {
            MessageResponse messageToReturn = null;
            ExecuteAndHandleExceptions(() =>
            {
                User user = CheckUserSession(sessionID);

                CryptoChatEntities context = new CryptoChatEntities();
                Message nextMsg =
                    (from m in context.Messages.Include("FromUser")
                    where m.ToUserId == user.UserId
                    orderby m.MsgDate
                    select m).FirstOrDefault();
                if (nextMsg != null)
                {
                    // A message is found --> return it as a result and delete it from DB
                    messageToReturn = new MessageResponse()
                    {
                        MsgType = nextMsg.MsgType,
                        MsgText = nextMsg.MsgText,
                        Msisdn = nextMsg.FromUser.MSISDN
                    };
                    context.DeleteObject(nextMsg);
                    context.SaveChanges();
                }
                else
                {
                    // No messages are waiting --> return MSG_NO_MESSAGES
                    messageToReturn = new MessageResponse()
                    {
                        MsgType = MessageType.MSG_NO_MESSAGES.ToString()
                    };
                }
            });

            return messageToReturn;
        }
        private void SendMessage(User senderUser, User recipientUser, 
			MessageType messageType, string msgText)
        {
            Message msg = new Message();
            msg.FromUserId = senderUser.UserId;
            msg.ToUserId = recipientUser.UserId;
            msg.MsgType = messageType.ToString();
            msg.MsgDate = DateTime.Now;
            msg.MsgText = msgText;
            CryptoChatEntities context = new CryptoChatEntities();
            context.Messages.AddObject(msg);
            context.SaveChanges();
        }
        private LoginResponse LoginUser(string msisdn, string authCode)
        {
            LoginResponse loginResult = null;
            ExecuteAndHandleExceptions(() =>
            {
                CheckMSISDN(msisdn);
                CheckAuthCode(authCode);

                // Check whether the MSISDN and authCode are correct
                CryptoChatEntities context = new CryptoChatEntities();
                var user =
                    (from u in context.Users
                     where u.MSISDN == msisdn && u.AuthCodeSHA1 == authCode
                     select u).FirstOrDefault();
                if (user == null)
                {
                    throw new ErrorResponseException(HttpStatusCode.Forbidden,
                        "ERR_INV_LOGIN", "Invalid MSISDN or password.");
                }

                // User found in the database -> perform login
                user.SessionKey = GenerateNewSessionKey(user.UserId);
                user.LastActivity = DateTime.Now;
                context.SaveChanges();

                // Delete all messages waiting at the server for the just logged user
                DeleteWaitingMessagesAndSessions(user);

                // Send the "user online" notification to all online users
                SendMessageToAllOnlineUsers(user,
                    MessageType.MSG_USER_ONLINE, "User logged in the system.");

                loginResult = new LoginResponse() { SessionID = user.SessionKey };
            });
            return loginResult;
        }
        private void DeleteWaitingMessagesAndSessions(User recipientUser)
        {
            CryptoChatEntities context = new CryptoChatEntities();

            // Delete any waiting messages for the user
            string deleteMessagesSQL = "DELETE FROM Messages WHERE ToUserId={0}";
            context.ExecuteStoreCommand(deleteMessagesSQL,
                new object[] { recipientUser.UserId });

            // Delete any existing chat sessions associated with the user
            string deleteChatSessionsSQL = "DELETE FROM ChatSessions WHERE " +
                "FromUserId={0} or ToUserId={0}";
            context.ExecuteStoreCommand(deleteChatSessionsSQL,
                new object[] { recipientUser.UserId });
        }
        private void DeleteChatSession(User senderUser, User recipientUser)
        {
            CryptoChatEntities context = new CryptoChatEntities();

            // Delete any existing chat sessions between the users
            string deleteChatSessionsSQL = "DELETE FROM ChatSessions WHERE " +
                "(FromUserId={0} and ToUserId={1}) or (FromUserId={1} and ToUserId={0})";
            context.ExecuteStoreCommand(deleteChatSessionsSQL,
                new object[] { senderUser.UserId, recipientUser.UserId });

            // Delete any waiting chat messages between the users
            string msgTypesToDelete =
                "'" + MessageType.MSG_CHALLENGE.ToString() + "'," +
                "'" + MessageType.MSG_RESPONSE.ToString() + "'," +
                "'" + MessageType.MSG_START_CHAT.ToString() + "'," +
                "'" + MessageType.MSG_CANCEL_CHAT.ToString() + "'," +
                "'" + MessageType.MSG_CHAT_MESSAGE.ToString() + "'";
            string deleteMessagesSQL = "DELETE FROM Messages WHERE " +
                "((FromUserId={0} and ToUserId={1}) or (FromUserId={1} and ToUserId={0})) AND " +
                "(MsgType in (" + msgTypesToDelete + "))";
            context.ExecuteStoreCommand(deleteMessagesSQL,
                new object[] { senderUser.UserId, recipientUser.UserId });
        }
        private User CheckUserSession(string sessionID)
        {
            CryptoChatEntities context = new CryptoChatEntities();
            DateTime minAllowedLastActivityTime =
                DateTime.Now.AddSeconds(-Settings.Default.HttpSessionTimeoutSeconds);
            var dbUser =
                (from u in context.Users
                    where u.SessionKey == sessionID &&
                    u.LastActivity >= minAllowedLastActivityTime
                    select u).FirstOrDefault();
            if (dbUser == null)
            {
                // The session is either too old or does not exist
                throw new ErrorResponseException(HttpStatusCode.Forbidden,
                    "ERR_SESSIONID", "Invalid sessionID.");
            }
            // The user session is valid -> update the last activity time
            dbUser.LastActivity = DateTime.Now;
            context.SaveChanges();

            return dbUser;
        }
 private User CheckIfUserIsOnline(string recipientMSISDN)
 {
     CryptoChatEntities context = new CryptoChatEntities();
     DateTime minAllowedLastActivityTime =
         DateTime.Now.AddSeconds(-Settings.Default.HttpSessionTimeoutSeconds);
     User user =
         (from u in context.Users
          where u.MSISDN == recipientMSISDN
          select u).FirstOrDefault();
     if (user == null)
     {
         throw new ErrorResponseException(HttpStatusCode.NotFound,
             "ERR_BAD_USER", "The specified user does not exists.");
     }
     if (user.LastActivity < minAllowedLastActivityTime)
     {
         throw new ErrorResponseException(HttpStatusCode.NotFound,
             "ERR_USER_OFF", "The specified user is offline.");
     }
     return user;
 }
        internal static void SendMessageToAllOnlineUsers(
			User senderUser, MessageType msgType, string msgText)
        {
            DateTime minAllowedLastActivityTime =
                DateTime.Now.AddSeconds(-Settings.Default.HttpSessionTimeoutSeconds);
            CryptoChatEntities context = new CryptoChatEntities();
            var allUserIds =
                from u in context.Users
                where u.LastActivity >= minAllowedLastActivityTime
                select u.UserId;
            foreach (var recipientUserId in allUserIds)
            {
                if (senderUser.UserId != recipientUserId)
                {
                    Message msg = new Message();
                    msg.FromUserId = senderUser.UserId;
                    msg.ToUserId = recipientUserId;
                    msg.MsgType = msgType.ToString();
                    msg.MsgText = msgText;
                    msg.MsgDate = DateTime.Now;
                    context.Messages.AddObject(msg);
                }
            }
            context.SaveChanges();
        }
        public StatusResponse StartChat(string sessionID, string recipientMSISDN)
        {
            ExecuteAndHandleExceptions(() =>
            {
                User senderUser = CheckUserSession(sessionID);

                CheckMSISDN(recipientMSISDN);
                User recipientUser = CheckIfUserIsOnline(recipientMSISDN);

                CryptoChatEntities context = new CryptoChatEntities();

                // Find the existing chat session between the users
                var existingChatSession =
                    (from s in context.ChatSessions
                     where s.FromUserId == senderUser.UserId && s.ToUserId == recipientUser.UserId
                     select s).FirstOrDefault();

                if (existingChatSession == null ||
                    existingChatSession.ChatState != ChatSessionState.RESPONSE_SENT.ToString())
                {
                    throw new ErrorResponseException(HttpStatusCode.NotFound,
                        "ERR_INVALID_STATE", "No accepted response exists from " +
                        recipientUser.MSISDN + " to " + senderUser.MSISDN + ".");
                }

                // Change the state of the chat session to "response sent"
                existingChatSession.ChatState = ChatSessionState.ACTIVE.ToString();
                context.SaveChanges();

                // Send a notification to the recipient user (through a message)
                SendMessage(senderUser, recipientUser, MessageType.MSG_START_CHAT, "Chat started");
            });
            return new StatusResponse();
        }
        public StatusResponse SendChatMessage(
			string sessionID, string recipientMSISDN, string encryptedMsg)
        {
            ExecuteAndHandleExceptions(() =>
            {
                User senderUser = CheckUserSession(sessionID);

                CheckMSISDN(recipientMSISDN);
                User recipientUser = CheckIfUserIsOnline(recipientMSISDN);
                CheckEncryptedMessage(encryptedMsg);

                CryptoChatEntities context = new CryptoChatEntities();

                // Find the existing chat session between the users
                var existingChatSession =
                    (from s in context.ChatSessions
                     where (s.FromUserId == senderUser.UserId && s.ToUserId == recipientUser.UserId) ||
                        (s.FromUserId == recipientUser.UserId && s.ToUserId == senderUser.UserId)
                     select s).FirstOrDefault();

                if (existingChatSession == null ||
                    existingChatSession.ChatState != ChatSessionState.ACTIVE.ToString())
                {
                    throw new ErrorResponseException(HttpStatusCode.NotFound,
                        "ERR_INVALID_STATE", "No active chat session exists between " +
                        senderUser.MSISDN + " and " + recipientUser.MSISDN + ".");
                }

                // Send the chat message to the recipient user
                SendMessage(senderUser, recipientUser, MessageType.MSG_CHAT_MESSAGE, encryptedMsg);
            });
            return new StatusResponse();
        }
        public LoginResponse RegisterNewUser(string msisdn, string authCode)
        {
            CheckMSISDN(msisdn);
            CheckAuthCode(authCode);
            LoginResponse loginResult = null;
            ExecuteAndHandleExceptions(() =>
            {
                // Register the user in the DB
                CryptoChatEntities context = new CryptoChatEntities();
                User user = new User();
                user.MSISDN = msisdn.ToLowerInvariant();
                user.AuthCodeSHA1 = authCode;
                context.Users.AddObject(user);
                context.SaveChanges();

                // Login the user into the system after the registration
                loginResult = LoginUser(msisdn, authCode);

                // Send the "user online" notification to all online users
                SendMessageToAllOnlineUsers(user,
                    MessageType.MSG_USER_ONLINE, "New user registered in the system.");
            });
            return loginResult;
        }
        public StatusResponse LogoutUser(string sessionID)
        {
            ExecuteAndHandleExceptions(() =>
            {
                User user = CheckUserSession(sessionID);

                CryptoChatEntities context = new CryptoChatEntities();
                int updatedSessionsCount = context.ExecuteStoreCommand(
                    "UPDATE Users SET SessionKey=null WHERE SessionKey={0}",
                    new object[] { sessionID });

                if (updatedSessionsCount != 1)
                {
                    throw new ErrorResponseException(HttpStatusCode.InternalServerError,
                        "ERR_LOGOUT_FAIL", "Logout failed unexpectedly.");
                }

                // Session sucessfully removed from DB (logout was successfull)
                DeleteWaitingMessagesAndSessions(user);

                // Send the "user online" notification to all online users
                SendMessageToAllOnlineUsers(user,
                    MessageType.MSG_USER_OFFLINE, "User left the system.");
            });
            return new StatusResponse();
        }
        public string[] ListUsers(string sessionID)
        {
            string[] allMSISDNs = null;
            ExecuteAndHandleExceptions(() =>
            {
                CheckUserSession(sessionID);

                DateTime minAllowedLastActivityTime =
                    DateTime.Now.AddSeconds(-Settings.Default.HttpSessionTimeoutSeconds);
                CryptoChatEntities context = new CryptoChatEntities();
                allMSISDNs =
                    (from u in context.Users
                     where u.LastActivity >= minAllowedLastActivityTime
                     orderby u.MSISDN
                     select u.MSISDN).ToArray();
            });
            return allMSISDNs;
        }
        public StatusResponse InviteUser(string sessionID, 
			string recipientMSISDN, string challenge)
        {
            ExecuteAndHandleExceptions(() =>
            {
                User senderUser = CheckUserSession(sessionID);

                CheckMSISDN(recipientMSISDN);
                User recipientUser = CheckIfUserIsOnline(recipientMSISDN);
                CheckChallengeCode(challenge);

                if (senderUser.UserId == recipientUser.UserId)
                {
                    throw new ErrorResponseException(HttpStatusCode.NotFound,
                        "ERR_AUTO_CHAT", "Users cannot send chat invitations to themselves.");
                }

                DeleteChatSession(senderUser, recipientUser);

                CryptoChatEntities context = new CryptoChatEntities();

                // Create a new chat session between the users
                ChatSession newChatSession = new ChatSession();
                newChatSession.FromUserId = senderUser.UserId;
                newChatSession.ToUserId = recipientUser.UserId;
                newChatSession.ChatState = ChatSessionState.CHALLENGE_SENT.ToString();
                context.ChatSessions.AddObject(newChatSession);
                context.SaveChanges();

                // Send the challenge to the recipient user (through a message)
                SendMessage(senderUser, recipientUser, MessageType.MSG_CHALLENGE, challenge);
            });
            return new StatusResponse();
        }