From fb3709d868dd7914a643d4d95c063ed5c7a5da9c Mon Sep 17 00:00:00 2001 From: cubixle <4376523+cubixle@users.noreply.github.com> Date: Tue, 23 Aug 2022 17:13:30 +0100 Subject: [PATCH] working on flash messages --- cookies/cookies.go | 109 ++++++++++++++++++++++++++++++++++++++++ cookies/cookies_test.go | 56 +++++++++++++++++++++ go.mod | 4 ++ go.sum | 2 + 4 files changed, 171 insertions(+) create mode 100644 cookies/cookies.go create mode 100644 cookies/cookies_test.go diff --git a/cookies/cookies.go b/cookies/cookies.go new file mode 100644 index 0000000..5f9dba3 --- /dev/null +++ b/cookies/cookies.go @@ -0,0 +1,109 @@ +package cookies + +import ( + "encoding/base64" + "encoding/json" + "net/http" + "time" + + "github.com/gorilla/securecookie" +) + +const flashCookieName = "tuukoti_flash" + +type Cookies struct { + secureCookies *securecookie.SecureCookie +} + +func New(sc *securecookie.SecureCookie) *Cookies { + return &Cookies{secureCookies: sc} +} + +func (c *Cookies) Create(name string, val string) (*http.Cookie, error) { + encodedValue, err := c.secureCookies.Encode(name, val) + if err != nil { + return nil, err + } + + cookie := &http.Cookie{ + Name: name, + Value: encodedValue, + Expires: time.Now().Add(3 * (24 * time.Hour)), + HttpOnly: true, + Path: "/", + } + + return cookie, nil +} + +// ReadCookie will decode the secure cookie value into `out`. +func (c *Cookies) Read(req *http.Request, name string, out interface{}) error { + cookie, err := req.Cookie(name) + if err != nil { + return err + } + + return c.secureCookies.Decode(name, cookie.Value, out) +} + +// SetFlashCookie will set a flash cookie with the data you give it a map[string]string{}. +func SetFlash(w http.ResponseWriter, val map[string]string) error { + b, err := json.Marshal(val) + if err != nil { + return err + } + + co := &http.Cookie{ + Name: flashCookieName, + Value: encode(b), + Path: "/", + HttpOnly: true, + } + + http.SetCookie(w, co) + + return nil +} + +// GetFlash will return any flash data as a map[string]string{}. +// It also sets the flash cookies value back to nothing so the flash only exists once. +func GetFlash(w http.ResponseWriter, req *http.Request) (map[string]string, error) { + co, err := req.Cookie(flashCookieName) + if err != nil { + switch err { + case http.ErrNoCookie: + return nil, nil + default: + return nil, err + } + } + + value, err := decode(co.Value) + if err != nil { + return nil, err + } + + out := map[string]string{} + if err := json.Unmarshal(value, &out); err != nil { + return nil, err + } + + http.SetCookie(w, &http.Cookie{ + Name: flashCookieName, + Value: "", + MaxAge: -1, + Expires: time.Unix(1, 0), + Path: "/", + HttpOnly: true, + }) + + return out, nil +} + +func encode(src []byte) string { + return base64.URLEncoding.EncodeToString(src) +} + +func decode(src string) ([]byte, error) { + return base64.URLEncoding.DecodeString(src) +} diff --git a/cookies/cookies_test.go b/cookies/cookies_test.go new file mode 100644 index 0000000..d5efb3f --- /dev/null +++ b/cookies/cookies_test.go @@ -0,0 +1,56 @@ +package cookies_test + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/gorilla/securecookie" + "github.com/stretchr/testify/require" + "github.com/tuukoti/framework/cookies" +) + +func TestCookieReadAndGet(t *testing.T) { + secureCookie := securecookie.New([]byte("very-secret"), []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) + c := cookies.New(secureCookie) + + w := httptest.NewRecorder() + + cookie, err := c.Create("testing", "test") + require.NoError(t, err) + + http.SetCookie(w, cookie) + + req := &http.Request{ + Header: http.Header{}, + } + + req.Header.Set("Cookie", w.Header().Get("Set-Cookie")) + + out := "" + + err = c.Read(req, "testing", &out) + require.NoError(t, err) + require.Equal(t, "test", out) +} + +func TestSetGetFlash(t *testing.T) { + w := httptest.NewRecorder() + + d := map[string]string{ + "test": "testing", + } + + err := cookies.SetFlash(w, d) + require.NoError(t, err) + + req := &http.Request{ + Header: http.Header{}, + } + + req.Header.Set("Cookie", w.Header().Get("Set-Cookie")) + + data, err := cookies.GetFlash(w, req) + require.NoError(t, err) + require.Equal(t, d, data) +} diff --git a/go.mod b/go.mod index 11e155a..9f78362 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,18 @@ module github.com/tuukoti/framework go 1.18 require ( + github.com/gorilla/securecookie v1.1.1 github.com/labstack/echo/v4 v4.7.2 + github.com/stretchr/testify v1.7.0 gopkg.in/yaml.v3 v3.0.1 ) require ( + github.com/davecgh/go-spew v1.1.1 // indirect github.com/labstack/gommon v0.3.1 // indirect github.com/mattn/go-colorable v0.1.11 // indirect github.com/mattn/go-isatty v0.0.14 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.1 // indirect golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect diff --git a/go.sum b/go.sum index 032ef51..8f43e00 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI= github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=