Created
September 27, 2016 06:03
-
-
Save IndianGuru/1cb16f5d853c22fb9c2cb47a7e19db67 to your computer and use it in GitHub Desktop.
A go package for the HaveIBeenPwned Rest API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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