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