cookie.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. package tango
  2. import (
  3. "net/http"
  4. "time"
  5. "fmt"
  6. "strings"
  7. "crypto/sha1"
  8. "crypto/hmac"
  9. "strconv"
  10. "bytes"
  11. "encoding/base64"
  12. "io/ioutil"
  13. )
  14. func isValidCookieValue(p []byte) bool {
  15. for _, b := range p {
  16. if b <= ' ' ||
  17. b >= 127 ||
  18. b == '"' ||
  19. b == ',' ||
  20. b == ';' ||
  21. b == '\\' {
  22. return false
  23. }
  24. }
  25. return true
  26. }
  27. func isValidCookieName(s string) bool {
  28. for _, r := range s {
  29. if r <= ' ' ||
  30. r >= 127 ||
  31. strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", r) {
  32. return false
  33. }
  34. }
  35. return true
  36. }
  37. type Cookies interface {
  38. Get(string) *http.Cookie
  39. Set(*http.Cookie)
  40. Expire(string, time.Time)
  41. Del(string)
  42. }
  43. type cookies struct {
  44. req *http.Request
  45. resp http.ResponseWriter
  46. }
  47. func NewCookie(name string, value string, age ...int64) *http.Cookie {
  48. if !isValidCookieName(name) || !isValidCookieValue([]byte(value)) {
  49. return nil
  50. }
  51. var utctime time.Time
  52. if len(age) == 0 {
  53. // 2^31 - 1 seconds (roughly 2038)
  54. utctime = time.Unix(2147483647, 0)
  55. } else {
  56. utctime = time.Unix(time.Now().Unix()+age[0], 0)
  57. }
  58. return &http.Cookie{Name: name, Value: value, Expires: utctime}
  59. }
  60. func (c *cookies) Get(key string) *http.Cookie {
  61. ck, err := c.req.Cookie(key)
  62. if err != nil {
  63. return nil
  64. }
  65. return ck
  66. }
  67. func (c *cookies) Set(ck *http.Cookie) {
  68. http.SetCookie(c.resp, ck)
  69. }
  70. func (c *cookies) Expire(key string, expire time.Time) {
  71. ck := c.Get(key)
  72. if ck != nil {
  73. ck.Expires = expire
  74. c.Set(ck)
  75. }
  76. }
  77. func (c *cookies) Del(key string) {
  78. c.Expire(key, time.Date(1900, 1, 1, 0, 0, 0, 0, time.Local))
  79. }
  80. func getCookieSig(key string, val []byte, timestamp string) string {
  81. hm := hmac.New(sha1.New, []byte(key))
  82. hm.Write(val)
  83. hm.Write([]byte(timestamp))
  84. hex := fmt.Sprintf("%02x", hm.Sum(nil))
  85. return hex
  86. }
  87. // secure cookies
  88. type secureCookies struct {
  89. *cookies
  90. secret string
  91. }
  92. func parseSecureCookie(secret string, value string) string {
  93. parts := strings.SplitN(value, "|", 3)
  94. val, timestamp, sig := parts[0], parts[1], parts[2]
  95. if getCookieSig(secret, []byte(val), timestamp) != sig {
  96. return ""
  97. }
  98. ts, _ := strconv.ParseInt(timestamp, 0, 64)
  99. if time.Now().Unix()-31*86400 > ts {
  100. return ""
  101. }
  102. buf := bytes.NewBufferString(val)
  103. encoder := base64.NewDecoder(base64.StdEncoding, buf)
  104. res, _ := ioutil.ReadAll(encoder)
  105. return string(res)
  106. }
  107. func (c *secureCookies) Get(key string) *http.Cookie {
  108. ck := c.cookies.Get(key)
  109. if ck == nil {
  110. return nil
  111. }
  112. v := parseSecureCookie(c.secret, ck.Value)
  113. if v == "" {
  114. return nil
  115. }
  116. ck.Value = v
  117. return ck
  118. }
  119. func NewSecureCookie(secret, name string, val string, age ...int64) *http.Cookie {
  120. var buf bytes.Buffer
  121. encoder := base64.NewEncoder(base64.StdEncoding, &buf)
  122. encoder.Write([]byte(val))
  123. encoder.Close()
  124. vs := buf.String()
  125. vb := buf.Bytes()
  126. timestamp := strconv.FormatInt(time.Now().Unix(), 10)
  127. sig := getCookieSig(secret, vb, timestamp)
  128. cookie := strings.Join([]string{vs, timestamp, sig}, "|")
  129. return NewCookie(name, cookie, age...)
  130. }
  131. func (c *secureCookies) Expire(key string, expire time.Time) {
  132. ck := c.Get(key)
  133. if ck != nil {
  134. ck.Expires = expire
  135. c.Set(ck)
  136. }
  137. }
  138. func (c *secureCookies) Del(key string) {
  139. c.Expire(key, time.Date(1900, 1, 1, 0, 0, 0, 0, time.Local))
  140. }