package sessions import ( "crypto/sha1" "encoding/json" "errors" "fmt" "math/rand" "net/http" "os" "strconv" "time" ) type Vars struct { Int map[string]int String map[string]string Bool map[string]bool } type Session struct { W *http.ResponseWriter R *http.Request VHost string DirVHostHome string RemoteIp string vars *Vars ident string changed bool } func New(w *http.ResponseWriter, r *http.Request, vhost string, vhosthome string, remoteip string) *Session { return &Session{w, r, vhost, vhosthome, remoteip, &Vars{}, "", false} } func (this *Session) Load() { var session, err = this.R.Cookie("fsession") if err == nil && len(session.Value) == 40 { // Load session this.ident = session.Value StartNewSession := true fsessfile := this.DirVHostHome + "/tmp/" + this.ident file, ferr := os.Open(fsessfile) if ferr == nil { defer file.Close() dec := json.NewDecoder(file) ferr = dec.Decode(&this.vars) if ferr == nil { StartNewSession = false } } if StartNewSession { sessdata := Vars{} sessdata.Int = map[string]int{} sessdata.String = map[string]string{} sessdata.Bool = map[string]bool{} this.vars = &sessdata this.changed = true } } else { // Create new session // Generate unique hash rand.Seed(time.Now().Unix()) rnd := rand.Intn(9999999-99) + 99 userstr := this.VHost + this.RemoteIp + this.R.Header.Get("User-Agent") + strconv.FormatInt((int64(time.Now().Unix())), 10) + strconv.FormatInt(int64(rnd), 10) userhashstr := fmt.Sprintf("%x", sha1.Sum([]byte(userstr))) this.ident = userhashstr // Try to create session file sessdata := Vars{} sessdata.Int = map[string]int{} sessdata.String = map[string]string{} sessdata.Bool = map[string]bool{} this.vars = &sessdata this.changed = true // Set session cookie expiration := time.Now().Add(365 * 24 * time.Hour) cookie := http.Cookie{ Name: "fsession", Value: userhashstr, Path: "/", Expires: expiration, HttpOnly: true, } http.SetCookie(*this.W, &cookie) } } func (this *Session) Save() bool { if !this.changed { return false } fsessfile := this.DirVHostHome + "/tmp/" + this.ident r, err := json.Marshal(this.vars) if err == nil { file, ferr := os.Create(fsessfile) if ferr == nil { defer file.Close() _, ferr = file.Write(r) if ferr == nil { this.changed = false return true } } } return false } func (this *Session) IsSetInt(name string) bool { if _, ok := this.vars.Int[name]; ok { return true } else { return false } } func (this *Session) IsSetString(name string) bool { if _, ok := this.vars.String[name]; ok { return true } else { return false } } func (this *Session) IsSetBool(name string) bool { if _, ok := this.vars.Bool[name]; ok { return true } else { return false } } func (this *Session) SetInt(name string, value int) { this.vars.Int[name] = value this.changed = true } func (this *Session) SetString(name string, value string) { this.vars.String[name] = value this.changed = true } func (this *Session) SetBool(name string, value bool) { this.vars.Bool[name] = value this.changed = true } func (this *Session) GetInt(name string) (int, error) { if this.IsSetInt(name) { return this.vars.Int[name], nil } else { return 0, errors.New("Variable is not found") } } func (this *Session) GetString(name string) (string, error) { if this.IsSetString(name) { return this.vars.String[name], nil } else { return "", errors.New("Variable is not found") } } func (this *Session) GetBool(name string) (bool, error) { if this.IsSetBool(name) { return this.vars.Bool[name], nil } else { return false, errors.New("Variable is not found") } } func (this *Session) GetIntDef(name string, def int) int { if this.IsSetInt(name) { return this.vars.Int[name] } else { return def } } func (this *Session) GetStringDef(name string, def string) string { if this.IsSetString(name) { return this.vars.String[name] } else { return def } } func (this *Session) GetBoolDef(name string, def bool) bool { if this.IsSetBool(name) { return this.vars.Bool[name] } else { return def } } func (this *Session) DelInt(name string) { if this.IsSetInt(name) { delete(this.vars.Int, name) this.changed = true } } func (this *Session) DelString(name string) { if this.IsSetString(name) { delete(this.vars.String, name) this.changed = true } } func (this *Session) DelBool(name string) { if this.IsSetBool(name) { delete(this.vars.Bool, name) this.changed = true } }