2019-03-16 01:59:05 +02:00
|
|
|
package drivers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"hash/fnv"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/MontFerret/ferret/pkg/runtime/core"
|
|
|
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
|
|
|
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
// Polyfill for Go 1.10
|
|
|
|
SameSite int
|
|
|
|
|
|
|
|
// HTTPCookie HTTPCookie object
|
|
|
|
HTTPCookie struct {
|
|
|
|
Name string
|
|
|
|
Value string
|
|
|
|
Path string
|
|
|
|
Domain string
|
|
|
|
Expires time.Time
|
|
|
|
MaxAge int
|
|
|
|
Secure bool
|
|
|
|
HTTPOnly bool
|
|
|
|
SameSite SameSite
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
SameSiteDefaultMode SameSite = iota + 1
|
|
|
|
SameSiteLaxMode
|
|
|
|
SameSiteStrictMode
|
|
|
|
)
|
|
|
|
|
2019-07-03 20:02:32 +02:00
|
|
|
func (s SameSite) String() string {
|
|
|
|
switch s {
|
|
|
|
case SameSiteLaxMode:
|
|
|
|
return "Lax"
|
|
|
|
case SameSiteStrictMode:
|
|
|
|
return "Strict"
|
|
|
|
default:
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-16 01:59:05 +02:00
|
|
|
func (c HTTPCookie) Type() core.Type {
|
|
|
|
return HTTPCookieType
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c HTTPCookie) String() string {
|
|
|
|
return fmt.Sprintf("%s=%s", c.Name, c.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c HTTPCookie) Compare(other core.Value) int64 {
|
|
|
|
if other.Type() != HTTPCookieType {
|
|
|
|
return Compare(HTTPCookieType, other.Type())
|
|
|
|
}
|
|
|
|
|
|
|
|
oc := other.(HTTPCookie)
|
|
|
|
|
|
|
|
if c.Name != oc.Name {
|
|
|
|
return int64(strings.Compare(c.Name, oc.Name))
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Value != oc.Value {
|
|
|
|
return int64(strings.Compare(c.Value, oc.Value))
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Path != oc.Path {
|
|
|
|
return int64(strings.Compare(c.Path, oc.Path))
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Domain != oc.Domain {
|
|
|
|
return int64(strings.Compare(c.Domain, oc.Domain))
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Expires.After(oc.Expires) {
|
|
|
|
return 1
|
|
|
|
} else if c.Expires.Before(oc.Expires) {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.MaxAge > oc.MaxAge {
|
|
|
|
return 1
|
|
|
|
} else if c.MaxAge < oc.MaxAge {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Secure && !oc.Secure {
|
|
|
|
return 1
|
|
|
|
} else if !c.Secure && oc.Secure {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.HTTPOnly && !oc.HTTPOnly {
|
|
|
|
return 1
|
|
|
|
} else if !c.HTTPOnly && oc.HTTPOnly {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.SameSite > oc.SameSite {
|
|
|
|
return 1
|
|
|
|
} else if c.SameSite < oc.SameSite {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c HTTPCookie) Unwrap() interface{} {
|
|
|
|
return c.Value
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c HTTPCookie) Hash() uint64 {
|
|
|
|
h := fnv.New64a()
|
|
|
|
|
|
|
|
h.Write([]byte(c.Type().String()))
|
|
|
|
h.Write([]byte(":"))
|
|
|
|
h.Write([]byte(c.Name))
|
|
|
|
h.Write([]byte(c.Value))
|
|
|
|
h.Write([]byte(c.Path))
|
|
|
|
h.Write([]byte(c.Domain))
|
|
|
|
h.Write([]byte(c.Expires.String()))
|
|
|
|
h.Write([]byte(strconv.Itoa(c.MaxAge)))
|
|
|
|
h.Write([]byte(fmt.Sprintf("%t", c.Secure)))
|
|
|
|
h.Write([]byte(fmt.Sprintf("%t", c.HTTPOnly)))
|
2019-07-03 20:02:32 +02:00
|
|
|
h.Write([]byte(c.SameSite.String()))
|
2019-03-16 01:59:05 +02:00
|
|
|
|
|
|
|
return h.Sum64()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c HTTPCookie) Copy() core.Value {
|
|
|
|
return *(&c)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c HTTPCookie) MarshalJSON() ([]byte, error) {
|
|
|
|
v := map[string]interface{}{
|
|
|
|
"name": c.Name,
|
|
|
|
"value": c.Value,
|
|
|
|
"path": c.Path,
|
|
|
|
"domain": c.Domain,
|
|
|
|
"expires": c.Expires,
|
|
|
|
"max_age": c.MaxAge,
|
|
|
|
"secure": c.Secure,
|
|
|
|
"http_only": c.HTTPOnly,
|
2019-07-03 20:02:32 +02:00
|
|
|
"same_site": c.SameSite.String(),
|
2019-03-16 01:59:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
out, err := json.Marshal(v)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c HTTPCookie) GetIn(_ context.Context, path []core.Value) (core.Value, error) {
|
|
|
|
if len(path) == 0 {
|
|
|
|
return values.None, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
segment := path[0]
|
|
|
|
|
|
|
|
err := core.ValidateType(segment, types.String)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return values.None, err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch segment.(values.String) {
|
|
|
|
case "name":
|
|
|
|
return values.NewString(c.Name), nil
|
|
|
|
case "value":
|
|
|
|
return values.NewString(c.Value), nil
|
|
|
|
case "path":
|
|
|
|
return values.NewString(c.Path), nil
|
|
|
|
case "domain":
|
|
|
|
return values.NewString(c.Domain), nil
|
|
|
|
case "expires":
|
|
|
|
return values.NewDateTime(c.Expires), nil
|
|
|
|
case "maxAge":
|
|
|
|
return values.NewInt(c.MaxAge), nil
|
|
|
|
case "secure":
|
|
|
|
return values.NewBoolean(c.Secure), nil
|
|
|
|
case "httpOnly":
|
|
|
|
return values.NewBoolean(c.HTTPOnly), nil
|
|
|
|
case "sameSite":
|
2019-07-03 20:02:32 +02:00
|
|
|
return values.NewString(c.SameSite.String()), nil
|
2019-03-16 01:59:05 +02:00
|
|
|
default:
|
|
|
|
return values.None, nil
|
|
|
|
}
|
|
|
|
}
|