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)));
            }
        }
Example #2
0
            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)));
            }
        }
Example #4
0
        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
            }));
        }
Example #5
0
        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);
        }
Example #6
0
            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");
                }
            }