Skip to content

Instantly share code, notes, and snippets.

@IndianGuru
Created September 27, 2016 06:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IndianGuru/1cb16f5d853c22fb9c2cb47a7e19db67 to your computer and use it in GitHub Desktop.
Save IndianGuru/1cb16f5d853c22fb9c2cb47a7e19db67 to your computer and use it in GitHub Desktop.
A go package for the HaveIBeenPwned Rest API
package pwned
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"time"
)
type jResp struct {
Title string `json:"Title"`
Name string `json:"Name"`
Domain string `json:"Domain"`
BreachDate string `json:"BreachDate"`
AddedDate time.Time `json:"AddedDate"`
PwnCount int `json:"PwnCount"`
Description string `json:"Description"`
DataClasses []string `json:"DataClasses"`
IsVerified bool `json:"IsVerified"`
IsSensitive bool `json:"IsSensitive"`
IsActive bool `json:"IsActive"`
IsRetired bool `json:"IsRetired"`
LogoType string `json:"LogoType"`
}
type jPasteResp struct {
Source string
ID string
Title string
Date string
EmailCount int
}
const baseURL = "https://haveibeenpwned.com/api/v2/%s"
func GetService(parameter, service, domain string) string {
var (
url string
record1 []jResp
record2 jResp
record3 interface{}
record4 []jPasteResp
body []byte
statuscode string
)
switch service {
case "breachedaccount/":
if domain == "" {
// build url for getting breaches for an account
url = fmt.Sprintf(baseURL, service+parameter)
} else {
// build url for getting breaches for an account on a specific domain
url = fmt.Sprintf(baseURL, service+parameter+"?domain="+domain)
}
body, statuscode = getURL(url)
if statuscode != "" {
return statuscode
}
// Decode JSON data
err := json.Unmarshal(body, &record1)
if err != nil {
log.Fatal(err)
}
// Encode JSON data
body, err = json.Marshal(record1)
if err != nil {
log.Fatal(err)
}
case "breaches/":
if domain == "" {
// build url for getting all breached sites in the system
url = fmt.Sprintf(baseURL, service)
} else {
// build url for getting all breached sites in the system, for a specific domain
url = fmt.Sprintf(baseURL, service+"?domain="+domain)
}
body, statuscode = getURL(url)
if statuscode != "" {
return statuscode
}
// Decode JSON data
err := json.Unmarshal(body, &record1)
if err != nil {
log.Fatal(err)
}
// Encode JSON data
body, err = json.Marshal(record1)
if err != nil {
log.Fatal(err)
}
case "breach/":
// build url for getting a single breached site
url = fmt.Sprintf(baseURL, service+domain)
body, statuscode = getURL(url)
if statuscode != "" {
return statuscode
}
// Decode JSON data
err := json.Unmarshal(body, &record2)
if err != nil {
log.Fatal(err)
}
// Encode JSON data
body, err = json.Marshal(record2)
if err != nil {
log.Fatal(err)
}
case "dataclasses/":
// build url for getting all data classes in the system
url = fmt.Sprintf(baseURL, service)
body, statuscode = getURL(url)
if statuscode != "" {
return statuscode
}
// Decode JSON data
err := json.Unmarshal(body, &record3)
if err != nil {
log.Fatal(err)
}
// Encode JSON data
body, err = json.Marshal(record3)
if err != nil {
log.Fatal(err)
}
case "pasteaccount/":
// build url for getting all pastes for an account
url = fmt.Sprintf(baseURL, service+parameter)
body, statuscode = getURL(url)
if statuscode != "" {
return statuscode
}
// Decode JSON data
err := json.Unmarshal(body, &record4)
if err != nil {
log.Fatal(err)
}
// Encode JSON data
body, err = json.Marshal(record4)
if err != nil {
log.Fatal(err)
}
}
return fmt.Sprintf("%s", body)
}
// private function
func getURL(url string) ([]byte, string) {
// Semantic HTTP response codes are used to indicate the result of the search
var respcodes = map[int]string{
400: "Bad request — the account does not comply with an acceptable format (i.e. it's an empty string)",
403: "Forbidden — no user agent has been specified in the request",
404: "Not found — the account could not be found and has therefore not been pwned",
429: "Too many requests — the rate limit has been exceeded",
}
// For control over HTTP client headers,
// redirect policy, and other settings,
// create a Client
// A Client is an HTTP client
client := &http.Client{}
// Build the request
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal("NewRequest: ", err)
}
// Set the User-Agent
req.Header.Add("User-Agent", "Go package pwned by Satish Talim to access the HaveIBeenPwned REST API")
// Send the request via a client
// Do sends an HTTP request and
// returns an HTTP response
resp, err := client.Do(req)
if err != nil {
log.Fatal("Do: ", err)
}
// Callers should close resp.Body
// when done reading from it
// Defer the closing of the body
defer resp.Body.Close()
// read body
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal("ReadAll: ", err)
}
statuscode := respcodes[resp.StatusCode]
return body, statuscode
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment