Albirew/nyaa-pantsu
Archivé
1
0
Bifurcation 0

Add session cookie config (#874)

This allows changing the cookie domain, maxage and the hash/encryption
keys via the config file.

If no key is provided a new one is generated on each reboot.
But if both keys are provided the session cookies are now valid even
after a server reboot.
Cette révision appartient à :
Atvaark 2017-06-01 15:10:00 +02:00 révisé par ewhal
Parent 95548878e6
révision 8cab61802c
3 fichiers modifiés avec 54 ajouts et 18 suppressions

Voir le fichier

@ -21,6 +21,16 @@ web_address: nyaa.pantsu.cat
auth_token_expiration: 1000
# EnableSecureCSRF : Enable CSRF https mode : True if website support https, false otherwise (eg. testing locally: false)
enable_secure_csrf: true
# the default config for session cookies
cookies:
# DomainName : The host domain so the cookies can be shared across subdomains
domain_name: pantsu.cat
# MaxAge : The expiration time of sessions cookies in seconds (default: 7 days)
max_age: 604800
# HashKey : 64 byte key used to authenticate cookies using HMAC. Leave blank for a random key after each restart.
hash_key:
# EncryptionKey : 32 byte key used to encrypt values. Leave blank for a random key after each restart.
encryption_key:
# the default config for bittorrent scraping
scraper:
addr: :9999

Voir le fichier

@ -15,6 +15,8 @@ type Config struct {
DBLogMode string `json:"db_logmode" yaml:"db_logmode,omitempty"`
Version string `json:"version" yaml:"version,omitempty"`
Build string `yaml:"-"`
// cookies config
Cookies CookiesConfig `yaml:"cookies,flow,omitempty"`
// tracker scraper config (required)
Scrape ScraperConfig `json:"scraper" yaml:"scraper,flow,omitempty"`
// cache config
@ -41,6 +43,14 @@ type Config struct {
Models ModelsConfig `yaml:"models,flow,omitempty"`
}
// CookiesConfig : Config struct for session cookies
type CookiesConfig struct {
DomainName string `yaml:"domain_name,omitempty"`
MaxAge int `yaml:"max_age,omitempty"`
HashKey string `yaml:"hash_key,omitempty"`
EncryptionKey string `yaml:"encryption_key,omitempty"`
}
// CacheConfig is config struct for caching strategy
type CacheConfig struct {
Dialect string `yaml:"dialect,omitempty"`

Voir le fichier

@ -2,6 +2,7 @@ package userService
import (
"errors"
"fmt"
"net/http"
"strconv"
"time"
@ -21,8 +22,6 @@ import (
const (
// CookieName : Name of cookie
CookieName = "session"
// Domain name : The host domain so these can be shared across sukebei and nyaa
DomainName = "pantsu.cat"
// UserContextKey : key for user context
UserContextKey = "nyaapantsu.user"
@ -30,8 +29,18 @@ const (
// If you want to keep login cookies between restarts you need to make these permanent
var cookieHandler = securecookie.New(
securecookie.GenerateRandomKey(64),
securecookie.GenerateRandomKey(32))
getOrGenerateKey(config.Conf.Cookies.HashKey, 64),
getOrGenerateKey(config.Conf.Cookies.EncryptionKey, 32))
func getOrGenerateKey(key string, requiredLen int) []byte {
data := []byte(key)
if len(data) == 0 {
data = securecookie.GenerateRandomKey(requiredLen)
} else if len(data) != requiredLen {
panic(fmt.Sprintf("failed to load cookie key. required key length is %d bytes and the provided key length is %d bytes.", requiredLen, len(data)))
}
return data
}
// DecodeCookie : Encoding & Decoding of the cookie value
func DecodeCookie(cookieValue string) (uint, error) {
@ -49,8 +58,7 @@ func DecodeCookie(cookieValue string) (uint, error) {
}
// EncodeCookie : Encoding of the cookie value
func EncodeCookie(userID uint) (string, error) {
validUntil := timeHelper.FewDaysLater(7) // 1 week
func EncodeCookie(userID uint, validUntil time.Time) (string, error) {
value := map[string]string{
"u": strconv.FormatUint(uint64(userID), 10),
"t": strconv.FormatInt(validUntil.Unix(), 10),
@ -60,13 +68,9 @@ func EncodeCookie(userID uint) (string, error) {
// ClearCookie : Erase cookie session
func ClearCookie(w http.ResponseWriter) (int, error) {
domain := DomainName
if config.Conf.Environment == "DEVELOPMENT" {
domain = ""
}
cookie := &http.Cookie{
Name: CookieName,
Domain: domain,
Domain: getDomainName(),
Value: "",
Path: "/",
HttpOnly: true,
@ -103,21 +107,20 @@ func SetCookieHandler(w http.ResponseWriter, r *http.Request, email string, pass
return http.StatusUnauthorized, errors.New("Account banned")
}
encoded, err := EncodeCookie(user.ID)
maxAge := getMaxAge()
validUntil := timeHelper.FewDurationLater(time.Duration(maxAge) * time.Second)
encoded, err := EncodeCookie(user.ID, validUntil)
if err != nil {
return http.StatusInternalServerError, err
}
domain := DomainName
if config.Conf.Environment == "DEVELOPMENT" {
domain = ""
}
cookie := &http.Cookie{
Name: CookieName,
Domain: domain,
Domain: getDomainName(),
Value: encoded,
Path: "/",
HttpOnly: true,
MaxAge: 2592000, // One month
MaxAge: maxAge,
}
http.SetCookie(w, cookie)
// also set response header for convenience
@ -176,12 +179,25 @@ func CurrentUser(r *http.Request) (model.User, error) {
return user, nil
}
func getDomainName() string {
domain := config.Conf.Cookies.DomainName
if config.Conf.Environment == "DEVELOPMENT" {
domain = ""
}
return domain
}
func getMaxAge() int {
return config.Conf.Cookies.MaxAge
}
func getUserFromContext(r *http.Request) model.User {
if rv := context.Get(r, UserContextKey); rv != nil {
return rv.(model.User)
}
return model.User{}
}
func setUserToContext(r *http.Request, val model.User) {
context.Set(r, UserContextKey, val)
}