// SignIn signs the user in by creating a new session and setting a cookie on // the client. func SignIn(g *gas.Gas, u User, password string) error { if store == nil { return ErrNoStore } // already signed in? sess, _ := GetSession(g) if sess != nil { cookie, err := g.Cookie("s") if err != nil && err != http.ErrNoCookie { return err } if err = VerifyCookie(cookie); err != nil { return err } id, err := base64.StdEncoding.DecodeString(cookie.Value) if err != nil { return err } //id := []byte(cookie.Value) if err := store.Update(id); err != nil { return err } return nil } pass, salt, err := u.Secrets() if err != nil { return err } if !VerifyHash([]byte(password), pass, salt) { return ErrBadPassword } username := u.Username() sessid := make([]byte, Env.SessidLen) rand.Read(sessid) err = store.Create(sessid, time.Now().Add(Env.MaxCookieAge), username) if err != nil { return err } cookie := &http.Cookie{ Name: "s", Path: "/", Value: base64.StdEncoding.EncodeToString(sessid), MaxAge: int(Env.MaxCookieAge / time.Second), HttpOnly: true, } SignCookie(cookie) g.SetCookie(cookie) return nil }
// GetSession figures out the session from the session cookie in the request, or // just return the session if that's been done already. func GetSession(g *gas.Gas) (*Session, error) { if store == nil { return nil, ErrNoStore } const sessKey = "_gas_session" if sessBox := g.Data(sessKey); sessBox != nil { if sess, ok := sessBox.(*Session); ok { return sess, nil } } cookie, err := g.Cookie("s") if err != nil { if err == http.ErrNoCookie { return nil, nil } SignOut(g) return nil, err } if err = VerifyCookie(cookie); err != nil { return nil, err } id, err := base64.StdEncoding.DecodeString(cookie.Value) if err != nil { // this means invalid session SignOut(g) return nil, err } //id := []byte(cookie.Value) sess, err := store.Read(id) if err != nil { if err == sql.ErrNoRows { SignOut(g) return nil, nil } return nil, err } if time.Now().After(sess.Expires) { SignOut(g) return nil, ErrCookieExpired } g.SetData(sessKey, sess) return sess, nil }
// SignOut signs the user out, destroying the associated session and cookie. func SignOut(g *gas.Gas) error { if store == nil { return ErrNoStore } cookie, err := g.Cookie("s") if err != nil { return err } if err := VerifyCookie(cookie); err != nil { return err } id, err := base64.StdEncoding.DecodeString(cookie.Value) if err != nil { return err } //id := []byte(cookie.Value) if err := store.Delete(id); err != nil && err != sql.ErrNoRows { return err } cookie = &http.Cookie{ Name: "s", Path: "/", Value: "", Expires: time.Time{}, MaxAge: -1, HttpOnly: true, } SignCookie(cookie) g.SetCookie(cookie) return nil }
// CheckReroute is a middleware handler that will check for and deal with // reroute cookies func CheckReroute(g *gas.Gas) (int, gas.Outputter) { reroute, err := g.Cookie("_reroute") if reroute != nil { if err == nil { blob, err := base64.StdEncoding.DecodeString(reroute.Value) if err == nil { g.SetData("_reroute", blob) } else { log.Println("gas: dispatch reroute:", err) } } else { log.Println("gas: reroute cookie:", err) } // Empty the cookie out and toss it back reroute.Value = "" reroute.MaxAge = -1 g.SetCookie(reroute) } return g.Continue() }