mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-06 10:19:31 -06:00
use byteutil.S2B to avoid allocations when comparing + generating password hashes
This commit is contained in:
parent
c6c212fb81
commit
9d10fb59b5
8 changed files with 53 additions and 18 deletions
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"codeberg.org/gruf/go-byteutil"
|
||||||
"github.com/gin-contrib/sessions"
|
"github.com/gin-contrib/sessions"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
|
|
@ -169,8 +170,8 @@ func (m *Module) validatePassword(
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bcrypt.CompareHashAndPassword(
|
if err := bcrypt.CompareHashAndPassword(
|
||||||
[]byte(user.EncryptedPassword),
|
byteutil.S2B(user.EncryptedPassword),
|
||||||
[]byte(password),
|
byteutil.S2B(password),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
err := fmt.Errorf("password hash didn't match for user %s during sign in attempt: %s", user.Email, err)
|
err := fmt.Errorf("password hash didn't match for user %s during sign in attempt: %s", user.Email, err)
|
||||||
return incorrectPassword(err)
|
return incorrectPassword(err)
|
||||||
|
|
@ -278,8 +279,8 @@ func (m *Module) validate2FACode(c *gin.Context, user *gtsmodel.User, code strin
|
||||||
// Check against the user's stored codes.
|
// Check against the user's stored codes.
|
||||||
for i := 0; i < len(user.TwoFactorBackups); i++ {
|
for i := 0; i < len(user.TwoFactorBackups); i++ {
|
||||||
err := bcrypt.CompareHashAndPassword(
|
err := bcrypt.CompareHashAndPassword(
|
||||||
[]byte(user.TwoFactorBackups[i]),
|
byteutil.S2B(user.TwoFactorBackups[i]),
|
||||||
[]byte(code),
|
byteutil.S2B(code),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Doesn't match,
|
// Doesn't match,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"codeberg.org/gruf/go-byteutil"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||||
|
|
@ -87,7 +88,10 @@ func (m *Module) AccountDeletePOSTHandler(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bcrypt.CompareHashAndPassword([]byte(authed.User.EncryptedPassword), []byte(form.Password)); err != nil {
|
if err := bcrypt.CompareHashAndPassword(
|
||||||
|
byteutil.S2B(authed.User.EncryptedPassword),
|
||||||
|
byteutil.S2B(form.Password),
|
||||||
|
); err != nil {
|
||||||
err = errors.New("invalid password provided in account delete request")
|
err = errors.New("invalid password provided in account delete request")
|
||||||
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGetV1)
|
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGetV1)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"codeberg.org/gruf/go-byteutil"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/user"
|
"github.com/superseriousbusiness/gotosocial/internal/api/client/user"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
|
|
@ -50,11 +51,17 @@ func (suite *PasswordChangeTestSuite) TestPasswordChangePOST() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// new password should pass
|
// new password should pass
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(dbUser.EncryptedPassword), []byte("peepeepoopoopassword"))
|
err = bcrypt.CompareHashAndPassword(
|
||||||
|
byteutil.S2B(dbUser.EncryptedPassword),
|
||||||
|
byteutil.S2B("peepeepoopoopassword"),
|
||||||
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// old password should fail
|
// old password should fail
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(dbUser.EncryptedPassword), []byte("password"))
|
err = bcrypt.CompareHashAndPassword(
|
||||||
|
byteutil.S2B(dbUser.EncryptedPassword),
|
||||||
|
byteutil.S2B("password"),
|
||||||
|
)
|
||||||
suite.EqualError(err, "crypto/bcrypt: hashedPassword is not the hash of the given password")
|
suite.EqualError(err, "crypto/bcrypt: hashedPassword is not the hash of the given password")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"codeberg.org/gruf/go-byteutil"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||||
|
|
@ -70,8 +71,8 @@ func (p *Processor) MoveSelf(
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bcrypt.CompareHashAndPassword(
|
if err := bcrypt.CompareHashAndPassword(
|
||||||
[]byte(authed.User.EncryptedPassword),
|
byteutil.S2B(authed.User.EncryptedPassword),
|
||||||
[]byte(form.Password),
|
byteutil.S2B(form.Password),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
const text = "invalid password provided in Move request"
|
const text = "invalid password provided in Move request"
|
||||||
return gtserror.NewErrorBadRequest(errors.New(text), text)
|
return gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"codeberg.org/gruf/go-byteutil"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
|
|
@ -41,7 +42,10 @@ func (p *Processor) EmailChange(
|
||||||
newEmail string,
|
newEmail string,
|
||||||
) (*apimodel.User, gtserror.WithCode) {
|
) (*apimodel.User, gtserror.WithCode) {
|
||||||
// Ensure provided password is correct.
|
// Ensure provided password is correct.
|
||||||
if err := bcrypt.CompareHashAndPassword([]byte(user.EncryptedPassword), []byte(password)); err != nil {
|
if err := bcrypt.CompareHashAndPassword(
|
||||||
|
byteutil.S2B(user.EncryptedPassword),
|
||||||
|
byteutil.S2B(password),
|
||||||
|
); err != nil {
|
||||||
err := gtserror.Newf("%w", err)
|
err := gtserror.Newf("%w", err)
|
||||||
return nil, gtserror.NewErrorUnauthorized(err, "password was incorrect")
|
return nil, gtserror.NewErrorUnauthorized(err, "password was incorrect")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package user
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"codeberg.org/gruf/go-byteutil"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/validate"
|
"github.com/superseriousbusiness/gotosocial/internal/validate"
|
||||||
|
|
@ -29,7 +30,10 @@ import (
|
||||||
// PasswordChange processes a password change request for the given user.
|
// PasswordChange processes a password change request for the given user.
|
||||||
func (p *Processor) PasswordChange(ctx context.Context, user *gtsmodel.User, oldPassword string, newPassword string) gtserror.WithCode {
|
func (p *Processor) PasswordChange(ctx context.Context, user *gtsmodel.User, oldPassword string, newPassword string) gtserror.WithCode {
|
||||||
// Ensure provided oldPassword is the correct current password.
|
// Ensure provided oldPassword is the correct current password.
|
||||||
if err := bcrypt.CompareHashAndPassword([]byte(user.EncryptedPassword), []byte(oldPassword)); err != nil {
|
if err := bcrypt.CompareHashAndPassword(
|
||||||
|
byteutil.S2B(user.EncryptedPassword),
|
||||||
|
byteutil.S2B(oldPassword),
|
||||||
|
); err != nil {
|
||||||
err := gtserror.Newf("%w", err)
|
err := gtserror.Newf("%w", err)
|
||||||
return gtserror.NewErrorUnauthorized(err, "old password was incorrect")
|
return gtserror.NewErrorUnauthorized(err, "old password was incorrect")
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +52,7 @@ func (p *Processor) PasswordChange(ctx context.Context, user *gtsmodel.User, old
|
||||||
|
|
||||||
// Hash the new password.
|
// Hash the new password.
|
||||||
encryptedPassword, err := bcrypt.GenerateFromPassword(
|
encryptedPassword, err := bcrypt.GenerateFromPassword(
|
||||||
[]byte(newPassword),
|
byteutil.S2B(newPassword),
|
||||||
bcrypt.DefaultCost,
|
bcrypt.DefaultCost,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"codeberg.org/gruf/go-byteutil"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
@ -37,7 +38,10 @@ func (suite *ChangePasswordTestSuite) TestChangePasswordOK() {
|
||||||
errWithCode := suite.user.PasswordChange(context.Background(), user, "password", "verygoodnewpassword")
|
errWithCode := suite.user.PasswordChange(context.Background(), user, "password", "verygoodnewpassword")
|
||||||
suite.NoError(errWithCode)
|
suite.NoError(errWithCode)
|
||||||
|
|
||||||
err := bcrypt.CompareHashAndPassword([]byte(user.EncryptedPassword), []byte("verygoodnewpassword"))
|
err := bcrypt.CompareHashAndPassword(
|
||||||
|
byteutil.S2B(user.EncryptedPassword),
|
||||||
|
byteutil.S2B("verygoodnewpassword"),
|
||||||
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// get user from the db again
|
// get user from the db again
|
||||||
|
|
@ -46,7 +50,10 @@ func (suite *ChangePasswordTestSuite) TestChangePasswordOK() {
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// check the password has changed
|
// check the password has changed
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(dbUser.EncryptedPassword), []byte("verygoodnewpassword"))
|
err = bcrypt.CompareHashAndPassword(
|
||||||
|
byteutil.S2B(dbUser.EncryptedPassword),
|
||||||
|
byteutil.S2B("verygoodnewpassword"),
|
||||||
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,7 +71,10 @@ func (suite *ChangePasswordTestSuite) TestChangePasswordIncorrectOld() {
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// check the password has not changed
|
// check the password has not changed
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(dbUser.EncryptedPassword), []byte("password"))
|
err = bcrypt.CompareHashAndPassword(
|
||||||
|
byteutil.S2B(dbUser.EncryptedPassword),
|
||||||
|
byteutil.S2B("password"),
|
||||||
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,7 +92,10 @@ func (suite *ChangePasswordTestSuite) TestChangePasswordWeakNew() {
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// check the password has not changed
|
// check the password has not changed
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(dbUser.EncryptedPassword), []byte("password"))
|
err = bcrypt.CompareHashAndPassword(
|
||||||
|
byteutil.S2B(dbUser.EncryptedPassword),
|
||||||
|
byteutil.S2B("password"),
|
||||||
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"codeberg.org/gruf/go-byteutil"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/pquerna/otp"
|
"github.com/pquerna/otp"
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
|
|
@ -251,8 +252,8 @@ func (p *Processor) TwoFactorDisable(
|
||||||
|
|
||||||
// Ensure provided password is correct.
|
// Ensure provided password is correct.
|
||||||
if err := bcrypt.CompareHashAndPassword(
|
if err := bcrypt.CompareHashAndPassword(
|
||||||
[]byte(user.EncryptedPassword),
|
byteutil.S2B(user.EncryptedPassword),
|
||||||
[]byte(password),
|
byteutil.S2B(password),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
const errText = "incorrect password"
|
const errText = "incorrect password"
|
||||||
return gtserror.NewErrorUnauthorized(errors.New(errText), errText)
|
return gtserror.NewErrorUnauthorized(errors.New(errText), errText)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue