private void attach_Session(Session entity)
		{
			this.SendPropertyChanging();
			entity.Login = this;
		}
		private void detach_Session(Session entity)
		{
			this.SendPropertyChanging();
			entity.Login = null;
		}
		private void detach_Sessions(Session entity)
		{
			this.SendPropertyChanging();
			entity.Alias = null;
		}
 partial void DeleteSession(Session instance);
		private void attach_Sessions(Session entity)
		{
			this.SendPropertyChanging();
			entity.Alias = this;
		}
 partial void UpdateSession(Session instance);
 partial void InsertSession(Session instance);
        /// <summary>
        /// Finds associated active key for these credentials and then
        /// decrypts the envelope.
        /// </summary>
        /// <param name="machineInfo">Resultant Machine Information retrieved from envelope.</param>
        public static CheckInStatus CheckIn(string username, string password, byte[] encryptedEnvelope, out Session session)
        {
            using (var db = new CSSDataContext())
            {
                var succeeded   = false;
                session         = null;

                MachineInformation machineInfo = null;

                //Check if username/password is valid, and account is not banned/locked.
                Login login;
                LoginStatus loginStatus;
                if (Login.TryGetAuthenticatedLogin(db, username, password, out login, out loginStatus) == false)
                    return CheckInStatus.InvalidCredentials;

                //Find user's session
                var currentSession = login.FindCurrentSession();

                //If session is not found, envelope cannot be decrypted.
                if (currentSession == null)
                    return CheckInStatus.InvalidCredentials;

                try
                {
                    //Retrieve the machine information
                    var activeKey       = currentSession.ActiveKey;
                    var decryptedData   = Encryption.DecryptRSA(encryptedEnvelope, activeKey.RSACspBlob.ToArray());
                    machineInfo         = MachineInformation.Deserialize(decryptedData);

                    //Record machine info & match identities
                    bool wasMerged;
                    Identity identity;
                    Identity.MatchIdentity(db, login, machineInfo, out identity, out wasMerged);

                    if (login.Identity != identity)
                        login.Identity = identity;

                    if (VirtualMachineMarker.IsMachineInformationFromAVirtualMachine(db, machineInfo, login) == true)
                    {
                        if (Identity.CanUseVirtualMachine(db, login) == false)
                            return CheckInStatus.VirtualMachineBlocked;
                    }
                    else
                    {
                        if (login.AllowVirtualMachineLogin == false)
                            login.AllowVirtualMachineLogin = true;
                    }

                    //Check if black box has timed out
                    if (!currentSession.ValidateSessionTimeout())
                        return CheckInStatus.Timeout;
                    else //Otherwise, ensure session status is marked active
                        currentSession.SessionStatusType = SessionStatusEnum.Active;

                    //Verify the token is correct
                    if (machineInfo.Token != activeKey.Token)
                        return CheckInStatus.InvalidHash;

                    //Verify the login is not banned
                    if (login.IsBanned)
                        return CheckInStatus.InvalidCredentials;

                    //Check-in succeeded
                    if (currentSession.SessionStatusType == SessionStatusEnum.Active)
                    {
                        succeeded                       = true;
                        currentSession.DateLastCheckIn  = DateTime.Now;
                        session                         = currentSession;

                        if (wasMerged == true)
                            return CheckInStatus.AccountLinked;
                        else
                            return CheckInStatus.Ok;
                    }

                    return CheckInStatus.InvalidCredentials;
                }
                catch (Exception error)
                {
                    Error.Write(error);
                    return CheckInStatus.InvalidHash;
                }
                finally
                {
                    //If not successful, mark session closed.
                    if (!succeeded)
                        currentSession.SessionStatusType = SessionStatusEnum.Closed;

                    db.SubmitChanges();
                }
            }
        }
        /// <summary>
        /// Creates a new session for these credentials; with a status of
        /// pending verification.
        /// </summary>
        public static LoginStatus CreateSession(string ipAddress, string username, 
            string password, int? lobbyId, bool debugMode, ref string callsignWithTags, out byte[] blackBoxData)
        {
            using (var db = new CSSDataContext())
            {
                blackBoxData = null;

                Login login;
                LoginStatus loginStatus;
                if (Login.TryGetAuthenticatedLogin(db, username, password, out login, out loginStatus) == false)
                    return loginStatus;

                if (lobbyId != null)
                {
                    //Ensure that the user has permission to log into this lobby
                    var lobby = db.Lobbies.FirstOrDefault(p => p.Id == lobbyId.GetValueOrDefault(0));
                    if (lobby == null || !lobby.IsEnabled)
                        return LoginStatus.PermissionDenied;
                    else if (lobby.IsRestrictive && !login.Lobby_Logins.Any(p => p.LobbyId == lobbyId.GetValueOrDefault(0)))
                        return LoginStatus.PermissionDenied;
                }

                // Ensure that the alias is in the user's list of available callsigns.
                var validAliases = login.Identity.Logins.SelectMany(p => p.Aliases).OrderBy(p => p.DateCreated).Take(Alias.GetAliasLimit(db, login));
                if (validAliases.Select(p => p.Callsign).Contains(Alias.GetCallsignFromStringWithTokensAndTags(db, callsignWithTags)) == false)
                {
                    if (validAliases.Count() > 0)
                        callsignWithTags = validAliases.FirstOrDefault().Callsign;
                    else
                        return LoginStatus.InvalidCredentials;
                }

                //Ensure that the alias is available for login
                Alias alias;
                if(Alias.ValidateUsage(db, login, true, password, ref callsignWithTags, out alias) != CheckAliasResult.Registered)
                    return LoginStatus.InvalidCredentials;

                //Destroy any existing sessions for this account
                db.Sessions.DeleteAllOnSubmit(login.Sessions);

                //Retrieve a blackbox for this user, if none exists, create one.
                var firstAvailableKey = RetrieveUnusedKey(db, login);

                if (firstAvailableKey == null)
                    firstAvailableKey = Task.GenerateBlackbox(db, debugMode);

                var root        = ConfigurationManager.AppSettings["OutputRoot"];
                var path        = Path.Combine(root, firstAvailableKey.Filename);
                blackBoxData    = File.ReadAllBytes(path);

                //Create a record of the usage of this key.
                var usedKey = new UsedKey()
                {
                    Login       = login,
                    ActiveKey   = firstAvailableKey,
                    DateUsed    = DateTime.Now
                };
                db.UsedKeys.InsertOnSubmit(usedKey);

                //string ipAddress = string.Empty;
                //var context = OperationContext.Current;
                //if (context != null)
                //{
                //    var remoteEndPoint = context
                //        .IncomingMessageProperties.[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
                //    ipAddress = remoteEndPoint.Address;
                //}

                //Create a new session for this login
                login.Identity.DateLastLogin = DateTime.Now;
                var session = new Session()
                {
                    Login               = login,
                    Id                  = Guid.NewGuid(),
                    DateLastCheckIn     = DateTime.Now,
                    SessionStatusType   = SessionStatusEnum.PendingVerification,
                    ActiveKeyId         = firstAvailableKey.Id,
                    IPAddress           = ipAddress,
                    AliasId				= alias.Id
                };
                db.Sessions.InsertOnSubmit(session);

                // Add the identity's IP address to the log.
                var existingLogIP = db.LogIPs.FirstOrDefault(p => p.IdentityId == login.IdentityId && p.IPAddress == ipAddress);

                if (existingLogIP != null)
                {
                    existingLogIP.LastAccessed = DateTime.Now;
                }
                else
                {
                    existingLogIP = new LogIP()
                    {
                        LastAccessed = DateTime.Now,
                        IdentityId = login.IdentityId,
                        IPAddress = ipAddress
                    };

                    db.LogIPs.InsertOnSubmit(existingLogIP);
                }

                db.SubmitChanges();

                return LoginStatus.Authenticated;
            }
        }