Merge pull request #5 from wneessen/breaches

Code cleanup
This commit is contained in:
Winni Neessen 2021-09-22 15:50:40 +02:00 committed by GitHub
commit 62d46ba435
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 33 additions and 120 deletions

View file

@ -99,7 +99,7 @@ func (b *BreachApi) Breaches(options ...BreachOption) ([]*Breach, *http.Response
queryParams := b.setBreachOpts(options...) queryParams := b.setBreachOpts(options...)
apiUrl := fmt.Sprintf("%s/breaches", BaseUrl) apiUrl := fmt.Sprintf("%s/breaches", BaseUrl)
hb, hr, err := b.hibp.HttpReqBody(http.MethodGet, apiUrl, queryParams) hb, hr, err := b.hibp.HttpResBody(http.MethodGet, apiUrl, queryParams)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -121,7 +121,7 @@ func (b *BreachApi) BreachByName(n string, options ...BreachOption) (*Breach, *h
} }
apiUrl := fmt.Sprintf("%s/breach/%s", BaseUrl, n) apiUrl := fmt.Sprintf("%s/breach/%s", BaseUrl, n)
hb, hr, err := b.hibp.HttpReqBody(http.MethodGet, apiUrl, queryParams) hb, hr, err := b.hibp.HttpResBody(http.MethodGet, apiUrl, queryParams)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -138,7 +138,7 @@ func (b *BreachApi) BreachByName(n string, options ...BreachOption) (*Breach, *h
// with all registered data classes known to HIBP // with all registered data classes known to HIBP
func (b *BreachApi) DataClasses() ([]string, *http.Response, error) { func (b *BreachApi) DataClasses() ([]string, *http.Response, error) {
apiUrl := fmt.Sprintf("%s/dataclasses", BaseUrl) apiUrl := fmt.Sprintf("%s/dataclasses", BaseUrl)
hb, hr, err := b.hibp.HttpReqBody(http.MethodGet, apiUrl, nil) hb, hr, err := b.hibp.HttpResBody(http.MethodGet, apiUrl, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -160,7 +160,7 @@ func (b *BreachApi) BreachedAccount(a string, options ...BreachOption) ([]*Breac
} }
apiUrl := fmt.Sprintf("%s/breachedaccount/%s", BaseUrl, a) apiUrl := fmt.Sprintf("%s/breachedaccount/%s", BaseUrl, a)
hb, hr, err := b.hibp.HttpReqBody(http.MethodGet, apiUrl, queryParams) hb, hr, err := b.hibp.HttpResBody(http.MethodGet, apiUrl, queryParams)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View file

@ -9,11 +9,6 @@ import (
// TestBreaches tests the Breaches() method of the breaches API // TestBreaches tests the Breaches() method of the breaches API
func TestBreaches(t *testing.T) { func TestBreaches(t *testing.T) {
hc := New() hc := New()
if hc == nil {
t.Errorf("hibp client creation failed")
return
}
breachList, _, err := hc.BreachApi.Breaches() breachList, _, err := hc.BreachApi.Breaches()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -26,11 +21,6 @@ func TestBreaches(t *testing.T) {
// TestBreachesWithNil tests the Breaches() method of the breaches API with a nil option // TestBreachesWithNil tests the Breaches() method of the breaches API with a nil option
func TestBreachesWithNil(t *testing.T) { func TestBreachesWithNil(t *testing.T) {
hc := New() hc := New()
if hc == nil {
t.Errorf("hibp client creation failed")
return
}
breachList, _, err := hc.BreachApi.Breaches(nil) breachList, _, err := hc.BreachApi.Breaches(nil)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -52,11 +42,6 @@ func TestBreachesWithDomain(t *testing.T) {
} }
hc := New() hc := New()
if hc == nil {
t.Error("failed to create HIBP client")
return
}
for _, tc := range testTable { for _, tc := range testTable {
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
breachList, _, err := hc.BreachApi.Breaches(WithDomain(tc.domain)) breachList, _, err := hc.BreachApi.Breaches(WithDomain(tc.domain))
@ -96,11 +81,6 @@ func TestBreachesWithoutUnverified(t *testing.T) {
} }
hc := New() hc := New()
if hc == nil {
t.Error("failed to create HIBP client")
return
}
for _, tc := range testTable { for _, tc := range testTable {
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
breachList, _, err := hc.BreachApi.Breaches(WithDomain(tc.domain), WithoutUnverified()) breachList, _, err := hc.BreachApi.Breaches(WithDomain(tc.domain), WithoutUnverified())
@ -129,11 +109,6 @@ func TestBreachByName(t *testing.T) {
} }
hc := New() hc := New()
if hc == nil {
t.Error("failed to create HIBP client")
return
}
for _, tc := range testTable { for _, tc := range testTable {
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
breachDetails, _, err := hc.BreachApi.BreachByName(tc.breachName) breachDetails, _, err := hc.BreachApi.BreachByName(tc.breachName)
@ -156,11 +131,6 @@ func TestBreachByName(t *testing.T) {
// TestDataClasses tests the DataClasses() method of the breaches API // TestDataClasses tests the DataClasses() method of the breaches API
func TestDataClasses(t *testing.T) { func TestDataClasses(t *testing.T) {
hc := New() hc := New()
if hc == nil {
t.Errorf("hibp client creation failed")
return
}
classList, _, err := hc.BreachApi.DataClasses() classList, _, err := hc.BreachApi.DataClasses()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -190,11 +160,6 @@ func TestBreachedAccount(t *testing.T) {
t.SkipNow() t.SkipNow()
} }
hc := New(WithApiKey(apiKey)) hc := New(WithApiKey(apiKey))
if hc == nil {
t.Error("failed to create HIBP client")
return
}
for _, tc := range testTable { for _, tc := range testTable {
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
breachDetails, _, err := hc.BreachApi.BreachedAccount( breachDetails, _, err := hc.BreachApi.BreachedAccount(
@ -244,12 +209,7 @@ func TestBreachedAccountWithoutTruncate(t *testing.T) {
if apiKey == "" { if apiKey == "" {
t.SkipNow() t.SkipNow()
} }
hc := New(WithApiKey(apiKey), WithRateLimitNoFail()) hc := New(WithApiKey(apiKey), WithRateLimitSleep())
if hc == nil {
t.Error("failed to create HIBP client")
return
}
for _, tc := range testTable { for _, tc := range testTable {
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
breachDetails, _, err := hc.BreachApi.BreachedAccount( breachDetails, _, err := hc.BreachApi.BreachedAccount(

View file

@ -2,15 +2,11 @@ package main
import ( import (
"fmt" "fmt"
hibp "github.com/wneessen/go-hibp" "github.com/wneessen/go-hibp"
) )
func main() { func main() {
hc := hibp.New() hc := hibp.New()
if hc == nil {
panic("failed to create HIBP client")
}
bl, _, err := hc.BreachApi.Breaches() bl, _, err := hc.BreachApi.Breaches()
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -2,15 +2,11 @@ package main
import ( import (
"fmt" "fmt"
hibp "github.com/wneessen/go-hibp" "github.com/wneessen/go-hibp"
) )
func main() { func main() {
hc := hibp.New() hc := hibp.New()
if hc == nil {
panic("failed to create HIBP client")
}
bl, _, err := hc.BreachApi.Breaches() bl, _, err := hc.BreachApi.Breaches()
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -7,10 +7,6 @@ import (
func main() { func main() {
hc := hibp.New() hc := hibp.New()
if hc == nil {
panic("failed to create HIBP client")
}
bd, _, err := hc.BreachApi.BreachByName("Adobe") bd, _, err := hc.BreachApi.BreachByName("Adobe")
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -2,15 +2,11 @@ package main
import ( import (
"fmt" "fmt"
hibp "github.com/wneessen/go-hibp" "github.com/wneessen/go-hibp"
) )
func main() { func main() {
hc := hibp.New(hibp.WithPwnedPadding()) hc := hibp.New(hibp.WithPwnedPadding())
if hc == nil {
panic("failed to create HIBP client")
}
m, _, err := hc.PwnedPassApi.CheckPassword("test") m, _, err := hc.PwnedPassApi.CheckPassword("test")
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -2,15 +2,11 @@ package main
import ( import (
"fmt" "fmt"
hibp "github.com/wneessen/go-hibp" "github.com/wneessen/go-hibp"
) )
func main() { func main() {
hc := hibp.New() hc := hibp.New()
if hc == nil {
panic("failed to create HIBP client")
}
m, _, err := hc.PwnedPassApi.CheckPassword("test") m, _, err := hc.PwnedPassApi.CheckPassword("test")
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -2,15 +2,11 @@ package main
import ( import (
"fmt" "fmt"
hibp "github.com/wneessen/go-hibp" "github.com/wneessen/go-hibp"
) )
func main() { func main() {
hc := hibp.New() hc := hibp.New()
if hc == nil {
panic("failed to create HIBP client")
}
pwHash := "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3" // represents the PW: "test" pwHash := "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3" // represents the PW: "test"
m, _, err := hc.PwnedPassApi.CheckSHA1(pwHash) m, _, err := hc.PwnedPassApi.CheckSHA1(pwHash)
if err != nil { if err != nil {

39
hibp.go
View file

@ -12,7 +12,7 @@ import (
) )
// Version represents the version of this package // Version represents the version of this package
const Version = "0.1.4" const Version = "0.1.5"
// BaseUrl is the base URL for the majority of API calls // BaseUrl is the base URL for the majority of API calls
const BaseUrl = "https://haveibeenpwned.com/api/v3" const BaseUrl = "https://haveibeenpwned.com/api/v3"
@ -24,11 +24,14 @@ const DefaultUserAgent = `go-hibp v` + Version // + ` - https://github.com/wnees
// Client is the HIBP client object // Client is the HIBP client object
type Client struct { type Client struct {
hc *http.Client // HTTP client to perform the API requests hc *http.Client // HTTP client to perform the API requests
to time.Duration // HTTP client timeout to time.Duration // HTTP client timeout
ak string // HIBP API key ak string // HIBP API key
ua string // User agent string for the HTTP client ua string // User agent string for the HTTP client
rlNoFail bool // Controls wether the HTTP client should fail or sleep in case the rate limiting hits
// If set to true, the HTTP client will sleep instead of failing in case the HTTP 429
// rate limit hits a request
rlSleep bool
PwnedPassApi *PwnedPassApi // Reference to the PwnedPassApi API PwnedPassApi *PwnedPassApi // Reference to the PwnedPassApi API
PwnedPassApiOpts *PwnedPasswordOptions // Additional options for the PwnedPassApi API PwnedPassApiOpts *PwnedPasswordOptions // Additional options for the PwnedPassApi API
@ -40,8 +43,8 @@ type Client struct {
type Option func(*Client) type Option func(*Client)
// New creates and returns a new HIBP client object // New creates and returns a new HIBP client object
func New(options ...Option) *Client { func New(options ...Option) Client {
c := &Client{} c := Client{}
// Set defaults // Set defaults
c.to = time.Second * 5 c.to = time.Second * 5
@ -53,15 +56,15 @@ func New(options ...Option) *Client {
if opt == nil { if opt == nil {
continue continue
} }
opt(c) opt(&c)
} }
// Add a http client to the Client object // Add a http client to the Client object
c.hc = httpClient(c.to) c.hc = httpClient(c.to)
// Associate the different HIBP service APIs with the Client // Associate the different HIBP service APIs with the Client
c.PwnedPassApi = &PwnedPassApi{hibp: c} c.PwnedPassApi = &PwnedPassApi{hibp: &c}
c.BreachApi = &BreachApi{hibp: c} c.BreachApi = &BreachApi{hibp: &c}
return c return c
} }
@ -97,10 +100,10 @@ func WithUserAgent(a string) Option {
} }
} }
// WithRateLimitNoFail let's the HTTP client sleep in case the API rate limiting hits (Defaults to fail) // WithRateLimitSleep let's the HTTP client sleep in case the API rate limiting hits (Defaults to fail)
func WithRateLimitNoFail() Option { func WithRateLimitSleep() Option {
return func(c *Client) { return func(c *Client) {
c.rlNoFail = true c.rlSleep = true
} }
} }
@ -146,8 +149,8 @@ func (c *Client) HttpReq(m, p string, q map[string]string) (*http.Request, error
return hr, nil return hr, nil
} }
// HttpReqBody performs the API call to the given path and returns the response body as byte array // HttpResBody performs the API call to the given path and returns the response body as byte array
func (c *Client) HttpReqBody(m string, p string, q map[string]string) ([]byte, *http.Response, error) { func (c *Client) HttpResBody(m string, p string, q map[string]string) ([]byte, *http.Response, error) {
hreq, err := c.HttpReq(m, p, q) hreq, err := c.HttpReq(m, p, q)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -165,7 +168,7 @@ func (c *Client) HttpReqBody(m string, p string, q map[string]string) ([]byte, *
return nil, hr, err return nil, hr, err
} }
if hr.StatusCode == 429 && c.rlNoFail { if hr.StatusCode == 429 && c.rlSleep {
headerDelay := hr.Header.Get("Retry-After") headerDelay := hr.Header.Get("Retry-After")
delayTime, err := time.ParseDuration(headerDelay + "s") delayTime, err := time.ParseDuration(headerDelay + "s")
if err != nil { if err != nil {
@ -173,7 +176,7 @@ func (c *Client) HttpReqBody(m string, p string, q map[string]string) ([]byte, *
} }
log.Printf("API rate limit hit. Retrying request in %s", delayTime.String()) log.Printf("API rate limit hit. Retrying request in %s", delayTime.String())
time.Sleep(delayTime) time.Sleep(delayTime)
return c.HttpReqBody(m, p, q) return c.HttpResBody(m, p, q)
} }
if hr.StatusCode != 200 { if hr.StatusCode != 200 {

View file

@ -10,7 +10,7 @@ import (
// TestNew tests the New() function // TestNew tests the New() function
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
hc := New() hc := New()
if hc == nil { if *hc.PwnedPassApi.hibp != hc {
t.Errorf("hibp client creation failed") t.Errorf("hibp client creation failed")
} }
} }
@ -18,7 +18,7 @@ func TestNew(t *testing.T) {
// TestNewWithNil tests the New() function with a nil option // TestNewWithNil tests the New() function with a nil option
func TestNewWithNil(t *testing.T) { func TestNewWithNil(t *testing.T) {
hc := New(nil) hc := New(nil)
if hc == nil { if *hc.PwnedPassApi.hibp != hc {
t.Errorf("hibp client creation failed") t.Errorf("hibp client creation failed")
} }
} }
@ -26,10 +26,6 @@ func TestNewWithNil(t *testing.T) {
// TestNewWithHttpTimeout tests the New() function with the http timeout option // TestNewWithHttpTimeout tests the New() function with the http timeout option
func TestNewWithHttpTimeout(t *testing.T) { func TestNewWithHttpTimeout(t *testing.T) {
hc := New(WithHttpTimeout(time.Second * 10)) hc := New(WithHttpTimeout(time.Second * 10))
if hc == nil {
t.Errorf("hibp client creation failed")
return
}
if hc.to != time.Second*10 { if hc.to != time.Second*10 {
t.Errorf("hibp client timeout option was not set properly. Expected %d, got: %d", t.Errorf("hibp client timeout option was not set properly. Expected %d, got: %d",
time.Second*10, hc.to) time.Second*10, hc.to)
@ -39,10 +35,6 @@ func TestNewWithHttpTimeout(t *testing.T) {
// TestNewWithPwnedPadding tests the New() function with the PwnedPadding option // TestNewWithPwnedPadding tests the New() function with the PwnedPadding option
func TestNewWithPwnedPadding(t *testing.T) { func TestNewWithPwnedPadding(t *testing.T) {
hc := New(WithPwnedPadding()) hc := New(WithPwnedPadding())
if hc == nil {
t.Errorf("hibp client creation failed")
return
}
if !hc.PwnedPassApiOpts.WithPadding { if !hc.PwnedPassApiOpts.WithPadding {
t.Errorf("hibp client pwned padding option was not set properly. Expected %v, got: %v", t.Errorf("hibp client pwned padding option was not set properly. Expected %v, got: %v",
true, hc.PwnedPassApiOpts.WithPadding) true, hc.PwnedPassApiOpts.WithPadding)
@ -53,10 +45,6 @@ func TestNewWithPwnedPadding(t *testing.T) {
func TestNewWithApiKey(t *testing.T) { func TestNewWithApiKey(t *testing.T) {
apiKey := os.Getenv("HIBP_API_KEY") apiKey := os.Getenv("HIBP_API_KEY")
hc := New(WithApiKey(apiKey)) hc := New(WithApiKey(apiKey))
if hc == nil {
t.Errorf("hibp client creation failed")
return
}
if hc.ak != apiKey { if hc.ak != apiKey {
t.Errorf("hibp client API key was not set properly. Expected %s, got: %s", t.Errorf("hibp client API key was not set properly. Expected %s, got: %s",
apiKey, hc.ak) apiKey, hc.ak)
@ -66,10 +54,6 @@ func TestNewWithApiKey(t *testing.T) {
// TestNewWithUserAgent tests the New() function with a custom user agent // TestNewWithUserAgent tests the New() function with a custom user agent
func TestNewWithUserAgent(t *testing.T) { func TestNewWithUserAgent(t *testing.T) {
hc := New() hc := New()
if hc == nil {
t.Errorf("hibp client creation failed")
return
}
if hc.ua != DefaultUserAgent { if hc.ua != DefaultUserAgent {
t.Errorf("hibp client default user agent was not set properly. Expected %s, got: %s", t.Errorf("hibp client default user agent was not set properly. Expected %s, got: %s",
DefaultUserAgent, hc.ua) DefaultUserAgent, hc.ua)
@ -77,10 +61,6 @@ func TestNewWithUserAgent(t *testing.T) {
custUA := fmt.Sprintf("customUA v%s", Version) custUA := fmt.Sprintf("customUA v%s", Version)
hc = New(WithUserAgent(custUA)) hc = New(WithUserAgent(custUA))
if hc == nil {
t.Errorf("hibp client creation failed")
return
}
if hc.ua != custUA { if hc.ua != custUA {
t.Errorf("hibp client custom user agent was not set properly. Expected %s, got: %s", t.Errorf("hibp client custom user agent was not set properly. Expected %s, got: %s",
custUA, hc.ua) custUA, hc.ua)

View file

@ -16,7 +16,6 @@ func TestPwnedPasswordString(t *testing.T) {
"F/0Ws#.%{Z/NVax=OU8Ajf1qTRLNS12p/?s/adX", false}, "F/0Ws#.%{Z/NVax=OU8Ajf1qTRLNS12p/?s/adX", false},
} }
hc := New() hc := New()
for _, tc := range testTable { for _, tc := range testTable {
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
m, _, err := hc.PwnedPassApi.CheckPassword(tc.pwString) m, _, err := hc.PwnedPassApi.CheckPassword(tc.pwString)
@ -47,11 +46,6 @@ func TestPwnedPasswordHash(t *testing.T) {
"90efc095c82eab44e882fda507cfab1a2cd31fc0", false}, "90efc095c82eab44e882fda507cfab1a2cd31fc0", false},
} }
hc := New() hc := New()
if hc == nil {
t.Error("failed to create HIBP client")
return
}
for _, tc := range testTable { for _, tc := range testTable {
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
m, _, err := hc.PwnedPassApi.CheckSHA1(tc.pwHash) m, _, err := hc.PwnedPassApi.CheckSHA1(tc.pwHash)