session.go (3863B)
1 package session 2 3 /* 4 Copyright (c) 2019 m15o <m15o@posteo.net> . All rights reserved. 5 Copyright (c) 2022 cblgh <m15o@posteo.net> . All rights reserved. 6 7 Redistribution and use in source and binary forms, with or without modification, 8 are permitted provided that the following conditions are met: 9 10 1. Redistributions of source code must retain the above copyright notice, 11 this list of conditions and the following disclaimer. 12 13 2. Redistributions in binary form must reproduce the above copyright notice, 14 this list of conditions and the following disclaimer in the documentation 15 and/or other materials provided with the distribution. 16 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 26 USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 import ( 30 "cerca/util" 31 "errors" 32 "fmt" 33 "net/http" 34 35 "github.com/gorilla/sessions" 36 ) 37 38 const cookieName = "cerca" 39 40 type Session struct { 41 Store *sessions.CookieStore 42 ShortLivedStore *sessions.CookieStore 43 } 44 45 func New(authKey string, developing bool) *Session { 46 store := sessions.NewCookieStore([]byte(authKey)) 47 store.Options = &sessions.Options{ 48 HttpOnly: true, 49 Secure: !developing, 50 MaxAge: 86400 * 30, 51 } 52 short := sessions.NewCookieStore([]byte(authKey)) 53 short.Options = &sessions.Options{ 54 HttpOnly: true, 55 // Secure: true, // TODO (2022-01-05): uncomment when served over https 56 MaxAge: 600, // 10 minutes 57 } 58 return &Session{ 59 Store: store, 60 ShortLivedStore: short, 61 } 62 } 63 64 func (s *Session) Delete(res http.ResponseWriter, req *http.Request) error { 65 ed := util.Describe("delete session cookie") 66 clearSession := func(store *sessions.CookieStore) error { 67 session, err := store.Get(req, cookieName) 68 if err != nil { 69 return ed.Eout(err, "get session") 70 } 71 session.Options.MaxAge = -1 72 err = session.Save(req, res) 73 return ed.Eout(err, "save expired session") 74 } 75 err := clearSession(s.Store) 76 if err != nil { 77 return err 78 } 79 err = clearSession(s.ShortLivedStore) 80 return err 81 } 82 83 func getValueFromSession(req *http.Request, store *sessions.CookieStore, key string) (interface{}, error) { 84 session, err := store.Get(req, cookieName) 85 if err != nil { 86 return nil, err 87 } 88 value, ok := session.Values[key] 89 if !ok { 90 err := errors.New(fmt.Sprintf("extracting %s from session; no such value", key)) 91 return nil, util.Eout(err, "get session") 92 } 93 return value, nil 94 } 95 96 func (s *Session) GetVerificationCode(req *http.Request) (string, error) { 97 val, err := getValueFromSession(req, s.ShortLivedStore, "verificationCode") 98 if val == nil || err != nil { 99 return "", err 100 } 101 return val.(string), err 102 } 103 104 func (s *Session) Get(req *http.Request) (int, error) { 105 val, err := getValueFromSession(req, s.Store, "userid") 106 if val == nil || err != nil { 107 return -1, err 108 } 109 return val.(int), err 110 } 111 112 func (s *Session) Save(req *http.Request, res http.ResponseWriter, userid int) error { 113 session, _ := s.Store.Get(req, cookieName) 114 session.Values["userid"] = userid 115 return session.Save(req, res) 116 } 117 118 func (s *Session) SaveVerificationCode(req *http.Request, res http.ResponseWriter, code string) error { 119 session, _ := s.ShortLivedStore.Get(req, cookieName) 120 session.Values["verificationCode"] = code 121 return session.Save(req, res) 122 }