mirror of
https://github.com/wneessen/go-hibp.git
synced 2024-11-23 13:20:51 +01:00
Compare commits
No commits in common. "1bff71201d2306361c226ed40139636ba7ea7e1a" and "758c046b43c49d3c7e3ef2fa10aa12cea5b0ac75" have entirely different histories.
1bff71201d
...
758c046b43
2 changed files with 4 additions and 158 deletions
92
breach.go
92
breach.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -87,40 +88,12 @@ type Breach struct {
|
||||||
LogoPath string `json:"LogoPath"`
|
LogoPath string `json:"LogoPath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubscribedDomains struct {
|
|
||||||
// DomainName is the full domain name that has been successfully verified.
|
|
||||||
DomainName string `json:"DomainName"`
|
|
||||||
|
|
||||||
// PwnCount is the total number of breached email addresses found on the domain at last search
|
|
||||||
// (will be null if no searches yet performed).
|
|
||||||
PwnCount *int `json:"PwnCount"`
|
|
||||||
|
|
||||||
// PwnCountExcludingSpamLists is the number of breached email addresses found on the domain
|
|
||||||
// at last search, excluding any breaches flagged as a spam list (will be null if no
|
|
||||||
// searches yet performed).
|
|
||||||
PwnCountExcludingSpamLists *int `json:"PwnCountExcludingSpamLists"`
|
|
||||||
|
|
||||||
// The total number of breached email addresses found on the domain when the current
|
|
||||||
// subscription was taken out (will be null if no searches yet performed). This number
|
|
||||||
// ensures the domain remains searchable throughout the subscription period even if the
|
|
||||||
// volume of breached accounts grows beyond the subscription's scope.
|
|
||||||
PwnCountExcludingSpamListsAtLastSubscriptionRenewal *int `json:"PwnCountExcludingSpamListsAtLastSubscriptionRenewal"`
|
|
||||||
|
|
||||||
// The date and time the current subscription ends in ISO 8601 format. The
|
|
||||||
// PwnCountExcludingSpamListsAtLastSubscriptionRenewal value is locked in until this time (will
|
|
||||||
// be null if there have been no subscriptions).
|
|
||||||
NextSubscriptionRenewal RenewalTime `json:"NextSubscriptionRenewal"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreachOption is an additional option the can be set for the BreachApiClient
|
// 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
|
// APIDate is a date string without time returned by the API represented as time.Time type
|
||||||
type APIDate time.Time
|
type APIDate time.Time
|
||||||
|
|
||||||
// RenewalTime is a timestamp returned by the API that doesn't have timezone information
|
|
||||||
type RenewalTime time.Time
|
|
||||||
|
|
||||||
// Breaches returns a list of all breaches in the HIBP system
|
// 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) {
|
||||||
qp := b.setBreachOpts(options...)
|
qp := b.setBreachOpts(options...)
|
||||||
|
@ -200,42 +173,6 @@ func (b *BreachAPI) BreachedAccount(a string, options ...BreachOption) ([]*Breac
|
||||||
return bd, hr, nil
|
return bd, hr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribedDomains returns domains that have been successfully added to the domain
|
|
||||||
// search dashboard after verifying control are returned via this API. This is an
|
|
||||||
// authenticated API requiring an HIBP API key which will then return all domains associated with that key.
|
|
||||||
func (b *BreachAPI) SubscribedDomains() ([]SubscribedDomains, *http.Response, error) {
|
|
||||||
au := fmt.Sprintf("%s/subscribeddomains", BaseURL)
|
|
||||||
hb, hr, err := b.hibp.HTTPResBody(http.MethodGet, au, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, hr, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var bd []SubscribedDomains
|
|
||||||
if err := json.Unmarshal(hb, &bd); err != nil {
|
|
||||||
return nil, hr, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return bd, hr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreachedDomain returns all email addresses on a given domain and the breaches they've appeared
|
|
||||||
// in can be returned via the domain search API. Only domains that have been successfully added
|
|
||||||
// to the domain search dashboard after verifying control can be searched.
|
|
||||||
func (b *BreachAPI) BreachedDomain(domain string) (map[string][]string, *http.Response, error) {
|
|
||||||
au := fmt.Sprintf("%s/breacheddomain/%s", BaseURL, domain)
|
|
||||||
hb, hr, err := b.hibp.HTTPResBody(http.MethodGet, au, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, hr, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var bd map[string][]string
|
|
||||||
if err := json.Unmarshal(hb, &bd); err != nil {
|
|
||||||
return nil, hr, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return bd, hr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithDomain sets the domain filter for the breaches API
|
// WithDomain sets the domain filter for the breaches API
|
||||||
func WithDomain(d string) BreachOption {
|
func WithDomain(d string) BreachOption {
|
||||||
return func(b *BreachAPI) {
|
return func(b *BreachAPI) {
|
||||||
|
@ -260,8 +197,9 @@ func WithoutUnverified() BreachOption {
|
||||||
|
|
||||||
// UnmarshalJSON for the APIDate type converts a give date string into a time.Time type
|
// UnmarshalJSON for the APIDate type converts a give date string into a time.Time type
|
||||||
func (d *APIDate) UnmarshalJSON(s []byte) error {
|
func (d *APIDate) UnmarshalJSON(s []byte) error {
|
||||||
ds := string(s[1 : len(s)-1])
|
ds := string(s)
|
||||||
if ds == "null" || ds == "" {
|
ds = strings.ReplaceAll(ds, `"`, ``)
|
||||||
|
if ds == "null" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,28 +218,6 @@ func (d *APIDate) Time() time.Time {
|
||||||
return time.Time(dp)
|
return time.Time(dp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON for the RenewalTime type converts a give date string into a time.Time type
|
|
||||||
func (d *RenewalTime) UnmarshalJSON(s []byte) error {
|
|
||||||
ds := string(s[1 : len(s)-1])
|
|
||||||
if ds == "null" || ds == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pd, err := time.Parse("2006-01-02T15:04:05", ds)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("convert API date string to time.Time type: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
*(*time.Time)(d) = pd
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time adds a Time() method to the RenewalTime converted time.Time type
|
|
||||||
func (d *RenewalTime) Time() time.Time {
|
|
||||||
dp := *d
|
|
||||||
return time.Time(dp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// setBreachOpts returns a map of default settings and overridden values from different BreachOption
|
// 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 {
|
||||||
qp := map[string]string{
|
qp := map[string]string{
|
||||||
|
|
|
@ -310,76 +310,6 @@ func TestBreachAPI_BreachedAccount_WithoutTruncate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestBreachAPI_SubscribedDomains tests the SubscribedDomains() method of the breaches API
|
|
||||||
func TestBreachAPI_SubscribedDomains(t *testing.T) {
|
|
||||||
apiKey := os.Getenv("HIBP_API_KEY")
|
|
||||||
if apiKey == "" {
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
hc := New(WithAPIKey(apiKey), WithRateLimitSleep())
|
|
||||||
|
|
||||||
domains, _, err := hc.BreachAPI.SubscribedDomains()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(domains) < 1 {
|
|
||||||
t.Log("no subscribed domains found with provided api key")
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, domain := range domains {
|
|
||||||
t.Run(fmt.Sprintf("checking domain %d", i), func(t *testing.T) {
|
|
||||||
if domain.DomainName == "" {
|
|
||||||
t.Error("domain name is missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
if domain.NextSubscriptionRenewal.Time().IsZero() {
|
|
||||||
t.Error("next subscription renewal is missing")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestBreachAPI_BreachedDomain tests the BreachedDomain() method of the breaches API
|
|
||||||
func TestBreachAPI_BreachedDomain(t *testing.T) {
|
|
||||||
apiKey := os.Getenv("HIBP_API_KEY")
|
|
||||||
if apiKey == "" {
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
hc := New(WithAPIKey(apiKey), WithRateLimitSleep())
|
|
||||||
|
|
||||||
domains, _, err := hc.BreachAPI.SubscribedDomains()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(domains) < 1 {
|
|
||||||
t.Log("no subscribed domains found with provided api key")
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, domain := range domains {
|
|
||||||
t.Run(fmt.Sprintf("checking domain %d", i), func(t *testing.T) {
|
|
||||||
breaches, _, err := hc.BreachAPI.BreachedDomain(domain.DomainName)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(breaches) < 1 {
|
|
||||||
t.Logf("domain %s contains no breaches", domain.DomainName)
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
for alias, list := range breaches {
|
|
||||||
if l := len(list); l == 0 {
|
|
||||||
t.Errorf("alias %s contains %d breaches, there should be at least 1", alias, l)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestAPIDate_UnmarshalJSON_Time tests the APIDate type JSON unmarshalling
|
// TestAPIDate_UnmarshalJSON_Time tests the APIDate type JSON unmarshalling
|
||||||
func TestAPIDate_UnmarshalJSON_Time(t *testing.T) {
|
func TestAPIDate_UnmarshalJSON_Time(t *testing.T) {
|
||||||
type testData struct {
|
type testData struct {
|
||||||
|
|
Loading…
Reference in a new issue