public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", "options", Route = null)] HttpRequest req, [StorageAccount("StorageConnectionString")] CloudStorageAccount storageAccount, TraceWriter log ) { var email = req.Query["email"].FirstOrDefault()?.ToLower(); if (string.IsNullOrWhiteSpace(email)) { return(new BadRequestObjectResult("The query parameter \"email\" is empty or missing")); } log.Info($"E-mail verification request received for {email}"); var client = storageAccount.CreateCloudTableClient(); var throttleService = new ThrottleService(client, log); var throttled = (await throttleService.ThrottleOrIncrement(email)) || (await throttleService.ThrottleOrIncrement(IpUtility.GetClientIp(req))); if (throttled) { return(new StatusCodeResult(429)); } var code = $"{new Random().Next(100, 999)}{new Random().Next(100, 999)}{new Random().Next(100, 999)}"; var token = Guid.NewGuid().ToString().Replace("-", ""); var auth = new EmailAuthToken(email, token, code) { Expiration = DateTimeOffset.UtcNow.AddHours(4), }; var secret = Environment.GetEnvironmentVariable("email-secret", EnvironmentVariableTarget.Process); if (Upload(log, "http://grimdawn.dreamcrash.org/ia/backup/auth.php", $"token={secret}&target={email}&code={code}")) { var table = client.GetTableReference(EmailAuthToken.TableName); await table.CreateIfNotExistsAsync(); await table.ExecuteAsync(TableOperation.Insert(auth)); log.Info($"Successfully posted email for {email}"); } return(new OkObjectResult(new ResponseDto { Token = token })); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", "options", Route = null)] HttpRequest req, [StorageAccount("StorageConnectionString")] CloudStorageAccount storageAccount, TraceWriter log ) { var token = req.Query["token"]; var code = req.Query["code"]; var client = storageAccount.CreateCloudTableClient(); if (string.IsNullOrWhiteSpace(token)) { return(new BadRequestObjectResult("The query parameter \"token\" is empty or missing")); } else if (string.IsNullOrWhiteSpace(code)) { return(new BadRequestObjectResult("The query parameter \"code\" is empty or missing")); } log.Info($"E-mail verification request received for {token}"); // Throttling required for verification as well, to prevent infinite attempts on a token. var throttleService = new ThrottleService(storageAccount.CreateCloudTableClient(), log); var throttled = (await throttleService.ThrottleOrIncrement("attempt-" + token)) || (await throttleService.ThrottleOrIncrement("attempt-" + IpUtility.GetClientIp(req))); if (throttled) { return(new StatusCodeResult(429)); } var table = client.GetTableReference(EmailAuthToken.TableName); await table.CreateIfNotExistsAsync(); var query = TableQuery.CombineFilters( TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, token), TableOperators.And, TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, code) ); var exQuery = new TableQuery <EmailAuthToken>().Where(query); var entry = await QueryHelper.Get(table, exQuery); if (entry != null) { if (DateTimeOffset.UtcNow < entry.Expiration) { log.Info($"Authentication successful for {entry.Email}"); var auth = new Authentication { PartitionKey = Authentication.PartitionName, RowKey = (Guid.NewGuid().ToString() + Guid.NewGuid().ToString()).Replace("-", ""), Identity = entry.Email }; var authTable = client.GetTableReference(Authentication.TableName); await authTable.CreateIfNotExistsAsync(); await authTable.ExecuteAsync(TableOperation.Insert(auth)); return(new OkObjectResult(new VerifyEmailTokenResponseDto { Success = true, Token = auth.RowKey })); } else { log.Info($"Authentication token {token} for {entry.Email} has already expired, expiration {entry.Expiration}"); return(new OkObjectResult(new VerifyEmailTokenResponseDto { Success = false })); } } else { log.Info("No entry found"); return(new OkObjectResult(new VerifyEmailTokenResponseDto { Success = false })); } }