public async Task <IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = "append/confirm")] HttpRequest req) { // Check that the data has been passed as JSON if (req.ContentType == null || !req.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) { // Incorrect Content-Type, bad request return(req.BadRequest("Content-Type must be application/json")); } string subscriptionId = req.Headers[SubscriptionIdHeaderKey].ToString(); if (string.IsNullOrEmpty(subscriptionId)) { return(req.BadRequest("Api-Subscription-Id header missing or invalid")); } Activity.Current?.AddTag("SubscriptionId", subscriptionId); try { PwnedPasswordsTransaction?data = await JsonSerializer.DeserializeAsync <PwnedPasswordsTransaction>(req.Body).ConfigureAwait(false); if (data != null && !string.IsNullOrEmpty(data.TransactionId)) { Activity.Current?.AddTag("TransactionId", data.TransactionId); if (await _tableStorage.ConfirmAppendDataAsync(subscriptionId, data)) { await _queueStorage.PushTransactionAsync(new QueueTransactionEntry { SubscriptionId = subscriptionId, TransactionId = data.TransactionId }); } return(new StatusCodeResult(StatusCodes.Status200OK)); } return(req.BadRequest("No content provided.")); } catch (ArgumentOutOfRangeException) // Thrown if transaction is not found. { return(new ContentResult { StatusCode = StatusCodes.Status404NotFound, Content = "TransactionId not found.", ContentType = "text/plain" }); } catch (ArgumentException) // Thrown if trying to confirm transaction multiple times as the same time { return(new ContentResult { StatusCode = StatusCodes.Status409Conflict, Content = "TransactionId is already being confirmed.", ContentType = "text/plain" }); } catch (InvalidOperationException) // Thrown for other errors { return(new ContentResult { StatusCode = StatusCodes.Status500InternalServerError, Content = "An error occurred.", ContentType = "text/plain" }); } catch (JsonException e) { // Error occurred trying to deserialize the JSON payload. _log.LogError(e, "Unable to parson JSON"); return(req.BadRequest($"Unable to parse JSON: {e.Message}")); } }
public async Task <IActionResult> RunAsync([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "range/{hashPrefix}")] HttpRequest req, string hashPrefix, CancellationToken cancellationToken = default) { if (!hashPrefix.IsHexStringOfLength(5)) { return(req.BadRequest("The hash format was not in a valid format")); } try { PwnedPasswordsFile entry = await _fileStorage.GetHashFileAsync(hashPrefix.ToUpper(), cancellationToken); return(new FileStreamResult(entry.Content, "text/plain") { LastModified = entry.LastModified }); } catch (FileNotFoundException) { return(req.NotFound()); } catch (Exception ex) { _log.LogError(ex, "Something went wrong."); return(req.InternalServerError()); } }
public async Task <IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = "append")] HttpRequest req) { // Check that the data has been passed as JSON if (req.ContentType == null || !req.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) { // Incorrect Content-Type, bad request return(req.BadRequest("Content-Type must be application/json")); } string subscriptionId = req.Headers[SubscriptionIdHeaderKey].ToString(); if (string.IsNullOrEmpty(subscriptionId)) { return(req.BadRequest("Api-Subscription-Id header missing or invalid")); } Activity.Current?.AddTag("SubscriptionId", subscriptionId); try { (bool Success, IActionResult? Error) = await req.TryValidateEntries(JsonSerializer.DeserializeAsyncEnumerable <PwnedPasswordsIngestionValue>(req.Body)); if (Success) { // Now insert the data req.Body.Seek(0, System.IO.SeekOrigin.Begin); PwnedPasswordsTransaction?transaction = await _tableStorage.InsertAppendDataAsync(subscriptionId).ConfigureAwait(false); await _fileStorage.StoreIngestionFileAsync(transaction.TransactionId, req.Body).ConfigureAwait(false); return(new OkObjectResult(transaction)); } #pragma warning disable CS8603 // Won't be null if Success=false. return(Error); #pragma warning restore CS8603 // Possible null reference return. } catch (JsonException e) { // Error occurred trying to deserialize the JSON payload. _log.LogError(e, "Unable to parse JSON for subscription {SubscriptionId}", subscriptionId); return(req.BadRequest($"Unable to parse JSON: {e.Message}")); } }
internal static async Task <(bool Success, IActionResult?Error)> TryValidateEntries(this HttpRequest req, IAsyncEnumerable <PwnedPasswordsIngestionValue?> entries) { // First validate the data if (entries == null) { // Json wasn't parsed from POST body, bad request return(false, req.BadRequest("Missing JSON body")); } int i = 0; await foreach (PwnedPasswordsIngestionValue? entry in entries) { i++; if (entry == null) { // Null item in the array, bad request return(false, req.BadRequest("Null PwnedPassword append entity at " + i)); } if (string.IsNullOrEmpty(entry.SHA1Hash)) { // Empty SHA-1 hash, bad request return(false, req.BadRequest("Missing SHA-1 hash for item at index " + i)); } if (!entry.SHA1Hash.IsStringSHA1Hash()) { // Invalid SHA-1 hash, bad request return(false, req.BadRequest("The SHA-1 hash was not in a valid format for item at index " + i)); } if (string.IsNullOrEmpty(entry.NTLMHash)) { // Empty NTLM hash, bad request return(false, req.BadRequest("Missing NTLM hash for item at index " + i)); } if (!entry.NTLMHash.IsStringNTLMHash()) { // Invalid NTLM hash, bad request return(false, req.BadRequest("The NTLM has was not in a valid format at index " + i)); } if (entry.Prevalence <= 0) { // Prevalence not set or invalid value, bad request return(false, req.BadRequest("Missing or invalid prevalence value for item at index " + i)); } } return(true, null); }