public async Task TestCreateMessage() { var serviceDescriptors = new ServiceCollection(); serviceDescriptors.AddSingleton <PacketService>(); serviceDescriptors.AddTestDatabaseContext($"{nameof(MessageInjectionServiceTests)}_{nameof(TestCreateMessage)}"); serviceDescriptors.AddScoped <MessageInjectionService>(); await using var serviceProvider = serviceDescriptors.BuildServiceProvider(); using IServiceScope scope = serviceProvider.CreateScope(); var packets = scope.ServiceProvider.GetRequiredService <PacketService>(); var database = scope.ServiceProvider.GetRequiredService <DatabaseContext>(); var injector = scope.ServiceProvider.GetRequiredService <MessageInjectionService>(); var packet = packets.New <P14MailAddress>(); packet.MessageFlags = MessageFlags.Unencrypted; packet.MailAddress = "*****@*****.**"; long channelId = SkynetRandom.Id(); long accountId = SkynetRandom.Id(); await injector.CreateMessage(packet, channelId, accountId).ConfigureAwait(false); Message message = await database.Messages.SingleAsync().ConfigureAwait(false); Assert.AreEqual(channelId, message.ChannelId); Assert.AreEqual(accountId, message.SenderId); Assert.AreEqual(MessageFlags.Unencrypted, message.MessageFlags); }
public async Task PrepareTest() { serviceProvider = FakeServiceProvider.Create($"{nameof(DeliveryServiceTests)}_{TestContext.TestName}"); scope = serviceProvider.CreateScope(); connections = scope.ServiceProvider.GetRequiredService <ConnectionsService>(); packets = scope.ServiceProvider.GetRequiredService <PacketService>(); database = scope.ServiceProvider.GetRequiredService <DatabaseContext>(); delivery = scope.ServiceProvider.GetRequiredService <DeliveryService>(); database.Accounts.Add(new Account { AccountId = alice }); database.MailConfirmations.Add(new MailConfirmation { AccountId = alice, MailAddress = "*****@*****.**", Token = SkynetRandom.String(10) }); database.Accounts.Add(new Account { AccountId = bob }); database.MailConfirmations.Add(new MailConfirmation { AccountId = bob, MailAddress = "*****@*****.**", Token = SkynetRandom.String(10) }); database.Accounts.Add(new Account { AccountId = charlie }); database.MailConfirmations.Add(new MailConfirmation { AccountId = charlie, MailAddress = "*****@*****.**", Token = SkynetRandom.String(10) }); await database.SaveChangesAsync().ConfigureAwait(false); }
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 async Task <Channel> AddChannel(Channel channel, params ChannelMember[] members) { bool saved = false; do { try { long id = SkynetRandom.Id(); channel.ChannelId = id; Channels.Add(channel); foreach (ChannelMember member in members) { member.ChannelId = id; } ChannelMembers.AddRange(members); await SaveChangesAsync().ConfigureAwait(false); saved = true; } catch (DbUpdateException ex) when(ex?.InnerException is MySqlException mex && mex.Number == 1062) { } } while (!saved); return(channel); } #endregion }
public async Task TestAddAccount() { await AsyncParallel.ForAsync(0, 500, async i => { using IServiceScope scope = serviceProvider.CreateScope(); var database = scope.ServiceProvider.GetRequiredService <DatabaseContext>(); (_, _, bool success) = await database.AddAccount($"{SkynetRandom.String(10)}@example.com", Array.Empty <byte>()).ConfigureAwait(false); Assert.IsTrue(success); }).ConfigureAwait(false); }
public async Task TestAddChannelWithOwner() { await AsyncParallel.ForAsync(0, 50, 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); Channel channel = new Channel() { OwnerId = account.AccountId, ChannelType = ChannelType.Loopback }; await database.AddChannel(channel).ConfigureAwait(false); }).ConfigureAwait(false); }
public async Task <Session> AddSession(Session session) { bool saved = false; do { try { long id = SkynetRandom.Id(); session.SessionId = id; Sessions.Add(session); await SaveChangesAsync().ConfigureAwait(false); saved = true; } catch (DbUpdateException ex) when(ex?.InnerException is MySqlException mex && mex.Number == 1062) { } } while (!saved); return(session); }
public async Task <(Account, MailConfirmation, bool)> AddAccount(string mailAddress, byte[] passwordHash) { Account account = new Account { PasswordHash = passwordHash }; MailConfirmation confirmation = new MailConfirmation { Account = account, MailAddress = mailAddress }; bool saved = false; do { try { long id = SkynetRandom.Id(); string token = SkynetRandom.String(10); account.AccountId = id; confirmation.Token = token; Accounts.Add(account); MailConfirmations.Add(confirmation); await SaveChangesAsync().ConfigureAwait(false); saved = true; } catch (DbUpdateException ex) when(ex?.InnerException is MySqlException mex && mex.Number == 1062) { // Return false if unique constraint violation is caused by the mail address // An example for mex.Message is "Duplicate entry '*****@*****.**' for key 'PRIMARY'" if (mex.Message.Contains('@', StringComparison.Ordinal)) { return(null, null, false); } } } while (!saved); return(account, confirmation, true); }
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); } }
private async Task OnExecute(IConsole console, IServiceProvider provider) { long accountId, channelId; Stopwatch stopwatch = new Stopwatch(); using (IServiceScope scope = provider.CreateScope()) { DatabaseContext database = scope.ServiceProvider.GetRequiredService <DatabaseContext>(); (var account, var confirmation, bool success) = await database .AddAccount($"{SkynetRandom.String(10)}@example.com", Array.Empty <byte>()).ConfigureAwait(false); accountId = account.AccountId; console.Out.WriteLine($"Created account {confirmation.MailAddress} with ID {accountId}"); console.Out.WriteLine($"Created mail confirmation for {confirmation.MailAddress} with token {confirmation.Token}"); } using (IServiceScope scope = provider.CreateScope()) { DatabaseContext database = scope.ServiceProvider.GetRequiredService <DatabaseContext>(); Channel channel = await database.AddChannel(new Channel() { OwnerId = accountId }).ConfigureAwait(false); channelId = channel.ChannelId; console.Out.WriteLine($"Created channel {channelId} with owner {accountId}"); } if (AccountCount > 0) { console.Out.WriteLine($"Inserting {AccountCount} accounts..."); stopwatch.Start(); await AsyncParallel.ForAsync(0, AccountCount, async i => { using IServiceScope scope = provider.CreateScope(); DatabaseContext ctx = scope.ServiceProvider.GetRequiredService <DatabaseContext>(); await ctx.AddAccount($"{SkynetRandom.String(10)}@example.com", Array.Empty <byte>()).ConfigureAwait(false); }).ConfigureAwait(false); stopwatch.Stop(); console.Out.WriteLine($"Finished saving {AccountCount} accounts after {stopwatch.ElapsedMilliseconds}ms"); stopwatch.Reset(); } if (MessageCount > 0) { console.Out.WriteLine($"Inserting {MessageCount} messages to channel {channelId}..."); stopwatch.Start(); await AsyncParallel.ForAsync(0, MessageCount, async i => { using IServiceScope scope = provider.CreateScope(); DatabaseContext database = scope.ServiceProvider.GetRequiredService <DatabaseContext>(); Message entity = new Message { ChannelId = channelId, SenderId = accountId }; database.Messages.Add(entity); await database.SaveChangesAsync().ConfigureAwait(false); }).ConfigureAwait(false); stopwatch.Stop(); console.Out.WriteLine($"Finished saving {MessageCount} messages after {stopwatch.ElapsedMilliseconds}ms"); stopwatch.Reset(); } }