feat: make user session timeout configurable (#2753)

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
pull/2800/head
Dardan 2023-11-02 22:01:56 +01:00 committed by GitHub
parent c3079d30e2
commit 7fabadc871
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 21 deletions

View File

@ -16,7 +16,7 @@ import (
) )
const ( const (
TokenExpirationTime = time.Hour * 2 DefaultTokenExpirationTime = time.Hour * 2
) )
type userInfo struct { type userInfo struct {
@ -101,19 +101,21 @@ func withAdmin(fn handleFunc) handleFunc {
}) })
} }
var loginHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { func loginHandler(tokenExpireTime time.Duration) handleFunc {
auther, err := d.store.Auth.Get(d.settings.AuthMethod) return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
if err != nil { auther, err := d.store.Auth.Get(d.settings.AuthMethod)
return http.StatusInternalServerError, err if err != nil {
} return http.StatusInternalServerError, err
}
user, err := auther.Auth(r, d.store.Users, d.settings, d.server) user, err := auther.Auth(r, d.store.Users, d.settings, d.server)
if err == os.ErrPermission { if err == os.ErrPermission {
return http.StatusForbidden, nil return http.StatusForbidden, nil
} else if err != nil { } else if err != nil {
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} else { } else {
return printToken(w, r, d, user) return printToken(w, r, d, user, tokenExpireTime)
}
} }
} }
@ -172,12 +174,14 @@ var signupHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int,
return http.StatusOK, nil return http.StatusOK, nil
} }
var renewHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { func renewHandler(tokenExpireTime time.Duration) handleFunc {
w.Header().Set("X-Renew-Token", "false") return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
return printToken(w, r, d, d.user) w.Header().Set("X-Renew-Token", "false")
}) return printToken(w, r, d, d.user, tokenExpireTime)
})
}
func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User) (int, error) { func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User, tokenExpirationTime time.Duration) (int, error) {
claims := &authToken{ claims := &authToken{
User: userInfo{ User: userInfo{
ID: user.ID, ID: user.ID,
@ -192,7 +196,7 @@ func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.Use
}, },
RegisteredClaims: jwt.RegisteredClaims{ RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(time.Now()), IssuedAt: jwt.NewNumericDate(time.Now()),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenExpirationTime)), ExpiresAt: jwt.NewNumericDate(time.Now().Add(tokenExpirationTime)),
Issuer: "File Browser", Issuer: "File Browser",
}, },
} }

View File

@ -48,9 +48,10 @@ func NewHandler(
api := r.PathPrefix("/api").Subrouter() api := r.PathPrefix("/api").Subrouter()
api.Handle("/login", monkey(loginHandler, "")) tokenExpirationTime := server.GetTokenExpirationTime(DefaultTokenExpirationTime)
api.Handle("/login", monkey(loginHandler(tokenExpirationTime), ""))
api.Handle("/signup", monkey(signupHandler, "")) api.Handle("/signup", monkey(signupHandler, ""))
api.Handle("/renew", monkey(renewHandler, "")) api.Handle("/renew", monkey(renewHandler(tokenExpirationTime), ""))
users := api.PathPrefix("/users").Subrouter() users := api.PathPrefix("/users").Subrouter()
users.Handle("", monkey(usersGetHandler, "")).Methods("GET") users.Handle("", monkey(usersGetHandler, "")).Methods("GET")

View File

@ -2,7 +2,9 @@ package settings
import ( import (
"crypto/rand" "crypto/rand"
"log"
"strings" "strings"
"time"
"github.com/filebrowser/filebrowser/v2/rules" "github.com/filebrowser/filebrowser/v2/rules"
) )
@ -47,6 +49,7 @@ type Server struct {
EnableExec bool `json:"enableExec"` EnableExec bool `json:"enableExec"`
TypeDetectionByHeader bool `json:"typeDetectionByHeader"` TypeDetectionByHeader bool `json:"typeDetectionByHeader"`
AuthHook string `json:"authHook"` AuthHook string `json:"authHook"`
TokenExpirationTime string `json:"tokenExpirationTime"`
} }
// Clean cleans any variables that might need cleaning. // Clean cleans any variables that might need cleaning.
@ -54,6 +57,19 @@ func (s *Server) Clean() {
s.BaseURL = strings.TrimSuffix(s.BaseURL, "/") s.BaseURL = strings.TrimSuffix(s.BaseURL, "/")
} }
func (s *Server) GetTokenExpirationTime(fallback time.Duration) time.Duration {
if s.TokenExpirationTime == "" {
return fallback
}
if duration, err := time.ParseDuration(s.TokenExpirationTime); err == nil {
return duration
} else {
log.Printf("[WARN] Failed to parse tokenExpirationTime: %v", err)
return fallback
}
}
// GenerateKey generates a key of 512 bits. // GenerateKey generates a key of 512 bits.
func GenerateKey() ([]byte, error) { func GenerateKey() ([]byte, error) {
b := make([]byte, 64) //nolint:gomnd b := make([]byte, 64) //nolint:gomnd