mirror of
https://github.com/pommee/goaway.git
synced 2026-01-11 16:40:32 -06:00
fix: dynamic jwt secret
This commit is contained in:
@@ -45,7 +45,7 @@ func (api *API) handleLogin(c *gin.Context) {
|
||||
}
|
||||
|
||||
if api.UserService.Authenticate(loginUser.Username, loginUser.Password) {
|
||||
token, err := generateToken(loginUser.Username)
|
||||
token, err := generateToken(loginUser.Username, api.Config.API.JWTSecret)
|
||||
if err != nil {
|
||||
log.Info("Token generation failed for user %s: %v", loginUser.Username, err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -12,7 +13,6 @@ import (
|
||||
|
||||
const (
|
||||
tokenDuration = 5 * time.Minute
|
||||
secret = "kMNSRwKip7Yet4rb2z8"
|
||||
)
|
||||
|
||||
func (api *API) authMiddleware() gin.HandlerFunc {
|
||||
@@ -37,7 +37,7 @@ func (api *API) authMiddleware() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
claims, err := parseToken(cookie)
|
||||
claims, err := parseToken(cookie, api.Config.API.JWTSecret)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"})
|
||||
return
|
||||
@@ -66,7 +66,7 @@ func (api *API) authMiddleware() gin.HandlerFunc {
|
||||
timeUntilExpiration := expiration - now
|
||||
|
||||
if timeUntilExpiration <= halfDurationSeconds {
|
||||
newToken, err := generateToken(username)
|
||||
newToken, err := generateToken(username, api.Config.API.JWTSecret)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Failed to renew token"})
|
||||
return
|
||||
@@ -80,11 +80,15 @@ func (api *API) authMiddleware() gin.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func parseToken(tokenString string) (jwt.MapClaims, error) {
|
||||
func parseToken(tokenString string, b64secret string) (jwt.MapClaims, error) {
|
||||
token, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
|
||||
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
|
||||
}
|
||||
secret, err := base64.RawURLEncoding.DecodeString(b64secret)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return []byte(secret), nil
|
||||
})
|
||||
if err != nil || !token.Valid {
|
||||
@@ -99,7 +103,7 @@ func parseToken(tokenString string) (jwt.MapClaims, error) {
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
func generateToken(username string) (string, error) {
|
||||
func generateToken(username string, b64secret string) (string, error) {
|
||||
now := time.Now()
|
||||
claims := jwt.MapClaims{
|
||||
"username": username,
|
||||
@@ -107,6 +111,10 @@ func generateToken(username string) (string, error) {
|
||||
"iat": now.Unix(),
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
secret, err := base64.RawURLEncoding.DecodeString(b64secret)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return token.SignedString([]byte(secret))
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ type RateLimitConfig struct {
|
||||
type APIConfig struct {
|
||||
Port int `yaml:"port" json:"port"`
|
||||
Authentication bool `yaml:"authentication" json:"authentication"`
|
||||
JWTSecret string `yaml:"jwtSecret" json:"-"`
|
||||
RateLimit RateLimitConfig `yaml:"rateLimit" json:"rateLimit"`
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"goaway/backend/logging"
|
||||
"net"
|
||||
@@ -83,6 +85,16 @@ func (config *Config) Update(updatedSettings Config) {
|
||||
config.Save()
|
||||
}
|
||||
|
||||
func GenerateSecret() string {
|
||||
secret := make([]byte, 32)
|
||||
_, err := rand.Read(secret)
|
||||
if err != nil {
|
||||
log.Error("Failed to generate secret: %v", err)
|
||||
return ""
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(secret)
|
||||
}
|
||||
|
||||
func createDefaultSettings(filePath string) (Config, error) {
|
||||
defaultConfig := Config{
|
||||
DNS: DNSConfig{
|
||||
@@ -110,6 +122,7 @@ func createDefaultSettings(filePath string) (Config, error) {
|
||||
API: APIConfig{
|
||||
Port: getEnvAsIntWithDefault("WEBSITE_PORT", 8080),
|
||||
Authentication: true,
|
||||
JWTSecret: GenerateSecret(),
|
||||
RateLimit: RateLimitConfig{
|
||||
Enabled: true,
|
||||
MaxTries: 5,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -133,6 +134,12 @@ func InitializeSettings(flags *SetFlags) *settings.Config {
|
||||
}
|
||||
|
||||
UpdateConfig(&config, flags)
|
||||
|
||||
secret, err := base64.RawURLEncoding.DecodeString(config.API.JWTSecret)
|
||||
if err != nil || len(secret) == 0 {
|
||||
config.API.JWTSecret = settings.GenerateSecret()
|
||||
}
|
||||
|
||||
config.Save()
|
||||
|
||||
return &config
|
||||
|
||||
@@ -52,6 +52,10 @@ api:
|
||||
# Set to true for increased security.
|
||||
authentication: true
|
||||
|
||||
# Secret key used for signing JWT tokens.
|
||||
# If empty, a random key will be generated automatically.
|
||||
jwtSecret: ""
|
||||
|
||||
# Currently only protects the login route
|
||||
rateLimit:
|
||||
# Enable or disable the usage of rate limiting
|
||||
|
||||
Reference in New Issue
Block a user