public async Task TestAddAccountAndSession()
        {
            await AsyncParallel.ForAsync(0, 100, async i =>
            {
                using IServiceScope scope = serviceProvider.CreateScope();
                var database = scope.ServiceProvider.GetRequiredService <DatabaseContext>();

                (var account, _, bool success) = await database
                                                 .AddAccount($"{SkynetRandom.String(10)}@example.com", Array.Empty <byte>()).ConfigureAwait(false);
                Assert.IsTrue(success);

                await AsyncParallel.ForAsync(0, 10, async j =>
                {
                    using IServiceScope scope = serviceProvider.CreateScope();
                    var database = scope.ServiceProvider.GetRequiredService <DatabaseContext>();

                    Session session = new Session()
                    {
                        AccountId             = account.AccountId,
                        SessionTokenHash      = SkynetRandom.Bytes(32), // No real hashes needed here
                        WebTokenHash          = SkynetRandom.Bytes(32),
                        ApplicationIdentifier = "windows/SkynetServer.Database.Tests"
                    };
                    await database.AddSession(session).ConfigureAwait(false);
                }).ConfigureAwait(false);
            }).ConfigureAwait(false);
        }
        public override async ValueTask Handle(P06CreateSession packet)
        {
            var response = Packets.New <P07CreateSessionResponse>();

            using var csp = SHA256.Create();
            byte[] passwordHash = csp.ComputeHash(packet.KeyHash);

            // As of RFC 5321 the local-part of an email address should not be case-sensitive.
            // EF Core converts the C# == operator to = in SQL which compares the contents of byte arrays
            var confirmation = await
                                   (from c in Database.MailConfirmations.AsQueryable().Where(c => c.MailAddress == packet.AccountName.ToLowerInvariant())
                                   join a in Database.Accounts.AsQueryable().Where(a => a.PasswordHash == passwordHash)
                                   on c.AccountId equals a.AccountId
                                   select c)
                               .SingleOrDefaultAsync().ConfigureAwait(false);

            if (confirmation == null)
            {
                response.StatusCode = CreateSessionStatus.InvalidCredentials;
                await Client.Send(response).ConfigureAwait(false);

                return;
            }
            if (confirmation.ConfirmationTime == default)
            {
                response.StatusCode = CreateSessionStatus.UnconfirmedAccount;
                await Client.Send(response).ConfigureAwait(false);

                return;
            }

            byte[] sessionToken     = SkynetRandom.Bytes(32);
            byte[] sessionTokenHash = csp.ComputeHash(sessionToken);
            string webToken         = SkynetRandom.String(30);

            byte[] webTokenHash = csp.ComputeHash(Encoding.UTF8.GetBytes(webToken));

            Session session = await Database.AddSession(new Session
            {
                AccountId             = confirmation.AccountId,
                SessionTokenHash      = sessionTokenHash,
                WebTokenHash          = webTokenHash,
                ApplicationIdentifier = Client.ApplicationIdentifier,
                LastConnected         = DateTime.Now,
                LastVersionCode       = Client.VersionCode,
                FcmToken = packet.FcmRegistrationToken
            }).ConfigureAwait(false);

            Message deviceList = await injector.CreateDeviceList(confirmation.AccountId).ConfigureAwait(false);

            Client.Authenticate(confirmation.AccountId, session.SessionId);

            response.StatusCode   = CreateSessionStatus.Success;
            response.AccountId    = session.AccountId;
            response.SessionId    = session.SessionId;
            response.SessionToken = sessionToken;
            response.WebToken     = webToken;
            await Client.Send(response).ConfigureAwait(false);

            await Delivery.StartSyncChannels(Client, new List <long>(), lastMessageId : default).ConfigureAwait(false);

            await Delivery.StartSendMessage(deviceList, null).ConfigureAwait(false);

            IClient old = connections.Add(Client);

            if (old != null)
            {
                _ = old.DisposeAsync(unregister: false);
            }
        }