github.com/MontFerret/ferret@v0.18.0/pkg/drivers/cookie.go (about)

     1  package drivers
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"hash/fnv"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/wI2L/jettison"
    12  
    13  	"github.com/MontFerret/ferret/pkg/runtime/core"
    14  	"github.com/MontFerret/ferret/pkg/runtime/values"
    15  )
    16  
    17  type (
    18  	// Polyfill for Go 1.10
    19  	SameSite int
    20  
    21  	// HTTPCookie HTTPCookie object
    22  	HTTPCookie struct {
    23  		Name     string
    24  		Value    string
    25  		Path     string
    26  		Domain   string
    27  		Expires  time.Time
    28  		MaxAge   int
    29  		Secure   bool
    30  		HTTPOnly bool
    31  		SameSite SameSite
    32  	}
    33  )
    34  
    35  const (
    36  	SameSiteDefaultMode SameSite = iota + 1
    37  	SameSiteLaxMode
    38  	SameSiteStrictMode
    39  )
    40  
    41  func (s SameSite) String() string {
    42  	switch s {
    43  	case SameSiteLaxMode:
    44  		return "Lax"
    45  	case SameSiteStrictMode:
    46  		return "Strict"
    47  	default:
    48  		return ""
    49  	}
    50  }
    51  
    52  func (c HTTPCookie) Type() core.Type {
    53  	return HTTPCookieType
    54  }
    55  
    56  func (c HTTPCookie) String() string {
    57  	return fmt.Sprintf("%s=%s", c.Name, c.Value)
    58  }
    59  
    60  func (c HTTPCookie) Compare(other core.Value) int64 {
    61  	if other.Type() != HTTPCookieType {
    62  		return Compare(HTTPCookieType, other.Type())
    63  	}
    64  
    65  	oc := other.(HTTPCookie)
    66  
    67  	if c.Name != oc.Name {
    68  		return int64(strings.Compare(c.Name, oc.Name))
    69  	}
    70  
    71  	if c.Value != oc.Value {
    72  		return int64(strings.Compare(c.Value, oc.Value))
    73  	}
    74  
    75  	if c.Path != oc.Path {
    76  		return int64(strings.Compare(c.Path, oc.Path))
    77  	}
    78  
    79  	if c.Domain != oc.Domain {
    80  		return int64(strings.Compare(c.Domain, oc.Domain))
    81  	}
    82  
    83  	if c.Expires.After(oc.Expires) {
    84  		return 1
    85  	} else if c.Expires.Before(oc.Expires) {
    86  		return -1
    87  	}
    88  
    89  	if c.MaxAge > oc.MaxAge {
    90  		return 1
    91  	} else if c.MaxAge < oc.MaxAge {
    92  		return -1
    93  	}
    94  
    95  	if c.Secure && !oc.Secure {
    96  		return 1
    97  	} else if !c.Secure && oc.Secure {
    98  		return -1
    99  	}
   100  
   101  	if c.HTTPOnly && !oc.HTTPOnly {
   102  		return 1
   103  	} else if !c.HTTPOnly && oc.HTTPOnly {
   104  		return -1
   105  	}
   106  
   107  	if c.SameSite > oc.SameSite {
   108  		return 1
   109  	} else if c.SameSite < oc.SameSite {
   110  		return -1
   111  	}
   112  
   113  	return 0
   114  }
   115  
   116  func (c HTTPCookie) Unwrap() interface{} {
   117  	return c.Value
   118  }
   119  
   120  func (c HTTPCookie) Hash() uint64 {
   121  	h := fnv.New64a()
   122  
   123  	h.Write([]byte(c.Type().String()))
   124  	h.Write([]byte(":"))
   125  	h.Write([]byte(c.Name))
   126  	h.Write([]byte(c.Value))
   127  	h.Write([]byte(c.Path))
   128  	h.Write([]byte(c.Domain))
   129  	h.Write([]byte(c.Expires.String()))
   130  	h.Write([]byte(strconv.Itoa(c.MaxAge)))
   131  	h.Write([]byte(fmt.Sprintf("%t", c.Secure)))
   132  	h.Write([]byte(fmt.Sprintf("%t", c.HTTPOnly)))
   133  	h.Write([]byte(c.SameSite.String()))
   134  
   135  	return h.Sum64()
   136  }
   137  
   138  func (c HTTPCookie) Copy() core.Value {
   139  	cop := c
   140  	return &cop
   141  }
   142  
   143  func (c HTTPCookie) MarshalJSON() ([]byte, error) {
   144  	v := map[string]interface{}{
   145  		"name":      c.Name,
   146  		"value":     c.Value,
   147  		"path":      c.Path,
   148  		"domain":    c.Domain,
   149  		"expires":   c.Expires,
   150  		"max_age":   c.MaxAge,
   151  		"secure":    c.Secure,
   152  		"http_only": c.HTTPOnly,
   153  		"same_site": c.SameSite.String(),
   154  	}
   155  
   156  	out, err := jettison.MarshalOpts(v, jettison.NoHTMLEscaping())
   157  
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  
   162  	return out, err
   163  }
   164  
   165  func (c HTTPCookie) GetIn(_ context.Context, path []core.Value) (core.Value, core.PathError) {
   166  	if len(path) == 0 {
   167  		return values.None, nil
   168  	}
   169  
   170  	segment := path[0]
   171  
   172  	switch values.ToString(segment) {
   173  	case "name":
   174  		return values.NewString(c.Name), nil
   175  	case "value":
   176  		return values.NewString(c.Value), nil
   177  	case "path":
   178  		return values.NewString(c.Path), nil
   179  	case "domain":
   180  		return values.NewString(c.Domain), nil
   181  	case "expires":
   182  		return values.NewDateTime(c.Expires), nil
   183  	case "maxAge":
   184  		return values.NewInt(c.MaxAge), nil
   185  	case "secure":
   186  		return values.NewBoolean(c.Secure), nil
   187  	case "httpOnly":
   188  		return values.NewBoolean(c.HTTPOnly), nil
   189  	case "sameSite":
   190  		return values.NewString(c.SameSite.String()), nil
   191  	default:
   192  		return values.None, nil
   193  	}
   194  }