Old code is not consistent for generating & decoding the JWT secrets.
Now, the callers only need to use 2 consistent functions:
NewJwtSecretWithBase64 and DecodeJwtSecretBase64
And remove a non-common function Base64FixedDecode from util.go
}
func runGenerateLfsJwtSecret(c *cli.Context) error {
- _, jwtSecretBase64, err := generate.NewJwtSecretBase64()
+ _, jwtSecretBase64, err := generate.NewJwtSecretWithBase64()
if err != nil {
return err
}
import (
"crypto/rand"
"encoding/base64"
+ "fmt"
"io"
"time"
return internalToken, nil
}
-// NewJwtSecret generates a new value intended to be used for JWT secrets.
-func NewJwtSecret() ([]byte, error) {
- bytes := make([]byte, 32)
- _, err := io.ReadFull(rand.Reader, bytes)
- if err != nil {
+const defaultJwtSecretLen = 32
+
+// DecodeJwtSecretBase64 decodes a base64 encoded jwt secret into bytes, and check its length
+func DecodeJwtSecretBase64(src string) ([]byte, error) {
+ encoding := base64.RawURLEncoding
+ decoded := make([]byte, encoding.DecodedLen(len(src))+3)
+ if n, err := encoding.Decode(decoded, []byte(src)); err != nil {
return nil, err
+ } else if n != defaultJwtSecretLen {
+ return nil, fmt.Errorf("invalid base64 decoded length: %d, expects: %d", n, defaultJwtSecretLen)
}
- return bytes, nil
+ return decoded[:defaultJwtSecretLen], nil
}
-// NewJwtSecretBase64 generates a new base64 encoded value intended to be used for JWT secrets.
-func NewJwtSecretBase64() ([]byte, string, error) {
- bytes, err := NewJwtSecret()
+// NewJwtSecretWithBase64 generates a jwt secret with its base64 encoded value intended to be used for saving into config file
+func NewJwtSecretWithBase64() ([]byte, string, error) {
+ bytes := make([]byte, defaultJwtSecretLen)
+ _, err := io.ReadFull(rand.Reader, bytes)
if err != nil {
return nil, "", err
}
--- /dev/null
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package generate
+
+import (
+ "encoding/base64"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestDecodeJwtSecretBase64(t *testing.T) {
+ _, err := DecodeJwtSecretBase64("abcd")
+ assert.ErrorContains(t, err, "invalid base64 decoded length")
+ _, err = DecodeJwtSecretBase64(strings.Repeat("a", 64))
+ assert.ErrorContains(t, err, "invalid base64 decoded length")
+
+ str32 := strings.Repeat("x", 32)
+ encoded32 := base64.RawURLEncoding.EncodeToString([]byte(str32))
+ decoded32, err := DecodeJwtSecretBase64(encoded32)
+ assert.NoError(t, err)
+ assert.Equal(t, str32, string(decoded32))
+}
+
+func TestNewJwtSecretWithBase64(t *testing.T) {
+ secret, encoded, err := NewJwtSecretWithBase64()
+ assert.NoError(t, err)
+ assert.Len(t, secret, 32)
+ decoded, err := DecodeJwtSecretBase64(encoded)
+ assert.NoError(t, err)
+ assert.Equal(t, secret, decoded)
+}
package setting
import (
- "encoding/base64"
"fmt"
"time"
"code.gitea.io/gitea/modules/generate"
- "code.gitea.io/gitea/modules/util"
)
// LFS represents the configuration for Git LFS
}
LFS.JWTSecretBase64 = loadSecret(rootCfg.Section("server"), "LFS_JWT_SECRET_URI", "LFS_JWT_SECRET")
- LFS.JWTSecretBytes, err = util.Base64FixedDecode(base64.RawURLEncoding, []byte(LFS.JWTSecretBase64), 32)
+ LFS.JWTSecretBytes, err = generate.DecodeJwtSecretBase64(LFS.JWTSecretBase64)
if err != nil {
- LFS.JWTSecretBytes, LFS.JWTSecretBase64, err = generate.NewJwtSecretBase64()
+ LFS.JWTSecretBytes, LFS.JWTSecretBase64, err = generate.NewJwtSecretWithBase64()
if err != nil {
return fmt.Errorf("error generating JWT Secret for custom config: %v", err)
}
package setting
import (
- "encoding/base64"
"math"
"path/filepath"
"code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/util"
)
// OAuth2UsernameType is enum describing the way gitea 'name' should be generated from oauth2 data
}
if InstallLock {
- if _, err := util.Base64FixedDecode(base64.RawURLEncoding, []byte(OAuth2.JWTSecretBase64), 32); err != nil {
- key, err := generate.NewJwtSecret()
+ if _, err := generate.DecodeJwtSecretBase64(OAuth2.JWTSecretBase64); err != nil {
+ _, OAuth2.JWTSecretBase64, err = generate.NewJwtSecretWithBase64()
if err != nil {
log.Fatal("error generating JWT secret: %v", err)
}
- OAuth2.JWTSecretBase64 = base64.RawURLEncoding.EncodeToString(key)
saveCfg, err := rootCfg.PrepareSaving()
if err != nil {
log.Fatal("save oauth2.JWT_SECRET failed: %v", err)
import (
"bytes"
"crypto/rand"
- "encoding/base64"
"fmt"
"math/big"
"strconv"
func ToPointer[T any](val T) *T {
return &val
}
-
-func Base64FixedDecode(encoding *base64.Encoding, src []byte, length int) ([]byte, error) {
- decoded := make([]byte, encoding.DecodedLen(len(src))+3)
- if n, err := encoding.Decode(decoded, src); err != nil {
- return nil, err
- } else if n != length {
- return nil, fmt.Errorf("invalid base64 decoded length: %d, expects: %d", n, length)
- }
- return decoded[:length], nil
-}
package util
import (
- "encoding/base64"
"regexp"
"strings"
"testing"
val123 := 123
assert.False(t, &val123 == ToPointer(val123))
}
-
-func TestBase64FixedDecode(t *testing.T) {
- _, err := Base64FixedDecode(base64.RawURLEncoding, []byte("abcd"), 32)
- assert.ErrorContains(t, err, "invalid base64 decoded length")
- _, err = Base64FixedDecode(base64.RawURLEncoding, []byte(strings.Repeat("a", 64)), 32)
- assert.ErrorContains(t, err, "invalid base64 decoded length")
-
- str32 := strings.Repeat("x", 32)
- encoded32 := base64.RawURLEncoding.EncodeToString([]byte(str32))
- decoded32, err := Base64FixedDecode(base64.RawURLEncoding, []byte(encoded32), 32)
- assert.NoError(t, err)
- assert.Equal(t, str32, string(decoded32))
-}
cfg.Section("server").Key("LFS_START_SERVER").SetValue("true")
cfg.Section("lfs").Key("PATH").SetValue(form.LFSRootPath)
var lfsJwtSecret string
- if _, lfsJwtSecret, err = generate.NewJwtSecretBase64(); err != nil {
+ if _, lfsJwtSecret, err = generate.NewJwtSecretWithBase64(); err != nil {
ctx.RenderWithErr(ctx.Tr("install.lfs_jwt_secret_failed", err), tplInstall, &form)
return
}
"path/filepath"
"strings"
+ "code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
// loadSymmetricKey checks if the configured secret is valid.
// If it is not valid, it will return an error.
func loadSymmetricKey() (any, error) {
- return util.Base64FixedDecode(base64.RawURLEncoding, []byte(setting.OAuth2.JWTSecretBase64), 32)
+ return generate.DecodeJwtSecretBase64(setting.OAuth2.JWTSecretBase64)
}
// loadOrCreateAsymmetricKey checks if the configured private key exists.