From a4d17ac489ba0485ebc12848dc9814bd67e98786 Mon Sep 17 00:00:00 2001 From: 0xCA Date: Wed, 3 Jan 2024 18:48:30 +0500 Subject: [PATCH] Added SESSION_MAX_DURATION param Added created_at field to the session --- README.md | 1 + handler/routes.go | 4 +++- handler/session.go | 22 ++++++++++++++++++++-- main.go | 3 +++ util/config.go | 37 +++++++++++++++++++------------------ 5 files changed, 46 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index e3a5617..633a680 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ docker-compose up | `BIND_ADDRESS` | The addresses that can access to the web interface and the port, use unix:///abspath/to/file.socket for unix domain socket. | 0.0.0.0:80 | | `SESSION_SECRET` | The secret key used to encrypt the session cookies. Set this to a random value | N/A | | `SESSION_SECRET_FILE` | Optional filepath for the secret key used to encrypt the session cookies. Leave `SESSION_SECRET` blank to take effect | N/A | +| `SESSION_MAX_DURATION` | Max time in days a remembered session is refreshed and valid. Non-refreshed session is valid for 7 days max, regardless of this setting. | 90 | | `SUBNET_RANGES` | The list of address subdivision ranges. Format: `SR Name:10.0.1.0/24; SR2:10.0.2.0/24,10.0.3.0/24` Each CIDR must be inside one of the server interfaces. | N/A | | `WGUI_USERNAME` | The username for the login page. Used for db initialization only | `admin` | | `WGUI_PASSWORD` | The password for the user on the login page. Will be hashed automatically. Used for db initialization only | `admin` | diff --git a/handler/routes.go b/handler/routes.go index b6520fb..d2eafd6 100644 --- a/handler/routes.go +++ b/handler/routes.go @@ -110,12 +110,14 @@ func Login(db store.IStore) echo.HandlerFunc { // set session_token tokenUID := xid.New().String() + now := time.Now().UTC().Unix() sess.Values["username"] = dbuser.Username sess.Values["user_hash"] = util.GetDBUserCRC32(dbuser) sess.Values["admin"] = dbuser.Admin sess.Values["session_token"] = tokenUID sess.Values["max_age"] = ageMax - sess.Values["updated_at"] = time.Now().UTC().Unix() + sess.Values["created_at"] = now + sess.Values["updated_at"] = now sess.Save(c.Request(), c.Response()) // set session_token in cookie diff --git a/handler/session.go b/handler/session.go index 81a6d1b..01142e4 100644 --- a/handler/session.go +++ b/handler/session.go @@ -53,6 +53,7 @@ func isValidSession(c echo.Context) bool { } // Check time bounds + createdAt := getCreatedAt(sess) updatedAt := getUpdatedAt(sess) maxAge := getMaxAge(sess) // Temporary session is considered valid within 24h if browser is not closed before @@ -62,7 +63,7 @@ func isValidSession(c echo.Context) bool { } expiration := updatedAt + int64(maxAge) now := time.Now().UTC().Unix() - if updatedAt > now || expiration < now { + if updatedAt > now || expiration < now || createdAt+util.SessionMaxDuration < now { return false } @@ -96,10 +97,11 @@ func doRefreshSession(c echo.Context) { } // Refresh no sooner than 24h + createdAt := getCreatedAt(sess) updatedAt := getUpdatedAt(sess) expiration := updatedAt + int64(getMaxAge(sess)) now := time.Now().UTC().Unix() - if expiration < now || now-updatedAt < 86400 { + if updatedAt > now || expiration < now || now-updatedAt < 86_400 || createdAt+util.SessionMaxDuration < now { return } @@ -140,6 +142,22 @@ func getMaxAge(sess *sessions.Session) int { } } +// Get a timestamp in seconds of the time the session was created +func getCreatedAt(sess *sessions.Session) int64 { + if util.DisableLogin { + return 0 + } + + createdAt := sess.Values["created_at"] + + switch typedCreatedAt := createdAt.(type) { + case int64: + return typedCreatedAt + default: + return 0 + } +} + // Get a timestamp in seconds of the last session update func getUpdatedAt(sess *sessions.Session) int64 { if util.DisableLogin { diff --git a/main.go b/main.go index a9db79c..386409d 100644 --- a/main.go +++ b/main.go @@ -49,6 +49,7 @@ var ( flagTelegramAllowConfRequest = false flagTelegramFloodWait = 60 flagSessionSecret = util.RandomString(32) + flagSessionMaxDuration = 90 flagWgConfTemplate string flagBasePath string flagSubnetRanges string @@ -93,6 +94,7 @@ func init() { flag.StringVar(&flagWgConfTemplate, "wg-conf-template", util.LookupEnvOrString("WG_CONF_TEMPLATE", flagWgConfTemplate), "Path to custom wg.conf template.") flag.StringVar(&flagBasePath, "base-path", util.LookupEnvOrString("BASE_PATH", flagBasePath), "The base path of the URL") flag.StringVar(&flagSubnetRanges, "subnet-ranges", util.LookupEnvOrString("SUBNET_RANGES", flagSubnetRanges), "IP ranges to choose from when assigning an IP for a client.") + flag.IntVar(&flagSessionMaxDuration, "session-max-duration", util.LookupEnvOrInt("SESSION_MAX_DURATION", flagSessionMaxDuration), "Max time in days a remembered session is refreshed and valid.") var ( smtpPasswordLookup = util.LookupEnvOrString("SMTP_PASSWORD", flagSmtpPassword) @@ -138,6 +140,7 @@ func init() { util.EmailFrom = flagEmailFrom util.EmailFromName = flagEmailFromName util.SessionSecret = sha512.Sum512([]byte(flagSessionSecret)) + util.SessionMaxDuration = int64(flagSessionMaxDuration) * 86_400 // Store in seconds util.WgConfTemplate = flagWgConfTemplate util.BasePath = util.ParseBasePath(flagBasePath) util.SubnetRanges = util.ParseSubnetRanges(flagSubnetRanges) diff --git a/util/config.go b/util/config.go index acc3a79..4af6bd2 100644 --- a/util/config.go +++ b/util/config.go @@ -9,24 +9,25 @@ import ( // Runtime config var ( - DisableLogin bool - BindAddress string - SmtpHostname string - SmtpPort int - SmtpUsername string - SmtpPassword string - SmtpNoTLSCheck bool - SmtpEncryption string - SmtpAuthType string - SmtpHelo string - SendgridApiKey string - EmailFrom string - EmailFromName string - SessionSecret [64]byte - WgConfTemplate string - BasePath string - SubnetRanges map[string]([]*net.IPNet) - SubnetRangesOrder []string + DisableLogin bool + BindAddress string + SmtpHostname string + SmtpPort int + SmtpUsername string + SmtpPassword string + SmtpNoTLSCheck bool + SmtpEncryption string + SmtpAuthType string + SmtpHelo string + SendgridApiKey string + EmailFrom string + EmailFromName string + SessionSecret [64]byte + SessionMaxDuration int64 + WgConfTemplate string + BasePath string + SubnetRanges map[string]([]*net.IPNet) + SubnetRangesOrder []string ) const (