code.gitea.io/gitea@v1.19.3/modules/web/middleware/cookie.go (about)

     1  // Copyright 2020 The Macaron Authors
     2  // Copyright 2020 The Gitea Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package middleware
     6  
     7  import (
     8  	"net/http"
     9  	"net/url"
    10  	"time"
    11  
    12  	"code.gitea.io/gitea/modules/setting"
    13  )
    14  
    15  // MaxAge sets the maximum age for a provided cookie
    16  func MaxAge(maxAge int) func(*http.Cookie) {
    17  	return func(c *http.Cookie) {
    18  		c.MaxAge = maxAge
    19  	}
    20  }
    21  
    22  // Path sets the path for a provided cookie
    23  func Path(path string) func(*http.Cookie) {
    24  	return func(c *http.Cookie) {
    25  		c.Path = path
    26  	}
    27  }
    28  
    29  // Domain sets the domain for a provided cookie
    30  func Domain(domain string) func(*http.Cookie) {
    31  	return func(c *http.Cookie) {
    32  		c.Domain = domain
    33  	}
    34  }
    35  
    36  // Secure sets the secure setting for a provided cookie
    37  func Secure(secure bool) func(*http.Cookie) {
    38  	return func(c *http.Cookie) {
    39  		c.Secure = secure
    40  	}
    41  }
    42  
    43  // HTTPOnly sets the HttpOnly setting for a provided cookie
    44  func HTTPOnly(httpOnly bool) func(*http.Cookie) {
    45  	return func(c *http.Cookie) {
    46  		c.HttpOnly = httpOnly
    47  	}
    48  }
    49  
    50  // Expires sets the expires and rawexpires for a provided cookie
    51  func Expires(expires time.Time) func(*http.Cookie) {
    52  	return func(c *http.Cookie) {
    53  		c.Expires = expires
    54  		c.RawExpires = expires.Format(time.UnixDate)
    55  	}
    56  }
    57  
    58  // SameSite sets the SameSite for a provided cookie
    59  func SameSite(sameSite http.SameSite) func(*http.Cookie) {
    60  	return func(c *http.Cookie) {
    61  		c.SameSite = sameSite
    62  	}
    63  }
    64  
    65  // NewCookie creates a cookie
    66  func NewCookie(name, value string, maxAge int) *http.Cookie {
    67  	return &http.Cookie{
    68  		Name:     name,
    69  		Value:    value,
    70  		HttpOnly: true,
    71  		Path:     setting.SessionConfig.CookiePath,
    72  		Domain:   setting.SessionConfig.Domain,
    73  		MaxAge:   maxAge,
    74  		Secure:   setting.SessionConfig.Secure,
    75  	}
    76  }
    77  
    78  // SetRedirectToCookie convenience function to set the RedirectTo cookie consistently
    79  func SetRedirectToCookie(resp http.ResponseWriter, value string) {
    80  	SetCookie(resp, "redirect_to", value,
    81  		0,
    82  		setting.AppSubURL,
    83  		"",
    84  		setting.SessionConfig.Secure,
    85  		true,
    86  		SameSite(setting.SessionConfig.SameSite))
    87  }
    88  
    89  // DeleteRedirectToCookie convenience function to delete most cookies consistently
    90  func DeleteRedirectToCookie(resp http.ResponseWriter) {
    91  	SetCookie(resp, "redirect_to", "",
    92  		-1,
    93  		setting.AppSubURL,
    94  		"",
    95  		setting.SessionConfig.Secure,
    96  		true,
    97  		SameSite(setting.SessionConfig.SameSite))
    98  }
    99  
   100  // DeleteCSRFCookie convenience function to delete SessionConfigPath cookies consistently
   101  func DeleteCSRFCookie(resp http.ResponseWriter) {
   102  	SetCookie(resp, setting.CSRFCookieName, "",
   103  		-1,
   104  		setting.SessionConfig.CookiePath,
   105  		setting.SessionConfig.Domain) // FIXME: Do we need to set the Secure, httpOnly and SameSite values too?
   106  }
   107  
   108  // SetCookie set the cookies. (name, value, lifetime, path, domain, secure, httponly, expires, {sameSite, ...})
   109  // TODO: Copied from gitea.com/macaron/macaron and should be improved after macaron removed.
   110  func SetCookie(resp http.ResponseWriter, name, value string, others ...interface{}) {
   111  	cookie := http.Cookie{}
   112  	cookie.Name = name
   113  	cookie.Value = url.QueryEscape(value)
   114  
   115  	if len(others) > 0 {
   116  		switch v := others[0].(type) {
   117  		case int:
   118  			cookie.MaxAge = v
   119  		case int64:
   120  			cookie.MaxAge = int(v)
   121  		case int32:
   122  			cookie.MaxAge = int(v)
   123  		case func(*http.Cookie):
   124  			v(&cookie)
   125  		}
   126  	}
   127  
   128  	cookie.Path = "/"
   129  	if len(others) > 1 {
   130  		if v, ok := others[1].(string); ok && len(v) > 0 {
   131  			cookie.Path = v
   132  		} else if v, ok := others[1].(func(*http.Cookie)); ok {
   133  			v(&cookie)
   134  		}
   135  	}
   136  
   137  	if len(others) > 2 {
   138  		if v, ok := others[2].(string); ok && len(v) > 0 {
   139  			cookie.Domain = v
   140  		} else if v, ok := others[2].(func(*http.Cookie)); ok {
   141  			v(&cookie)
   142  		}
   143  	}
   144  
   145  	if len(others) > 3 {
   146  		switch v := others[3].(type) {
   147  		case bool:
   148  			cookie.Secure = v
   149  		case func(*http.Cookie):
   150  			v(&cookie)
   151  		default:
   152  			if others[3] != nil {
   153  				cookie.Secure = true
   154  			}
   155  		}
   156  	}
   157  
   158  	if len(others) > 4 {
   159  		if v, ok := others[4].(bool); ok && v {
   160  			cookie.HttpOnly = true
   161  		} else if v, ok := others[4].(func(*http.Cookie)); ok {
   162  			v(&cookie)
   163  		}
   164  	}
   165  
   166  	if len(others) > 5 {
   167  		if v, ok := others[5].(time.Time); ok {
   168  			cookie.Expires = v
   169  			cookie.RawExpires = v.Format(time.UnixDate)
   170  		} else if v, ok := others[5].(func(*http.Cookie)); ok {
   171  			v(&cookie)
   172  		}
   173  	}
   174  
   175  	if len(others) > 6 {
   176  		for _, other := range others[6:] {
   177  			if v, ok := other.(func(*http.Cookie)); ok {
   178  				v(&cookie)
   179  			}
   180  		}
   181  	}
   182  
   183  	resp.Header().Add("Set-Cookie", cookie.String())
   184  }
   185  
   186  // GetCookie returns given cookie value from request header.
   187  func GetCookie(req *http.Request, name string) string {
   188  	cookie, err := req.Cookie(name)
   189  	if err != nil {
   190  		return ""
   191  	}
   192  	val, _ := url.QueryUnescape(cookie.Value)
   193  	return val
   194  }