Explorar el Código

Add web session management

tags/v0.1.0
Matt Baer hace 5 años
padre
commit
62abc11142
Se han modificado 5 ficheros con 196 adiciones y 1 borrados
  1. +2
    -0
      app.go
  2. +11
    -0
      errors.go
  3. +6
    -1
      keys.go
  4. +126
    -0
      session.go
  5. +51
    -0
      users.go

+ 2
- 0
app.go Ver fichero

@@ -60,6 +60,8 @@ func Serve() {
}

// Initialize modules
app.sessionStore = initSession(app)

r := mux.NewRouter()
handler := NewHandler(app.sessionStore)



+ 11
- 0
errors.go Ver fichero

@@ -0,0 +1,11 @@
package writefreely

import (
"github.com/writeas/impart"
"net/http"
)

// Commonly returned HTTP errors
var (
ErrInternalCookieSession = impart.HTTPError{http.StatusInternalServerError, "Could not get cookie session."}
)

+ 6
- 1
keys.go Ver fichero

@@ -5,13 +5,18 @@ import (
)

type keychain struct {
cookieAuthKey, cookieKey []byte
emailKey, cookieAuthKey, cookieKey []byte
}

func initKeys(app *app) error {
var err error
app.keys = &keychain{}

app.keys.emailKey, err = ioutil.ReadFile("keys/email.aes256")
if err != nil {
return err
}

app.keys.cookieAuthKey, err = ioutil.ReadFile("keys/cookies_auth.aes256")
if err != nil {
return err


+ 126
- 0
session.go Ver fichero

@@ -0,0 +1,126 @@
package writefreely

import (
"encoding/gob"
"github.com/gorilla/sessions"
"github.com/writeas/web-core/log"
"net/http"
"strings"
)

const (
day = 86400
sessionLength = 180 * day
cookieName = "wfu"
cookieUserVal = "u"
)

// initSession creates the cookie store. It depends on the keychain already
// being loaded.
func initSession(app *app) *sessions.CookieStore {
// Register complex data types we'll be storing in cookies
gob.Register(&User{})

// Create the cookie store
store := sessions.NewCookieStore(app.keys.cookieAuthKey, app.keys.cookieKey)
store.Options = &sessions.Options{
Path: "/",
MaxAge: sessionLength,
HttpOnly: true,
Secure: strings.HasPrefix(app.cfg.Server.Host, "https://"),
}
return store
}

func getSessionFlashes(app *app, w http.ResponseWriter, r *http.Request, session *sessions.Session) ([]string, error) {
var err error
if session == nil {
session, err = app.sessionStore.Get(r, cookieName)
if err != nil {
return nil, err
}
}

f := []string{}
if flashes := session.Flashes(); len(flashes) > 0 {
for _, flash := range flashes {
if str, ok := flash.(string); ok {
f = append(f, str)
}
}
}
saveUserSession(app, r, w)

return f, nil
}

func addSessionFlash(app *app, w http.ResponseWriter, r *http.Request, m string, session *sessions.Session) error {
var err error
if session == nil {
session, err = app.sessionStore.Get(r, cookieName)
}

if err != nil {
log.Error("Unable to add flash '%s': %v", m, err)
return err
}

session.AddFlash(m)
saveUserSession(app, r, w)
return nil
}

func getUserAndSession(app *app, r *http.Request) (*User, *sessions.Session) {
session, err := app.sessionStore.Get(r, cookieName)
if err == nil {
// Got the currently logged-in user
val := session.Values[cookieUserVal]
var u = &User{}
var ok bool
if u, ok = val.(*User); ok {
return u, session
}
}

return nil, nil
}

func getUserSession(app *app, r *http.Request) *User {
u, _ := getUserAndSession(app, r)
return u
}

func saveUserSession(app *app, r *http.Request, w http.ResponseWriter) error {
session, err := app.sessionStore.Get(r, cookieName)
if err != nil {
return ErrInternalCookieSession
}

// Extend the session
session.Options.MaxAge = int(sessionLength)

// Remove any information that accidentally got added
// FIXME: find where Plan information is getting saved to cookie.
val := session.Values[cookieUserVal]
var u = &User{}
var ok bool
if u, ok = val.(*User); ok {
session.Values[cookieUserVal] = u.Cookie()
}

err = session.Save(r, w)
if err != nil {
log.Error("Couldn't saveUserSession: %v", err)
}
return err
}

func getFullUserSession(app *app, r *http.Request) *User {
u := getUserSession(app, r)
if u == nil {
return nil
}

u, _ = app.db.GetUserByID(u.ID)
return u
}

+ 51
- 0
users.go Ver fichero

@@ -0,0 +1,51 @@
package writefreely

import (
"time"

"github.com/guregu/null/zero"
"github.com/writeas/web-core/data"
"github.com/writeas/web-core/log"
)

type (
// User is a consistent user object in the database and all contexts (auth
// and non-auth) in the API.
User struct {
ID int64 `json:"-"`
Username string `json:"username"`
HashedPass []byte `json:"-"`
HasPass bool `json:"has_pass"`
Email zero.String `json:"email"`
Created time.Time `json:"created"`

clearEmail string `json:"email"`
}
)

// EmailClear decrypts and returns the user's email, caching it in the user
// object.
func (u *User) EmailClear(keys *keychain) string {
if u.clearEmail != "" {
return u.clearEmail
}

if u.Email.Valid && u.Email.String != "" {
email, err := data.Decrypt(keys.emailKey, []byte(u.Email.String))
if err != nil {
log.Error("Error decrypting user email: %v", err)
} else {
u.clearEmail = string(email)
return u.clearEmail
}
}
return ""
}

// Cookie strips down an AuthUser to contain only information necessary for
// cookies.
func (u User) Cookie() *User {
u.HashedPass = []byte{}

return &u
}

Cargando…
Cancelar
Guardar