From f4212cddf00b6c93be94b2a00caa2e21c7f77b42 Mon Sep 17 00:00:00 2001 From: Huxley Date: Wed, 29 Apr 2026 17:02:49 +0800 Subject: [PATCH] Change config JWT duration fields to time.Duration - fix: The AccessTTL and RefreshTTL fields in JWTConfig now use time.Duration type directly instead of string with ParseDuration methods. The config validation now checks for positive durations rather than parsing strings. --- internal/app/webapp.go | 4 ++-- internal/config/config.go | 24 +++++++----------------- internal/config/load_test.go | 24 ++++++++++++------------ internal/server/server_test.go | 4 ++-- 4 files changed, 23 insertions(+), 33 deletions(-) diff --git a/internal/app/webapp.go b/internal/app/webapp.go index a2886f0..a916550 100644 --- a/internal/app/webapp.go +++ b/internal/app/webapp.go @@ -44,8 +44,8 @@ func Bootstrap(cfg *config.Config) (*WebApp, error) { authService := service.NewAuthService( userRepo, sessionRepo, credentialRepo, jwtSecret, - cfg.JWT.AccessDuration(), - cfg.JWT.RefreshDuration(), + cfg.JWT.AccessTTL, + cfg.JWT.RefreshTTL, ) return &WebApp{ diff --git a/internal/config/config.go b/internal/config/config.go index 6ab8f81..9e706b9 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -48,19 +48,9 @@ type LocalStorageConfig struct { } type JWTConfig struct { - Secret string `mapstructure:"secret"` - AccessTTL string `mapstructure:"access_ttl"` - RefreshTTL string `mapstructure:"refresh_ttl"` -} - -func (j JWTConfig) AccessDuration() time.Duration { - d, _ := time.ParseDuration(j.AccessTTL) - return d -} - -func (j JWTConfig) RefreshDuration() time.Duration { - d, _ := time.ParseDuration(j.RefreshTTL) - return d + Secret string `mapstructure:"secret"` + AccessTTL time.Duration `mapstructure:"access_ttl"` + RefreshTTL time.Duration `mapstructure:"refresh_ttl"` } func (c *Config) Validate() error { @@ -104,12 +94,12 @@ func (c *Config) Validate() error { errs = append(errs, errors.New("jwt.secret: must not be empty")) } - if _, err := time.ParseDuration(c.JWT.AccessTTL); err != nil { - errs = append(errs, fmt.Errorf("jwt.access_ttl: %w", err)) + if c.JWT.AccessTTL <= 0 { + errs = append(errs, errors.New("jwt.access_ttl: must be positive")) } - if _, err := time.ParseDuration(c.JWT.RefreshTTL); err != nil { - errs = append(errs, fmt.Errorf("jwt.refresh_ttl: %w", err)) + if c.JWT.RefreshTTL <= 0 { + errs = append(errs, errors.New("jwt.refresh_ttl: must be positive")) } return errors.Join(errs...) diff --git a/internal/config/load_test.go b/internal/config/load_test.go index 2a44c5b..24e75a6 100644 --- a/internal/config/load_test.go +++ b/internal/config/load_test.go @@ -25,8 +25,8 @@ func TestDefaults(t *testing.T) { {"database.sqlite.path", cfg.Database.SQLite.Path, "data/mygo.db"}, {"storage.driver", cfg.Storage.Driver, "local"}, {"storage.local.path", cfg.Storage.Local.Path, "data/files"}, - {"jwt.access_ttl", cfg.JWT.AccessTTL, "15m"}, - {"jwt.refresh_ttl", cfg.JWT.RefreshTTL, "168h"}, + {"jwt.access_ttl", cfg.JWT.AccessTTL, 15 * time.Minute}, + {"jwt.refresh_ttl", cfg.JWT.RefreshTTL, 168 * time.Hour}, } for _, tt := range tests { @@ -87,11 +87,11 @@ jwt: if cfg.JWT.Secret != "test-secret" { t.Errorf("jwt.secret = %q, want %q", cfg.JWT.Secret, "test-secret") } - if cfg.JWT.AccessTTL != "30m" { - t.Errorf("jwt.access_ttl = %q, want %q", cfg.JWT.AccessTTL, "30m") + if cfg.JWT.AccessTTL != 30*time.Minute { + t.Errorf("jwt.access_ttl = %v, want %v", cfg.JWT.AccessTTL, 30*time.Minute) } - if cfg.JWT.RefreshTTL != "72h" { - t.Errorf("jwt.refresh_ttl = %q, want %q", cfg.JWT.RefreshTTL, "72h") + if cfg.JWT.RefreshTTL != 72*time.Hour { + t.Errorf("jwt.refresh_ttl = %v, want %v", cfg.JWT.RefreshTTL, 72*time.Hour) } } @@ -198,15 +198,15 @@ func TestExplicitConfigFileNotFound(t *testing.T) { } func TestJWTConfigAccessDuration(t *testing.T) { - j := JWTConfig{AccessTTL: "15m"} - if got := j.AccessDuration(); got != 15*time.Minute { - t.Errorf("AccessDuration() = %v, want %v", got, 15*time.Minute) + j := JWTConfig{AccessTTL: 15 * time.Minute} + if j.AccessTTL != 15*time.Minute { + t.Errorf("AccessTTL = %v, want %v", j.AccessTTL, 15*time.Minute) } } func TestJWTConfigRefreshDuration(t *testing.T) { - j := JWTConfig{RefreshTTL: "168h"} - if got := j.RefreshDuration(); got != 168*time.Hour { - t.Errorf("RefreshDuration() = %v, want %v", got, 168*time.Hour) + j := JWTConfig{RefreshTTL: 168 * time.Hour} + if j.RefreshTTL != 168*time.Hour { + t.Errorf("RefreshTTL = %v, want %v", j.RefreshTTL, 168*time.Hour) } } diff --git a/internal/server/server_test.go b/internal/server/server_test.go index aef9323..72cadb5 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -16,8 +16,8 @@ func TestVersionRoute(t *testing.T) { cfg := &config.Config{ JWT: config.JWTConfig{ Secret: "test-secret", - AccessTTL: "15m", - RefreshTTL: "168h", + AccessTTL: 15 * time.Minute, + RefreshTTL: 168 * time.Hour, }, } authService := service.NewAuthService(nil, nil, nil, nil, 15*time.Minute, 7*24*time.Hour)