diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1941a8f --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +build: + docker build -t test-pwned-passwords -f test.Dockerfile . + +test: + docker run --volume=$(CURDIR):/go/pwned-passwords/ test-pwned-passwords go test diff --git a/hibp.go b/hibp.go index 7a20ae1..12ede18 100644 --- a/hibp.go +++ b/hibp.go @@ -103,8 +103,14 @@ func (c *Client) Do(req *http.Request) ([]string, error) { // Compromised will build and execute a request to HIBP to check to see if the passed value is compromised or not. func (c *Client) Compromised(value string) (bool, error) { + compromised, _, error := c.CompromisedCount(value) + return compromised, error +} + +// Compromised will build and execute a request to HIBP to check to see if the passed value is compromised or not. +func (c *Client) CompromisedCount(value string) (bool, int64, error) { if value == "" { - return false, errors.New("value for compromised check cannot be empty") + return false, 0, errors.New("value for compromised check cannot be empty") } hashedStr := hashString(value) @@ -113,12 +119,12 @@ func (c *Client) Compromised(value string) (bool, error) { request, err := c.NewRequest("GET", fmt.Sprintf("range/%s", prefix), nil) if err != nil { - return false, err + return false, 0, err } response, err := c.Do(request) if err != nil { - return false, err + return false, 0, err } for _, target := range response { @@ -127,15 +133,16 @@ func (c *Client) Compromised(value string) (bool, error) { } if target[:35] == suffix { - if _, err = strconv.ParseInt(target[36:], 10, 64); err != nil { - return false, err + var count int64 + if count, err = strconv.ParseInt(target[36:], 10, 64); err != nil { + return false, 0, err } - return true, err + return true, count, err } } - return false, err + return false, 0, err } // hashString will return a sha1 hash of the given value. diff --git a/hibp_test.go b/hibp_test.go index 4e92d8e..82ff3b9 100644 --- a/hibp_test.go +++ b/hibp_test.go @@ -46,6 +46,27 @@ func TestCompromisedHash(t *testing.T) { } } +// TestCompromisedCountHash will test a compromised value against the HIBP API. +func TestCompromisedCountHash(t *testing.T) { + // Register the test. + RegisterTestingT(t) + + client := NewClient() + + compromised, count, err := client.CompromisedCount("p@ssword") + if err != nil { + t.Fatalf("Unexpected error running client.Pwned.Compromised(): %s", err) + } + + if !compromised { + t.Fatalf("Expected compromised hash (p@ssword) to be true but got: %v", compromised) + } + + if count == 0 { + t.Fatalf("Expected compromised hash (p@ssword) to have been compromised at least once but got: %v", count) + } +} + // TestNonCompromisedHash will test a non-compromised value against the HIBP API. func TestNonCompromisedHash(t *testing.T) { // Register the test. @@ -66,6 +87,30 @@ func TestNonCompromisedHash(t *testing.T) { } } +// TestNonCompromisedCountHash will test a non-compromised value against the HIBP API. +func TestNonCompromisedCountHash(t *testing.T) { + // Register the test. + RegisterTestingT(t) + + client := NewClient() + + // Check if input is compromised. + value := fmt.Sprintf("SHOULD_NOT_BE_COMPROMISED_%s", time.Now().Format("2006-01-02 15:04:05")) + + compromised, count, err := client.CompromisedCount(value) + if err != nil { + t.Fatalf("Unexpected error running client.Pwned.Compromised(): %s", err) + } + + if compromised { + t.Fatalf("Expected non-compromised hash to be false but got: %v", compromised) + } + + if count != 0 { + t.Fatalf("Expected non-compromised hash to have been compromised exactly 0 times but got: %v", count) + } +} + func TestEmptyCompromisedHash(t *testing.T) { // Register the test. RegisterTestingT(t) @@ -86,3 +131,28 @@ func TestEmptyCompromisedHash(t *testing.T) { t.Fatalf("Expected empty compromised hash to be false but got: %v", compromised) } } + +func TestEmptyCompromisedCountHash(t *testing.T) { + // Register the test. + RegisterTestingT(t) + + client := NewClient() + + // Check if input is compromised. + compromised, count, err := client.CompromisedCount("") + if err == nil { + t.Fatal("Expected error when checking empty value, but got: nil") + } + + if err.Error() != "value for compromised check cannot be empty" { + t.Fatalf("Expected err to read 'value for compromised check cannot be empty' but got: '%v'", err) + } + + if compromised { + t.Fatalf("Expected empty compromised hash to be false but got: %v", compromised) + } + + if count != 0 { + t.Fatalf("Expected empty compromised hash to have been compromised exactly 0 times but got: %v", count) + } +} diff --git a/test.Dockerfile b/test.Dockerfile new file mode 100644 index 0000000..0d71bcf --- /dev/null +++ b/test.Dockerfile @@ -0,0 +1,7 @@ +FROM golang:1.13-buster + +COPY go.* ./pwned-passwords/ + +WORKDIR /go/pwned-passwords/ + +RUN go mod download