Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/configurable hashing and encoding #355

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"context"
"net/http"

"golang.org/x/crypto/bcrypt"

"github.com/volatiletech/authboss/v3"
)

Expand Down Expand Up @@ -77,7 +75,7 @@ func (a *Auth) LoginPost(w http.ResponseWriter, r *http.Request) error {
r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyUser, pidUser))

var handled bool
err = bcrypt.CompareHashAndPassword([]byte(password), []byte(creds.GetPassword()))
err = a.Authboss.Core.Hasher.CompareHashAndPassword(password, creds.GetPassword())
if err != nil {
handled, err = a.Authboss.Events.FireAfter(authboss.EventAuthFail, w, r)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func testSetup() *testHarness {

harness.ab.Config.Core.BodyReader = harness.bodyReader
harness.ab.Config.Core.Logger = mocks.Logger{}
harness.ab.Config.Core.Hasher = mocks.Hasher{}
harness.ab.Config.Core.Responder = harness.responder
harness.ab.Config.Core.Redirector = harness.redirector
harness.ab.Config.Storage.SessionState = harness.session
Expand Down
28 changes: 24 additions & 4 deletions authboss.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ func New() *Authboss {

// Init authboss, modules, renderers
func (a *Authboss) Init(modulesToLoad ...string) error {
// Create the hasher
// Have to do it in Init for backwards compatibility.
// If a user did not previously use defaults.SetCore() then they will
// suddenly start getting panics
// We also cannot use config.Defaults() so we can respect the user's BCryptCost
stephenafamo marked this conversation as resolved.
Show resolved Hide resolved
if a.Config.Core.Hasher == nil {
a.Config.Core.Hasher = NewBCryptHasher(a.Config.Modules.BCryptCost)
}

if len(modulesToLoad) == 0 {
modulesToLoad = RegisteredModules()
}
Expand All @@ -65,12 +74,12 @@ func (a *Authboss) Init(modulesToLoad ...string) error {
// in sessions for a user requires special mechanisms not currently provided
// by authboss.
func (a *Authboss) UpdatePassword(ctx context.Context, user AuthableUser, newPassword string) error {
pass, err := bcrypt.GenerateFromPassword([]byte(newPassword), a.Config.Modules.BCryptCost)
pass, err := a.Config.Core.Hasher.GenerateHash(newPassword)
if err != nil {
return err
}

user.PutPassword(string(pass))
user.PutPassword(pass)

storer := a.Config.Storage.Server
if err := storer.Save(ctx, user); err != nil {
Expand All @@ -85,9 +94,20 @@ func (a *Authboss) UpdatePassword(ctx context.Context, user AuthableUser, newPas
return rmStorer.DelRememberTokens(ctx, user.GetPID())
}

// VerifyPassword check that the provided password for the user is correct.
// Returns nil on success otherwise there will be an error.
// Simply a wrapper for [a.Core.Hasher.CompareHashAndPassword]
func (a *Authboss) VerifyPassword(user AuthableUser, password string) error {
return a.Core.Hasher.CompareHashAndPassword(user.GetPassword(), password)
}

// VerifyPassword uses authboss mechanisms to check that a password is correct.
// Returns nil on success otherwise there will be an error. Simply a helper
// to do the bcrypt comparison.
//
// NOTE: This function will work ONLY if no custom hasher was configured in global ab.config
//
// Deperecated: use [a.VerifyPassword] instead
func VerifyPassword(user AuthableUser, password string) error {
return bcrypt.CompareHashAndPassword([]byte(user.GetPassword()), []byte(password))
}
Expand All @@ -96,7 +116,7 @@ func VerifyPassword(user AuthableUser, password string) error {
// in order to access the routes in protects. Requirements is a bit-set integer
// to be able to easily combine requirements like so:
//
// authboss.RequireFullAuth | authboss.Require2FA
// authboss.RequireFullAuth | authboss.Require2FA
type MWRequirements int

// MWRespondOnFailure tells authboss.Middleware how to respond to
Expand Down Expand Up @@ -153,7 +173,7 @@ func MountedMiddleware(ab *Authboss, mountPathed, redirectToLogin, forceFullAuth
//
// requirements are set by logical or'ing together requirements. eg:
//
// authboss.RequireFullAuth | authboss.Require2FA
// authboss.RequireFullAuth | authboss.Require2FA
//
// failureResponse is how the middleware rejects the users that don't meet
// the criteria. This should be chosen from the MWRespondOnFailure constants.
Expand Down
1 change: 1 addition & 0 deletions authboss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func TestAuthbossUpdatePassword(t *testing.T) {

ab := New()
ab.Config.Storage.Server = storer
ab.Config.Core.Hasher = mockHasher{}

if err := ab.UpdatePassword(context.Background(), user, "hello world"); err != nil {
t.Error(err)
Expand Down
9 changes: 9 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type Config struct {

Modules struct {
// BCryptCost is the cost of the bcrypt password hashing function.
// Deprecated: Use Hasher instead.
BCryptCost int

// ConfirmMethod IS DEPRECATED! See MailRouteMethod instead.
Expand Down Expand Up @@ -239,6 +240,12 @@ type Config struct {
// Mailer is the mailer being used to send e-mails out via smtp
Mailer Mailer

// Hasher hashes passwords into hashes
Hasher Hasher

// OneTimeTokenGenerator generates credentials (selector+verified+token)
OneTimeTokenGenerator OneTimeTokenGenerator

// Logger implies just a few log levels for use, can optionally
// also implement the ContextLogger to be able to upgrade to a
// request specific logger.
Expand Down Expand Up @@ -272,4 +279,6 @@ func (c *Config) Defaults() {
c.Modules.MailRouteMethod = http.MethodGet
c.Modules.RecoverLoginAfterRecovery = false
c.Modules.RecoverTokenDuration = 24 * time.Hour

c.Core.OneTimeTokenGenerator = NewSha512TokenGenerator()
}
19 changes: 11 additions & 8 deletions confirm/confirm.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"path"

"github.com/friendsofgo/errors"

"github.com/volatiletech/authboss/v3"
)

Expand All @@ -33,9 +32,6 @@ const (
// DataConfirmURL is the name of the e-mail template variable
// that gives the url to send to the user for confirmation.
DataConfirmURL = "url"

confirmTokenSize = 64
confirmTokenSplit = confirmTokenSize / 2
)

func init() {
Expand Down Expand Up @@ -128,7 +124,7 @@ func (c *Confirm) StartConfirmationWeb(w http.ResponseWriter, r *http.Request, h
func (c *Confirm) StartConfirmation(ctx context.Context, user authboss.ConfirmableUser, sendEmail bool) error {
logger := c.Authboss.Logger(ctx)

selector, verifier, token, err := GenerateConfirmCreds()
selector, verifier, token, err := c.Authboss.Core.OneTimeTokenGenerator.GenerateToken()
if err != nil {
return err
}
Expand Down Expand Up @@ -198,13 +194,14 @@ func (c *Confirm) Get(w http.ResponseWriter, r *http.Request) error {
return c.invalidToken(w, r)
}

if len(rawToken) != confirmTokenSize {
credsGenerator := c.Authboss.Core.OneTimeTokenGenerator

if len(rawToken) != credsGenerator.TokenSize() {
logger.Infof("invalid confirm token submitted, size was wrong: %d", len(rawToken))
return c.invalidToken(w, r)
}

selectorBytes := sha512.Sum512(rawToken[:confirmTokenSplit])
verifierBytes := sha512.Sum512(rawToken[confirmTokenSplit:])
selectorBytes, verifierBytes := credsGenerator.ParseToken(string(rawToken))
selector := base64.StdEncoding.EncodeToString(selectorBytes[:])

storer := authboss.EnsureCanConfirm(c.Authboss.Config.Storage.Server)
Expand Down Expand Up @@ -303,11 +300,17 @@ func Middleware(ab *authboss.Authboss) func(http.Handler) http.Handler {
// verifier: hash of the second half of a 64 byte value
// (to be stored in database but never used in SELECT query)
// token: the user-facing base64 encoded selector+verifier
//
// Deprecated: use [authboss.OneTimeTokenGenerator] instead.
func GenerateConfirmCreds() (selector, verifier, token string, err error) {
stephenafamo marked this conversation as resolved.
Show resolved Hide resolved
confirmTokenSize := 64
confirmTokenSplit := confirmTokenSize / 2

rawToken := make([]byte, confirmTokenSize)
if _, err = io.ReadFull(rand.Reader, rawToken); err != nil {
return "", "", "", err
}

selectorBytes := sha512.Sum512(rawToken[:confirmTokenSplit])
verifierBytes := sha512.Sum512(rawToken[confirmTokenSplit:])

Expand Down
11 changes: 8 additions & 3 deletions confirm/confirm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func testSetup() *testHarness {

harness.ab.Config.Core.BodyReader = harness.bodyReader
harness.ab.Config.Core.Logger = mocks.Logger{}
harness.ab.Config.Core.Hasher = mocks.Hasher{}
harness.ab.Config.Core.Mailer = harness.mailer
harness.ab.Config.Core.Redirector = harness.redirector
harness.ab.Config.Core.MailRenderer = harness.renderer
Expand Down Expand Up @@ -176,7 +177,7 @@ func TestGetSuccess(t *testing.T) {

harness := testSetup()

selector, verifier, token, err := GenerateConfirmCreds()
selector, verifier, token, err := harness.ab.Config.Core.OneTimeTokenGenerator.GenerateToken()
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -271,7 +272,7 @@ func TestGetUserNotFoundFailure(t *testing.T) {

harness := testSetup()

_, _, token, err := GenerateConfirmCreds()
_, _, token, err := harness.ab.Config.Core.OneTimeTokenGenerator.GenerateToken()
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -380,7 +381,9 @@ func TestMailURL(t *testing.T) {
func TestGenerateRecoverCreds(t *testing.T) {
t.Parallel()

selector, verifier, token, err := GenerateConfirmCreds()
credsGenerator := authboss.NewSha512TokenGenerator()

selector, verifier, token, err := credsGenerator.GenerateToken()
if err != nil {
t.Error(err)
}
Expand All @@ -389,6 +392,8 @@ func TestGenerateRecoverCreds(t *testing.T) {
t.Error("the verifier and selector should be different")
}

confirmTokenSplit := credsGenerator.TokenSize() / 2

// base64 length: n = 64; 4*(64/3) = 85.3; round to nearest 4: 88
if len(verifier) != 88 {
t.Errorf("verifier length was wrong (%d): %s", len(verifier), verifier)
Expand Down
13 changes: 9 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ module github.com/volatiletech/authboss/v3

go 1.19

require (
github.com/friendsofgo/errors v0.9.2
github.com/pquerna/otp v1.4.0
golang.org/x/crypto v0.14.0
golang.org/x/oauth2 v0.6.0
)

require (
cloud.google.com/go v0.34.0 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/friendsofgo/errors v0.9.2
github.com/golang/protobuf v1.5.3 // indirect
github.com/pquerna/otp v1.4.0
golang.org/x/crypto v0.7.0
golang.org/x/oauth2 v0.6.0
golang.org/x/net v0.10.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.29.0 // indirect
)
57 changes: 6 additions & 51 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
Expand All @@ -10,81 +8,38 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/friendsofgo/errors v0.9.2 h1:X6NYxef4efCBdwI7BgS820zFaN7Cphrmb+Pljdzjtgk=
github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok=
github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.29.0 h1:44S3JjaKmLEE4YIkjzexaP+NzZsudE3Zin5Njn/pYX0=
google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
33 changes: 33 additions & 0 deletions hasher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package authboss

import (
"golang.org/x/crypto/bcrypt"
)

// Hasher is the interface that wraps the hashing and comparison of passwords
type Hasher interface {
stephenafamo marked this conversation as resolved.
Show resolved Hide resolved
CompareHashAndPassword(hash, password string) error
GenerateHash(password string) (string, error)
}

// NewBCryptHasher creates a new bcrypt hasher with the given cost
func NewBCryptHasher(cost int) *bcryptHasher {
return &bcryptHasher{cost: cost}
}

type bcryptHasher struct {
cost int
}

func (h *bcryptHasher) GenerateHash(password string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(password), h.cost)
if err != nil {
return "", err
}

return string(hash), nil
}

func (h *bcryptHasher) CompareHashAndPassword(hashedPassword, password string) error {
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
}
Loading
Loading