add Context.SetSameSite(integrates with sessions too) , iris.JSON.ASCII and iris.JSON.Secure option fields

Former-commit-id: fdf0dae234b219c9ca449ae8907d3e459d485dc7
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-04-07 19:23:30 +03:00
parent 6876f94e67
commit f03afeef2f
2 changed files with 71 additions and 3 deletions

View File

@ -22,6 +22,7 @@ import (
"strings"
"sync/atomic"
"time"
"unsafe"
"github.com/kataras/iris/v12/core/memstore"
@ -896,6 +897,14 @@ type Context interface {
//
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
SetCookie(cookie *http.Cookie, options ...CookieOption)
// SetSameSite sets a same-site rule for cookies to set.
// SameSite allows a server to define a cookie attribute making it impossible for
// the browser to send this cookie along with cross-site requests. The main
// goal is to mitigate the risk of cross-origin information leakage, and provide
// some protection against cross-site request forgery attacks.
//
// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details.
SetSameSite(sameSite http.SameSite)
// SetCookieKV adds a cookie, requires the name(string) and the value(string).
//
// By default it expires at 2 hours and it's added to the root path,
@ -3163,6 +3172,8 @@ type JSON struct {
UnescapeHTML bool
Indent string
Prefix string
ASCII bool // if true writes with unicode to ASCII content.
Secure bool // if true then it adds a "while(1);" when Go slice (to JSON Array) value.
}
// JSONP contains the options for the JSONP (Context's) Renderer.
@ -3187,7 +3198,7 @@ type Markdown struct {
var (
newLineB = []byte("\n")
// the html codes for unescaping
// the html codes for unescaping.
ltHex = []byte("\\u003c")
lt = []byte("<")
@ -3196,6 +3207,11 @@ var (
andHex = []byte("\\u0026")
and = []byte("&")
// secure JSON.
jsonArrayPrefix = []byte("[")
jsonArraySuffix = []byte("]")
secureJSONPrefix = []byte("while(1);")
)
// WriteJSON marshals the given interface object and writes the JSON response to the 'writer'.
@ -3237,6 +3253,27 @@ func WriteJSON(writer io.Writer, v interface{}, options JSON, optimize bool) (in
result = bytes.Replace(result, andHex, and, -1)
}
if options.Secure {
if bytes.HasPrefix(result, jsonArrayPrefix) && bytes.HasSuffix(result, jsonArraySuffix) {
result = append(secureJSONPrefix, result...)
}
}
if options.ASCII {
if len(result) > 0 {
buf := new(bytes.Buffer)
for _, s := range bytesToString(result) {
char := string(s)
if s >= 128 {
char = fmt.Sprintf("\\u%04x", int64(s))
}
buf.WriteString(char)
}
result = buf.Bytes()
}
}
if prefix := options.Prefix; prefix != "" {
result = append([]byte(prefix), result...)
}
@ -3244,6 +3281,11 @@ func WriteJSON(writer io.Writer, v interface{}, options JSON, optimize bool) (in
return writer.Write(result)
}
// See https://golang.org/src/strings/builder.go#L45
func bytesToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
// DefaultJSONOptions is the optional settings that are being used
// inside `ctx.JSON`.
var DefaultJSONOptions = JSON{}
@ -3304,7 +3346,7 @@ func WriteJSONP(writer io.Writer, v interface{}, options JSONP, optimize bool) (
}
if !optimize && options.Indent == "" {
options.Indent = " "
options.Indent = " "
}
if indent := options.Indent; indent != "" {
@ -4359,6 +4401,8 @@ func CookieDecode(decode CookieDecoder) CookieOption {
//
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
func (ctx *context) SetCookie(cookie *http.Cookie, options ...CookieOption) {
cookie.SameSite = ctx.getSameSite()
for _, opt := range options {
opt(cookie)
}
@ -4366,6 +4410,30 @@ func (ctx *context) SetCookie(cookie *http.Cookie, options ...CookieOption) {
http.SetCookie(ctx.writer, cookie)
}
const sameSiteContextKey = "iris.cookie_same_site"
// SetSameSite sets a same-site rule for cookies to set.
// SameSite allows a server to define a cookie attribute making it impossible for
// the browser to send this cookie along with cross-site requests. The main
// goal is to mitigate the risk of cross-origin information leakage, and provide
// some protection against cross-site request forgery attacks.
//
// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details.
func (ctx *context) SetSameSite(sameSite http.SameSite) {
ctx.Values().Set(sameSiteContextKey, sameSite)
}
func (ctx *context) getSameSite() http.SameSite {
if v := ctx.Values().Get(sameSiteContextKey); v != nil {
sameSite, ok := v.(http.SameSite)
if ok {
return sameSite
}
}
return http.SameSiteDefaultMode
}
// SetCookieKV adds a cookie, requires the name(string) and the value(string).
//
// By default it expires at 2 hours and it's added to the root path,

View File

@ -95,7 +95,7 @@ func (s *Sessions) Start(ctx context.Context, cookieOptions ...context.CookieOpt
return s.provider.Read(cookieValue, s.config.Expires)
}
const contextSessionKey = "_iris_session"
const contextSessionKey = "iris.session"
// Handler returns a sessions middleware to register on application routes.
func (s *Sessions) Handler(cookieOptions ...context.CookieOption) context.Handler {