Skip to content

Commit d6fa74e

Browse files
authored
[bugfix] Change maximumPasswordLength to 72 bytes (#2012)
1 parent 95e2024 commit d6fa74e

File tree

2 files changed

+23
-18
lines changed

2 files changed

+23
-18
lines changed

internal/validate/formvalidation.go

+21-16
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"errors"
2222
"fmt"
2323
"net/mail"
24-
"strings"
2524

2625
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
2726
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -32,8 +31,8 @@ import (
3231
)
3332

3433
const (
35-
maximumPasswordLength = 256
36-
minimumPasswordEntropy = 60 // dictates password strength. See https://github.com/wagslane/go-password-validator
34+
maximumPasswordLength = 72 // 72 bytes is the maximum length afforded by bcrypt. See https://pkg.go.dev/golang.org/x/crypto/bcrypt#GenerateFromPassword.
35+
minimumPasswordEntropy = 60 // Heuristic for password strength. See https://github.com/wagslane/go-password-validator.
3736
minimumReasonLength = 40
3837
maximumReasonLength = 500
3938
maximumSiteTitleLength = 40
@@ -47,23 +46,29 @@ const (
4746
maximumListTitleLength = 200
4847
)
4948

50-
// NewPassword returns an error if the given password is not sufficiently strong, or nil if it's ok.
49+
// NewPassword returns a helpful error if the given password
50+
// is too short, too long, or not sufficiently strong.
5151
func NewPassword(password string) error {
52-
if password == "" {
53-
return errors.New("no password provided")
54-
}
55-
56-
if len([]rune(password)) > maximumPasswordLength {
57-
return fmt.Errorf("password should be no more than %d chars", maximumPasswordLength)
52+
// Ensure length is OK first.
53+
if pwLen := len(password); pwLen == 0 {
54+
return errors.New("no password provided / provided password was 0 bytes")
55+
} else if pwLen > maximumPasswordLength {
56+
return fmt.Errorf(
57+
"password should be no more than %d bytes, provided password was %d bytes",
58+
maximumPasswordLength, pwLen,
59+
)
5860
}
5961

6062
if err := pwv.Validate(password, minimumPasswordEntropy); err != nil {
61-
// Modify error message to include percentage requred entropy the password has
62-
percent := int(100 * pwv.GetEntropy(password) / minimumPasswordEntropy)
63-
return errors.New(strings.ReplaceAll(
64-
err.Error(),
65-
"insecure password",
66-
fmt.Sprintf("password is only %d%% strength", percent)))
63+
// Calculate the percentage of our desired entropy this password fulfils.
64+
entropyPercent := int(100 * pwv.GetEntropy(password) / minimumPasswordEntropy)
65+
66+
// Replace the first 17 bytes (`insecure password`)
67+
// of the error string with our own entropy message.
68+
entropyMsg := fmt.Sprintf("password is only %d%% strength", entropyPercent)
69+
errMsg := entropyMsg + err.Error()[17:]
70+
71+
return errors.New(errMsg)
6772
}
6873

6974
return nil // password OK

internal/validate/formvalidation_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (suite *ValidationTestSuite) TestCheckPasswordStrength() {
4545

4646
err = validate.NewPassword(empty)
4747
if suite.Error(err) {
48-
suite.Equal(errors.New("no password provided"), err)
48+
suite.Equal(errors.New("no password provided / provided password was 0 bytes"), err)
4949
}
5050

5151
err = validate.NewPassword(terriblePassword)
@@ -75,7 +75,7 @@ func (suite *ValidationTestSuite) TestCheckPasswordStrength() {
7575

7676
err = validate.NewPassword(tooLong)
7777
if suite.Error(err) {
78-
suite.Equal(errors.New("password should be no more than 256 chars"), err)
78+
suite.Equal(errors.New("password should be no more than 72 bytes, provided password was 571 bytes"), err)
7979
}
8080

8181
err = validate.NewPassword(strongPassword)

0 commit comments

Comments
 (0)