diff options
| author | Max Resnick <max@ofmax.li> | 2025-03-29 16:29:49 -0700 |
|---|---|---|
| committer | Max Resnick <max@ofmax.li> | 2025-03-29 16:31:35 -0700 |
| commit | 6d4cd2c3353c6d94a3d29f675388e647788a83c3 (patch) | |
| tree | a3e92af5466c4cb3441ba88fbe5821c9c9baa34b /internal | |
| parent | 657ec55ac99aa06514710e9d72329f1d80c59118 (diff) | |
| download | go-git-server-6d4cd2c3353c6d94a3d29f675388e647788a83c3.tar.gz | |
feat: upgrade token security, upgrade go, packages, fix linting issues
Token generation changes:
1. Increasing to 32 bytes (256 bits) of entropy
2. Using crypto/rand.Read directly instead of loop
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/admin/service_test.go | 15 | ||||
| -rw-r--r-- | internal/authz/model.go | 21 |
2 files changed, 24 insertions, 12 deletions
diff --git a/internal/admin/service_test.go b/internal/admin/service_test.go index 06088bc..9af6bb9 100644 --- a/internal/admin/service_test.go +++ b/internal/admin/service_test.go @@ -108,7 +108,12 @@ func TestInitServer(t *testing.T) { {"role:maintainers", "/thisismynewrepo/git-receive-pack", "POST"}, } for _, policy := range expectedPolicies { - if !svc.HasPolicy(policy[0], policy[1], policy[2]) { + hasPolicy, err := svc.HasPolicy(policy[0], policy[1], policy[2]) + if err != nil { + t.Log("error checking policies", err) + t.Fail() + } + if !hasPolicy { t.Log("policy not found", policy) t.Fail() } @@ -136,10 +141,16 @@ func TestInitServer(t *testing.T) { {"role:admin", "/mgmt/git-receive-pack", "POST"}, } for _, policy := range expectedPolicies { - if !svc.HasPolicy(policy[0], policy[1], policy[2]) { + hasPolicy, err := svc.HasPolicy(policy[0], policy[1], policy[2]) + if err != nil { + t.Log("error checking policies", err) + t.Fail() + } + if !hasPolicy { t.Log("policy not found", policy) t.Fail() } + } }) t.Run("test an unitialized server config", func(t *testing.T) { diff --git a/internal/authz/model.go b/internal/authz/model.go index c43a159..0c55c15 100644 --- a/internal/authz/model.go +++ b/internal/authz/model.go @@ -6,12 +6,14 @@ import ( "encoding/hex" "fmt" "log/slog" - "math/big" "os" "golang.org/x/crypto/bcrypt" ) +// TokenSize is the number of random bytes used for token generation +const TokenSize = 32 + // NewTokenMap create a new token map func NewTokenMap() TokenMap { return TokenMap{} @@ -42,17 +44,16 @@ func (tm TokenMap) LoadTokensFromFile(path string) error { return err } -// GenerateNewToken generate a new token +// GenerateNewToken generates a new secure random token and its bcrypt hash +// The token is 32 bytes (256 bits) of cryptographically secure random data +// encoded as a 64-character hex string. The hash is a bcrypt hash of the +// random bytes using default cost parameters. func GenerateNewToken() (string, string, error) { - tokenBytes := make([]byte, 28) - for i := range tokenBytes { - maxInt := big.NewInt(int64(255)) - randInt, err := rand.Int(rand.Reader, maxInt) - if err != nil { - return "", "", err - } - tokenBytes[i] = uint8(randInt.Int64()) + tokenBytes := make([]byte, TokenSize) + if _, err := rand.Read(tokenBytes); err != nil { + return "", "", fmt.Errorf("failed to generate random token: %w", err) } + hashBytes, err := bcrypt.GenerateFromPassword(tokenBytes, bcrypt.DefaultCost) if err != nil { return "", "", err |