diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 149b339..55ec872 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -52,12 +52,12 @@ func (r *ErrMalformedToken) Error() string { } // NewAccessToken generates a new JWT access token with the correct claims -func NewAccessToken(userID string, restrictedMode RestrictedMode, orgRole string, jwtKey []byte) (string, error) { +func NewAccessToken(userID string, restrictedMode RestrictedMode, orgRole string, jwtKey []byte, expirationTime time.Duration) (string, error) { role := RoleMember if orgRole == "admin" { role = RoleAdmin } - accessExpirationTime := time.Now().Add(5 * time.Second) + accessExpirationTime := time.Now().Add(expirationTime) accessClaims := &AccessTokenClaims{ UserID: userID, Restricted: restrictedMode, diff --git a/internal/commands/commands.go b/internal/commands/commands.go index be45364..082cf02 100644 --- a/internal/commands/commands.go +++ b/internal/commands/commands.go @@ -80,6 +80,7 @@ func Execute() { viper.SetDefault("database.user", "taskcafe") viper.SetDefault("database.password", "taskcafe_test") viper.SetDefault("database.port", "5432") + viper.SetDefault("security.token_expiration", "15m") viper.SetDefault("queue.broker", "amqp://guest:guest@localhost:5672/") viper.SetDefault("queue.store", "memcache://localhost:11211") diff --git a/internal/commands/web.go b/internal/commands/web.go index 439d604..7751fae 100644 --- a/internal/commands/web.go +++ b/internal/commands/web.go @@ -76,6 +76,7 @@ func newWebCmd() *cobra.Command { log.Warn("server.secret is not set, generating a random secret") secret = uuid.New().String() } + security, err := utils.GetSecurityConfig(viper.GetString("security.token_expiration"), []byte(secret)) r, _ := route.NewRouter(db, utils.EmailConfig{ From: viper.GetString("smtp.from"), Host: viper.GetString("smtp.host"), @@ -83,7 +84,7 @@ func newWebCmd() *cobra.Command { Username: viper.GetString("smtp.username"), Password: viper.GetString("smtp.password"), InsecureSkipVerify: viper.GetBool("smtp.skip_verify"), - }, []byte(secret)) + }, security) return http.ListenAndServe(viper.GetString("server.hostname"), r) }, } diff --git a/internal/route/auth.go b/internal/route/auth.go index 42f94b2..e981b5a 100644 --- a/internal/route/auth.go +++ b/internal/route/auth.go @@ -143,7 +143,7 @@ func (h *TaskcafeHandler) RefreshTokenHandler(w http.ResponseWriter, r *http.Req } log.Info("here 1") - accessTokenString, err := auth.NewAccessToken(token.UserID.String(), auth.Unrestricted, user.RoleCode, h.jwtKey) + accessTokenString, err := auth.NewAccessToken(token.UserID.String(), auth.Unrestricted, user.RoleCode, h.SecurityConfig.Secret, h.SecurityConfig.AccessTokenExpiration) if err != nil { w.WriteHeader(http.StatusInternalServerError) return @@ -220,7 +220,7 @@ func (h *TaskcafeHandler) LoginHandler(w http.ResponseWriter, r *http.Request) { refreshExpiresAt := refreshCreatedAt.AddDate(0, 0, 1) refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), db.CreateRefreshTokenParams{user.UserID, refreshCreatedAt, refreshExpiresAt}) - accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.jwtKey) + accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.SecurityConfig.Secret, h.SecurityConfig.AccessTokenExpiration) if err != nil { w.WriteHeader(http.StatusInternalServerError) } @@ -283,7 +283,7 @@ func (h *TaskcafeHandler) InstallHandler(w http.ResponseWriter, r *http.Request) refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), db.CreateRefreshTokenParams{user.UserID, refreshCreatedAt, refreshExpiresAt}) log.WithField("userID", user.UserID.String()).Info("creating install access token") - accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.jwtKey) + accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.SecurityConfig.Secret, h.SecurityConfig.AccessTokenExpiration) if err != nil { w.WriteHeader(http.StatusInternalServerError) } @@ -386,7 +386,7 @@ func (h *TaskcafeHandler) ConfirmUser(w http.ResponseWriter, r *http.Request) { refreshExpiresAt := refreshCreatedAt.AddDate(0, 0, 1) refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), db.CreateRefreshTokenParams{user.UserID, refreshCreatedAt, refreshExpiresAt}) - accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.jwtKey) + accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.SecurityConfig.Secret, h.SecurityConfig.AccessTokenExpiration) if err != nil { w.WriteHeader(http.StatusInternalServerError) } diff --git a/internal/route/route.go b/internal/route/route.go index e3e4764..e552d86 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -60,12 +60,12 @@ func (h FrontendHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // TaskcafeHandler contains all the route handlers type TaskcafeHandler struct { - repo db.Repository - jwtKey []byte + repo db.Repository + SecurityConfig utils.SecurityConfig } // NewRouter creates a new router for chi -func NewRouter(dbConnection *sqlx.DB, emailConfig utils.EmailConfig, jwtKey []byte) (chi.Router, error) { +func NewRouter(dbConnection *sqlx.DB, emailConfig utils.EmailConfig, securityConfig utils.SecurityConfig) (chi.Router, error) { formatter := new(log.TextFormatter) formatter.TimestampFormat = "02-01-2006 15:04:05" formatter.FullTimestamp = true @@ -81,7 +81,7 @@ func NewRouter(dbConnection *sqlx.DB, emailConfig utils.EmailConfig, jwtKey []by r.Use(middleware.Timeout(60 * time.Second)) repository := db.NewRepository(dbConnection) - taskcafeHandler := TaskcafeHandler{*repository, jwtKey} + taskcafeHandler := TaskcafeHandler{*repository, securityConfig} var imgServer = http.FileServer(http.Dir("./uploads/")) r.Group(func(mux chi.Router) { @@ -91,7 +91,7 @@ func NewRouter(dbConnection *sqlx.DB, emailConfig utils.EmailConfig, jwtKey []by mux.Post("/auth/confirm", taskcafeHandler.ConfirmUser) mux.Post("/auth/register", taskcafeHandler.RegisterUser) }) - auth := AuthenticationMiddleware{jwtKey} + auth := AuthenticationMiddleware{securityConfig.Secret} r.Group(func(mux chi.Router) { mux.Use(auth.Middleware) mux.Post("/users/me/avatar", taskcafeHandler.ProfileImageUpload) diff --git a/internal/utils/security.go b/internal/utils/security.go new file mode 100644 index 0000000..5ca0604 --- /dev/null +++ b/internal/utils/security.go @@ -0,0 +1,21 @@ +package utils + +import ( + "time" + + log "github.com/sirupsen/logrus" +) + +type SecurityConfig struct { + AccessTokenExpiration time.Duration + Secret []byte +} + +func GetSecurityConfig(accessTokenExp string, secret []byte) (SecurityConfig, error) { + exp, err := time.ParseDuration(accessTokenExp) + if err != nil { + log.WithError(err).Error("issue parsing duration") + return SecurityConfig{}, err + } + return SecurityConfig{AccessTokenExpiration: exp, Secret: secret}, nil +}