From 20ebd4c965de88879bb53f482b0d8acd29d80466 Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Sat, 29 Oct 2022 15:32:12 +0200 Subject: [PATCH] Implement a golangci-lint workflow and the accordingly GH action --- .github/workflows/golangci-lint.yml | 49 +++++++++++++++++ .golangci.toml | 11 ++++ breach.go | 54 +++++++++---------- breach_test.go | 82 ++++++++++++++++------------- hibp.go | 44 ++++++++-------- hibp_test.go | 12 ++--- password.go | 16 +++--- password_test.go | 80 +++++++++++++++------------- paste.go | 14 ++--- paste_test.go | 12 ++--- 10 files changed, 225 insertions(+), 149 deletions(-) create mode 100644 .github/workflows/golangci-lint.yml create mode 100644 .golangci.toml diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 0000000..2d0a327 --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,49 @@ +# SPDX-FileCopyrightText: 2022 Winni Neessen +# +# SPDX-License-Identifier: CC0-1.0 + +name: golangci-lint +on: + push: + tags: + - v* + branches: + - main + pull_request: +permissions: + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + # pull-requests: read +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v3 + with: + go-version: 1.19 + - uses: actions/checkout@v3 + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version + version: latest + + # Optional: working directory, useful for monorepos + # working-directory: somedir + + # Optional: golangci-lint command line arguments. + # args: --issues-exit-code=0 + + # Optional: show only new issues if it's a pull request. The default value is `false`. + # only-new-issues: true + + # Optional: if set to true then the all caching functionality will be complete disabled, + # takes precedence over all other caching options. + # skip-cache: true + + # Optional: if set to true then the action don't cache or restore ~/go/pkg. + # skip-pkg-cache: true + + # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. + # skip-build-cache: true diff --git a/.golangci.toml b/.golangci.toml new file mode 100644 index 0000000..7d1b888 --- /dev/null +++ b/.golangci.toml @@ -0,0 +1,11 @@ +## SPDX-FileCopyrightText: 2022 Winni Neessen +## +## SPDX-License-Identifier: MIT + +[run] +go = "1.16" +tests = true + +[linters] +enable = ["stylecheck", "whitespace", "containedctx", "contextcheck", "decorder", + "errname", "errorlint", "gofmt", "gofumpt"] \ No newline at end of file diff --git a/breach.go b/breach.go index cecfb76..962b030 100644 --- a/breach.go +++ b/breach.go @@ -8,8 +8,8 @@ import ( "time" ) -// BreachApi is a HIBP breaches API client -type BreachApi struct { +// BreachAPI is a HIBP breaches API client +type BreachAPI struct { hibp *Client // References back to the parent HIBP client domain string // Filter for a specific breach domain @@ -37,7 +37,7 @@ type Breach struct { // BreachDate is the date (with no time) the breach originally occurred on in ISO 8601 format. This is not // always accurate — frequently breaches are discovered and reported long after the original incident. Use // this attribute as a guide only - BreachDate *ApiDate `json:"BreachDate,omitempty"` + BreachDate *APIDate `json:"BreachDate,omitempty"` // AddedDate represents the date and time (precision to the minute) the breach was added to the system // in ISO 8601 format @@ -89,17 +89,17 @@ type Breach struct { } // BreachOption is an additional option the can be set for the BreachApiClient -type BreachOption func(*BreachApi) +type BreachOption func(*BreachAPI) -// ApiDate is a date string without time returned by the API represented as time.Time type -type ApiDate time.Time +// APIDate is a date string without time returned by the API represented as time.Time type +type APIDate time.Time // Breaches returns a list of all breaches in the HIBP system -func (b *BreachApi) Breaches(options ...BreachOption) ([]*Breach, *http.Response, error) { +func (b *BreachAPI) Breaches(options ...BreachOption) ([]*Breach, *http.Response, error) { queryParams := b.setBreachOpts(options...) - apiUrl := fmt.Sprintf("%s/breaches", BaseUrl) + apiURL := fmt.Sprintf("%s/breaches", BaseURL) - hb, hr, err := b.hibp.HttpResBody(http.MethodGet, apiUrl, queryParams) + hb, hr, err := b.hibp.HTTPResBody(http.MethodGet, apiURL, queryParams) if err != nil { return nil, nil, err } @@ -113,15 +113,15 @@ func (b *BreachApi) Breaches(options ...BreachOption) ([]*Breach, *http.Response } // BreachByName returns a single breached site based on its name -func (b *BreachApi) BreachByName(n string, options ...BreachOption) (*Breach, *http.Response, error) { +func (b *BreachAPI) BreachByName(n string, options ...BreachOption) (*Breach, *http.Response, error) { queryParams := b.setBreachOpts(options...) if n == "" { return nil, nil, fmt.Errorf("no breach name given") } - apiUrl := fmt.Sprintf("%s/breach/%s", BaseUrl, n) - hb, hr, err := b.hibp.HttpResBody(http.MethodGet, apiUrl, queryParams) + apiURL := fmt.Sprintf("%s/breach/%s", BaseURL, n) + hb, hr, err := b.hibp.HTTPResBody(http.MethodGet, apiURL, queryParams) if err != nil { return nil, nil, err } @@ -136,9 +136,9 @@ func (b *BreachApi) BreachByName(n string, options ...BreachOption) (*Breach, *h // DataClasses are attribute of a record compromised in a breach. This method returns a list of strings // with all registered data classes known to HIBP -func (b *BreachApi) DataClasses() ([]string, *http.Response, error) { - apiUrl := fmt.Sprintf("%s/dataclasses", BaseUrl) - hb, hr, err := b.hibp.HttpResBody(http.MethodGet, apiUrl, nil) +func (b *BreachAPI) DataClasses() ([]string, *http.Response, error) { + apiURL := fmt.Sprintf("%s/dataclasses", BaseURL) + hb, hr, err := b.hibp.HTTPResBody(http.MethodGet, apiURL, nil) if err != nil { return nil, nil, err } @@ -152,15 +152,15 @@ func (b *BreachApi) DataClasses() ([]string, *http.Response, error) { } // BreachedAccount returns a single breached site based on its name -func (b *BreachApi) BreachedAccount(a string, options ...BreachOption) ([]*Breach, *http.Response, error) { +func (b *BreachAPI) BreachedAccount(a string, options ...BreachOption) ([]*Breach, *http.Response, error) { queryParams := b.setBreachOpts(options...) if a == "" { return nil, nil, fmt.Errorf("no account id given") } - apiUrl := fmt.Sprintf("%s/breachedaccount/%s", BaseUrl, a) - hb, hr, err := b.hibp.HttpResBody(http.MethodGet, apiUrl, queryParams) + apiURL := fmt.Sprintf("%s/breachedaccount/%s", BaseURL, a) + hb, hr, err := b.hibp.HTTPResBody(http.MethodGet, apiURL, queryParams) if err != nil { return nil, nil, err } @@ -175,7 +175,7 @@ func (b *BreachApi) BreachedAccount(a string, options ...BreachOption) ([]*Breac // WithDomain sets the domain filter for the breaches API func WithDomain(d string) BreachOption { - return func(b *BreachApi) { + return func(b *BreachAPI) { b.domain = d } } @@ -183,20 +183,20 @@ func WithDomain(d string) BreachOption { // WithoutTruncate disables the truncateResponse parameter in the breaches API // This option only influences the BreachedAccount method func WithoutTruncate() BreachOption { - return func(b *BreachApi) { + return func(b *BreachAPI) { b.disableTrunc = true } } // WithoutUnverified suppress unverified breaches from the query func WithoutUnverified() BreachOption { - return func(b *BreachApi) { + return func(b *BreachAPI) { b.noUnverified = true } } -// UnmarshalJSON for the ApiDate type converts a give date string into a time.Time type -func (d *ApiDate) UnmarshalJSON(s []byte) error { +// UnmarshalJSON for the APIDate type converts a give date string into a time.Time type +func (d *APIDate) UnmarshalJSON(s []byte) error { ds := string(s) ds = strings.ReplaceAll(ds, `"`, ``) if ds == "null" { @@ -205,21 +205,21 @@ func (d *ApiDate) UnmarshalJSON(s []byte) error { pd, err := time.Parse("2006-01-02", ds) if err != nil { - return fmt.Errorf("failed to convert API date string to time.Time type: %s", err) + return fmt.Errorf("failed to convert API date string to time.Time type: %w", err) } *(*time.Time)(d) = pd return nil } -// Time adds a Time() method to the ApiDate converted time.Time type -func (d *ApiDate) Time() time.Time { +// Time adds a Time() method to the APIDate converted time.Time type +func (d *APIDate) Time() time.Time { dp := *d return time.Time(dp) } // setBreachOpts returns a map of default settings and overridden values from different BreachOption -func (b *BreachApi) setBreachOpts(options ...BreachOption) map[string]string { +func (b *BreachAPI) setBreachOpts(options ...BreachOption) map[string]string { queryParams := map[string]string{ "truncateResponse": "true", "includeUnverified": "true", diff --git a/breach_test.go b/breach_test.go index 554e02b..0cc2783 100644 --- a/breach_test.go +++ b/breach_test.go @@ -17,7 +17,7 @@ const ( // TestBreaches tests the Breaches() method of the breaches API func TestBreaches(t *testing.T) { hc := New() - breachList, _, err := hc.BreachApi.Breaches() + breachList, _, err := hc.BreachAPI.Breaches() if err != nil { t.Error(err) } @@ -29,7 +29,7 @@ func TestBreaches(t *testing.T) { // TestBreachesWithNil tests the Breaches() method of the breaches API with a nil option func TestBreachesWithNil(t *testing.T) { hc := New() - breachList, _, err := hc.BreachApi.Breaches(nil) + breachList, _, err := hc.BreachAPI.Breaches(nil) if err != nil { t.Error(err) } @@ -52,7 +52,7 @@ func TestBreachesWithDomain(t *testing.T) { hc := New(WithRateLimitSleep()) for _, tc := range testTable { t.Run(tc.testName, func(t *testing.T) { - breachList, _, err := hc.BreachApi.Breaches(WithDomain(tc.domain)) + breachList, _, err := hc.BreachAPI.Breaches(WithDomain(tc.domain)) if err != nil { t.Error(err) } @@ -91,7 +91,7 @@ func TestBreachesWithoutUnverified(t *testing.T) { hc := New(WithRateLimitSleep()) for _, tc := range testTable { 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()) if err != nil { t.Error(err) } @@ -119,7 +119,7 @@ func TestBreachByName(t *testing.T) { hc := New(WithRateLimitSleep()) for _, tc := range testTable { t.Run(tc.testName, func(t *testing.T) { - breachDetails, _, err := hc.BreachApi.BreachByName(tc.breachName) + breachDetails, _, err := hc.BreachAPI.BreachByName(tc.breachName) if err != nil && !tc.shouldFail { t.Error(err) } @@ -139,7 +139,7 @@ func TestBreachByName(t *testing.T) { // TestDataClasses tests the DataClasses() method of the breaches API func TestDataClasses(t *testing.T) { hc := New() - classList, _, err := hc.BreachApi.DataClasses() + classList, _, err := hc.BreachAPI.DataClasses() if err != nil { t.Error(err) } @@ -156,10 +156,14 @@ func TestBreachedAccount(t *testing.T) { isBreached bool moreThanOneBreach bool }{ - {"account-exists is breached once", "account-exists", true, - false}, - {"multiple-breaches is breached multiple times", "multiple-breaches", - true, true}, + { + "account-exists is breached once", "account-exists", true, + false, + }, + { + "multiple-breaches is breached multiple times", "multiple-breaches", + true, true, + }, {"opt-out is not breached", "opt-out", false, false}, } @@ -167,10 +171,10 @@ func TestBreachedAccount(t *testing.T) { if apiKey == "" { t.SkipNow() } - hc := New(WithApiKey(apiKey), WithRateLimitSleep()) + hc := New(WithAPIKey(apiKey), WithRateLimitSleep()) for _, tc := range testTable { t.Run(tc.testName, func(t *testing.T) { - breachDetails, _, err := hc.BreachApi.BreachedAccount( + breachDetails, _, err := hc.BreachAPI.BreachedAccount( fmt.Sprintf("%s@hibp-integration-tests.com", tc.accountName)) if err != nil && tc.isBreached { t.Error(err) @@ -206,10 +210,14 @@ func TestBreachedAccountWithoutTruncate(t *testing.T) { breachDomain string shouldFail bool }{ - {"account-exists is breached once", "account-exists@hibp-integration-tests.com", "Adobe", - "adobe.com", false}, - {"multiple-breaches is breached multiple times", "multiple-breaches@hibp-integration-tests.com", "Adobe", - "adobe.com", false}, + { + "account-exists is breached once", "account-exists@hibp-integration-tests.com", "Adobe", + "adobe.com", false, + }, + { + "multiple-breaches is breached multiple times", "multiple-breaches@hibp-integration-tests.com", "Adobe", + "adobe.com", false, + }, {"opt-out is not breached", "opt-out@hibp-integration-tests.com", "", "", true}, {"empty string should fail", "", "", "", true}, } @@ -218,10 +226,10 @@ func TestBreachedAccountWithoutTruncate(t *testing.T) { if apiKey == "" { t.SkipNow() } - hc := New(WithApiKey(apiKey), WithRateLimitSleep()) + hc := New(WithAPIKey(apiKey), WithRateLimitSleep()) for _, tc := range testTable { t.Run(tc.testName, func(t *testing.T) { - breachDetails, _, err := hc.BreachApi.BreachedAccount(tc.accountName, WithoutTruncate()) + breachDetails, _, err := hc.BreachAPI.BreachedAccount(tc.accountName, WithoutTruncate()) if err != nil && !tc.shouldFail { t.Error(err) return @@ -246,10 +254,10 @@ func TestBreachedAccountWithoutTruncate(t *testing.T) { } } -// TestApiDate_UnmarshalJSON_Time tests the ApiDate type JSON unmarshalling -func TestApiDate_UnmarshalJSON_Time(t *testing.T) { +// TestAPIDate_UnmarshalJSON_Time tests the APIDate type JSON unmarshalling +func TestAPIDate_UnmarshalJSON_Time(t *testing.T) { type testData struct { - Date *ApiDate `json:"date"` + Date *APIDate `json:"date"` } tt := []struct { n string @@ -271,24 +279,24 @@ func TestApiDate_UnmarshalJSON_Time(t *testing.T) { t.Errorf("failed to unmarshal test JSON: %s", err) } if td.Date == nil && !tc.nil { - t.Errorf("unmarshal on ApiDate type failed. Expected data but got nil") + t.Errorf("unmarshal on APIDate type failed. Expected data but got nil") return } if !tc.nil { tdd := td.Date.Time().Format("2006-01-02") if tdd != tc.d && !tc.sf { - t.Errorf(`unmarshal of ApiDate type failed. Expected: %q, got %q"`, tc.d, tdd) + t.Errorf(`unmarshal of APIDate type failed. Expected: %q, got %q"`, tc.d, tdd) } } }) } } -// ExampleBreachApi_Breaches_getAllBreaches is a code example to show how to fetch all breaches from the +// ExampleBreachAPI_Breaches_getAllBreaches is a code example to show how to fetch all breaches from the // HIBP breaches API -func ExampleBreachApi_Breaches_getAllBreaches() { +func ExampleBreachAPI_Breaches_getAllBreaches() { hc := New() - bl, _, err := hc.BreachApi.Breaches() + bl, _, err := hc.BreachAPI.Breaches() if err != nil { panic(err) } @@ -300,11 +308,11 @@ func ExampleBreachApi_Breaches_getAllBreaches() { } } -// ExampleBreachApi_Breaches_getAllBreachesNoUnverified is a code example to show how to fetch all breaches from the +// ExampleBreachAPI_Breaches_getAllBreachesNoUnverified is a code example to show how to fetch all breaches from the // HIBP breaches API but ignoring unverified breaches -func ExampleBreachApi_Breaches_getAllBreachesNoUnverified() { +func ExampleBreachAPI_Breaches_getAllBreachesNoUnverified() { hc := New() - bl, _, err := hc.BreachApi.Breaches() + bl, _, err := hc.BreachAPI.Breaches() if err != nil { panic(err) } @@ -312,7 +320,7 @@ func ExampleBreachApi_Breaches_getAllBreachesNoUnverified() { fmt.Printf("Found %d breaches total.\n", len(bl)) } - bl, _, err = hc.BreachApi.Breaches(WithoutUnverified()) + bl, _, err = hc.BreachAPI.Breaches(WithoutUnverified()) if err != nil { panic(err) } @@ -321,11 +329,11 @@ func ExampleBreachApi_Breaches_getAllBreachesNoUnverified() { } } -// ExampleBreachApi_BreachByName is a code example to show how to fetch a specific breach +// ExampleBreachAPI_BreachByName is a code example to show how to fetch a specific breach // from the HIBP breaches API using the BreachByName method -func ExampleBreachApi_BreachByName() { +func ExampleBreachAPI_BreachByName() { hc := New() - bd, _, err := hc.BreachApi.BreachByName("Adobe") + bd, _, err := hc.BreachAPI.BreachByName("Adobe") if err != nil { panic(err) } @@ -337,15 +345,15 @@ func ExampleBreachApi_BreachByName() { } } -// ExampleBreachApi_BreachedAccount is a code example to show how to fetch a list of breaches +// ExampleBreachAPI_BreachedAccount is a code example to show how to fetch a list of breaches // for a specific site/account from the HIBP breaches API using the BreachedAccount method -func ExampleBreachApi_BreachedAccount() { +func ExampleBreachAPI_BreachedAccount() { apiKey := os.Getenv("HIBP_API_KEY") if apiKey == "" { panic("A API key is required for this API") } - hc := New(WithApiKey(apiKey)) - bd, _, err := hc.BreachApi.BreachedAccount("multiple-breaches@hibp-integration-tests.com") + hc := New(WithAPIKey(apiKey)) + bd, _, err := hc.BreachAPI.BreachedAccount("multiple-breaches@hibp-integration-tests.com") if err != nil { panic(err) } diff --git a/hibp.go b/hibp.go index 047522e..0e6626f 100644 --- a/hibp.go +++ b/hibp.go @@ -15,8 +15,8 @@ import ( // Version represents the version of this package const Version = "1.0.2" -// BaseUrl is the base URL for the majority of API calls -const BaseUrl = "https://haveibeenpwned.com/api/v3" +// BaseURL is the base URL for the majority of API calls +const BaseURL = "https://haveibeenpwned.com/api/v3" // DefaultUserAgent defines the default UA string for the HTTP client // Currently the URL in the UA string is comment out, as there is a bug in the HIBP API @@ -34,11 +34,11 @@ type Client struct { // rate limit hits a request rlSleep bool - PwnedPassApi *PwnedPassApi // Reference to the PwnedPassApi API - PwnedPassApiOpts *PwnedPasswordOptions // Additional options for the PwnedPassApi API + PwnedPassAPI *PwnedPassAPI // Reference to the PwnedPassAPI API + PwnedPassAPIOpts *PwnedPasswordOptions // Additional options for the PwnedPassAPI API - BreachApi *BreachApi // Reference to the BreachApi - PasteApi *PasteApi // Reference to the PasteApi + BreachAPI *BreachAPI // Reference to the BreachAPI + PasteAPI *PasteAPI // Reference to the PasteAPI } // Option is a function that is used for grouping of Client options. @@ -50,7 +50,7 @@ func New(options ...Option) Client { // Set defaults c.to = time.Second * 5 - c.PwnedPassApiOpts = &PwnedPasswordOptions{} + c.PwnedPassAPIOpts = &PwnedPasswordOptions{} c.ua = DefaultUserAgent // Set additional options @@ -65,22 +65,22 @@ func New(options ...Option) Client { c.hc = httpClient(c.to) // Associate the different HIBP service APIs with the Client - c.PwnedPassApi = &PwnedPassApi{hibp: &c} - c.BreachApi = &BreachApi{hibp: &c} - c.PasteApi = &PasteApi{hibp: &c} + c.PwnedPassAPI = &PwnedPassAPI{hibp: &c} + c.BreachAPI = &BreachAPI{hibp: &c} + c.PasteAPI = &PasteAPI{hibp: &c} return c } -// WithHttpTimeout overrides the default http client timeout -func WithHttpTimeout(t time.Duration) Option { +// WithHTTPTimeout overrides the default http client timeout +func WithHTTPTimeout(t time.Duration) Option { return func(c *Client) { c.to = t } } -// WithApiKey set the optional API key to the Client object -func WithApiKey(k string) Option { +// WithAPIKey set the optional API key to the Client object +func WithAPIKey(k string) Option { return func(c *Client) { c.ak = k } @@ -89,7 +89,7 @@ func WithApiKey(k string) Option { // WithPwnedPadding enables padding-mode for the PwnedPasswords API client func WithPwnedPadding() Option { return func(c *Client) { - c.PwnedPassApiOpts.WithPadding = true + c.PwnedPassAPIOpts.WithPadding = true } } @@ -110,8 +110,8 @@ func WithRateLimitSleep() Option { } } -// HttpReq performs an HTTP request to the corresponding API -func (c *Client) HttpReq(m, p string, q map[string]string) (*http.Request, error) { +// HTTPReq performs an HTTP request to the corresponding API +func (c *Client) HTTPReq(m, p string, q map[string]string) (*http.Request, error) { u, err := url.Parse(p) if err != nil { return nil, err @@ -145,16 +145,16 @@ func (c *Client) HttpReq(m, p string, q map[string]string) (*http.Request, error if c.ak != "" { hr.Header.Set("hibp-api-key", c.ak) } - if c.PwnedPassApiOpts.WithPadding { + if c.PwnedPassAPIOpts.WithPadding { hr.Header.Set("Add-Padding", "true") } return hr, nil } -// HttpResBody performs the API call to the given path and returns the response body as byte array -func (c *Client) HttpResBody(m string, p string, q map[string]string) ([]byte, *http.Response, error) { - hreq, err := c.HttpReq(m, p, q) +// HTTPResBody performs the API call to the given path and returns the response body as byte array +func (c *Client) HTTPResBody(m string, p string, q map[string]string) ([]byte, *http.Response, error) { + hreq, err := c.HTTPReq(m, p, q) if err != nil { return nil, nil, err } @@ -179,7 +179,7 @@ func (c *Client) HttpResBody(m string, p string, q map[string]string) ([]byte, * } log.Printf("API rate limit hit. Retrying request in %s", delayTime.String()) time.Sleep(delayTime) - return c.HttpResBody(m, p, q) + return c.HTTPResBody(m, p, q) } if hr.StatusCode != 200 { diff --git a/hibp_test.go b/hibp_test.go index f2112c9..4423cb1 100644 --- a/hibp_test.go +++ b/hibp_test.go @@ -10,7 +10,7 @@ import ( // TestNew tests the New() function func TestNew(t *testing.T) { hc := New() - if *hc.PwnedPassApi.hibp != hc { + if *hc.PwnedPassAPI.hibp != hc { t.Errorf("hibp client creation failed") } } @@ -18,14 +18,14 @@ func TestNew(t *testing.T) { // TestNewWithNil tests the New() function with a nil option func TestNewWithNil(t *testing.T) { hc := New(nil) - if *hc.PwnedPassApi.hibp != hc { + if *hc.PwnedPassAPI.hibp != hc { t.Errorf("hibp client creation failed") } } // TestNewWithHttpTimeout tests the New() function with the http timeout option func TestNewWithHttpTimeout(t *testing.T) { - hc := New(WithHttpTimeout(time.Second * 10)) + hc := New(WithHTTPTimeout(time.Second * 10)) if hc.to != time.Second*10 { t.Errorf("hibp client timeout option was not set properly. Expected %d, got: %d", time.Second*10, hc.to) @@ -35,16 +35,16 @@ func TestNewWithHttpTimeout(t *testing.T) { // TestNewWithPwnedPadding tests the New() function with the PwnedPadding option func TestNewWithPwnedPadding(t *testing.T) { hc := New(WithPwnedPadding()) - if !hc.PwnedPassApiOpts.WithPadding { + if !hc.PwnedPassAPIOpts.WithPadding { t.Errorf("hibp client pwned padding option was not set properly. Expected %v, got: %v", - true, hc.PwnedPassApiOpts.WithPadding) + true, hc.PwnedPassAPIOpts.WithPadding) } } // TestNewWithApiKey tests the New() function with the API key set func TestNewWithApiKey(t *testing.T) { apiKey := os.Getenv("HIBP_API_KEY") - hc := New(WithApiKey(apiKey), WithRateLimitSleep()) + hc := New(WithAPIKey(apiKey), WithRateLimitSleep()) if hc.ak != apiKey { t.Errorf("hibp client API key was not set properly. Expected %s, got: %s", apiKey, hc.ak) diff --git a/password.go b/password.go index 7157558..9a6f7b2 100644 --- a/password.go +++ b/password.go @@ -19,8 +19,8 @@ const ( ErrSHA1LengthMismatch = "SHA1 hash size needs to be 160 bits" ) -// PwnedPassApi is a HIBP Pwned Passwords API client -type PwnedPassApi struct { +// PwnedPassAPI is a HIBP Pwned Passwords API client +type PwnedPassAPI struct { hibp *Client // References back to the parent HIBP client } @@ -38,13 +38,13 @@ type PwnedPasswordOptions struct { } // CheckPassword checks the Pwned Passwords database against a given password string -func (p *PwnedPassApi) CheckPassword(pw string) (*Match, *http.Response, error) { +func (p *PwnedPassAPI) CheckPassword(pw string) (*Match, *http.Response, error) { shaSum := fmt.Sprintf("%x", sha1.Sum([]byte(pw))) return p.CheckSHA1(shaSum) } // CheckSHA1 checks the Pwned Passwords database against a given SHA1 checksum of a password string -func (p *PwnedPassApi) CheckSHA1(h string) (*Match, *http.Response, error) { +func (p *PwnedPassAPI) CheckSHA1(h string) (*Match, *http.Response, error) { if len(h) != 40 { return nil, nil, fmt.Errorf(ErrSHA1LengthMismatch) } @@ -67,7 +67,7 @@ func (p *PwnedPassApi) CheckSHA1(h string) (*Match, *http.Response, error) { // // NOTE: If the `WithPwnedPadding` option is set to true, the returned list will be padded and might // contain junk data -func (p *PwnedPassApi) ListHashesPassword(pw string) ([]Match, *http.Response, error) { +func (p *PwnedPassAPI) ListHashesPassword(pw string) ([]Match, *http.Response, error) { shaSum := fmt.Sprintf("%x", sha1.Sum([]byte(pw))) return p.ListHashesSHA1(shaSum) } @@ -77,7 +77,7 @@ func (p *PwnedPassApi) ListHashesPassword(pw string) ([]Match, *http.Response, e // // NOTE: If the `WithPwnedPadding` option is set to true, the returned list will be padded and might // contain junk data -func (p *PwnedPassApi) ListHashesSHA1(h string) ([]Match, *http.Response, error) { +func (p *PwnedPassAPI) ListHashesSHA1(h string) ([]Match, *http.Response, error) { if len(h) != 40 { return nil, nil, fmt.Errorf(ErrSHA1LengthMismatch) } @@ -89,11 +89,11 @@ func (p *PwnedPassApi) ListHashesSHA1(h string) ([]Match, *http.Response, error) // // NOTE: If the `WithPwnedPadding` option is set to true, the returned list will be padded and might // contain junk data -func (p *PwnedPassApi) ListHashesPrefix(pf string) ([]Match, *http.Response, error) { +func (p *PwnedPassAPI) ListHashesPrefix(pf string) ([]Match, *http.Response, error) { if len(pf) != 5 { return nil, nil, fmt.Errorf(ErrPrefixLengthMismatch) } - hreq, err := p.hibp.HttpReq(http.MethodGet, fmt.Sprintf("https://api.pwnedpasswords.com/range/%s", pf), + hreq, err := p.hibp.HTTPReq(http.MethodGet, fmt.Sprintf("https://api.pwnedpasswords.com/range/%s", pf), nil) if err != nil { return nil, nil, err diff --git a/password_test.go b/password_test.go index a4ad5b9..cb1bd60 100644 --- a/password_test.go +++ b/password_test.go @@ -21,21 +21,23 @@ const ( PwHashSecure = "90efc095c82eab44e882fda507cfab1a2cd31fc0" ) -// TestPwnedPassApi_CheckPassword verifies the Pwned Passwords API with the CheckPassword method -func TestPwnedPassApi_CheckPassword(t *testing.T) { +// TestPwnedPassAPI_CheckPassword verifies the Pwned Passwords API with the CheckPassword method +func TestPwnedPassAPI_CheckPassword(t *testing.T) { testTable := []struct { testName string pwString string isLeaked bool }{ {"weak password 'test123' is expected to be leaked", PwStringInsecure, true}, - {"strong, unknown password is expected to be not leaked", - PwStringSecure, false}, + { + "strong, unknown password is expected to be not leaked", + PwStringSecure, false, + }, } hc := New() for _, tc := range testTable { t.Run(tc.testName, func(t *testing.T) { - m, _, err := hc.PwnedPassApi.CheckPassword(tc.pwString) + m, _, err := hc.PwnedPassAPI.CheckPassword(tc.pwString) if err != nil { t.Error(err) } @@ -50,25 +52,31 @@ func TestPwnedPassApi_CheckPassword(t *testing.T) { } } -// TestPwnedPassApi_CheckSHA1 verifies the Pwned Passwords API with the CheckSHA1 method -func TestPwnedPassApi_CheckSHA1(t *testing.T) { +// TestPwnedPassAPI_CheckSHA1 verifies the Pwned Passwords API with the CheckSHA1 method +func TestPwnedPassAPI_CheckSHA1(t *testing.T) { testTable := []struct { testName string pwHash string isLeaked bool shouldFail bool }{ - {"weak password 'test' is expected to be leaked", - PwHashInsecure, true, false}, - {"strong, unknown password is expected to be not leaked", - PwHashSecure, false, false}, - {"empty string should fail", - "", false, true}, + { + "weak password 'test' is expected to be leaked", + PwHashInsecure, true, false, + }, + { + "strong, unknown password is expected to be not leaked", + PwHashSecure, false, false, + }, + { + "empty string should fail", + "", false, true, + }, } hc := New() for _, tc := range testTable { t.Run(tc.testName, func(t *testing.T) { - m, _, err := hc.PwnedPassApi.CheckSHA1(tc.pwHash) + m, _, err := hc.PwnedPassAPI.CheckSHA1(tc.pwHash) if err != nil && !tc.shouldFail { t.Error(err) return @@ -84,13 +92,13 @@ func TestPwnedPassApi_CheckSHA1(t *testing.T) { } } -// TestPwnedPassApi_ListHashesPrefix tests the ListHashesPrefix method (especially for failures that are not +// TestPwnedPassAPI_ListHashesPrefix tests the ListHashesPrefix method (especially for failures that are not // tested by the other tests already) -func TestPwnedPassApi_ListHashesPrefix(t *testing.T) { +func TestPwnedPassAPI_ListHashesPrefix(t *testing.T) { hc := New() // Should return at least 1 restults - l, _, err := hc.PwnedPassApi.ListHashesPrefix("a94a8") + l, _, err := hc.PwnedPassAPI.ListHashesPrefix("a94a8") if err != nil { t.Errorf("ListHashesPrefix was not supposed to fail, but did: %s", err) } @@ -99,24 +107,24 @@ func TestPwnedPassApi_ListHashesPrefix(t *testing.T) { } // Prefix has wrong size - _, _, err = hc.PwnedPassApi.ListHashesPrefix("ZZZZZZZZZZZZZZ") + _, _, err = hc.PwnedPassAPI.ListHashesPrefix("ZZZZZZZZZZZZZZ") if err == nil { t.Errorf("ListHashesPrefix was supposed to fail, but didn't") } // Non allowed characters - _, _, err = hc.PwnedPassApi.ListHashesPrefix(string([]byte{0, 0, 0, 0, 0})) + _, _, err = hc.PwnedPassAPI.ListHashesPrefix(string([]byte{0, 0, 0, 0, 0})) if err == nil { t.Errorf("ListHashesPrefix was supposed to fail, but didn't") } } -// TestPwnedPassApi_ListHashesSHA1 tests the PwnedPassApi.ListHashesSHA1 metethod -func TestPwnedPassApi_ListHashesSHA1(t *testing.T) { +// TestPwnedPassApi_ListHashesSHA1 tests the PwnedPassAPI.ListHashesSHA1 metethod +func TestPwnedPassAPI_ListHashesSHA1(t *testing.T) { hc := New() // List length should be >0 - l, _, err := hc.PwnedPassApi.ListHashesSHA1(PwHashInsecure) + l, _, err := hc.PwnedPassAPI.ListHashesSHA1(PwHashInsecure) if err != nil { t.Errorf("ListHashesSHA1 was not supposed to fail, but did: %s", err) } @@ -125,18 +133,18 @@ func TestPwnedPassApi_ListHashesSHA1(t *testing.T) { } // Hash has wrong size - _, _, err = hc.PwnedPassApi.ListHashesSHA1(PwStringInsecure) + _, _, err = hc.PwnedPassAPI.ListHashesSHA1(PwStringInsecure) if err == nil { t.Errorf("ListHashesSHA1 was supposed to fail, but didn't") } } -// TestPwnedPassApi_ListHashesPassword tests the PwnedPassApi.ListHashesPassword metethod -func TestPwnedPassApi_ListHashesPassword(t *testing.T) { +// TestPwnedPassAPI_ListHashesPassword tests the PwnedPassAPI.ListHashesPassword metethod +func TestPwnedPassAPI_ListHashesPassword(t *testing.T) { hc := New() // List length should be >0 - l, _, err := hc.PwnedPassApi.ListHashesPassword(PwStringInsecure) + l, _, err := hc.PwnedPassAPI.ListHashesPassword(PwStringInsecure) if err != nil { t.Errorf("ListHashesPassword was not supposed to fail, but did: %s", err) } @@ -145,17 +153,17 @@ func TestPwnedPassApi_ListHashesPassword(t *testing.T) { } // Empty string has no checksum - _, _, err = hc.PwnedPassApi.ListHashesSHA1("") + _, _, err = hc.PwnedPassAPI.ListHashesSHA1("") if err == nil { t.Errorf("ListHashesPassword was supposed to fail, but didn't") } } -// ExamplePwnedPassApi_CheckPassword is a code example to show how to check a given password +// ExamplePwnedPassAPI_CheckPassword is a code example to show how to check a given password // against the HIBP passwords API -func ExamplePwnedPassApi_CheckPassword() { +func ExamplePwnedPassAPI_CheckPassword() { hc := New() - m, _, err := hc.PwnedPassApi.CheckPassword("test") + m, _, err := hc.PwnedPassAPI.CheckPassword("test") if err != nil { panic(err) } @@ -166,11 +174,11 @@ func ExamplePwnedPassApi_CheckPassword() { } } -// ExamplePwnedPassApi_CheckPassword_withPadding is a code example to show how to check a given password +// ExamplePwnedPassAPI_CheckPassword_withPadding is a code example to show how to check a given password // against the HIBP passwords API with the WithPadding() option set -func ExamplePwnedPassApi_CheckPassword_withPadding() { +func ExamplePwnedPassAPI_CheckPassword_withPadding() { hc := New(WithPwnedPadding()) - m, _, err := hc.PwnedPassApi.CheckPassword("test") + m, _, err := hc.PwnedPassAPI.CheckPassword("test") if err != nil { panic(err) } @@ -181,12 +189,12 @@ func ExamplePwnedPassApi_CheckPassword_withPadding() { } } -// ExamplePwnedPassApi_CheckSHA1 is a code example to show how to check a given password SHA1 hash +// ExamplePwnedPassAPI_checkSHA1 is a code example to show how to check a given password SHA1 hash // against the HIBP passwords API using the CheckSHA1() method -func ExamplePwnedPassApi_CheckSHA1() { +func ExamplePwnedPassAPI_checkSHA1() { hc := New() pwHash := "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3" // represents the PW: "test" - m, _, err := hc.PwnedPassApi.CheckSHA1(pwHash) + m, _, err := hc.PwnedPassAPI.CheckSHA1(pwHash) if err != nil { panic(err) } diff --git a/paste.go b/paste.go index 0832b72..7eb7e18 100644 --- a/paste.go +++ b/paste.go @@ -7,8 +7,8 @@ import ( "time" ) -// PasteApi is a HIBP pastes API client -type PasteApi struct { +// PasteAPI is a HIBP pastes API client +type PasteAPI struct { hibp *Client // References back to the parent HIBP client } @@ -18,9 +18,9 @@ type Paste struct { // Pastie, Slexy, Ghostbin, QuickLeak, JustPaste, AdHocUrl, PermanentOptOut, OptOut Source string `json:"Source"` - // Id of the paste as it was given at the source service. Combined with the "Source" attribute, this + // ID of the paste as it was given at the source service. Combined with the "Source" attribute, this // can be used to resolve the URL of the paste - Id string `json:"Id"` + ID string `json:"ID"` // Title of the paste as observed on the source site. This may be null and if so will be omitted from // the response @@ -36,13 +36,13 @@ type Paste struct { } // PastedAccount returns a single breached site based on its name -func (p *PasteApi) PastedAccount(a string) ([]*Paste, *http.Response, error) { +func (p *PasteAPI) PastedAccount(a string) ([]*Paste, *http.Response, error) { if a == "" { return nil, nil, fmt.Errorf("no account id given") } - apiUrl := fmt.Sprintf("%s/pasteaccount/%s", BaseUrl, a) - hb, hr, err := p.hibp.HttpResBody(http.MethodGet, apiUrl, nil) + apiURL := fmt.Sprintf("%s/pasteaccount/%s", BaseURL, a) + hb, hr, err := p.hibp.HTTPResBody(http.MethodGet, apiURL, nil) if err != nil { return nil, nil, err } diff --git a/paste_test.go b/paste_test.go index ff17511..7396caf 100644 --- a/paste_test.go +++ b/paste_test.go @@ -23,10 +23,10 @@ func TestPasteAccount(t *testing.T) { if apiKey == "" { t.SkipNow() } - hc := New(WithApiKey(apiKey), WithRateLimitSleep()) + hc := New(WithAPIKey(apiKey), WithRateLimitSleep()) for _, tc := range testTable { t.Run(tc.testName, func(t *testing.T) { - pasteDetails, _, err := hc.PasteApi.PastedAccount(tc.accountName) + pasteDetails, _, err := hc.PasteAPI.PastedAccount(tc.accountName) if err != nil && !tc.shouldFail { t.Error(err) } @@ -43,15 +43,15 @@ func TestPasteAccount(t *testing.T) { } } -// ExamplePasteApi_PastedAccount is a code example to show how to fetch a specific paste +// ExamplePasteAPI_pastedAccount is a code example to show how to fetch a specific paste // based on its name from the HIBP pastes API using the PastedAccount() method -func ExamplePasteApi_PastedAccount() { +func ExamplePasteAPI_pastedAccount() { apiKey := os.Getenv("HIBP_API_KEY") if apiKey == "" { panic("A API key is required for this API") } - hc := New(WithApiKey(apiKey)) - pd, _, err := hc.PasteApi.PastedAccount("account-exists@hibp-integration-tests.com") + hc := New(WithAPIKey(apiKey)) + pd, _, err := hc.PasteAPI.PastedAccount("account-exists@hibp-integration-tests.com") if err != nil { panic(err) }