Add logging, including the json one
get infos from I've been pwned and the API on install.dm.gg/vpn-log.php and send mail if there is anything strange
This commit is contained in:
5
vendor/github.com/mattevans/pwned-passwords/.travis.yml
generated
vendored
Normal file
5
vendor/github.com/mattevans/pwned-passwords/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
sudo: false
|
||||
language: go
|
||||
go:
|
||||
- 1.11.x
|
||||
- tip
|
||||
19
vendor/github.com/mattevans/pwned-passwords/LICENSE
generated
vendored
Normal file
19
vendor/github.com/mattevans/pwned-passwords/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (C) 2018 by Matt Evans
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
62
vendor/github.com/mattevans/pwned-passwords/README.md
generated
vendored
Normal file
62
vendor/github.com/mattevans/pwned-passwords/README.md
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# pwned-passwords
|
||||
|
||||
[](https://godoc.org/github.com/mattevans/pwned-passwords)
|
||||
[](https://travis-ci.org/mattevans/pwned-passwords)
|
||||
[](https://goreportcard.com/report/github.com/mattevans/pwned-passwords)
|
||||
[](https://github.com/mattevans/pwned-passwords/blob/master/LICENSE)
|
||||
|
||||
A simple [Go](http://golang.org) client library for checking compromised passwords against [HIBP Pwned Passwords](https://haveibeenpwned.com/Passwords).
|
||||
|
||||
Upon request, results will be cached (in-memory), keyed by hash. With a two hour expiry window, subsequent requests will use cached data or fetch fresh data accordingly.
|
||||
|
||||
Installation
|
||||
-----------------
|
||||
|
||||
`go get -u github.com/mattevans/pwned-passwords`
|
||||
|
||||
Usage
|
||||
-----------------
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
hibp "github.com/mattevans/pwned-passwords"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Init a client.
|
||||
client := hibp.NewClient()
|
||||
|
||||
// Check to see if your given string is compromised.
|
||||
pwned, err := client.Pwned.Compromised("string to check")
|
||||
if err != nil {
|
||||
fmt.Println("Pwned failed")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if pwned {
|
||||
// Oh dear!
|
||||
// You should avoid using that password
|
||||
} else {
|
||||
// Woo!
|
||||
// All clear!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Expire in-memory cache**
|
||||
|
||||
```go
|
||||
client.Cache.Expire(HASHED_VALUE)
|
||||
```
|
||||
|
||||
```go
|
||||
client.Cache.ExpireAll()
|
||||
```
|
||||
|
||||
Contributing
|
||||
-----------------
|
||||
If you've found a bug or would like to contribute, please create an issue here on GitHub, or better yet fork the project and submit a pull request!
|
||||
65
vendor/github.com/mattevans/pwned-passwords/cache.go
generated
vendored
Normal file
65
vendor/github.com/mattevans/pwned-passwords/cache.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package hibp
|
||||
|
||||
import "time"
|
||||
|
||||
// cache holds our our cached hash/compromised pairs results.
|
||||
var cache map[string]*PwnedStore
|
||||
|
||||
// cacheTTL stores the time to live of our cache (2 hours).
|
||||
var cacheTTL = 2 * time.Hour
|
||||
|
||||
// CacheService handles in-memory caching of our hash/compromised pairs.
|
||||
type CacheService service
|
||||
|
||||
// Get will return our stored in-memory hash/compromised pairs, if we have them.
|
||||
func (s *CacheService) Get(hash string) *PwnedStore {
|
||||
// Is our cache expired?
|
||||
if s.IsExpired(hash) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Use stored results.
|
||||
return cache[hash]
|
||||
}
|
||||
|
||||
// Store will save our hash/compromised pairs to a PwnedStore.
|
||||
func (s *CacheService) Store(hash string, compromised bool) {
|
||||
// No cache? Initialize it.
|
||||
if cache == nil {
|
||||
cache = map[string]*PwnedStore{}
|
||||
}
|
||||
|
||||
// Store
|
||||
tn := time.Now()
|
||||
cache[hash] = &PwnedStore{
|
||||
Hash: hash,
|
||||
Compromised: compromised,
|
||||
UpdatedAt: &tn,
|
||||
}
|
||||
}
|
||||
|
||||
// IsExpired checks if we have cached hash and that it isn't expired.
|
||||
func (s *CacheService) IsExpired(hash string) bool {
|
||||
// No cache? bail.
|
||||
if cache[hash] == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// Expired cache? bail.
|
||||
lastUpdated := cache[hash].UpdatedAt
|
||||
if lastUpdated != nil && lastUpdated.Add(cacheTTL).Before(time.Now()) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Expire will expire the cache for a given hash.
|
||||
func (s *CacheService) Expire(hash string) {
|
||||
cache[hash] = nil
|
||||
}
|
||||
|
||||
// ExpireAll will expire all cache.
|
||||
func (s *CacheService) ExpireAll() {
|
||||
cache = nil
|
||||
}
|
||||
115
vendor/github.com/mattevans/pwned-passwords/hibp.go
generated
vendored
Normal file
115
vendor/github.com/mattevans/pwned-passwords/hibp.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
package hibp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
packageVersion = "0.0.1"
|
||||
backendURL = "https://api.pwnedpasswords.com"
|
||||
userAgent = "pwned-passwords-golang/" + packageVersion
|
||||
)
|
||||
|
||||
// Client holds a connection to the HIBP API.
|
||||
type Client struct {
|
||||
client *http.Client
|
||||
AppID string
|
||||
UserAgent string
|
||||
BackendURL *url.URL
|
||||
|
||||
// Services used for communicating with the API.
|
||||
Pwned *PwnedService
|
||||
Cache *CacheService
|
||||
}
|
||||
|
||||
type service struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// NewClient creates a new Client with the appropriate connection details and
|
||||
// services used for communicating with the API.
|
||||
func NewClient() *Client {
|
||||
// Init new http.Client.
|
||||
httpClient := http.DefaultClient
|
||||
|
||||
// Parse BE URL.
|
||||
baseURL, _ := url.Parse(backendURL)
|
||||
|
||||
c := &Client{
|
||||
client: httpClient,
|
||||
BackendURL: baseURL,
|
||||
UserAgent: userAgent,
|
||||
}
|
||||
|
||||
c.Pwned = &PwnedService{client: c}
|
||||
c.Cache = &CacheService{client: c}
|
||||
return c
|
||||
}
|
||||
|
||||
// NewRequest creates an API request. A relative URL can be provided in urlPath,
|
||||
// which will be resolved to the BackendURL of the Client.
|
||||
func (c *Client) NewRequest(method, urlPath string, body interface{}) (*http.Request, error) {
|
||||
// Parse our URL.
|
||||
rel, err := url.Parse(urlPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Resolve to absolute URI.
|
||||
u := c.BackendURL.ResolveReference(rel)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if body != nil {
|
||||
err = json.NewEncoder(buf).Encode(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create the request.
|
||||
req, err := http.NewRequest(method, u.String(), buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add our packages UA.
|
||||
req.Header.Add("User-Agent", c.UserAgent)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// Do sends an API request and returns the API response.
|
||||
func (c *Client) Do(req *http.Request) ([]string, error) {
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if rerr := resp.Body.Close(); err == nil {
|
||||
err = rerr
|
||||
}
|
||||
}()
|
||||
|
||||
// Error if anything else but 200.
|
||||
// The API should always return a 200 (unless something is wrong) as per
|
||||
// https://haveibeenpwned.com/API/v2#SearchingPwnedPasswordsByRange
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("Unexpected API response status: %v", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Parse our resp.Body.
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Response is returned as new-line'd string, split and return.
|
||||
return strings.Split(string(body), "\r\n"), err
|
||||
}
|
||||
89
vendor/github.com/mattevans/pwned-passwords/pwned.go
generated
vendored
Normal file
89
vendor/github.com/mattevans/pwned-passwords/pwned.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
package hibp
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PwnedService handles retrieving pwned hashes from in-memory cache or
|
||||
// by fetching fresh results.
|
||||
type PwnedService service
|
||||
|
||||
// PwnedStore holds our pwned password hashes and compromised status.
|
||||
type PwnedStore struct {
|
||||
Hash string `json:"hash"`
|
||||
Compromised bool `json:"compromised"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Compromised will build and execute a request to HIBP to check to see
|
||||
// if the passed value is compromised or not.
|
||||
func (s *PwnedService) Compromised(value string) (bool, error) {
|
||||
var err error
|
||||
|
||||
// Our value being checked is empty, we don't want that.
|
||||
if value == "" {
|
||||
return false, errors.New("Value for compromised check cannot be empty")
|
||||
}
|
||||
|
||||
// SHA-1 hash our input value.
|
||||
hashedStr := _hashString(value)
|
||||
|
||||
// If we have cached results, use them.
|
||||
cache := s.client.Cache.Get(hashedStr)
|
||||
if cache != nil {
|
||||
hashedStr = cache.Hash
|
||||
return cache.Compromised, err
|
||||
}
|
||||
|
||||
// Pop our prefix and suffix.
|
||||
prefix := strings.ToUpper(hashedStr[:5])
|
||||
suffix := strings.ToUpper(hashedStr[5:])
|
||||
|
||||
// Build request.
|
||||
request, err := s.client.NewRequest("GET", fmt.Sprintf("range/%s", prefix), nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Make request.
|
||||
response, err := s.client.Do(request)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Range our response ([]string).
|
||||
for _, target := range response {
|
||||
// If our target, minus the compromised count matches our suffix.
|
||||
if string(target[:35]) == suffix {
|
||||
_, err = strconv.ParseInt(target[36:], 10, 64)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Store in cache as compromised.
|
||||
s.client.Cache.Store(hashedStr, true)
|
||||
|
||||
// Return.
|
||||
return true, err
|
||||
}
|
||||
}
|
||||
|
||||
// Store in cache as non-compromised.
|
||||
s.client.Cache.Store(hashedStr, false)
|
||||
|
||||
// Return.
|
||||
return false, err
|
||||
}
|
||||
|
||||
// _hashString will return a sha1 hash of the given value.
|
||||
func _hashString(value string) string {
|
||||
alg := sha1.New()
|
||||
alg.Write([]byte(value))
|
||||
return strings.ToUpper(hex.EncodeToString(alg.Sum(nil)))
|
||||
}
|
||||
Reference in New Issue
Block a user