-
Notifications
You must be signed in to change notification settings - Fork 402
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add haveibeenpwned.org password strength check (#1324)
Uses Supabase's HIBP Go library to perform password strength checks using the HaveIBeenPwned.org Pwned Passwords API. You can configure this behavior by: - `GOTRUE_PASSWORD_HIBP_ENABLED` to turn it on - `GOTRUE_PASSWORD_HIBP_USER_AGENT` to specify your project's identifier - `GOTRUE_PASSWORD_HIBP_FAIL_CLOSED` if the API is unavailable (or unresponsive for 5 seconds) the response is ignored and any password is accepted, set this to true to fail with a 500 error in such cases - `GOTRUE_PASSWORD_HIBP_BLOOM_ENABLED` to enable a bloom filter cache - `GOTRUE_PASSWORD_HIBP_BLOOM_ITEMS` to specify the maximum number of pwned password hashes to be stored in the bloom filter - `GOTRUE_PASSWORD_HIBP_BLOOM_FALSE_POSITIVES` to specify the maximum number of false positives returned by the bloom filter, a value between 0 and 1 indicating _1 in X_ For bloom filters, use this calculator to understand the values: https://hur.st/bloomfilter By default 100,000 password hashes can be stored in the filter (about 100 hash prefixes). The filter resets at 80% of this value to ensure that the cache is cleared and the actual false positive rate does not go too high.
- Loading branch information
Showing
6 changed files
with
146 additions
and
0 deletions.
There are no files selected for viewing
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
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
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package utilities | ||
|
||
import ( | ||
"context" | ||
"sync" | ||
|
||
"github.com/bits-and-blooms/bloom/v3" | ||
) | ||
|
||
const ( | ||
// hibpHashLength is the length of a hex-encoded SHA1 hash. | ||
hibpHashLength = 40 | ||
// hibpHashPrefixLength is the length of the hashed password prefix. | ||
hibpHashPrefixLength = 5 | ||
) | ||
|
||
type HIBPBloomCache struct { | ||
sync.RWMutex | ||
|
||
n uint | ||
items uint | ||
filter *bloom.BloomFilter | ||
} | ||
|
||
func NewHIBPBloomCache(n uint, fp float64) *HIBPBloomCache { | ||
cache := &HIBPBloomCache{ | ||
n: n, | ||
filter: bloom.NewWithEstimates(n, fp), | ||
} | ||
|
||
return cache | ||
} | ||
|
||
func (c *HIBPBloomCache) Cap() uint { | ||
return c.filter.Cap() | ||
} | ||
|
||
func (c *HIBPBloomCache) Add(ctx context.Context, prefix []byte, suffixes [][]byte) error { | ||
c.Lock() | ||
defer c.Unlock() | ||
|
||
c.items += uint(len(suffixes)) | ||
|
||
if c.items > (4*c.n)/5 { | ||
// clear the filter if 80% full to keep the actual false | ||
// positive rate low | ||
c.filter.ClearAll() | ||
|
||
// reduce memory footprint when this happens | ||
c.filter.BitSet().Compact() | ||
|
||
c.items = uint(len(suffixes)) | ||
} | ||
|
||
var combined [hibpHashLength]byte | ||
copy(combined[:], prefix) | ||
|
||
for _, suffix := range suffixes { | ||
copy(combined[hibpHashPrefixLength:], suffix) | ||
|
||
c.filter.Add(combined[:]) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (c *HIBPBloomCache) Contains(ctx context.Context, prefix, suffix []byte) (bool, error) { | ||
var combined [hibpHashLength]byte | ||
copy(combined[:], prefix) | ||
copy(combined[hibpHashPrefixLength:], suffix) | ||
|
||
c.RLock() | ||
defer c.RUnlock() | ||
|
||
return c.filter.Test(combined[:]), nil | ||
} |