github.com/mistwind/reviewdog@v0.0.0-20230322024206-9cfa11856d58/doghouse/server/cookieman/cookieman.go (about)

     1  package cookieman
     2  
     3  import (
     4  	"encoding/base64"
     5  	"net/http"
     6  )
     7  
     8  // Cipher is crypt interface to encrypt/decrypt cookie.
     9  type Cipher interface {
    10  	Encrypt(plaintext []byte) ([]byte, error)
    11  	Decrypt(ciphertext []byte) ([]byte, error)
    12  }
    13  
    14  // CookieMan manages cookies.
    15  type CookieMan struct {
    16  	defaultOpt CookieOption
    17  	cipher     Cipher
    18  }
    19  
    20  // CookieOption represents cookie options.
    21  type CookieOption struct {
    22  	http.Cookie
    23  }
    24  
    25  // CookieStore stores a cookie.
    26  type CookieStore struct {
    27  	name      string
    28  	cookieman *CookieMan
    29  	opt       *CookieOption
    30  }
    31  
    32  // Name returns the cookie name this CookieStore manages.
    33  func (cs *CookieStore) Name() string {
    34  	return cs.name
    35  }
    36  
    37  // Set sets cookie value.
    38  func (cs *CookieStore) Set(w http.ResponseWriter, value []byte) error {
    39  	return cs.cookieman.Set(w, cs.name, value, cs.opt)
    40  }
    41  
    42  // Get returns cookie value.
    43  func (cs *CookieStore) Get(r *http.Request) ([]byte, error) {
    44  	return cs.cookieman.Get(r, cs.name)
    45  }
    46  
    47  // Clear clears the cookie.
    48  func (cs *CookieStore) Clear(w http.ResponseWriter) {
    49  	cs.cookieman.Clear(w, cs.name)
    50  }
    51  
    52  // New returns new CookieMan with default cookie option.
    53  func New(cipher Cipher, defaultOpt CookieOption) *CookieMan {
    54  	return &CookieMan{defaultOpt: defaultOpt, cipher: cipher}
    55  }
    56  
    57  // NewCookieStore returns new CookieStore which manages cookie whose key is
    58  // given name and with given cookie option.
    59  func (c *CookieMan) NewCookieStore(name string, opt *CookieOption) *CookieStore {
    60  	return &CookieStore{
    61  		name:      name,
    62  		cookieman: c,
    63  		opt:       opt,
    64  	}
    65  }
    66  
    67  // Set sets cookie.
    68  func (c *CookieMan) Set(w http.ResponseWriter, name string, value []byte, opt *CookieOption) error {
    69  	v, err := c.cipher.Encrypt(value)
    70  	if err != nil {
    71  		return err
    72  	}
    73  	http.SetCookie(w, c.cookie(name, base64.URLEncoding.EncodeToString(v), opt))
    74  	return nil
    75  }
    76  
    77  // Get returns a cookie with given name.
    78  func (c *CookieMan) Get(r *http.Request, name string) ([]byte, error) {
    79  	cookie, err := r.Cookie(name)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	ciphertext, err := base64.URLEncoding.DecodeString(cookie.Value)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  	return c.cipher.Decrypt(ciphertext)
    88  }
    89  
    90  // Clear clears a cookie with given name.
    91  func (c *CookieMan) Clear(w http.ResponseWriter, name string) {
    92  	opt := &CookieOption{}
    93  	opt.MaxAge = -1
    94  	http.SetCookie(w, c.cookie(name, "", opt))
    95  }
    96  
    97  func (c *CookieMan) cookie(name, value string, opt *CookieOption) *http.Cookie {
    98  	cookie := c.defaultOpt.Cookie
    99  	cookie.Name = name
   100  	cookie.Value = value
   101  	if opt == nil {
   102  		return &cookie
   103  	}
   104  	if opt.Path != "" {
   105  		cookie.Path = opt.Path
   106  	}
   107  	if opt.Domain != "" {
   108  		cookie.Domain = opt.Domain
   109  	}
   110  	if opt.MaxAge != 0 {
   111  		cookie.MaxAge = opt.MaxAge
   112  	}
   113  	if !opt.Expires.IsZero() {
   114  		cookie.Expires = opt.Expires
   115  	}
   116  	if opt.Secure {
   117  		cookie.Secure = opt.Secure
   118  	}
   119  	if opt.HttpOnly {
   120  		cookie.HttpOnly = opt.HttpOnly
   121  	}
   122  	return &cookie
   123  }