public async Task <IActionResult> Post(string token) { MailConfirmation confirmation = await ctx.MailConfirmations.AsTracking() .SingleOrDefaultAsync(x => x.Token == token).ConfigureAwait(false); if (confirmation == null) { return(View("Invalid")); } if (confirmation.ConfirmationTime == default) { // Remove confirmations that have become obsolete due to an address change // TODO: Add protocol interaction to inform clients about a suceeded address change ctx.MailConfirmations.RemoveRange( ctx.MailConfirmations.Where(c => c.AccountId == confirmation.AccountId && c.Token != token)); confirmation.ConfirmationTime = DateTime.Now; await ctx.SaveChangesAsync().ConfigureAwait(false); return(View("Success", new MailConfirmationViewModel(confirmation.MailAddress, token))); } else { return(View("Confirmed", new MailConfirmationViewModel(confirmation.MailAddress, token))); } }
private async Task <int> OnExecute(IConsole console, DatabaseContext database, ConfirmationMailService mailingService) { MailConfirmation confirmation = await database.MailConfirmations.SingleOrDefaultAsync(c => c.MailAddress == MailAddress).ConfigureAwait(false); if (confirmation != null) { console.Out.WriteLine("Sending confirmation mail..."); await mailingService.SendMailAsync(MailAddress, confirmation.Token).ConfigureAwait(false); return(0); } else { console.Out.WriteLine($"The AccountName {MailAddress} does not exist!"); return(1); } }
public async Task <IActionResult> Get(string token) { MailConfirmation confirmation = await ctx.MailConfirmations.SingleOrDefaultAsync(x => x.Token == token).ConfigureAwait(false); if (confirmation == null) { return(View("Invalid")); } if (confirmation.ConfirmationTime == default) { return(View("Pending", new MailConfirmationViewModel(confirmation.MailAddress, token))); } else { return(View("Confirmed", new MailConfirmationViewModel(confirmation.MailAddress, token))); } }
public async Task <IActionResult> Confirm(string token) { string status; string content; MailConfirmation confirmation = await ctx.MailConfirmations.AsTracking() .SingleOrDefaultAsync(x => x.Token == token).ConfigureAwait(false); if (confirmation == null) { status = "Invalid"; content = localizer["InvalidContent"]; } else if (confirmation.ConfirmationTime == default) { // Remove confirmations that have become obsolete due to an address change // TODO: Add protocol interaction to inform clients about a suceeded address change ctx.MailConfirmations.RemoveRange( ctx.MailConfirmations.Where(c => c.AccountId == confirmation.AccountId && c.Token != token)); confirmation.ConfirmationTime = DateTime.Now; await ctx.SaveChangesAsync().ConfigureAwait(false); status = "Success"; content = localizer["SuccessContent", confirmation.MailAddress]; } else { status = "Confirmed"; content = localizer["ConfirmedContent", confirmation.MailAddress]; } return(new ObjectResult(new ConfirmationResult { Title = localizer[status + "Title"], Header = localizer[status + "Header"], Content = content })); }
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); }
private async Task <int> OnExecute(IConsole console, DatabaseContext database) { MailConfirmation confirmation = await database.MailConfirmations.AsTracking() .SingleOrDefaultAsync(c => c.MailAddress == MailAddress).ConfigureAwait(false); if (confirmation != null) { if (confirmation.ConfirmationTime == default) { confirmation.ConfirmationTime = DateTime.Now; await database.SaveChangesAsync().ConfigureAwait(false); } else { console.Out.WriteLine($"The address {MailAddress} has already been confirmed on {confirmation.ConfirmationTime}"); } return(0); } else { console.Error.WriteLine($"There is no confirmation pending for {MailAddress}"); return(1); } }
private async Task OnExecute(IConsole console, IServiceProvider serviceProvider, DatabaseContext database) { bool empty = true; await foreach (Account account in database.Accounts .Include(a => a.MailConfirmations) .Include(a => a.OwnedChannels) .AsAsyncEnumerable()) { empty = false; MailConfirmation confirmation = account.MailConfirmations.OrderByDescending(c => c.ConfirmationTime).FirstOrDefault(); if (confirmation == null) { console.Out.WriteLine($"Account {account.AccountId:x8} is missing a MailConfirmation"); continue; } if (confirmation.ConfirmationTime == default) { console.Out.WriteLine($"Account {account.AccountId:x8} has not yet confirmed the address {confirmation.MailAddress}"); continue; } Channel SingeOrDefault(IEnumerable <Channel> channels, ChannelType type) { Channel[] value = channels.Where(c => c.ChannelType == type).ToArray(); if (value.Length == 0) { console.Out.WriteLine($"Account {confirmation.MailAddress} has no channel of type {type}"); return(null); } else if (value.Length == 1) { return(value[0]); } else { console.Out.WriteLine($"Account {confirmation.MailAddress} has mutiple channels of type {type}"); return(null); } } Channel loopback = SingeOrDefault(account.OwnedChannels, ChannelType.Loopback); Channel accountData = SingeOrDefault(account.OwnedChannels, ChannelType.AccountData); if (loopback == null || accountData == null) { continue; } using (IServiceScope scope = serviceProvider.CreateScope()) { var database2 = scope.ServiceProvider.GetRequiredService <DatabaseContext>(); bool privateKey = await database2.Messages.AsQueryable() .Where(m => m.ChannelId == loopback.ChannelId && m.SenderId == account.AccountId && m.PacketId == 0x17).AnyAsync() .ConfigureAwait(false); if (!privateKey) { console.Out.WriteLine($"Account {confirmation.MailAddress} is missing a private key"); } bool publicKey = await database2.Messages.AsQueryable() .Where(m => m.ChannelId == accountData.ChannelId && m.SenderId == account.AccountId && m.PacketId == 0x18).AnyAsync() .ConfigureAwait(false); if (!publicKey) { console.Out.WriteLine($"Account {confirmation.MailAddress} is missing a public key"); } if (!privateKey || !publicKey) { continue; } } console.Out.WriteLine($"Account {confirmation.MailAddress} is healthy"); } if (empty) { console.Out.WriteLine("No accounts found to audit"); } }